大家好,今天我将在这篇文章中详细介绍我最近的研究,即针对WAF规则使用一个特殊的侧信道形式进行攻击,即基于时间的形式。这部分研究目前还不是非常主流,但是其结果却是令人震惊的。这篇文章挺长的,那么从现在就开始吧。
维基百科这么定义侧信道攻击:
基于从计算机系统组成搜集到的信息进行的攻击,而不是针对系统实现算法本身的弱点。
所以基础上来讲,我们需要提取或者搜集一些本不应该被公开读取到的敏感信息进行侧信道攻击。而这种攻击的成功实施往往是因为业务逻辑错误设计导致的。
今天我们谈论的攻击是基于时钟的,这种基于时间攻击专注在硬盘或者算法中的数据在CPU/内存的计算时间。只需要观察CPU处理数据的用时变化就可以从系统中获取敏感信息。
WAF可以用于检测和阻止对易受攻击的Web应用程序的攻击。除了阻止恶意请求进入,WAF通常也用于隐藏一些敏感信息泄露传出的问题(例如错误的堆栈信息)。通常来说WAF通过正则表达式来区分正常和恶意请求。
因为我们想要找到WAF规则中存在的漏洞问题,所以需要去识别WAF的规则,从而就能得知针对某种攻击WAF使用了哪种过滤策略,然后去调整我们的攻击方式从而避开检测。一旦攻击绕过了WAF那么就可以进一步发现WEB应用的更多漏洞。
在这篇文章中我使用了一种常见的指纹识别方法,称为正则表达式反转(regex-reverse),它通常依赖检测请求数据包的每个部分,来分析得出是该数据包的哪个部分导致异常发生。
通常,WAF部署在如下4个网络拓扑中:
反向代理
WAF在客户端和服务器之间拦截请求。客户端直接请求连接在WAF上面,然后WAF将客户端请求数据包传递给服务器。如果请求被WAF阻止,那么该数据包就永远不会达到服务器。
服务器部署
WAF安装在它需要保护的那台服务器上,这种情况可以分为两种:a) WAF是作为插件安装的;b) WAF是作为开发引入到代码中的。
带外形式
这种情况下,WAF通常连入的是网络设备上的监控端口,获取到的是流量镜像副本。这种方式限制了WAF对请求数据包的阻断功能,只有在检测到恶意数据包时才能发送TCP重置数据包来中断流量。
云部署
这种包括了在网络云提供商内部部署WAF的方法。这种类似于反向代理形式,即每个单独的数据请求都会经过云和云WAF。
在我的实验当中,我使用了2个最为常见的WAF部署方式:反向代理方式和作为插件的服务器内部部署方式。
通常任何WAF都是可以通过独特的HTTP头字段,cookie字段,阻断报错信息(例如响应码,响应页面)这些来进行识别的。有很多不错的WAF识别和绕过工具,例如WAFW00F(https://github.com/enablesecurity/wafw00f),WAFNinja(https://github.com/khalilbijjou/wafninja)等等。他们常常是通过侧信道来识别WAF的规则(例如一个请求是被阻断还是转发),进而绕过WAF。所以这些工具都对如下信息进行了观察分析:
WAF拦截信息
表示WAF已经标记请求为恶意请求并且进行了阻断。通常,拦截后的响应页面或者一个HTTP头字段都定义了这个请求已经被拦截。响应码(403 Forbidden)也有可能表示已经拦截请求数据包。
WEB错误信息
表示WEB在解析请求数据包时出错,但是错误信息页面会被WAF的自定义报错页面覆盖。这种请求下,WAF不会阻断请求,而是知识隐藏WEB本身的错误消息页面,以防止出现错误堆栈信息等导致的信息泄露。
正常响应
表示请求数据包已经经过WAF传递到达WEB服务器。但是请求在传递到服务器之间,WAF有可能对该请求进行了部分恶意字段删除的操作。
所以通过上文可以发现,仅通过观察响应数据包,无法明确区分出已经被转发和已经被阻断的请求(WAF拦截信息和WEB错误信息)。因为不管是WAF拦截了恶意数据还是WEB报错,页面显示出来的响应页面都可能是一样的。
针对上述缺点的解决方案就是本文提出的基于时间的攻击。通过利用基于时间攻击,可以准确判断导致一种特殊响应形式的请求是被转发还是被阻断的;由于服务器针对产生报错的请求的响应时间远远大于转发正常请求的时间,所以在这种识别下会被忽略。实验结果表明,该攻击可以精确识别请求在遇到WAF后被如何处理(转发还是阻拦),且准确率可以达到95%。
这种攻击技术的主要原理就是,通常被阻断的恶意请求从WAF直接响应给客户端比转发后从服务器响应给客户端的时间花费会更少(ms为单位)。即被阻断的请求比被转发的请求耗时更短,所以阻断请求和转发请求之间的时间差等于应用逻辑的处理时间。
假设:这里唯一的假设是当我们的WAF检测到恶意请求就会阻断请求并立即响应一个错误信息。但是其他WAF会存在删除恶意数据字段然后再将处理后的数据包转发给服务器。
为了区分阻断请求和转发请求。我们需要传递两种不同类型的请求数据包:一种是正常无害的请求数据包,它将顺利通过WAF并被转发;一种是包含恶意负载字符串<script>alert()</script>的请求,WAF很容易就可以检测到它。
我们最初解决这个问题的方法是将攻击分为两个阶段:
学习阶段
在此阶段,我们测试并记录阻断请求和转发请求的相应耗时,为之后的攻击阶段做准备。
攻击阶段
在此阶段,我们执行实际的攻击,恶意构造的请求会被发送以获取攻击结果或为未来的攻击做准备。
现在来计算具体的数学方法。在学习阶段,首先在n个阻断请求中测量相应时间集合<Tn = t1, t2, ... tn>,并且定义一个“标记阈值”。这个标记阈值在确定一个请求是否是阻断还是转发时作为一个参考值。这个阈值定义如下:
同理,再在n个转发请求中的响应时间集合定义一个“转发阈值”,该阈值的边界可以被定义为所有正常WAF转发请求的耗时集合中的最小值(译者注:因为转发请求耗时明显大于阻断请求,所以以最小值作为边界)。这个阈值可以定义如下:
在如上两个公式当中,常量δ表示由于一些网络因素等导致转发阈值和标记阈值边界的微小位移变化。
所以理论上,我们的转发边界和标记边界都是作为转发请求和阻断请求的耗时阈值。且网络本身的一些噪声等因素,这些阈值是不可在多个攻击场景下进行复制使用的。所以我们最终采用这两个边界值的均值来获得最终阻断请求和转发请求的耗时之间的边界值。
显然时间测量后,一个请求的耗时大于tβ即这个请求为转发请求,如果耗时小于tβ那么它就是阻断请求。但是任何请求耗时如果接近tβ可以极有可能是低网络噪声环境下的转发请求,也有可能是高网络噪声环境下的转发请求。为了排除这一点,攻击者需要放大这个攻击向量。我们将详细讨论这个问题。
为了验证上述理论,我采用了两种最常用的WAF部署拓扑:反向代理和插件部署服务器。我在我自己的服务器上做了这些设置,并完全按照正常的部署方式进行了场景复制。为了测试这种攻击方法,我选择了Shadow Daemon(https://github.com/zecure/shadowd),因为它是开源的,且规则维护度很小。且它很容易设置,因此将它的代码改写成系统插件不是很难。
我写了一个小python代码,在学习阶段它会一个接一个每2秒重复发送正常的和恶意的请求。一共发送了200个请求,其中正常请求和恶意请求各100个。学习阶段得出的结果清晰地表明这种方法具有一定有效性。
转发请求和阻断请求的一些样例如下:
可能会注意到的是,请求被阻断的情况下,某些请求可能超过了预想的标记边界,这可能是网络连接丢包或者网络堵塞问题。但是可以清楚发现任何一个正常数据包或者恶意数据包都没有越过最终的绝对时间边界。
实际攻击测试下,将会收集一组最常见的恶意payload,以便对目标进行测试。现在想法是一串天街了不同的混淆值而生成多种形式的变种payload。这种变种payload和原来的恶意payload语义相同,但是语法不同导致WAF的正则表达式可能无法检测到它。举几个例子:
现在将一系列此类请求发送到部署了WAF的服务器并记录其响应时间,为了进一步验证实验无误,同时会记录请求对应的响应码和响应页面,并识别出403状态和响应页面阻止保证结果一致。
在反向代理部署的WAF上,结果符合预期。标记边界和转发边界中间的最小时间间隔为53.2ms。结果显示,96.4%的案例中,我们可以正确区分转发请求和阻断其你去。因此可以有把握得说这种拓扑情况该方法准确性和可靠性都很高。只要重复几次学习阶段的测量就可以得到完美的测量结果。
在插件部署服务器系统的情况,我本来没想到会有这种结果输出(译者注:因为软WAF和逻辑代码处理之间的时间差会小很多)。但是令人震惊的是这种拓扑情况下方法的有效度和反向代理的情况一样好。这个拓扑情况下,阻断请求和转发请求之间的耗时差(58.8ms)还大于反向代理情况下的耗时差(53.2ms)。
因此可以有把握地说,这种攻击在95%以上的案例中可以明确区分转发请求和阻断请求。
这种方法的主要缺点就是攻击者都需要发送大量的请求来查找WAF规则集中的漏洞。除此之外,网络问题是一个比较大的障碍,可能会导致测量结果不稳定。因此服务器负载也可以作为一个因素加入到计算方法中,可以作为常数加入或者乘上。另外现代WAF也会通常实现针对发送包含恶意字符串的请求的客户端进行一定时间内封IP处理,从而极大限制该方法的能力。但是我们可以使用另一种技术来解决这个问题。
这种问题的解决就是在合理的时间内(译者注:封IP前的一段时间内)执行更多的测试,直到我们可以获得平均结果,从而排除具有大响应时间的请求。另外,因为网络噪声确实对我们的测试结果产生了一定影响,例如在测试布尔值结果时。一旦WAF封了客户端的IP地址,换新IP攻击以及换站点进行继续攻击都可以有效对WAF这种封禁IP行为进行了绕过。在很多情况下,在学习阶段中的连续测量请求之间设置延迟也非常有帮助。
如何放大攻击向量?
选择更长URL路径
当从服务器查询资源时,查询操作将由CPU来处理,查询到的结果的各个部分都会累积到一起(图片,CSS等)然后一起返回给客户端。然后我们选择在所有URL路径中响应内容最大的一个(例如,在一个博客站点我们可以选择查询文章图片最多的那个),因为这个响应内容最大的请求将会产生更多的CPU负载,服务器也就会使用更长的时间去处理该请求,使得该方法更具有有效性。
拒绝服务攻击
第二,我们可以结合不同的拒绝服务攻击的原理,例如在查询框中提交体量更大的查询,发送包含大体积的body主体的POST数据包,hash碰撞攻击(HashDoS)(https://cryptanalysis.eu/blog/2011/12/28/effective-dos-attacks-against-web-application-plattforms-hashdos/)等。请求处理的时间越长,网络噪声导致的负影响就越小。
跨站规则识别
最后,我们可以使用CSRF攻击来串联我们的识别过程,这需要攻击者将用户引诱到一个可以嵌入HTML和JS代码的站点(译者注:也就是存在XSS的站点)来让用户帮助它访问目标测试站点。一个样例代码如下:
<script> var test = document.getElementById(’test’); var start = new Date(); test.onerror = function() { var end = new Date(); alert("Total time: " + (end - start)); } test.src = "http://sitename.tld/path?" + parameter + "=" + payload; </script>
在上述代码中,我们创建一个不可见的img标签,就在我们将payload复制到图片的引用链接之前,我们开始记录时间,由于图像无效,浏览器会触onerror事件,并且时间记录停止时执行相关功能,并且演出具有记录时间的警报框。
这个方法有三个优点:
首先,攻击者的身份会被隐藏。因为由于是多个用户因为CSRF攻击被引诱到向目标服务器发送请求,因此无法区分这背后谁是真的攻击角色;
这种方法避免了封禁IP地址的影响;
特别重要的事该方法仅在基于时间的攻击时可靠有效。有时SOP(同源策略)可能会限制从其他源读取页面,因此这种情况下可能使用上文一些WAF识别工具所用到的指纹识别方法;
总结一下,该攻击方法突出了时间在侧信道攻击中的有效性,以及WAF开发人员编写严格的规则的必要性。在这个小小的研究中,我在ShadowD WAF的规则集中发现了一个可以绕过的安全漏洞,在我的下一篇文章中我将会写到我发现的问题。
感谢大家。