Server Side Template Injection

Definition: Template engines are widely used by web applications to present dynamic data via web pages and emails. Unsafely embedding user input in templates enables Server-Side Template Injection.

Pravinrp
Server Side Template Injection
6 min readJul 30, 2019

--

We will be able to run remote code execution via server side template injection attack. Below report from hackerone inspired me to learn about this latest attack.

https://hackerone.com/reports/125980

Now, the bug has been fixed. However, the way the author has implemented his creativity is amazing. He has injected {{‘7’*7}} in place of username and has identified that the template engine has created “7777777” in result. This is how he got to know that the template engine was vulnerable for an injection attack.

Web applications frequently use template systems such as Twig and FreeMarker to embed dynamic content in web pages and emails. Template Injection occurs when user input is embedded in a template in an unsafe manner. Consider a marketing application that sends bulk emails, and uses a Twig template to greet recipients by name. If the name is merely passed in to the template, as in the following example, everything works fine:

$output = $twig->render(“Dear {first_name},”, array(“first_name” =>$user.first_name) );

However, if users are allowed to customize these emails, problems arise:

$output = $twig->render($_GET['custom_email'], array("first_name" => $user.first_name) );

In this example the user controls the content of the template itself via the “custom_email” GET parameter, rather than a value passed into it.

If we provide the “custom_email” value as {{7*7}} and the application is vulnerable, then we will be getting the output as follows.

Output:

Dear 49,

Note: 49 has been replaced in “username” place which confirms the server side template injection attack

Template injection attack can be achieved by identifying the template engine and customizing the payload accordingly. Template injection can also arise by accident when user input is simply concatenated directly into a template.

Identify:

When the user input is allowed without filtering then there is a chance for any sort of injection attack. Here, as shown in the example user input is allowed for making an e-mail template.

Code: personal_greeting=username

Input: user1

Output: Hello user1, We wish you all the best.

Note: if we feed in {{7*7}} in place of a username, then “Hello 49” will be obtained in the result.

After detecting template injection, the next step is to identify the template engine in use. This step is sometimes as trivial as submitting invalid syntax, as template engines may identify themselves in the resulting error messages. However, this technique fails when error messages are suppressed, and isn’t well suited for automation. In some cases, a single payload can have multiple distinct success responses — for example, the probe {{7*’7'}} would result in 49 in Twig, 7777777 in Jinja2, and neither if no template language is in use.

Green arrow shows success,Red arrow shows failure

Now, we need to customize the payload based on what sort of template engine we are dealing with.

Now let us try to inject some codes in the application and see whether the application executes or not. Below example process the input {{7*7}} and produces the result 49 in output which confirms the code template code execution.

{{7*7}} gives 49 in the result

Now, we need to read any file system from the application for further exploitation.

This command will show /etc/passwd file in the output. In order to understand the command, we need to read below explanation as well.

The MRO in __mro__ stands for Method Resolution Order, and is defined here as, "a tuple of classes that are considered when looking for base classes during method resolution." The __mro__ attribute consists of the object's inheritance map in a tuple consisting of the class, its base, its base's base, and so on up to object (if using new-style classes). It is an attribute of each object's metaclass, but is a truly hidden attribute, as Python explicitly leaves it out of dir output (see Objects/object.c at line 1812) when conducting introspection.

The __subclasses__ attribute is defined here as a method that "keeps a list of weak references to its immediate subclasses." for each new-style class, and "returns a list of all those references still alive."

Greatly simplified, __mro__ allows us to go back up the tree of inherited objects in the current Python environment, and __subclasses__ lets us come back down. So what's the impact on the search of a greater exploit for SSTI in Flask/Jinja2? By starting with a new-type object, e.g. type str, we can crawl up the inheritance tree to the root object class using __mro__, then crawl back down to every new-style object in the Python environment using __subclasses__. Yes, this gives us access to every class loaded in the current python environment

The first thing we want to do is select a new-style object to use for accessing the object base class. We can simply use '', a blank string, object type str. Then, we can use the __mro__ attribute to access the object's inherited classes. Inject {{ ''.__class__.__mro__ }} as a payload into the SSTI vulnerability. Since we want to go back to the root object class, we'll leverage an index of 2 to select the class type object. Now that we're at the root object, we can leverage the __subclasses__ attribute to dump all of the classes used in the application. Inject {{ ''.__class__.__mro__[2].__subclasses__() }} into the SSTI vulnerability.

‘’.__class__.__mro__[2].__subclasses__()[40](‘/etc/passwd’).read() }}

Note: Subclass 40 is to read a file.

/etc/passwd file content displayed

Ruby

Basic injection

Retrieve /etc/passwd

List files and directories

Java

Basic injection

Retrieve the system’s environment variables

Retrieve /etc/passwd

Twig

Basic injection

Template format

Code execution

Smarty

Freemarker

You can try your payloads at https://try.freemarker.apache.org

Basic injection

The template can be ${3*3} or the legacy #{3*3}

Code execution

Jade / Codepen

Velocity

Mako

Jinja2

Official website

Jinja2 is a full featured template engine for Python. It has full unicode support, an optional integrated sandboxed execution environment, widely used and BSD licensed.

Basic injection

Jinja2 is used by Python Web Frameworks such as Django or Flask. The above injections have been tested on Flask application.

Template format

Dump all used classes

Dump all config variables

Read remote file

Write into remote file

Remote Code Execution

Listen for connection

Exploit the SSTI by calling subprocess.Popen.

⚠️ the number 396 will vary depending of the application.

Exploit the SSTI by calling Popen without guessing the offset

Exploit the SSTI by writing an evil config file.

Filter bypass

Bypassing _

Bypassing [ and ]

Bypassing |join

Jinjava

Basic injection

Jinjava is an open source project developped by Hubspot, available at https://github.com/HubSpot/jinjava/

Command execution

Fixed by https://github.com/HubSpot/jinjava/pull/230

If you like the content, please follow me on medium and LinkedIn

LinkedIn: https://www.linkedin.com/in/pravin-r-p-oscp-28497712b/

--

--

Pravinrp
Server Side Template Injection

OSCP/Security geek &researcher(Application/infrastructure/Mobile/cloud security)