Photo by Halacious on Unsplash

Server-Side Template Injection (SSTI)

On last day, When i was Playing CTF games, I played with one interesting vulnerability, Server-Side Template Injection (SSTI)

Now a days Template engines are widely used by web applications to display dynamic data via web pages. Unsafely embedding of user input to templates enables Server-Side Template Injection, Template Injection may cause with client side XSS or leads to critical Remote Code Execution(RCE)

Here, In that CTF ,Template injection leads to RCE to obtain flag. This is not a walkthrough of that CTF. Its just a note or explanation for, how the Template Injection works, and how i gains access to that server.

When i started the server, One simple webpage loads. After my simple enumeration using burp-suite response header told me, this web app using Werkzeug (It’s a Python based WSGI web application library). Then i started enumerate directory or possible URLs, On that time i noticed what ever i submitted in the URL it gets reflects on that webpage.

`home` is reflected in this page

Werkzeug is also a template based engines, So i want to confirm Template Injection in this web app, for that i entered this simple calculation payload {{ 2 * 7 }}, If its displays 14 then the template injection possible.

Then our attempt is success ,so i want to execute codes remotely. Before RCE,I used to read the ‘/etc/passwd’ in that server. For that i used the payload {{‘’.__class__.__mro__[2].__subclasses__()[40](‘/etc/passwd’).read()}}
There are many another payloads to read the files use reference from swisskyrepo

Finally to my favorite part Code execution, In this server RCE is pretty simple. When i executed the {{‘’.__class__.__mro__[2].__subclasses__()[396](‘id’,shell=True,stdout=-1).communicate()[0].strip()}}

There may be several methods to execute SSTI(Server side Template Injection), Template Injection is possible With every template based web application (Not only in Python In Other languages too)

Source Code Explanation

from flask import Flask,request,render_template_string 
from urllib import unquote
app = Flask(__name__)
def hello():
return "python template injection"
def page_not_found(error):
url = unquote(request.url)
return render_template_string("<h1>URL %s not found</h1><br/>"%url), 404
if __name__ == '__main__':, host='')

When page_not_found(error): function execute, The url parameter (unquote(request.url)) is directly Stored to a variable url, This variable directly rendered with the error template, So what ever user entered on URL, That will reflect on that templates. So we utilize this loophole to execute our payload, That will render on that page. This Leads To XSS(Cross Site Injection) or RCE ( Remote Code Execution )


For securing from this kind of attack validate all the user controlled areas, Like urls, User Inputs etc… Don't render user inputs directly to the template.

Security Researcher || Web Penetration Tester || Reverse Engineer || Web & Flutter Developer

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Little Kidogo Sprint Retro Report #3

101 Questions an Agile BA in software dev should ask and seek answers to.

Naming your functions, files & paths

Random thought on Distributed Transaction Management

The Complete Guide on Getting Certified in Kubernetes(CKA) and getting Hands-on

SIREN Deep Sea Updates April 2021

Naming, Code Conventions & Glory

epiAnalyst 2.0 Release

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Roshan Cheriyan

Roshan Cheriyan

Security Researcher || Web Penetration Tester || Reverse Engineer || Web & Flutter Developer

More from Medium

Getting started with Pentest Management | Cyver Core

Oh My Webserver - WriteUP

Intigriti’s February XSS challenge By aszx87410

Write-up: CORS vulnerability with trusted insecure protocols @ PortSwigger Academy