Introduction
To understand Server-Side Template Injection (SSTI), one must first grasp the role of templates, and to understand templates, one should be familiar with the Model-View-Controller (MVC) design pattern. The MVC pattern is a software design pattern primarily used for developing user interfaces by separating an application into three interconnected parts.
As illustrated above, a user initiates a request to the Controller. The Controller then uses the Model to gather necessary information from the backend database. This information is passed back to the Controller. Next, the Controller passes the information to the View, which uses the data to update values in its structure. The final, updated View is then passed back to the Controller, which is subsequently sent to the user and rendered in the browser.
Templates and Template Engines
The View component is used to dynamically manipulate the HTML code and is normally implemented using templates. Templates allow a developer to have placeholders in their HTML code where dynamic variables can be passed in.
As seen on the fourth line in the example, there is a title tag holding the expression {{Title}}. This string will be replaced by whatever argument is passed to the template engine at runtime. This allows developers to easily reuse their code and separate logic from presentation.
A template engine enables you to use static template files in your application. At runtime, the template engine replaces variables in the template file with actual values, transforming the template into the final HTML file sent to the client.
One might question why a template engine is used to modify an HTML document when a simple format string operator could suffice. The reason is that template engines are much more powerful than a simple format string operator. Template engines can perform complex actions such as calling functions and methods, looping over variables, performing arithmetic, and much more.
As you will find out in the following sections, attackers can abuse template engines to perform all kinds of malicious actions. Server-Side Template Injection can be leveraged for Cross-Site Scripting (XSS), sensitive information disclosures, and even full remote code execution (RCE).
Python: Jinja2 Template Engine
Jinja2 is a popular template engine in Python and is frequently used in Flask and Django applications.
When testing for Server-Side Template Injection (SSTI) in a Jinja2 application, the following payloads are usually tried first to confirm vulnerability:
{{7*7}}(Expected Output: 49){{7*'7'}}(Expected Output: 7777777)
If the output 7777777 is displayed, you can assume the application is vulnerable and is likely using the Jinja2 or Tornado template engine.
Exploiting Jinja2 using MRO
To fully understand how to exploit this vulnerability, you first need to understand Method Resolution Order (MRO). MRO is the order in which Python looks for a method in a hierarchy of classes, and the MRO function can be used to list these classes.
To start, we can inspect the MRO of an empty string:
'' .__class__.__mro__
This command will first search the string class for a method. If it’s not found there, it will search the root object class. For this attack, we only care about the root object class because we can use it to get a handle to all other classes used by the application. To get the root object, access the second index (index [1]) in the array:
'' .__class__.__mro__[1]
Note: You can also use the
__base__method on an empty array or list to get this root object, as shown in the following command:
[].__class__.__base__
The __subclasses__() method can be used to list all the subclasses of a class. By using this on the root object, we can get a handle to every class the application uses:
{{[].__class__.__mro__[1].__subclasses__()}}
As you can see, all subclasses of the root object have been displayed. The next step is to look for something interesting that allows for system interaction. If we have access to the subprocess.Popen class, an attacker can leverage this class to execute commands on the server, as shown below:
{{[].__class__.__mro__[1].__subclasses__()[-3]('whoami',shell=True,stdout=-1).communicate()[0] }}
If you are familiar with Python and the Popen method, you will see that this is simply using legitimate functionalities of Python to execute a system command. Note that you can also use the following command for code execution if the one above doesn’t work (this payload relies on accessing the os module from the application’s configuration):
{{config.__class__.__init__.__globals__['os'].popen('whoami').read()}}
If you find SSTI in the Jinja2 template engine, the severity of the finding depends on what Python classes you have access to. If you don’t have access to any system command classes, code execution might be impossible (though not always). If you have access to the file class, you might be able to read/write files to the system. You must properly enumerate all the classes the root object has access to so you can figure out what capabilities you have.
Python: Tornado Template Engine
According to Google, Tornado is a scalable, non-blocking web server and web application framework written in Python. Tornado also has its own template engine which, like many others, is vulnerable to SSTI if implemented incorrectly.
Exploiting SSTI in the Tornado template engine is relatively easy compared to other engines. Looking at the Tornado template engine documentation, it mentions that you can import Python libraries directly into the template.
Any library available to Python is also available to the template engine. This means you can import a Python library and call its functions. This functionality can be abused to execute system commands, as shown below:
{% import os %}{{ os.popen("whoami").read() }}{% import subprocess %}{{subprocess.Popen('whoami',shell=True,stdout=-1).communicate()[0]}}
[Image showing the ‘whoami’ command output after successful SSTI exploitation in Tornado]
As you can see, the whoami command was run on the server, and the output was displayed on the screen. Since we can import any Python library, the attacker is not limited to just executing shell commands; they can execute arbitrary Python code.
Ruby: ERB Template Engine
ERB is an Eruby templating engine used to embed Ruby code within a document. According to Google, “An ERB template looks like a plain-text document interspersed with tags containing Ruby code. When evaluated, this tagged code can modify text in the template.”
Note that ERB uses the following tags for embedding code:
: Used to execute Ruby code without returning a result (e.g., control flow).: Used to execute Ruby code and return (print) the results.
To test for SSTI in the ERB engine, use the following command:
As seen, the code was executed and returned the value of 49. This is a strong indicator that the server is vulnerable to Server-Side Template Injection. To test for code execution, simply run your Ruby code to execute a system command:
whoami%>(Uses backticks for command execution)
[Image showing the ‘whoami’ command output after successful SSTI exploitation in ERB]
As shown, the whoami command ran, and the results were outputted to the screen.
Ruby: Slim Template Engine
According to Google, Slim is “a fast, lightweight templating engine with support for Rails 3 and later.” Like many other template engines, SSTI can arise when Slim is improperly implemented.
In terms of exploiting SSTI, the Slim template engine is very similar to ERB, but the syntax is different:
#{code}
To execute a shell command, simply wrap your command in backticks:
#{ \whoami` }`
Again, just like the ERB template engine, if vulnerable, an attacker can execute any Ruby command they want.
Java: Freemarker Template Engine
Freemarker is the most popular template engine for Java, making it a valuable target to understand.
As you can see, this vulnerability stems from concatenating user-supplied input with a template, just like every other template engine vulnerability. To test for SSTI vulnerability, use the following payload:
${7*7}
Similar to other template engines, to exploit this vulnerability, we are going to use an object to execute shell commands. The ?new() command in Freemarker can be used to instantiate classes, so all we need is a class that can execute shell commands.
The Execute class is available in Freemarker and can be used to execute shell commands. The documentation even mentions that this class can be used to run arbitrary code on the server. To use this class, we can run one of the following commands:
${ ex("whoami")}[#assign ex = 'freemarker.template.utility.Execute'?new()]${ ex('whoami')}${"freemarker.template.utility.Execute"?new()("whoami")}
[Image showing the ‘whoami’ command output after successful SSTI exploitation in Freemarker]
As demonstrated, the command whoami ran, and the output was displayed in the browser. From here, it would be trivial to run a command to execute a backdoor or any other malicious payload.
