记录一些python常见的trick
python反序列化
python原型链污染
与javascript类似,也是一切皆对象
__base__
代表着某个类的父类,可以用来去污染到上一层父类的属性,如果有多层的话就要多个base1
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
38
39
40class father:
secret = "haha"
class son_a(father):
pass
class son_b(father):
pass
def merge(src, dst):
# Recursive merge function
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" : "no way"
}
}
}
print(son_a.secret)
#haha
print(instance.secret)
#haha
merge(payload, instance)
print(son_a.secret)
#no way
print(instance.secret)
#no way__class__
用来获取实例化对象的引用1
2instance.__class__ == son_b
True
__globals__
代表全局变量
对于类的内置方法,在重写前都是装饰器,不存在 __globals__
1
2
3
4
5
6
7
8
9def test():
pass
class a:
def __init__(self):
pass
print(test.__globals__ == globals() == a.__init__.__globals__)
#True
这样就可以通过 __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
38
39
40
41
42
43
44
45
46
47secret_var = 114
def test():
pass
class a:
secret_class_var = "secret"
class b:
def __init__(self):
pass
def merge(src, dst):
# Recursive merge function
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 = b()
payload = {
"__init__" : {
"__globals__" : {
"secret_var" : 514,
"a" : {
"secret_class_var" : "Pooooluted ~"
}
}
}
}
print(a.secret_class_var)
#secret
print(secret_var)
#114
merge(payload, instance)
print(a.secret_class_var)
#Pooooluted ~
print(secret_var)
#514
把这里的payload,改成下面的,也可以给b增加原本不存在的属性1
2
3
4
5
6
7
8
9
10payload = {
"__init__" : {
"__globals__" : {
"secret_var" : 514,
"b" : {
"secret_class_var" : "Pooooluted ~"
}
}
}
}
这里并不是非要去污染
__init__
,如果b中有其他成员方法也是可以的
还可以污染到其他文件的内容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
38
39
40
41
42
43import test_1
class cls:
def __init__(self):
pass
def merge(src, dst):
# Recursive merge function
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 = cls()
payload = {
"__init__" : {
"__globals__" : {
"test_1" : {
"secret_var" : 514,
"target_class" : {
"secret_class_var" : "Poluuuuuuted ~"
}
}
}
}
}
print(test_1.secret_var)
#secret
print(test_1.target_class.secret_class_var)
#114
merge(payload, instance)
print(test_1.secret_var)
#514
print(test_1.target_class.secret_class_var)
#Poluuuuuuted ~
sys.modules
sys
模块的 modules
属性以字典的形式包含了程序自开始运行时所有已加载过的模块,可以直接从该属性中获取到目标模块
1 | #test.py |
import
顺序没有影响
当然,在没有 import sys
的情况下,应该如何去拿到modules
可以通过 <模块名>.__spec__.__init__.__globals__['sys']
获取
1 | #test.py |
形参默认值
__defaults__
中存储着函数参数的默认值,可以通过污染该值进行一些攻击
1 | def evilFunc(arg_1 , shell = False): |
上面记录一下原理,其他trick可以看
https://tttang.com/archive/1876