Strict statement: This article is only for technical discussion and academic study, and is strictly prohibited to be used for other purposes (especially for illegal purposes, such as unauthorized attacks). Otherwise, it will bear the consequences on its own. It has nothing to do with the author and the platform. If there is anything wrong, please contact the author and the platform in time.
Preface
Flask is a lightweight MVC (also known as MTV, t: template) framework written in Python
See for details
http://docs.jinkan.org/docs/flask/
For the flask framework itself, this article will not discuss it.
In this paper, we test several examples to show the security risks brought by the server template injection in the flask framework
0 × 01. Test code
from flask import Flask, request, render_template_string, render_template
app = Flask(__name__)
@app.route('/hello-template-injection')
def hello_ssti():
person = {'name': "world", 'secret': "UGhldmJoZj8gYWl2ZnZoei5wYnovcG5lcnJlZg=="}
if request.args.get('name'):
person['name'] = request.args.get('name')
template = '''<h2>Hello %s!</h2>''' % person['name']
return render_template_string(template, person=person)
@app.route('/hello-xss')
def hello_xss():
name = "world"
template = 'hello.unsafe'# 'unsafe' file extension... totally legit.
if request.args.get('name'):
name = request.args.get('name')
return render_template(template, name=name)
@app.route('/html-attribute-xss')
def hello_hi():
template = '''<title>No Injection Allowed!</title>
<a href={{ url_for('hello_xss')}}?name={{ name |e}}>
Click here for a welcome message</a>'''
name = "world"
if request.args.get('name'):
name = request.args.get('name')
return render_template_string(template, name=name)
####
# Private function if the user has local files.
###
def get_user_file(f_name):
with open(f_name) as f:
return f.readlines()
app.jinja_env.globals['get_user_file'] = get_user_file# Allows for use in Jinja2 templates
if __name__ == "__main__":
app.run(debug=True)
0 × 02. Security risks caused by string splicing or replacement in template string
Let's take a look at the Hello? SSTI function in the test code
Template content in function
template = '''<h2>Hello %s!</h2>''' % person['name']
http://localhost:5000/hello-template-injection?name=ForrestX386. {{person.secret}}
Secret value is leaked
Reason:
We know that jinja2 is used as the template rendering engine in flask, and {}} is used as the variable package identifier in jinja2. Jinja2 will parse and replace the {} package content as a variable during rendering. If the name = forrestx386. {{person. Secret}}} is passed in, then {}} will be replaced with the value of the secret element in the dictionary person during template rendering
**Raise local File Inclusion Vulnerability**
http://localhost:5000/hello-template-injection?name=ForrestX386. {{get_user_file('E:\haha.txt')}}
E: Content of \ haha.txt is leaked
Reason:
As above, when jinja2 renders the template, replace the contents of {get ﹣ user ﹣ file ('e: \ haha. TXT ')}}}} with the return value of get ﹣ user ﹣ file ('e: \ haha. TXT') function
How to solve the above problems:
Set template = "'< H2 > Hello% s! < / H2 >"'% person ['name ']
Change to template = '< H2 > Hello {{person ['name']}}! < / H2 > "'
In this way, jinja2 replaces the value of person ['name '] with {{person ['name']}}} during template rendering, instead of re rendering the content of person ['name '] (in this way, even if {}} is included in' person ['name '], it will not be rendered, but just as a normal string)
Security risks of 0 × 03. Render template string
We know that during template rendering (using jinja2 template engine), the flag render ﹐ template function will automatically transcode the template (common template suffixes, such as. HTML, . HTM, etc., the uncommon template suffix will not be automatically encoded with HTML, as will be described below) the content will be encoded with HTML entity to avoid XSS vulnerability, but the render ﹐ template ﹐ string function in flag will not automatically encode the template string to be rendered, which has XSS security risks
Here's an example
Trigger XSS
http://localhost:5000/hello-template-injection?name=ForrestX386. <script>alert(“welcome to visit ForrestX386.github.io.”)</script>
XSS pop-up does occur, indicating that the render template string function is not automatically HTML entity encoded
Note: if you are using Chrome browser during the test and there is no pop-up box, please turn off the chrome XSS filter
You can turn off the chrome XSS filter like this
Add ` - args – disable XSS auditor after the target`
OK, restart chrome, that's it
How to solve the above problems
We can add '| e' after the output content, which requires jinja2 template engine to encode the output content HTML entity and then output it to the user
template = '<h2>Hello {{ person['name'] | e }}!</h2>'
Well, there's no XSS vulnerability
0 × 04. Security risks caused by using uncommon template suffix
Let's take a look at the hello_xssmethod in the test code, where the template is' template = 'hello. Unsafe'. The suffix unsafe is not the template suffix of automatic HTML coding supported by jinja2 template engine. If the content of the template is not written carefully or thoughtfully, XSS vulnerability can be caused. See the following example
If the content of hello.unsafe template is as follows:
{% autoescape true %}
<h2>Good</h2>
<p>
Hello {{ name }}! I don't trust your input. I escaped it, just in case.
</p>
{% endautoescape %}
<h2>Bad</h2>
<p>
I trust all data! How are you {{ name }}?
</p>
Block good uses the autoescape method in jinja2, while block bad does not. Let's visit the following URL to see what happens
http://localhost:5000/hello-xss?name=ForrestX386.<script>document.title="xss";</script>
Yes, there is no XSS vulnerability in the block using the autoescape method (the autoescape function will automatically encode the wrapped block with HTML entity), while XSS vulnerability occurs in the block without the autoescape method (bad block), which indicates that render template will not automatically encode the template suffix that does not support automatic HTML entity encoding
So when using render template to render the template suffix that jinja2 template engine does not support automatic HTML entity encoding, please be careful and use the autoescape method where there is user input
How to solve the above problems
In addition to using the autoescape method, we can also add '| e' after the content to be rendered for HTML entity coding
For example, change the bad block content to
<h2>Bad</h2>
<p>
I trust all data! How are you {{ name |e }}?
</p>
So there's no XSS vulnerability
0 × 05. Using HTML tag attribute field in template to bypass XSS filtering
In section 0 × 03, we talked about that render template string does not perform automatic HTML entity code conversion on the strings to be rendered, but you can use|e to perform HTML entity code conversion on the output content. Is it safe to use ` |e '? Not necessarily. Take a look at the following test:
Let's take a look at the Hello? Hi method in the test code
@app.route('/html-attribute-xss')
def hello_hi():
template = '''<title>No Injection Allowed!</title>
<a href={{ url_for('hello_xss')}}?name={{ name |e}}>
Click here for a welcome message</a>'''
name = "world"
if request.args.get('name'):
name = request.args.get('name')
return render_template_string(template, name=name)
Although name uses|e to escape HTML entities, we can bypass it in the following ways
Browser access:
http://localhost:5000/html-attribute-xss?name=test onmouseover=document.title="xss-again"
<a href={{ url_for('hello_xss')}}?name=test onmouseover=document.title="xss-again" >
Because the injected name parameter value appears in the attribute value of HTML tag after rendering, and|e will not filter the attribute value by HTML escape
How to solve:
Just use single or double quotes to enclose the value of the href
<a href="{{ url_for('hello_xss')}}?name={{ name |e}}">
0 × 06. Summary
Through the above examples, we summarize some potential security risks and corresponding solutions brought by using templates in the re flash framework, and let us know some tips in using templates. In a word, when we use flask to develop, we must keep in mind that any input of the user is untrustworthy, and we should filter the input and output well
Origin Refer:https://nvisium.com/blog/2015/12/07/injecting-flask/
*Forrestx386, reprinted by freebuf.com