|
2013年7月,远程Struts2的代码S2-016漏洞被公开那天,我正好在给一个客户做渗透测试。执行目标站点的漏洞登录框后面跑的就是Struts2,版本号2.3.15。远程我往URL里塞了一段OGNL表达式,代码服务器直接把执行结果回显在了页面上——那个瞬间的执行感觉,就像你随手拧了一下门把手,漏洞整扇门直接掉下来了。远程 Struts2的代码远程代码执行漏洞不是某一个孤立的bug,而是执行一类反复发作的老毛病。核心问题出在它处理用户输入的漏洞方式上。Struts2有一套自己的远程表达式语言叫OGNL(Object-Graph Navigation Language),本来是代码用来在框架内部做数据流转的。问题是执行,某些参数在进入OGNL解析器之前没有经过严格过滤,攻击者可以构造恶意表达式,让服务器执行任意代码。 最早的S2-001可以追溯到2007年,影响面相对有限。真正让Struts2“出圈”的是2010年的S2-005和2011年的S2-009。但要说破坏力最大的,还得是2013年的S2-016和2014年的S2-032。S2-016的影响范围覆盖了2.0.0到2.3.15几乎所有版本,国内大量政府网站、银行系统、电商平台都中招了。当时圈子里流传一个段子:你不需要知道目标用什么框架,只要看到URL里带 漏洞的利用方式其实不复杂。以S2-016为例,攻击者只需要在URL的 我后来复盘过几个被入侵的案例。有一个电商站点,攻击者通过S2-016上传了一个JSP Webshell,放在 Apache官方对这类漏洞的修复态度一直比较被动。S2-016出来之后,他们发了2.3.15.1补丁,但很快就被绕过了。S2-032又补了一次,S2-045、S2-046接着来。每次都是“禁用某些OGNL特性”或者“增加沙箱限制”,但OGNL本身的表达能力太强,沙箱很难做到滴水不漏。这种打补丁的方式本质上是在和攻击者赛跑,而框架的历史包袱又太重,没法推倒重来。 如果你现在还在维护跑着Struts2的老系统,第一件事就是确认版本号。2.5.30之后的版本安全性好了很多,但如果还停留在2.3.x系列,升级到2.5.x可能会遇到兼容性问题——这也是很多团队一直拖着不升的原因。临时缓解措施可以用WAF拦截包含 说到底,Struts2的RCE漏洞史就是一部“输入信任”的反面教材。框架信任了用户的输入,用户信任了框架的过滤,最后谁都没防住。写代码的人总觉得“这个参数用户改不了”,但攻击者恰恰就盯着你觉得改不了的地方下手。 |
