#120 | pen13 – Analyzing Smarty’s attack surface with what might be a 0day

Hi, today I’ll do a quick article to talk about Smarty PHP and I’ll reveal something I found on the template library that could be a 0day.

 

What’s Smarty?

Smarty is a PHP library allowing the usage of Templates in PHP. It is a library widely used in PHP development, MVC and so on. It has a cache system to avoid generating the templates every time. The syntax uses curly braces as most of the other template systems.

 

Attack surface

Server-side Template Injection

Server-side Template Injection or SSTI is when a template is automatically generated from untrusted data input. It can easily be detected by sending for example {{ 7*7 }}, if the result is 49 then it means that the expression language is interpreting your input.

In Smarty, there is a quick way to exploit SSTI if the secure mode of smarty is disabled by using the tags {php} such as:

{php}phpinfo();{/php}

This function is deprecated in Smarty and as of Smarty 3.1, it is only available with Smarty BC (backward compatibility)

There are other interestings tags such as {include_php} (deprecated as well) and {include}.

 

fetch and display

I’ll talk about a CVE created by a friend of mine in early 2018 (CVE-2017-1000480). It is based on the fact that when creating a cache file, Smarty will put the name of the template resource in a comment in the header of the file.

As such, it is possible because of poorly sanitized input to send a comment ending in PHP when it is using fetch or display on untrusted data, for example:

fetch($untrusted); // or display($untrusted);

Imagine that $untrusted is $_GET[‘untrusted’].

smarty.php?untrusted=*/phpinfo();/*

This will do the trick and allow you to get remote code execution.

This trick does not work after Smarty 3.1.32

 

assign

Assign is a function used by Smarty to setup a template variable to a certain value. Using assign will make it so that SSTI is not possible. However, due to the caching system in Smarty, it is saving the content of the variable inside a php file (that would get executed when this file is used).

To save the content of a variable to a file, it will check if the file is containing PHP content using a regex there. However, as you can see, there is no “i” modifier, meaning that it can be EASILY bypassed using uppercase, big fail for them.

The bypass only works on <script language=”php”></script> since “<?” is filtered so you can’t use “<?PHP”, it means then that it only works on PHP 5 since that way of calling PHP has been scrapped from PHP 7.

Imagine a code that do something such as:

$smarty->assign('name', $_GET['name']);

All you’ll have to do is:

smarty.php?name=<script language="PHP">phpinfo();</script>

Or uppercase any other part of script, language and so on and you’ll get your RCE, easy.

There’s your 0day, I’ll work a little bit more on the subject and see how I’ll report that issue, until then, see you!

Leave a Reply

Your email address will not be published.