Server-Side Template Injection

Overview

Server-Side Template Injection vulnerabilities occur when untrusted user input is used to dynamically render templates allowing the user to inject template directives. Server-Side Templating engines provide a way to populate HTML pages with data and generate the HTML dynamically before serving it to the client. When untrusted user input is used directly in a template it can be misused to inject malicious template directives and possibly allow executing arbitrary code on the backend server.

Example

Here is an example provided by h4rsh4d of intentionally vulnerable python code that runs on localhost:1337 and takes a user supplied URL parameter and embeds it in a template:

#Source https://github.com/h4rsh4d/SSTI/blob/master/Vulnerable%20Code/Flask_Code.py

from flask import *

app = Flask(__name__)

@app.route("/")
def home():
        #Retrieve URL request argument 'name'
        output = request.args.get('name')
        #render the user provided value 'name'       
        output = render_template_string(output)
        if output:
                pass
        else:
                output = "Test"
        return output

if __name__ == "__main__":
    app.run(debug=True, host="localhost", port=1337)
    
Accessing the application on localhost:1337 and providing a SSTI payload in the URL name parameter successfully executes SSTI. 

The vulnerability occurs in line 10 and 12 where the URL parameter input is retrieved and passed to the render_template_string function without input validation/sanitization. Accessing the application on localhost:1337 and providing a SSTI payload in the URL name parameter successfully executes SSTI. Entering the URL http://localhost:1337/?name={{7*7}} the application evaluates the template statement server-side to 49 and returns it to the user.

Exploitation

There are many things that can potentially be done once a SSTI has been discovered. The most obvious being launching a C2 beacon or spawning a reverse shell using something like telnet. We can also inspect the different objects the template engine uses such as the local and global variables. For example the config object in Flask contains configuration information and can contain credentials. Use the payload {{config.item()}} to retrieve the configuration items.

For further reading start with these then head over to the resources page:

Last updated