# Pickle opcodes. See pickletools.py for extensive docs. The listing # here is in kind-of alphabetical order of 1-character pickle code. # pickletools groups them by purpose.
MARK = b'('# push special markobject on stack 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 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
换行符代表参数的结束
( 为压入一个 mark object,用以构建 tuple、list 等对象或调用函数时标识数据的开始位置
. 为每个 pickle 序列化数据都必须有的结束标识符
I为压入整数,接收一个整数参数,其后跟一个换行符表示参数结束
1 2
>>> pickle.loads(b'I12345\n.') 12345
0 执行 POP 操作,1 针对 mark object 执行 POP 操作,2 复制栈顶元素,即将栈顶元素再次入栈
d l t 分别从栈中数据创建 dict、list、tuple 对象,以 mark object 标识数据开始,并会将数据和 mark object 从栈中移除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
data2 = b"""(S'a' S'b' S'c' S'd' t."""
('a', 'b', 'c', 'd')
0: ( MARK 1: S STRING 'a' 6: S STRING 'b' 11: S STRING 'c' 16: S STRING 'd' 21: t TUPLE (MARK at 0) 22: . STOP highest protocol among opcodes = 0
a = A() data4 = b"""c__main__ a (S'a' I1 db.""" pickle.loads(data4) print(a.a)
1
0: c GLOBAL '__main__ a'
12: ( MARK
13: S STRING 'a'
18: I INT 1
21: d DICT (MARK at 12)
22: b BUILD
23: . STOP
highest protocol among opcodes = 0<br />
c push self.find_class(modname, name);
这里是用c find到了对象a
然后b调用函数来修改对象中的属性,因为要求传入一个dict所以调用d,上面压入的是两个参数
栈底是要修改的对象a,栈顶是传入的参数,很好理解
c 为最常见的 opcode 之一,其作用可以归结为调用 find_class 方法并将结果入栈,其接收两个参数,第一个参数为 modname,第二个参数为 name
for _ inrange(10): #猜10次 number = '' while number == '': try: number = input('Input the number you guess\n> ') number = int(number) except ValueError: number = '' pass #将number封装到ticket中,序列化ticket对象 ticket = Ticket(number) ticket = pickle.dumps(ticket)
asserttype(ticket) == Ticket #判断反序列化后的ticket是不是ticket对象 ifnot ticket.is_valid(): #is_valid判断 print('The number is invalid.') game.next_game(Ticket(-1)) continue win = game.next_game(ticket) if win: text = "Congratulations, you get the right number!" else: text = "Wrong number, better luck next time." print(text)
if game.is_win(): text = "Game over! You win all the rounds, here is your flag %s" % get_flag() else: text = "Game over! You got %d/%d." % (game.win_count, game.round_count) print(text)
except Exception: print('Houston, we got a problem.')
def__eq__(self, other): returntype(other) is Animal and self.name == other.name and self.category == other.category classRestrictedUnpickler(pickle.Unpickler): deffind_class(self, module, name): print(name) if module == '__main__': #限制模块 returngetattr(sys.modules['__main__'], name) raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name)) defrestricted_loads(s): return RestrictedUnpickler(io.BytesIO(s)).load()
defread(filename, encoding='utf-8'): withopen(filename, 'r', encoding=encoding) as fin: return fin.read()
@app.route('/', methods=['GET', 'POST']) defindex(): if request.args.get('source'): return Response(read(__file__), mimetype='text/plain')
if request.method == 'POST': try: pickle_data = request.form.get('data') ifb'R'in base64.b64decode(pickle_data): #过滤R return'No... I don\'t like R-things. No Rabits, Rats, Roosters or RCEs.' else: result = restricted_loads(base64.b64decode(pickle_data)) iftype(result) isnot Animal: return'Are you sure that is an animal???' correct = (result == Animal(secret.name, secret.category)) #判断 return"result={}\npickle_data={}\ngiveflag={}\n".format(result, pickle_data, correct) except Exception as e: print(repr(e)) return"Something wrong"