Last active
May 30, 2022 03:33
Revisions
-
maple3142 revised this gist
May 30, 2022 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,5 @@ # use xx.py to build the opcode mapping # need to compile https://github.com/python/cpython/tree/702e0da000bf28aa20cb7f3893b575d977506495 at ./cpython-702e0da000bf28aa20cb7f3893b575d977506495 rm -rf __pycache__;PYTHONHOME=`pwd` ./bin/python -c 'import hello' ; mv __pycache__/hello.cpython-312.pyc patched_hello.pyc rm -rf __pycache__; ./cpython-702e0da000bf28aa20cb7f3893b575d977506495/python -c 'import hello' ; mv __pycache__/hello.cpython-312.pyc original_hello.pyc ./cpython-702e0da000bf28aa20cb7f3893b575d977506495/python xx.py -
maple3142 revised this gist
May 30, 2022 . 1 changed file with 1 addition and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -143,10 +143,7 @@ def walk(code): mask = consts[bc[j + 16 + 1]] # assert opname[bc[j + 22]] == "LOAD_CONST" value = consts[bc[j + 22 + 1]] print(f"{j} flag[{idx}] & {mask} == {value}") if mask == value: flag[idx] |= mask print(flag) -
maple3142 revised this gist
May 30, 2022 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,5 +1,6 @@ # A Python 3 script trying to in include every bytecode in Python 3.12, but it actually misses these bytecode: # {'LOAD_ASSERTION_ERROR', 'CHECK_EG_MATCH', 'UNPACK_EX', 'POP_JUMP_BACKWARD_IF_NONE', 'DELETE_DEREF', 'POP_JUMP_FORWARD_IF_NOT_NONE', 'EXTENDED_ARG', 'PRINT_EXPR', 'LOAD_CLASSDEREF', 'MAP_ADD', 'POP_JUMP_BACKWARD_IF_NOT_NONE', 'JUMP_IF_FALSE_OR_POP', 'IS_OP', 'LIST_TO_TUPLE', 'JUMP_IF_TRUE_OR_POP', 'PREP_RERAISE_STAR'} # the idea comes from https://github.com/kholia/dedrop def main(): (lambda:1)() -
maple3142 created this gist
May 30, 2022 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,430 @@ # A Python 3 script trying to in include every bytecode in Python 3.12, but it actually misses these bytecode: # {'LOAD_ASSERTION_ERROR', 'CHECK_EG_MATCH', 'UNPACK_EX', 'POP_JUMP_BACKWARD_IF_NONE', 'DELETE_DEREF', 'POP_JUMP_FORWARD_IF_NOT_NONE', 'EXTENDED_ARG', 'PRINT_EXPR', 'LOAD_CLASSDEREF', 'MAP_ADD', 'POP_JUMP_BACKWARD_IF_NOT_NONE', 'JUMP_IF_FALSE_OR_POP', 'IS_OP', 'LIST_TO_TUPLE', 'JUMP_IF_TRUE_OR_POP', 'PREP_RERAISE_STAR'} def main(): (lambda:1)() zzz = 1 del zzz a = 1; b = 2 (a, b) = (b, a) a = 1 (a, a, a) = (a, a, a) {'a':1} x = list(range(6)) x[2:4] += 'abc' a = 1 a = +a a = 1 a = -a a = 1 a = not a a = 1 a = 1 a = ~a a = [i*i for i in (1,2)] a = 2 a = a ** 2 a = 2 a = a * 2 a = 2 a = a / 2 a = 2 a = a % 2 a = 2 a = a + 2 a = 2 a = a - 2 a = [1] a[0] a = 2 a = a // 2 a = 2 a = a / 2 a = a // 2 a = 1 a //= 10.2 a = 1 a /= 2 a //= 2 b = 2 a //= b a /= b a = [1,2,3] a = a[:] a = [1,2,3] a = a[1:] a = [1,2,3] a = a[:2] a = [1,2,3] a = a[1:2] a = [1,2,3] a[:] = [1,2,3] a = [1,2,3] a[1:] = [2,3] a = [1,2,3] a[:2] = [1,2] a = [1,2,3] a[1:2] = [2] a = [1,2,3] del a[:] a = [1,2,3] del a[1:] a = [1,2,3] del a[:2] a = [1,2,3] del a[1:2] a = 1 a += 1 a = 1 a -= 1 a = 1 a *= 1 a = 1 a /= 1 a = 1 a %= 1 a = [0, 1] a[0] = 1 a = [1] del a[0] a = 1 a = a << 1 a = 1 a = a >> 1 a = 1 a = a & 1 a = 1 a = a ^ 1 a = 1 a = a | 1 a = 1 a **= 1 for a in (1,2): pass print("hello world!") print() def fv(a,b): pass av = (1,2) fv(*av) def fkv(a,b,c): pass akv = {"b":1,"c":2} b = (3,) fkv(*b, **akv) def fk(a,b): pass ak = {"a":1,"b":2} fk(**ak) import sys print("hello world", end=' ', file=sys.stdout) import sys print(file=sys.stdout) del sys.api_version zzz = 89 del zzz a = 1 a <<= 1 a = 1 a >>= 1 a = 1 a &= 1 a = 1 a ^= 1 a = 1 a |= 1 for a in (1,2): break try: with open("1.txt") as f: print(f.read()) except: pass class a: pass # empty file exec("print('hello world')", globals(), locals()) frozenset({1, 2, 3}) for a in (1,2): break try: a = 1 except ValueError: a = 2 finally: a = 3 class a: pass a = 1 a = 1 del a (a, b) = "ab" for i in (1,2): pass a = 0 b = [0] b[a] += 1 a = 1 a = 1 a = a a = 1; a = (a, a) [1,2,3] {"a":1,"b":2} [].sort() a = 1 == 2 a = 2+3+4 "@"*4 a="abc" + "def" a = 3**4 a = 13//4 a //= 2 from dis import opmap if 1 == 2: pass else: pass if 1 == 2: pass else: pass if not(1 == 2): pass else: pass for i in (1,2): pass for x in (1,2): try: continue except: pass while 0 > 1: pass try: a = 1 except ValueError: a = 2 finally: a = 3 try: a = 1 except ValueError: a = 2 finally: a = 3 a = [1,2,3,4] b = a[::-1] xyz = 0 def lolcats(): global xyz pass raise ValueError def fc(): a = 1 zyx = set() zyx.add("hello") zyx.add("abc") zyx.remove("hello") def g(): return a + 1 return g() print(fc()) def f(): pass f() def f1(): from sys import environ a = 1 a = a def f2(): a = 1 a = a def f3(): a = 1 del a import sys sys.stderr = sys.stdout import sys # del sys.stderr l1 = 0 def lolx(): global l1 l1 = 1 l2 = 0 def loly(): global l2 del l2 def f(): a = 3 b = 5 def g(): return a + b f() mylist = [1, 1, 1, 2, 2, 3] z = {x for x in mylist if mylist.count(x) >= 2} a = {x for x in 'abracadabra' if x not in 'abc'} set([20, 0]) lolx() loly() def foo(): print('hello') yield 1 print('world') yield 2 a = foo() print(next(a)) print(next(a)) def myfunc(alist: list): return len(alist) def peko(*args, **kwargs): yield from f() 1 2 3 if True: return 1 1 2 3 pass async def f(): await f() async for x in f(): pass async def g(): await g() yield 1 async with x: pass class A: n: int a = 1 match a: case 1: print(1) case []: pass case A(): pass case {1:a}: pass peko(*[123]) peko(**{'a':1}) peko(*[123], **{'a':1}) (x for x in []) dt={} dt|={'1':123} f'1{2}3' {**{1:2}} tuple([1,2,3]) del a from os import * peko(*[1,2,3,4,5,6,7,8,9]) assert True class A: pass main() This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,158 @@ # fix the opcode from mapping, and attempt to solve for the flag # but it turns out the bytecode also patches python to make `bytes([ord('F'), ...])` behavior different # so it is necessary to guess or reverse how it works # out team got the flag by guessing import dis import marshal from dis import opname fmap = { 151: 151, 100: 108, 132: 133, 90: 98, 2: 12, 101: 103, 166: 166, 0: 10, 171: 172, 1: 11, 108: 100, 106: 106, 95: 95, 97: 99, 102: 101, 71: 70, 120: 120, 107: 104, 114: 111, 110: 115, 32: 30, 30: 33, 152: 152, 129: 129, 92: 96, 31: 32, 33: 31, 99: 97, 103: 107, 142: 142, 105: 102, 164: 163, 68: 71, 122: 122, 155: 155, 157: 157, 165: 162, 162: 0, 91: 91, 84: 84, 9: 15, 83: 86, 125: 125, 126: 126, 124: 124, 116: 116, 133: 131, 25: 35, 60: 61, 10: 0, 11: 1, 12: 2, 15: 9, 61: 60, 93: 93, 140: 140, 156: 156, 172: 171, 96: 92, 53: 53, 160: 160, 35: 25, 49: 0, 115: 112, 119: 119, 89: 87, 104: 109, 163: 164, 36: 49, 109: 105, 176: 176, 130: 130, 145: 145, 135: 137, 138: 138, 136: 136, 149: 146, 137: 139, 98: 90, 175: 175, 146: 147, 118: 118, 75: 82, 86: 83, 69: 69, 123: 0, 134: 128, 131: 0, 50: 37, 51: 51, 54: 54, 87: 89, 52: 52, 85: 85, } imap = {v: k for k, v in fmap.items()} with open("chall.pyc", "rb") as f: header = f.read(16) code = marshal.load(f) def walk(code): new_code = bytes([v if i & 1 else imap[v] for i, v in enumerate(code.co_code)]) new_consts = tuple( [c if type(c) != type(code) else walk(c) for c in code.co_consts] ) return code.replace(co_consts=new_consts, co_code=new_code) new_code = walk(code) # dis.dis(new_code) with open("new_chall.pyc", "wb") as f: f.write(header) marshal.dump(new_code, f) # dis.dis(new_code) check_flag = new_code.co_consts[1] bc = check_flag.co_code consts = check_flag.co_consts base = 48 chk = 84 - 48 flag = bytearray(59) for i in range(1000): j = base + chk * i if j + 4 >= len(bc): break # dis.dis(bc[j:j+chk]) # assert opname[bc[j + 4]] == "LOAD_CONST" idx = consts[bc[j + 4 + 1]] # assert opname[bc[j + 18]] == "BINARY_OP" assert bc[j + 18 + 1] == 1 # assert opname[bc[j + 16]] == "LOAD_CONST" mask = consts[bc[j + 16 + 1]] # assert opname[bc[j + 22]] == "LOAD_CONST" value = consts[bc[j + 22 + 1]] # if mask in [8,64,128]: # value ^= mask if idx <= 0: print(f"{j} flag[{idx}] & {mask} == {value}") if mask == value: flag[idx] |= mask print(flag) # bytearray(b'\x8e\x86\x8d\x95\xbb\xaa\xb9\xb2\xc8\xb3\xba\xc5\xaf\xc3\xc8\xc7\xc5\xb9\xcf\xe3\xe3\xe6\xd3\xd3\xd1\xe4\xe1\xcd\xe3\xf2\xed\xfa\xe0\xe9\xea\xddC0EH\xe7\xf3\x0f\xed\x06\x17\x02\xf5_Z^\x13`\x16\x15fhj)') from new_chall import check_flag print(check_flag(flag)) This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,35 @@ # compare the bytecode difference to build a mapping from original opcode and patched opcode # it is actually not correct as it assumes every instruction is 2 bytes, which is untrue is later python versions import dis import marshal # rm -rf __pycache__;PYTHONHOME=`pwd` ./bin/python -c 'import hello' ; xxd __pycache__/hello.cpython-312.pyc && mv __pycache__/hello.cpython-312.pyc patched_hello.pyc # rm -rf __pycache__; ./cpython-702e0da000bf28aa20cb7f3893b575d977506495/python -c 'import hello' ; xxd __pycache__/hello.cpython-312.pyc && mv __pycache__/hello.cpython-312.pyc original_hello.pyc fp=open('patched_hello.pyc','rb') fo=open('original_hello.pyc','rb') fp.seek(16) fo.seek(16) orig = marshal.load(fo) patched = marshal.load(fp) dt = {} dt2 = {} def walk(orig, patched): print(orig.co_name, len(orig.co_code), len(patched.co_code)) for i in range(0, len(orig.co_code), 2): o = dis.opname[orig.co_code[i]] p = dis.opname[patched.co_code[i]] if o in dt: if dt[o] != p: print('NEQ',o, dt[o], p) dt[o] = p dt2[orig.co_code[i]] = patched.co_code[i] for x, y in zip(orig.co_consts, patched.co_consts): if type(x) == type(orig) and type(y) == type(patched): walk(x,y) walk(orig, patched) print(dt) print(len(dt.keys())) print(set(dis.opmap.keys()) - set(dt.keys())) print(dt2) This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,4 @@ # use xx.py to build the opcode mapping rm -rf __pycache__;PYTHONHOME=`pwd` ./bin/python -c 'import hello' ; mv __pycache__/hello.cpython-312.pyc patched_hello.pyc rm -rf __pycache__; ./cpython-702e0da000bf28aa20cb7f3893b575d977506495/python -c 'import hello' ; mv __pycache__/hello.cpython-312.pyc original_hello.pyc ./cpython-702e0da000bf28aa20cb7f3893b575d977506495/python xx.py