Server-side template injection or SSTI is a way for an attacker to execute code in the template engine. and the code which the attacker is running is totally dependent upon the language in which the template engine is coded. In this article, I am going to explain SSTI deeply. we will see what is the mistake developer usually make, which cause bugs like SSTI. and we will also see the way to secure our website from such attacks.

This is an input validation bug which means a user input is required to exploit this vulnerability. For demonstration, I will be using the Flask web application cause it is easy to exploit SSTI on it. first, we need to understand how the dynamic web pages work in order to understand the attack. for example, you have a website which shows the student grade for each student. No other student can view the grade of any other student (login/sign password-based Authentication is available on that site). so here the grade may be different for each student. such a page is called dynamic. whereas a static page is more likely hosted to serve the same content to every single visitor of the website.

for example, run this code in your terminal:

# reference: https://github.com/epinna/tplmap
from flask import Flask, request
from jinja2 import Environment

app = Flask(__name__)
Jinja2 = Environment()

@app.route("/page")
def page():

    name = request.values.get('name')
    output = Jinja2.from_string('Hello ' + name + '!\n').render()
    return output

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80)

And this will require the Flask library installed in your system to run. code defines a route `/page` which seems to take a GET parameter `name`. and in the response, it will show our name with `Hello`.

as you can see that I try to send `KINGPING` as a GET parameter and it sends back `Hello KINGPING!`. which makes it dynamic and we can say that it is different for every user. but when you see such a response (reflected), you can always check if SSTI exists there or not. you can send the payload `{{7*7}}`, and the server should evaluate it first before sending it to you.

%7B = {
%7D = }
which makes %7B%7B 7*7 %7D, {{7*7}}

we can say that the website is vulnerable to SSTI if we get the evaluated output, which is 49 (7*7) here. Actually, you can do more than just arithmetic and logical operations between these curly brackets. and it will be better if you could just URL encode the payload before sending it. I always go to this GitHub repo which has amazing payloads for every vulnerability. if I want to execute a system command in it, I can find many payloads for that.

#examples
{{config.__class__.__init__.__globals__['os'].popen('ls').read()}}
{{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('id')|attr('read')()}}

It is happening because we are adding the variable as a string with the template. the following line is vulnerable here:

Jinja2.from_string('Hello ' + name + '!\n').render()

we can use curly brackets to prevent SSTI vulnerability. The following line is a secure code where it is not possible to exploit this vulnerability:

Jinja2.from_string('Hello {{name}}!').render(name = name)

TPLMAP

There is this tool called TPLMAP which sounds like SQLmap, cause it works the same as SQLmap except it exploits SSTI bugs instead of SQLI(SQL injection). you can download this from GitHub and install the requirements of python.

git clone https://github.com/epinna/tplmap
pip3 install -r requirements.txt

Then you will be able to run the `tplmap.py` with python. you can supply the URL with -u flag. I am using the above Flask code for the demonstration of tplmap.

It checks whether the parameter is exploitable or not. if it is, it provides some other flags which are for getting a reverse shell, binds shell, downloading a file, uploading a file etc. I can get a hell of the vulnerable server using `–os-shell`.

There is a really amazing GitHub repo to test out other SSTI on the template engines (of other languages). It has java, javascript, ruby, PHP, python, golang SSTI vulnerable codes which you can run in Docker containers and test using tplmap tool. the steps are simple to run all vulnerable servers.

git clone https://github.com/DiogoMRSilva/websitesVulnerableToSSTI
cd websitesVulnerableToSSTI
bash build.sh # may take a while
bash run.sh
bash startAllDockersIndividually.sh

The Github repo also contains some payloads for the different template engines. But I would suggest you take help from PayloadAllTheThings.

LEAVE A REPLY

Please enter your comment!
Please enter your name here