Smarty是一个PHP的模板引擎,提供让程序逻辑与页面显示(HTML/CSS)代码分离的功能。对于该框架的SSTI漏洞很多文章往往只是一笔带过,讲解的重心往往在flask等框架上。本篇文章结合一道CTF题目对Smarty的SSTI漏洞进行了一定的分析。题目地址:https://buuoj.cn/challenges CISCN2019华东南赛区Web11
基本信息题目模拟了一个获取IP的API,并且可以在最下方看到“Build With Smarty !”可以确定页面使用的是Smarty模板引擎。题目中显示的API的URL由于环境的原因无法使用,但是我们的IP依旧显示在了页面的右上角。很容易猜测出这个IP的值受XFF头控制 。将XFF头改为{2-1}会发现该位置的值变为了1,便可以确定这里存在SSTI。
Smarty SSTI利用Smarty是基于PHP开发的,对于Smarty的SSTI的利用手段与常见的flask的SSTI有很大区别。
漏洞确认一般情况下输入{$smarty.version}就可以看到返回的smarty的版本号。该题目的Smarty版本是3.1.30
常规利用方式Smarty支持使用{php}{/php}标签来执行被包裹其中的php指令,最常规的思路自然是先测试该标签。但就该题目而言,使用{php}{/php}标签会报错:
在Smarty3的官方手册里有以下描述:
Smarty已经废弃{php}
标签,强烈建议不要使用。在Smarty 3.1,{php}
仅在SmartyBC中可用。
该题目使用的是Smarty类,所以只能另寻它路。
{literal} 标签官方手册这样描述这个标签:
{literal}
可以让一个模板区域的字符原样输出。这经常用于保护页面上的Javascript或css样式表,避免因为Smarty的定界符而错被解析。
那么对于php5的环境我们就可以使用
phpinfo();
来实现PHP代码的执行,但这道题的题目环境是PHP7,这种方法就失效了。
静态方法通过self获取Smarty类再调用其静态方法实现文件读写被网上很多文章采用。
Smarty类的getStreamVariable方法的代码如下:
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;
}
$smarty = isset($this->smarty) ? $this->smarty : $this;
if ($smarty->error_unassigned) {
throw new SmartyException('Undefined stream variable "' . $variable . '"');
} else {
return null;
}
}
可以看到这个方法可以读取一个文件并返回其内容,所以我们可以用self来获取Smarty对象并调用这个方法,很多文章里给的payload都形如:{self::getStreamVariable("file:///etc/passwd")}。然而使用这个payload会触发报错如下:
Fatal error: Uncaught --> Smarty Compiler: Syntax error in template "string:Current IP:{self::getStreamVariable(‘file:///etc/passwd’)}" static class 'self' is undefined or not allowed by security setting
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?


微信扫码登录