Introduction Link to heading

Server-Side Template Injection (SSTI) is a powerful vulnerability that can lead to severe security issues, including data leakage, remote code execution, and full server compromise. This write-up covers the exploitation of SSTI in a Flask application from DownUnderCTF 2024.

Initial Analysis Link to heading

Application Structure Link to heading

The challenge provided a Flask web application with the following structure:

parrot-the-emu
└── main-app
    ├── app.py
    ├── flag
    ├── requirements.txt
    ├── static
    │   └── css
    │       └── styles.css
    └── templates
        └── index.html

Key Files Link to heading

  • app.py: The main application logic.
  • index.html: The HTML template for the web interface.
  • flag: The file containing the flag.
  • requirements.txt: Dependencies required to run the Flask application.

Code Review Link to heading

app.py Analysis Link to heading

The core functionality of the application resides in app.py. Here is the code:

from flask import Flask, render_template, request, render_template_string

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def vulnerable():
    chat_log = []

    if request.method == 'POST':
        user_input = request.form.get('user_input')
        try:
            result = render_template_string(user_input)
        except Exception as e:
            result = str(e)

        chat_log.append(('User', user_input))
        chat_log.append(('Emu', result))
    
    return render_template('index.html', chat_log=chat_log)

if __name__ == '__main__':
    app.run(debug=True, port=80)

Identifying the Vulnerability Link to heading

The critical vulnerability in this code is within the vulnerable function, specifically at this line:

result = render_template_string(user_input)

This line takes user_input, which is directly sourced from the HTTP request, and passes it to render_template_string. The render_template_string function interprets this input as a Jinja2 template, thus allowing the user to inject and execute arbitrary code.

Validating the Vulnerability Link to heading

To validate that the application is vulnerable to SSTI, we can use a simple payload that performs a basic arithmetic operation. This test will help us determine if the input is being executed as a template.

Start the Flask Application Link to heading

Ensure that the Flask application is running. You should see output similar to this:

┌──(kali㉿kali)-[~/parrot-the-emu/main-app]
└─$ python ./app.py
...
 * Running on http://127.0.0.1:80
Press CTRL+C to quit
...

Access the Application Link to heading

Open your web browser and navigate to http://127.0.0.1:80/.

Submit the Payload Link to heading

In the web form provided by the application, enter the following payload:

{{ 7 * 7 }}

Analyze the Response Link to heading

After submitting the form, check the response from the server. If the application is vulnerable, you should see the result of the arithmetic operation rendered in the response:

49

Interpreting the Results Link to heading

This confirms that the application is interpreting the input as a Jinja2 template and executing it. This indicates that the application is vulnerable to SSTI.

Crafting the Exploit Link to heading

We can exploit this SSTI vulnerability by crafting a payload that executes arbitrary code on the server. The payload used in this challenge was:

{{ config.__class__.__init__.__globals__['os'].popen('cat flag').read() }}

Let’s break down this payload step by step to understand how it works and why it effectively exploits the vulnerability.

Breakdown of the Payload Link to heading

1. config.__class__ Link to heading

  • config is an object in the server’s environment.
  • config.__class__ returns the class type of the config object.

2. .__init__ Link to heading

  • Every Python class has an __init__ method, which initializes the object.
  • config.__class__.__init__ accesses the constructor method of the config object’s class.

3. .__globals__ Link to heading

  • The __globals__ attribute of a function returns the global namespace where the function was defined.
  • config.__class__.__init__.__globals__ accesses the global variables and modules available in the __init__ method’s scope.

4. ['os'] Link to heading

  • Using __globals__, the os module can be retrieved.
  • config.__class__.__init__.__globals__['os'] retrieves the os module from the global namespace.

5. .popen('cat flag') Link to heading

  • The os.popen method opens a pipe to or from a command.
  • config.__class__.__init__.__globals__['os'].popen('cat flag') executes the cat flag command.

6. .read() Link to heading

  • The read() method reads the output of the executed command.
  • config.__class__.__init__.__globals__['os'].popen('cat flag').read() captures the output of the cat flag command, which is the contents of the flag file.

Summary of the Payload Link to heading

Combining all parts, the payload effectively:

  1. Accesses the class type of the config object.
  2. Retrieves the __init__ method of this class.
  3. Accesses the global namespace where the __init__ method was defined.
  4. Retrieves the os module from the global namespace.
  5. Executes the cat flag command using os.popen.
  6. Reads and captures the output of this command, displaying the contents of the flag file.

Executing the Exploit Link to heading

Submitting the payload to the web application causes the server to execute the cat flag command, revealing the flag:

DUCTF{PaRrOt_EmU_ReNdErS_AnYtHiNg}

Conclusion Link to heading

Server-Side Template Injection is a critical vulnerability that can lead to severe security breaches. By understanding how SSTI works and where vulnerabilities lie in the code, developers can take appropriate measures to secure their applications. Always sanitize and validate user inputs, and avoid using functions that directly render user data as templates. Following these best practices can protect your applications from SSTI and other injection-based attacks.

References and Further Reading Link to heading

Documentation Link to heading

  • Flask Documentation: Comprehensive guide to Flask, essential for understanding and developing secure Flask applications.
  • Jinja2 Documentation: Official website and documentation for Jinja2, providing insights into template rendering and security practices.

Educational Articles Link to heading