前言
WAF(Web应用防护系统)最近变得非常流行,针对从小型企业到大型企业的不同客户,WAF供应商也设计了许多有针对性的解决方案。 WAF之所以很受欢迎,是因为它是保护Web应用程序的复杂解决方案,涵盖了所有防护任务。这就是为什么Web应用程序开发人员可以在某些安全方面依赖WAF的原因。尽管如此,WAF还是存在某些漏洞,它并不完美。
那么,WAF应该如何证明它在项目中的实现是合理的呢?它的主要功能是根据WAF的分析,检测和阻止任何有异常或攻击向量的请求。这种分析不能妨碍合法用户与web应用程序的交互,同时必须准确、及时地检测到任何攻击企图。为了实现这些功能,WAF开发人员使用正则表达式、标签器、行为分析、信誉分析,当然还有机器学习。通常,所有这些技术一起使用。WAF还可以实现其他功能,DDoS保护、禁止攻击者的IP、监控可疑IP、添加安全标头(X-XSS-Protection,X-Frame-Options等)、向cookie添加http-only标志、实现HSTS机制和CSRF令牌。此外,一些WAF还为网站提供了JavaScrIPt客户端模块。
当然,WAF为黑客和测试人员设置了一些障碍。WAF使漏洞发现和利用更加耗费资源,除非攻击者知道特定WAF的有效绕过方法。在分析受WAF保护的web应用程序时,自动扫描器实际上毫无用处。WAF是对脚本骇客新手 (script-kiddy) 的可靠保护。不过,一个经验丰富的黑客或没有足够动机的研究人员可能不会愿意浪费时间去寻找绕过它的方法。需要注意的是,web应用程序越复杂,其攻击面越大,越容易找到绕过方法。
在我们最近的审计中,我们经常会发现不同的WAF,稍后我们会讨论其中的一些。我们已经在两个主要场景中测试了两个专有的WAF:
1.我们知道web应用程序中存在一定的漏洞,我们试图绕过WAF来利用它;
2.我们不知道任何漏洞,所以我们必须找到漏洞,然后利用它绕过WAF。
首先,让我们仔细研究一下WAF背后的基本机制,看看它们有什么问题。
现代WAF
为了能够有效地找到各种绕过WAF的方法,首先,我们需要找到请求分类的现代机制。每个WAF都是特定的、唯一构建的,但是有一些通用的分析方法。
基于正则表达式的规则
现有的WAF大多使用基于正则表达式的规则,开发人员通过研究一组已知的攻击,以确定可能指向攻击的关键语法结构。基于这些数据,开发人员创建可以找到此类语法结构的正则表达式。这听起来很简单,但是这种方法有一定的缺点。首先,正则表达式可以应用于单个请求,甚至单个请求参数,这明显降低了此类规则的效率,并留下了一些盲点。其次,正则表达式的语法和文本协议的复杂逻辑允许替换等价的结构和使用不同的符号表示,在创建这些规则时会导致错误。
Scorebuilding
了解网络防火墙和反病毒工作原理的人应该熟悉这种机制,它不会检测攻击,但会补充其他机制,使其更加精确和灵活。问题是,请求中的“可疑”结构不是检测攻击的充分条件,并可能导致许多误报。这个问题是通过实行分级制度来解决的,因为基于正则表达式的每条规则都由其关键性信息补充,在确定所有触发的规则之后,总结总临界值。如果总临界值达到阈值,则检测到攻击并阻止请求。尽管这个机制很简单,但该机制被证明是有效的并且广泛用于这些任务。
标签器
这种检测方法在Black Hat 2012年以C/C+库libinject的形式提出,可以快速、准确地识别SQL注入。目前,有许多针对不同编程语言的libinject端口,如PHP、Lua、Python等。该机制搜索作为一组令牌表示的签名。一定数量的签名被列入黑名单,它们被认为是不受欢迎和恶意的。换句话说,在分析某个请求之前,它被转换成一组令牌。令牌分为特定类型,如变量、字符串、常规操作符、未知操作符、数字、注释、类union操作符、函数、逗号等。该方法的主要缺点之一是,可能会构建导致令牌错误形成的结构,因此请求签名将与预期的不同。这些结构通常被称为令牌破解程序,我们将在稍后讨论它们。
行为分析
检测和阻止请求中的利用尝试并不是WAF的唯一任务,识别漏洞搜索过程也很重要,WAF必须做出相应的反应。它可以表现为扫描尝试、目录暴力破解、参数模糊和其他自动方法。高级WAF可以构建请求链,并阻止发送不寻常请求的尝试。这种方法与其说是检测攻击,不如说是阻碍了漏洞搜索的过程。限制每分钟的请求数量不会影响普通用户,但对于在多线程中工作的扫描程序来说,将会受到严重的影响。
信誉分析
这是直接继承自防火墙和杀毒软件的另一种机制。当前,几乎任何WAF都包含VPN、匿名者、Tor节点和僵尸网络的地址列表,以阻止来自这些地址的请求。高级WAF可以自动更新其基础架构,并根据分析的流量添加额外的条目。
机器学习
这是WAF最值得怀疑的方面之一,因为“机器学习”这个术语相当广泛,包括许多技术和方法。此外,它只是人工智能的一个类。机器学习的“实现”或“人工智能的使用”是非常流行的营销用语。其实人们并不清楚到底使用了哪些算法,那些真正使用机器学习并有效地使用它的供应商不愿意分享他们的经验。
首先,机器学习完全依赖于它所训练的数据,这就产生了一定的问题。开发人员应该拥有最新的、完整的攻击数据,作为分析基础,而这是很难实现的。这就是为什么许多开发人员要记录他们的WAF的结果,并与提供IDS和SIEM系统的供应商合作,以获得真实的攻击示例。第二, 在抽象的Web应用程序上训练的模型可能在真实的Web应用程序上完全无效。为了获得更好的模型质量,建议在实施阶段另外训练模型。
识别WAF
WAF开发人员使用不同的方法通知用户请求被阻止,因此,我们可以通过分析对攻击请求的响应来识别WAF。这通常被称为WAF指纹。如果WAF由于某种原因没有更新,那么指纹会有所帮助。专有WAF的开发人员关心他们的客户并实现自动更新。此外,一旦我们确定了WAF,我们仍然可以使用关于它的信息来了解它的逻辑。
以下是可能的WAF指纹列表:
额外的cookie;
任何响应或请求的附加标头;
响应内容(如果被阻止请求);
响应代码(如果被阻止请求);
IP地址(云WAF);
JS客户端模块(客户端WAF)。
让我们用一些具体的示例来说明:
PT AF
被阻止请求的响应代码:403,可以将客户端模块waf.js插入响应页面,响应对象如下:
<h1>Forbidden</h1> <pre>Request ID: 2017-07-31-13-59-56-72BCA33A11EC3784</pre>
由waf.js添加的额外标头:
X-RequestId: cbb8ff9a-4e91-48b4-8ce6-1beddc197a30
Nemesida WAF
被阻止请求的响应代码:403,响应对象如下:
<p style="font-size: 16px; align: center;"> Suspicious activity detected. Access to the site is blocked. If you think that is's an erroneous blocking, please email us at <a href="mailto:[email protected]">[email protected]</a> and specify your IP-address. </p>
Wallarm
被阻止请求的响应代码:403,附加标头:nginx-wallarm。
Citrix NetScaler AppFirewall
额外的cookie:
ns_af=31+LrS3EeEOBbxBV7AWDFIEhrn8A000; ns_af_.target.br_%2F_wat=QVNQU0VTU0lP TklEQVFRU0RDU0Nf?6IgJizHRbTRNuNoOpbBOiKRET2gA
Mod_Security ver. 2.9
被阻止请求的响应代码:403,响应对象如下:
<head> <title>403 Forbidden</title> </head><body> <h1>Forbidden</h1> <p>You don't have permission to access /form.php on this server.<br /></p>
Mod_Security ver. 2.9
被阻止请求的响应代码:406或501,在响应对象中,你可以找到mod_security、mod_security或NOYB。
Varnish防火墙
将以下标头添加到响应中:
X-Varnish: 127936309 131303037. X-Varnish: 435491096 Via: 1.1 varnish-v4
WAF开发人员自己决定在阻止请求时返回哪些响应代码以及一些特定的代码。例如,Web_Knight WAF返回代码999, 并且dotDefender返回带有空响应对象或错误消息的代码200。除此之外,开发人员还可以使用其他内容定制响应页面。
WAF和其他应用程序一样,也在不断发展和变化。这就是为什么经常检查指纹的相关性很重要。
WAF绕过备忘单
寻找绕过WAF的方法的基本思想是转换我们需要的请求,这样它对web应用程序仍然有效,但对WAF无效。对于这种类型的WAF,能够为许多不同类型的服务器提供服务是很重要的,包括“外来的”服务器,如Unicorn、Tornado、Weblogic、Lighttpd等。每个服务器可能以不同的方式对HTTP请求进行解析,WAF也应该考虑这一点。因此,攻击者可以使用服务器的HTTP请求解析细节来找到绕过WAF的方法。
很难通过WAF安全机制或使用领域对所有可能的绕过WAF的方法进行分类,相同的绕过方式可以相互作用,并同时影响WAF的不同组件。下面描述的技术是从开放资源中收集的,或者是在我们自己的研究中发现的,实践证明是有效的。
添加特殊符号
添加的各种特殊符号可能违反WAF的分析逻辑,同时又被服务器有效地解释。这些符号的变化可能是不同的,它们可能被转换成urlencode(尽管大多数WAF可以处理这个问题)或其他编码。也可以在没有任何编码的情况下,以原始格式将特殊符号插入到请求中,这对于WAF来说可能是个意外。例如,在本文的示例中,\r\n\r\n可能被认为是HTTP请求对象的结尾,而空字节可能完全违反正则表达式和数据解析器的分析逻辑。此外,还可以使用来自ASCII表的前20个符号的其他特殊符号。
示例
0x00:空字节;
0x0D:回车;
0x0A:换行;
0x0B:垂直制表符;
0x09:水平制表符;
0x0C :新建页面。
在搜索绕过时,在请求对象的不同位置插入特殊符号是非常有用的,而不仅仅是插入参数值。例如,如果请求是一个JSON格式的,我们可以在参数中插入null字节,也可以在参数之间插入null字节,包括JSON的开头和结尾。这同样适用于POST请求主体的其他格式,总的来说,我们建议寻找可以被WAF监控和解析的位置,并尝试在那里使用不同的特殊符号。
例如:
{"id":1337,"string0x00":"test' or sleep(9)#"} {"id":1337,"string":"test'/*0x00*/ or sleep(9)#"} {"id":1337,"string"0x0A0x0D:"test' or sleep(9)#"}
<a href="ja0x09vas0x0A0x0Dcript:alert(1)">clickme</a> <a 0x00 href="javascript:alert(1)">clickme</a> <svg/0x00/onload="alert(1)">
id=1337/*0x0C*/1 UNION SELECT version(), user() --
为清楚起见,我们用十六进制表示替换了的特殊符号。
替换空间符号
在大多数语法中,关键字和操作符必须分开,但由于没有指定的空格符号。因此,可以使用0x0B(垂直制表符)或0x09(水平制表符)代替普通的0x20(空格)。在SQL中,分隔结构的空间是/ ** /(多行SQL注释),#\ r \ n(单行SQL注释,以换行符结尾), – \ r \ n(代替单行SQL注释,用换行结束)。下面是一些具体示例:
http://test.com/test?id=1%09union/**/select/**/1,2,3 http://test.com/test?id=1%09union%23%0A%0Dselect%2D%2D%0A%0D1,2,3
此外,我们还可以使用该语言的语法转换表达式,以消除空格。例如,在SQL中,我们可以使用括号:
UNION(SELECT(1),2,3,4,5,(6)FROM(Users)WHERE(login='admin'))
在JS中,使用/:
<svg/onload=confirm(1)>
更改编码
这种方法是基于使用不同的编码来防止WAF在某些地方解码数据,例如,如果用其url代码替换符号,WAF将无法理解它必须解码数据并传递请求。同时,web应用程序将接受相同的参数并成功解码。
HTML符号的十进制形式为&#106或&#0000106.WAF可能知道短版本而不知道具有附加零的版本(总共应该不超过7个符号)。同样,HTML符号的十六进制形式为&#x6A或&#x000006A。
还有一个使用反斜杠\转义字符的技巧,如下所示:
<svg/on\load=a\lert(1)>
不过,这取决于web应用程序如何处理这些输入数据。因此,序列\l将被处理为l并转换为单个符号,WAF可以单独处理每个符号,它可以中断正则表达式或另一个WAF逻辑。因此,WAF会漏掉关键字。使用这种技术,我们不能转义字符 \n, \r, \t,因为它们将被转换成不同的字符:换行符,回车符和制表符。
HTML编码可以在标签属性中使用,例如:
<a href="javascript:alert(1)">clickme</a> <input/onmouseover="javascript:confirm(1rpar;">
这些字符可以很容易地替换为目标字符的另一种HTML表示形式,你可以在这里https://dev.w3.org/html5/html-author/charref查找不同的字符转换。
除了HTML编码,我们还可以插入\u字符:
<a href="javascript:\u0061lert(1)">Clickme</a> <svg onload=confir\u006d(1)>
我们还来看看与插入特殊字符相关的向量,让我们用HTML编码破解有效负载:
<a href="ja	vas cript:alert(1)">clickme</a>
在本文的示例中,我们还可以放置其他分隔字符。
因此,我们建议将不同的编码与其他方法结合使用,例如,对特殊字符进行编码。
搜索非典型的等效句法结构
这种方法的目的是找到一种WAF开发人员没有考虑到的利用方式,或者在机器学习训练样本中没有出现的攻击向量。简单的例子是JavaScrIPt函数:this, top self, parent, frame;标签属性: data-bind,ontoggle,onfilterchange,onbeforescriptexecute,onpointerover,srcdoc;SQL运算符:lpad,field,bit_count。
下面是一些例子:
<script>window['alert'](0)</script> <script>parent['alert'](1)</script> <script>self['alert'](2)</script>
SELECT if(LPAD(' ',4,version())='5.7',sleep(5),null);
你也可以使用JavaScrIPt表达式的非符号表示:
JSFuck;
Jjencode;
Xchars.js。
其中,一个明显的问题是长有效载荷。
采用这种技术的WAF绕过依赖于攻击和被利用的技术栈,著名的ImageTragick漏洞就是一个很好的例子。大多数保护免受此攻击的WAF都将url、容量和标签等关键字列入黑名单。另外,大多数论文和描述此漏洞的PoC可能还会使用其他关键字,例如ephemeral和pango。因此,可以使用这些关键字绕过WAF。
HTTP参数污染(HPP)和HTTP参数碎片(HPF)
HPP攻击基于服务器如何解释具有相同名称的参数,以下是一些可能的绕过参数:
服务器使用最后接收到的参数,而WAF只检查第一个参数;
服务器将类似参数的值合并,而WAF只会单独检查它们。
你可以在下表中比较不同的服务器如何处理相同的参数:
而HPF的攻击则基于不同的原则,如果一个web应用程序的逻辑将请求中的两个或多个参数联合起来,则攻击者可以将请求分开以绕过某些WAF检查。
下面的SQL注入就是这种攻击的一个例子:
http://test.com/url?a=1+select&b=1+from&c=base
HPF和HPP非常相似,但是前者针对的是web应用程序,后者针对的是它所运行的环境。结合这些技术可以增加绕过WAF的机会。