今天我们来接着上一篇,讲讲WAF绕过技术的其他几个方面。
Unicode标准化
让Unicode标准化是Unicode的一个功能,用于比较看起来相似的Unicode符号。例如,符号“ª”和“ᵃ”有不同的代码,但肉眼看起来非常相似。标准化之后他们都将看起来像一个简单的'a',并且被认为是相同的。标准化允许将一些复杂的unicode符号转换为更简单的代替符号。有一个Unicode规范化表,其中包含所有Unicode符号及其可能的规范化。使用它,你可以制作不同的有效载荷,并将它们与其他方法结合起来。尽管如此,它并不适用于所有web应用程序,并且非常依赖于运行环境。PHP大马
例如,在上表中,我们可以看到符号<和<都转换为简单的<..如果应用程序在标准化之后使用HTML编码,那么标准化符号<很可能被编码为<。但是,在其他情况下,开发人员可能忽略了这个功能,而没有编码Unicode符号。这样,我们得到了非HTML编码的符号<和>,可以转化为XSS攻击。 WAF可能无法理解Unicode符号,它可能根本没有理解这些技巧的规则,机器学习也可能没用,在使用Unicode规范化的Web应用程序中找到绕过方法时,我们不仅可以替换<>,还可以替换有效载荷中的其他符号。
例如:
<img src﹦x onerror=alert︵1)>
最近,在HackerOne的Rockstar BugBounty程序中发现了这个漏洞。没有WAF,只有严格的用户输入过滤:
令牌破坏程序(Token breaker)
对令牌程序的攻击试图在所谓的令牌破坏程序的帮助下,攻击将请求拆分为令牌的逻辑。令牌破坏程序是允许影响字符串元素和特定令牌之间的通信的符号,因此可以通过签名绕过搜索。但是当使用令牌破坏程序时,请求必须保持有效。下面的请求是使用令牌破坏程序进行攻击的一个示例。
SELECT-@1,version()
其中-@是令牌破坏程序,其中有一个chear表,是通过mysql模糊测试并在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)# ----
以下是一个更有趣的示例:
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服务器的解析器查找第一个“boundary”条目,然后查找“=”符号,之后才定义边界的值。反过来,WAF解析器只查找“boundary=”条目,然后定义边界的值。如果满足这些条件,WAF将无法在请求中找到边界,因此它将无法找到并分析参数。相反,web服务器将获取请求并处理参数。这种攻击也将以另一种方式工作,即web服务器解析器查找“boundary=”,而WAF解析器只查找“boundary”。在这种情况下,我们只需要将实际边界从第一个改为第二个即可。
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--
这种攻击还使用了特殊字符,在边界参数中,我们添加了空字节,以便web服务器将其关闭,但是WAF将完全接受它。在这种情况下,WAF无法分析参数,因为它无法找到其边界。
绕过机器学习
绕过机器学习进行攻击的逻辑很简单,机器学习的前提是我们必须构造一个满足训练统计模型参数的攻击样本。但这在很大程度上取决于WAF是如何训练的以及使用了什么训练模型。有时候可以找到漏洞,有时候则不行。通常,在实践过程中,带有机器学习的WAF需要根据对客户端web应用程序的请求进行额外的培训。这对于测试者来说是一个问题,因为他们无法测试看起来很像并且在不同请求之间变化不大的参数,因为任何偏离通常参数形式的内容都会被认为是异常。假设有一个到api.test.com/getuser?id=123的请求,参数ID始终为数字,并且在训练样本中为数字。如果机器学习模块在这个参数中发现数字以外的东西,它很可能会认为这是一个异常。在举一个例子:假设WAF被训练为使用带有markdown文本的POST参数对api.test.com/setMarkDown的POST请求进行分类。显然,可能有引号、特殊符号和markdown中的任何东西。在这种情况下,绕过机器学习模块要容易得多,因为WAF允许引用引号和特殊符号。
另外,根据实践中的示例,我们将展示由于上面描述的绕过方法导致的参数解析问题,它并不总是像机器学习模块那样进行深度学习。
通常,我们必须考虑测试请求及其参数的细节,假定WAF可能允许引用参数值的任何可能选项,并以此为基础进行模型构建。
什么时候WAF没用?
WAF分析请求并查找其中的异常行为,但是它不能发现某些类型的漏洞。例如,逻辑漏洞,它没有异常,但是有一些破坏web应用程序逻辑的操作。最可能的情况是,WAF在竞争条件、IDOR和不安全的用户身份验证中也是无用的。
现有的自动查找工具
有一些自动工具来寻找WAF绕过,它们由该领域的爱好者编写。以下是一些比较有名的工具:天天好彩
lightbulb-framework:用于测试受WAF保护的web应用程序的完整框架,它是用Python编写的,并作为Burp套件的插件进行了额外的修改。它的主要特点是以下两种算法:
GOFA :一种主动机器学习算法,可以分析Web应用程序中参数的过滤和清理情况;
SFADiff:基于符号有限自动机(symbolic finite automats ,SFA)训练的偏差黑盒测试算法。它允许发现web应用程序行为的差异,这有助于识别WAF并找到绕过方法。
Bypass WAF :一个Burp Suite的插件,允许根据不同的规则和编码更改设置请求对象中元素的自动更改,它还可以自动化HPP攻击。
WAFW00F:一种用于WAF识别的工具,用Python编写。它有一个不错的WAF基础,仍在不断更新。但是,结果可能不精确,因为许多WAF比项目本身更新频率更高。
实际绕过WAF的案例
我们正在对一个受PTAF(Positive Technologies Application Firewall)保护的网上商店进行渗透测试。说实话,很难找到其中存在的攻击点。但是,通过分析,我们很快就发现了web应用程序的异常行为,而这些行为并未被WAF过滤掉。这一异常现象是在购买商品的历史搜索中发现的。请求以JSON格式发送,如下所示:
{"request":{"Count":10,"Offset":0,"ItemName":"Phone"}}
我们将Phone '和Phone ' + '值放入ItemName参数中,发现服务器为这两个请求返回了不同的响应。在第一种情况下,响应是空的;而在第二种情况下,它包含关于其他商品的数据,其名称中包含Phone一词,就好像参数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和new line)以原始格式添加到任何文本字段中,而不进行任何编码,WAF就会将其传递给它,web应用程序就会认为它是正确的并处理它。此时,很可能是JSON解析器出了问题,它不是为特殊符号而设计的,而是在这些符号出现的地方才解析JSON。因此,WAF分析器不会得到完整的请求,所以我们可以在特殊字符之后插入任何攻击向量。除了换行符之外,其他字符(例如NULL-byte)也可以工作。因此,我们可以编写以下请求,当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-query中使用%03%04这样的特殊字符是不正确的。所以,我们只需要使用comments /**/。因此,结果请求如下:
/*0x03 0x04*/1 UNION SELECT version(), user() --
可以看出,0x03和0x04是一个原始字节。
此外,在Nemesida WAF也发现了另一个问题,它与使用multipart / form-data处理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 ----
正如我们苏商所分析的,WAF可能是现代的和智能的,但有时可以通过添加一个特殊的字符来绕过它们。当今,我们无法预测所有服务器在开发阶段的所有可能输入数据类型,而机器学习正是为了实现这一点而实现的,它可以被当做特殊字符的解析器来使用。
总结
那么,我们应该完全依赖WAF吗?答案是否定的。
在我们的实际测试中,我们发现了一个WAF绕过,它允许我们利用一些漏洞。事实证明,,在受到WAF保护之前,开发人员已经对其进行了安全检查,并且发现了相同的漏洞。他们没有修复它们,而是决定买一台配备了机器学习功能的现代WAF。遗憾的是,这样做是不对的,WAF的供应商应该首先修复漏洞。同样值得注意的是,机器学习仍然是一个很虚的东西,看起来更像是一种营销手段,而不是真正的防御手段。
一般来说,WAF是一种非常现代的安全解决方案,它不会影响你的web应用程序。虽然在今天,它只能阻止漏洞搜索和漏洞利用的过程,但它不能完全保护它们。就目前情况而言,WAF在相当长一段时间内,还属于比较新潮的技术。web应用程序中的漏洞只能通过更正与其相关的代码来修复,这是唯一万无一失的解决方案。