污染示例
污染函数,类似于js中的merge
1 2 3 4 5 6 7 8 9 10 11 12
| 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__.__base__
获取到父类属性并修改
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
| from utils import merge
class father: secret = "haha"
class son_a(father): pass
class son_b(father): pass
instance = son_b() payload = { "__class__" : { "__base__" : { "secret" : "no way" } } }
print(son_a.secret)
print(instance.secret)
merge(payload, instance) print(son_a.secret)
print(instance.secret)
|
在Python
中,函数或类方法(对于类的内置方法如__init__
这些来说,内置方法在并未重写时其数据类型为装饰器即wrapper_descriptor
,只有在重写后才是函数function
)均具有一个__globals__
属性,该属性将函数或类方法所申明的变量空间中的全局变量以字典的形式返回(相当于这个变量空间中的globals
函数的返回值
1 2 3 4 5 6 7 8 9 10 11
| secret_var = 114
def test(): pass
class a: def __init__(self): pass
print(test.__globals__ == globals() == a.__init__.__globals__)
|
所以我们可以使用__globals__
来获取到全局变量,这样就可以修改无继承关系的类属性甚至全局变量
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 34 35 36 37
| from utils import merge
secret_var = 114
def test(): pass
class a: secret_class_var = "secret"
class b: def __init__(self): pass
instance = b()
payload = { "__init__" : { "__globals__" : { "secret_var" : 514, "a" : { "secret_class_var" : "Pooooluted ~" } } } }
print(a.secret_class_var)
print(secret_var)
merge(payload, instance) print(a.secret_class_var)
print(secret_var)
|
实际环境中的合并函数
依据原博主所述,目前发现了Pydash
模块中的set_
和set_with
函数具有如上实例中merge
函数类似的类属性赋值逻辑,能够实现污染攻击。idekctf 2022*
中的task manager
这题就设计使用该函数提供可以污染的环境
例题
2023IdekCTFWriteup | Y4tacker’s Blog
Reference
Python原型链污染变体(prototype-pollution-in-python) - 跳跳糖 (tttang.com)
2023IdekCTFWriteup | Y4tacker’s Blog