class father:
secret = "hello"
class son_a(father):
pass
class son_b(father):
pass
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)
instance = son_b()
payload = {
"__class__" : {
"__base__" : {
"secret" : "world"
}
}
}
print(son_a.secret)
#hello
print(instance.secret)
#hello
merge(payload, instance)
print(son_a.secret)
#world
print(instance.secret)
#world
我们在merge下断点
首先取出我们的k和v
然后进行判断我们dst里面是否有__getitem__
属性,肯定没有,我们dst只是一个object
然后进入elif,判断我们的dst里面有没有k这个属性,并取出来的值为一个dict,看到上面的是满足的
然后又进入merge函数,注意传入参数的顺序
可以看到我们的src和dst的新值
然后又进行同样的判断,还是会进入elif那里
一样的符合重新进行merge操作
可以看到现在的src和dst的新值,但是这次会进入setattr(dst, k, v)方法,因为我们的v已经不是dict了
会把我们的dst也就是父类father的secret属性赋值为secret![image-20240318200933369]
到这里我们就明白了污染的整个过程了,也明白了原理
别卷了,别卷了,再卷死人了