Server-Side Template Injection + Hack the Box Walkthrough
Author Sagi Liba
Sagi Liba on Jun 19, 2021
6 min 🕐

Lately, I’ve been interested in learning more about cybersecurity, and especially about web application penetration testing. I’ve been fortunate enough to receive two SANS courses which gave me a wide knowledge base about the different attack vectors you could use on a web application.

I’ve done the following courses:

  • SEC542: Web App Penetration Testing and Ethical Hacking

  • SEC642: Advanced Web App Penetration Testing, Ethical Hacking, and Exploitation Techniques

Introduction To Server Side Template Injection - SSTI

Template engines are of common use when working with different languages, and there could be multiple templating engines for each programming language.

Here are a few examples you might already be familiar with:


A Templating engine allow you to write a document once, and inject the data dynamically to the document with the engine’s bracket notation.

I will be focusing on Python, Flask and Jinja2 as it will be the basis for the following “Hack the Box” walkthrough that shows the vulnerability injection, and gaining code execution.

Flask uses Jinja2 as its default templating engine and is actually a requirement when installing Flask.

To view the vulnerability, I’ve created a purposely insecure simple Flask server with a route named home, that will render our URL parameter named cmd.

from flask import Flask, render_template_string, request
app = Flask(__name__)
def home():
if request.args.get('cmd'):
return render_template_string(request.args.get('cmd',""))
return "Hello World"
if __name__ == "__main__":

When accessing this server’s home route, we will be greeted with a “Hello World” message.


Now we are going to learn how to discover and then exploit the vulnerability using the cmd parameter.

Template Injection Discovery

Every template engine has its own bracket notation syntax to inject our data into the document being dynamically generated.

We could try to inject a simple payload to abuse the template engine’s functionality.

When trying to discover a template injection, using a logical math operation is desirable.

The idea is that if you were able to inject a math operation which is supported by all major programming languages, you could check to see if the result was reflected back to you.

For example:

{{ 7*7 }} // Jinja2 / Twig / Mustache
{$ 7*7 } // Smarty
<%= 7*7 %> // eRB / eJS

If you see the result “49” reflected back through the web application you know you’ve found a valid injection.

Lets test it against our vulnerable parameter cmd:


We can see that the parameter is indeed vulnerable.

Attack Vectors

When you’ve found a valid injection there are multiple things you can do, some of them depending on the language capabilities.

Reflecting Available Variables

You could try to use common reserved keywords to try and see their data, or even guess variables names and print their data.

By doing so, you will be able to read and reflect anything that is available in that scope in memory.

For example, using python you could reference the current class, or a variable currently available:

{{ self }} // current class refernce
{{ variable_name }} // Prior knowledge / guessing / brute-force.

Code Execution

Depending on the language code execution might be possible, and even running a reverse-shell to gain control over the machine.

You can open a process to run you code with the following:

subprocess.popen // Python2 / Python3
Java.lange.Runtime.exec() // JAVA
IO.popen // Ruby

Google for other command execution methods for your particular use-case and language.

Exploit Class Inheritance To Gain Remote Code Execution

Depending on the language you will find ways that will help you reach remote code execution by accessing the above-mentioned attributes and functions to open a process and run your code.

In Python, you will have the following attributes and functions to traverse the class inheritance:


__class__ – An attribute on the object that refers to the class from which the object was created.__mro__ – stands for Method Resolution Order. It returns a list of types the class is derived from._subclasses__ – Returns all the subclasses of the object / class it was called on.

By using a combination of the above attributes and functions, you could be able to reach subprocess.popen and run your code.

Now we will use all that we learned until now to successfully exploit the Templated machine at “Hack the Box”.

Hack The Box - Templated Walkthrough

Using “Hack the Box” Templated machine we will demonstrate the Server-Side Template Injection ( SSTI ) vulnerability.

When entering the application this is the first page we see:


We are instantly given the framework and templating engine being used in this machine. This saves us time trying to enumerate the services or going over the requests.

The application has no apparent functionality, the only thing I could think of was to try and view the error page, so I’ve added to the URL the text: “unknownpage”.


It seems the application is reflecting our injected URL text. Let’s try and check for Server-Side Template Injection, using the discovery method we have previously learned.

Inject a logical math operation and check if it was reflected back, so let’s use the following payload:

{{7*7}} // We expect to see 49

I’ve injected the payload into the URL and it worked! We can see the value “49” is being reflected back to us instead of the page name.


As I’ve said earlier you could brute-force / guess or have prior knowledge about variable names that exists in the current scope of the code execution.

Playing around with the injection I’ve managed to reflect back the variable config:


The above config variable was just an example of the variable reflection I’ve discussed earlier.

To exploit the vulnerability we don’t have to reflect any variable back, we can use existing data types to reach our goal.

Let’s try and find subprocess.popen, to run our code and hopefully find the flag file.

FIX THIS !!!!!!!!!!!!!!!!!

We can use a combination of class, mro & subclasses() to find all available classes:


We can then create an empty string and access the class it was created from:

// Result: The page '<class 'str'>' could not be found

Then we can access the Method Resolution Order, using mro to find the classes class ‘str’ was created from.

// Result: The page '(<class 'str'>, <class 'object'>)' could not be found

Now we have found the object class which every class inherits from. All that is left is getting all of its subclasses:



We’ve found a list of all available sub classes and inside the subprocess.popen class, this means code execution is possible!

I’ve searched Google to find the final implementation to run the code execution, and I’ve assumed that such a small application won’t have any complex file system structure, and ran the ls command.

There I saw the flag.txt file and then I’ve used cat to display it’s contents:


We have successfully found the flag!


Final Notes

  • Never trust user input, always remember to sanitize by removing unwanted characters before parsing the data.

  • If allowing these risky characters is a business requirement, remember that code execution is possible. You should use docker to sandbox the application and minimize the risk.

  • When dealing with templates always pass the user input as parameters, the framework will be able to prevent any code execution (Make sure to check it yourself).

I hope you’ve enjoyed the article, and you are now capable of exploiting Server-Side Template Injection by yourself.

© 2020-present Sagi Liba. All Rights Reserved