【网络安全】WAF Bypass——长亭雷池、安全狗下的SQL绕过

目录

一、前言

二、搭建环境

[三、尝试绕过雷池防护的 sqli-labs 靶场](#三、尝试绕过雷池防护的 sqli-labs 靶场)

四、通用型入门绕过思路

[4.1 技术原理及绕过思路:](#4.1 技术原理及绕过思路:)

[4.2 multipart/form-data](#4.2 multipart/form-data)

[4.2.1 0x00 截断filename](#4.2.1 0x00 截断filename)

[4.2.2 双写上传描述行【绕过】](#4.2.2 双写上传描述行【绕过】)

[4.2.3 双写整个part开头部分](#4.2.3 双写整个part开头部分)

[4.2.4 构造假的part部分1【绕过】](#4.2.4 构造假的part部分1【绕过】)

[4.2.5 构造假的part部分2 【绕过】](#4.2.5 构造假的part部分2 【绕过】)

[4.2.6 两个boundary](#4.2.6 两个boundary)

[4.2.7 两个Content-Type](#4.2.7 两个Content-Type)

[4.2.8 空boundary](#4.2.8 空boundary)

[4.2.9 空格boundary](#4.2.9 空格boundary)

[4.2.10 boundary 中的逗号](#4.2.10 boundary 中的逗号)

[4.3 进阶绕过](#4.3 进阶绕过)

[4.3.1 0x00 截断进阶【绕过X2】](#4.3.1 0x00 截断进阶【绕过X2】)

[4.3.2 boundary 进阶](#4.3.2 boundary 进阶)

[4.3.3 单双引号混合进阶](#4.3.3 单双引号混合进阶)

[4.3.4 urlencoded伪装成为multipart【绕过】](#4.3.4 urlencoded伪装成为multipart【绕过】)

[4.4 skip_upload 进阶](#4.4 skip_upload 进阶)

五、总结


一、前言

记录一下在测试环境中的 waf 绕过思路和技巧。本文方法仅用于技术研习提升企业安全防护能力,严禁一切未授权测试与非法利用。


二、搭建环境

雷池社区版 + 宝塔面板 + SQLi-LABS + Windows10 + 安全狗

雷池 WAF | 下一代 Web 应用防火墙 | 免费使用

宝塔linux面板,一键安装LAMP/LNMP/SSL/Tomcat

安全狗-领先云安全服务与解决方案提供商|云原生安全|服务器安全|网站安全|态势感知


三、尝试绕过雷池防护的 sqli-labs 靶场

搭建好环境后,首先来看一下第11关的靶场,通过POST传参可以看到是查询了两个字段,尝试构造注入语句。

sql 复制代码
 admin' union select 1,users()#

sql 注入已经被雷池拦截了,现在尝试绕过需要考虑拦截了哪些函数。接下来通过构造 sql 语句来进行测试,看一下 waf 认为不合法的传入都有什么?

admin' and updatexml(1,concat(0x7e,user(),0xe7),1)#

admin' and aaa(1,concat(0x7e,user(),0xe7),1)#

admin' and aaa(1,concat(0x7e,ccc(),0xe7),1)#

admin' and aaa(1,bbb(0x7e,ccc(),0xe7),1)#

构造的这四个语句都被 waf 拦截了,很明显最后一个根本不是注入语句了,但是仍然被拦截。

那问题出在 and 上,继续构造sql语句进行测试。第一个没有被拦截,第二个**&& 替换 and** 没有被拦截,第三个updatexml 报错函数被拦截,第四个 concatusers 没被拦截。最终结果就是 and 和 updatexml 报错函数被拦截了,and 替换&&没有被杀掉,updatexml报错函数怎么进行绕过?将updatexml()报错函数替换为ST_LatFromGeoHash()(mysql>=5.7.x)最终系统函数被拦截了。。

admin' andb aaa(1,bbb(0x7e,ccc(),0xe7),1)#

admin' && aaa(1,bbb(0x7e,ccc(),0xe7),1)#

admin' && updatexml(1,bbb(0x7e,ccc(),0xe7),1)#

admin' && aaa(1,concat(0x7e,user(),0xe7),1)#

admin' && ST_LatFromGeoHash(concat(0x7e,user(),0x7e))#

系统函数被杀了,尝试@@ 绕过,结果还是不行。或者可以使用 MySQL 自带库 information 进行查询,就不测试了因为关键词也被杀了。。

【网络安全】SQL注入------无列名注入_sql无联名注入-CSDN博客

admin' && ST_LatFromGeoHash(concat(0x7e,@@user(),0x7e))#

admin' && ST_LatFromGeoHash(concat(0x7e,(select 1,2,3),0x7e))#


四、通用型入门绕过思路

进入正题,以上绕过只是想着绕过查杀了哪些函数,就算绕过一句语句,在后续的查询语句中很有可能会被继续拦截。这种只是属于事件型的绕过。本次事件型绕过就不继续往下做了。我们追求通用型的绕过,这一次要绕过的方案是通过差异化进行绕过,一但绕过所有语句将畅通无阻。通用型的理念就是差异化绕过,waf认为传入的是合法的值,而后端接收的确是非法的值。

4.1 技术原理及绕过思路:

先来看一下师傅们的思路:

首先谈一下WAF。Web应用防火墙,主要用途是对HTTP(s)协议进行校验,拦截恶意的攻击请求,放行正常的业务请求。从架构来看,主要分为:网络层、应用层、云WAF 三类。从绕过来看,分为通用型绕过和单一规则绕过。通用型绕过即完全绕过WAF防护,一 旦产生绕过后,可以利用该Payload实现任意一种攻击;而单一规则绕过,则仅能够绕过特 定规则,例如:SQL注入规则中使用 select-1.1from......来绕过 select\b[\s\S]*\bfrom 这一正则规则,绕过以后仅能够实现SQL注入攻击。我所致力研究的属于前者。

从网络层、应用层、云WAF三类场景来看他们的绕过思路也有所区别,例如,对于传 统的网络层WAF,采用 chunked编码即可绕过,目前多数WAF厂商已经修复,但是我们仍 然可以在网络层发包这一方向进行尝试和探索。对于应用层WAF,WAF的处理引擎是经过 前端Nginx或Apache(大多数场景都是Nginx及Tengine)完成HTTP协议初步解析以后, 再转发给WAF处理引擎的,因而一些网络层组包的技术是无法绕过的。那么就需要我们去 研究:对于一个HTTP请求,Nginx解析了什么内容?交给后面的PHP、ASP又解析了什么 内容?

本文介绍的思路主要围绕: multipart/form-data。主要针对于POST参数的,对于漏洞 点在GET参数位置则用处不大。


4.2 multipart/form-data

以php为例写一个测试脚本,了解除了常规的 application/x-www form-urlencoded 以外,还有 multipart/form-data 这种形式。基于 Nginx+PHP 的架构,Nginx 实际上是不负责解析 multipart/form-data 的 body 部分,而是交由PHP来解析,因此WAF所获取的内容就很有可能与后端的PHP发生不一 致。

php 复制代码
<?php
echo "POST CONTENT: " . file_put_contents("php://input") . "\n";
echo "POST: "; 
var_dump($_POST);
echo "FILES: ";
var_dump($_FILES);
?>

当我们用 multipart 形式进行文件上传时,实际上与 urlencoded 是一个效果,参数并没有进入_FILES 数组,而是进入了_POST数组。文件上传 POST 也可以接到,为什么可以接到,少一个参数,缺失这个参数就不认为是文件上传了,如果没有 filename 这个字段,那么认为就是post提交。 正常我认为 file 就是上传 file,post 就是上传 post,这里是一个上传图片,实际上还是在 post 下接收到了。那何时是上传文件?何时是POST参数呢?这个关键点在于有没有一个完整的 filename=

加上了 filename= 以后的效果:

Bypass WAF 的核心思想在于,一些WAF产品处于降低误报考虑,对用户上传文件的内 容不做匹配,直接放行。事实上,这些内容在绝大多数场景也无法引起攻击。但关键问题在于,WAF 能否准确有效识别出哪些内容是传给_POST 数组的,哪些传给_FILES 数组?如果不能,那我们是否就可以想办法让WAF以为我们是在上传文件,而实际上却是在POST 一个参数,这个参数可以是命令注入、SQL注入、SSRF等任意的一种攻击,这样就实现了通用WAF Bypass。

4.2.1 0x00 截断filename

0x00截断在php5.2版本出现过,也就是遇到\0自动结束,因为C语言的结束符就是\0。我们看一下如何截断filename。

在filename 之前加入了0x00,而有些WAF在检测前会删除HTTP协议中的0x00, 这样就导致了WAF认为是含有filename的普通上传,而后端PHP则认为是POST参数。

进行测试我们的靶场,将第11关靶场字段修改成一个,更方便进行测试。输入正确user,查询到了数据,证明接收到的确实是post提交,00截断成功。

4.2.2 双写上传描述行【绕过】

双写后,一些WAF会取第二行,而实际PHP会获取第一行。php获取的确实是第一个,那 waf 获取的是第二个吗?

通过双写上传描述行成功绕过!!

4.2.3 双写整个part开头部分

该参数会引入一些垃圾数据,在命令注入及 SQL 注入的攻击场景,需要尽可能将前面的内容闭合。就是post提交在后端的是光标所选部分,需要注意闭合前面的垃圾数据。

4.2.4 构造假的part部分1【绕过】

第二次绕过了长亭的 waf ,很明显 waf 取的是第一个,而后端接收到了第二个。

4.2.5 构造假的part部分2 【绕过】

这里比前一种【构造假的part部分1】少了一个换行,数据纯净了许多。这种通用型只要能绕过一次那么就畅通无阻。报错注入和联合查询等都是成功绕过。

4.2.6 两个boundary

对于php来说,真正的 boundary 是 a, waf 也是一样。

4.2.7 两个Content-Type

真正的 boundary 仍然是a,经测试没有取到b。同样也没有绕过长亭的 waf。

4.2.8 空boundary

boundary为空,php依然取的是里面的,现在想让 waf 取空boundary,但是没有绕过。

4.2.9 空格boundary

同样可以接收到空格boundary,但是没有绕过waf。

4.2.10 boundary 中的逗号

同样php取值还是取的里面的,和上面的几种方法类似,都没有绕过waf。

4.3 进阶绕过

4.3.1 0x00 截断进阶【绕过X2】

如果是双写,其实是以第一行为主的,这样就是上传文件。但如果我们在适当的地方加入0x00、空格 和 \t , 就会破坏第一行,让PHP以第二行为主。

第一种 在Content-Disposition后加入\t,从而破坏第一行,让php取第二行,但是waf也是取的第二行,没有绕过。

第二种 在Content-Disposition前加入\t ,依然没有绕过。

第三种 在 filename 后加入\t ,又一次绕过了长亭的waf。

此外在name="uname"加入00截断,也是可以的。 最容易被忽视的是参数名中的0x00。

4.3.2 boundary 进阶

boundary 的名称是可以前后加入任意内容的,WAF如果严格按 boundary 去取,可能又会被绕过。将boundary前后加入字符,会被php忽略,那waf是怎么样的?

waf 的取值和php一样,没有绕过长亭 waf 也取到了 boundary=a

4.3.3 单双引号混合进阶

Content-Disposition中的字段使用单引号还是双引号?想破坏掉file的取值让php取第二个,但是没有绕过长亭的 waf。

4.3.4 urlencoded伪装成为multipart【绕过】

这个poc很特殊。实际上是 urlencoded,但是伪装成了 multipart,通过&来截取前后装饰部分,保留 uname 参数的完整性。理论上 multipart/form-data 下的内容不进行urldecoded, 一些WAF也正是这样设计的,这样做本没有问题,但是如果是 urlencoded 格式的内容,不进行 url 解码就会引入%0a这样字符,而这样的字符不解码是可以直接绕过防护规则的,从而导致了绕过。

4.4 skip_upload 进阶

在PHP 中,skip_upload 是可以来控制上传行是否为上传文件的。

前面内容中介绍了,如果在第一行的 Content-Disposition 位置添加 \0,是有可能引起第一行失效,从而从上传文件变为 POST参数的。除此以外,我们来看一下php源码php 5.3.3/main/rfc1867.c ,其中 line: 991 有这样一段内容:

php 复制代码
if (!skip_upload) {  
char *tmp = param;  
long c = 0;  
while (*tmp) {  
if (*tmp == '[') {  
c++;  
} else if (*tmp == ']') {  
c--;  
if (tmp[1] && tmp[1] != '[') {  
skip_upload = 1;  
break;  
}  
}  
if (c < 0) { 
skip_upload = 1;  
break;  
}  
tmp++; }  
}

其中的param参数是name="uname" 也就是 id 这个参数,那么如何能让它skip_upload ? 通过想办法进入c < 0,c原本是 0,遇到 [ 就自增一,遇到 ] 就减一。那么,我们构造 name="f]" 即可让c=-1 。

虽然没有绕过,事实上,只要参数中有不成对匹配的左右中括号都可以引发skip_upload。


五、总结

本次在waf下测试和分析绕过waf的技巧和思路到此结束,以上共有六种方式能够绕过长亭的雷池waf。经过后续测试,发现长亭雷池对webshell的查杀并不是很强,主要还是防御 Top10 漏洞。上述研究的绕过技巧在安全狗下也有多种方式能够绕过。本文方法仅用于技术研习提升企业安全防护能力,严禁一切未授权测试与非法利用。

相关推荐
万行6 小时前
点评项目(Redis中间件)&第二部分Redis基础
java·数据库·redis·spring·中间件
茫忙然6 小时前
【WEB】[BUUCTF] <GXYCTF2019禁止套娃>《php函数的运用》
php·web·rce
Hy行者勇哥8 小时前
现代软件系统架构:前端、后端、数据库、部署、算法与AI学习的结构与交互分析
前端·数据库·学习
TDengine (老段)8 小时前
TDengine 日期时间函数 DAYOFWEEK 使用手册
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
九河云9 小时前
AI+云,双擎驱动——华为云让智能触手可及
网络·人工智能·科技·安全·华为云
DS小龙哥9 小时前
STM32F103C8T6的智能医疗药品存储柜系统设计与华为云实现
数据库·stm32·华为云
lypzcgf9 小时前
Coze源码分析-API授权-删除令牌-后端源码
数据库·人工智能·后端·系统架构·开源·go·安全架构
一伦明悦დ9 小时前
jetson开发板Ubuntu系统Docker中使用 MySQL 数据库详解-安装与配置指南
数据库·mysql·ubuntu
学Java的bb10 小时前
后端Web实战-多表操作&员工列表查询
数据库