Cyber Cooperative CTF 2023

Dis [300 pts]

Our field agents extracted the disassembly for a function that we think generates a secret flag. But it doesn’t look like any kind of disassembly we can recognize. Can you figure it out?

dis.txt


We’re given a .txt file. Here it is:

 20           0 LOAD_CONST               1 (36054)

 21           2 LOAD_CONST               2 (55674)

 22           4 LOAD_CONST               3 (30924)

 23           6 LOAD_CONST               4 (59454)

 24           8 LOAD_CONST               5 (53145)

 25          10 LOAD_CONST               6 (70425)

 26          12 LOAD_CONST               7 (72954)

 27          14 LOAD_CONST               8 (15984)

 28          16 LOAD_CONST               9 (97605)

 29          18 LOAD_CONST              10 (93024)

 30          20 LOAD_CONST              11 (74205)

 31          22 LOAD_CONST              12 (34515)

 32          24 LOAD_CONST              13 (91584)

 33          26 LOAD_CONST              13 (91584)

 34          28 LOAD_CONST              14 (95364)

 35          30 LOAD_CONST              13 (91584)

 36          32 LOAD_CONST               4 (59454)

 37          34 LOAD_CONST              10 (93024)

 38          36 LOAD_CONST              15 (38394)

 39          38 LOAD_CONST              16 (17235)

 40          40 LOAD_CONST              17 (11115)

 41          42 LOAD_CONST               7 (72954)

 42          44 LOAD_CONST               8 (15984)

 43          46 LOAD_CONST              13 (91584)

 44          48 LOAD_CONST              10 (93024)

 45          50 LOAD_CONST               8 (15984)

 46          52 LOAD_CONST              13 (91584)

 47          54 LOAD_CONST              10 (93024)

 48          56 LOAD_CONST               3 (30924)

 49          58 LOAD_CONST              10 (93024)

 50          60 LOAD_CONST              18 (78084)

 51          62 LOAD_CONST               3 (30924)

 52          64 LOAD_CONST              14 (95364)

 53          66 LOAD_CONST              13 (91584)

 54          68 LOAD_CONST               1 (36054)

 55          70 LOAD_CONST              11 (74205)

 56          72 LOAD_CONST               3 (30924)

 57          74 LOAD_CONST              18 (78084)

 58          76 LOAD_CONST              19 (13644)

 59          78 LOAD_CONST              10 (93024)

 60          80 LOAD_CONST              20 (99144)

 61          82 LOAD_CONST               3 (30924)

 62          84 LOAD_CONST              18 (78084)

 63          86 LOAD_CONST              13 (91584)

 64          88 LOAD_CONST              21 (99945)
             90 BUILD_LIST              45
             92 STORE_FAST               0 (n)

 67          94 SETUP_LOOP              82 (to 178)
             96 LOAD_GLOBAL              0 (enumerate)
             98 LOAD_FAST                0 (n)
            100 CALL_FUNCTION            1
            102 GET_ITER
        >>  104 FOR_ITER                70 (to 176)
            106 UNPACK_SEQUENCE          2
            108 STORE_FAST               1 (i)
            110 STORE_FAST               2 (x)

 68         112 LOAD_GLOBAL              1 (int)
            114 LOAD_GLOBAL              2 (str)
            116 LOAD_FAST                0 (n)
            118 LOAD_FAST                1 (i)
            120 BINARY_SUBSCR
            122 CALL_FUNCTION            1
            124 LOAD_CONST               0 (None)
            126 LOAD_CONST               0 (None)
            128 LOAD_CONST              26 (-1)
            130 BUILD_SLICE              3
            132 BINARY_SUBSCR
            134 CALL_FUNCTION            1
            136 LOAD_FAST                0 (n)
            138 LOAD_FAST                1 (i)
            140 STORE_SUBSCR

 69         142 LOAD_FAST                0 (n)
            144 LOAD_FAST                1 (i)
            146 DUP_TOP_TWO
            148 BINARY_SUBSCR
            150 LOAD_CONST              23 (999)
            152 INPLACE_SUBTRACT
            154 ROT_THREE
            156 STORE_SUBSCR

 70         158 LOAD_FAST                0 (n)
            160 LOAD_FAST                1 (i)
            162 DUP_TOP_TWO
            164 BINARY_SUBSCR
            166 LOAD_CONST              24 (432)
            168 INPLACE_FLOOR_DIVIDE
            170 ROT_THREE
            172 STORE_SUBSCR
            174 JUMP_ABSOLUTE          104
        >>  176 POP_BLOCK

 72     >>  178 LOAD_CONST              25 ('')
            180 STORE_FAST               3 (o)

 73         182 SETUP_LOOP              24 (to 208)
            184 LOAD_FAST                0 (n)
            186 GET_ITER
        >>  188 FOR_ITER                16 (to 206)
            190 STORE_FAST               4 (p)

 74         192 LOAD_FAST                3 (o)
            194 LOAD_GLOBAL              3 (chr)
            196 LOAD_FAST                4 (p)
            198 CALL_FUNCTION            1
            200 INPLACE_ADD
            202 STORE_FAST               3 (o)
            204 JUMP_ABSOLUTE          188
        >>  206 POP_BLOCK

 75     >>  208 LOAD_FAST                3 (o)
            210 RETURN_VALUE

If you’re not aware of what this is, a quick search of one of the instructions immediately tells you that this is Python bytecode.

I tried seraching for a way to compile bytecode to a source file, but came up empty. Hence, I had to just read the assembly. Using this helped me determine what all of the instructiosn did.

There’s really no way to explain it. I will just provide my comments, which should be sufficient at explaining what’s happening. If you want to solve this yourself, be patient – it may take several read-throughs to understand the bytecode.

My comments:

 20           0 LOAD_CONST               1 (36054)

 21           2 LOAD_CONST               2 (55674)

 22           4 LOAD_CONST               3 (30924)

 23           6 LOAD_CONST               4 (59454)

 24           8 LOAD_CONST               5 (53145)

 25          10 LOAD_CONST               6 (70425)

 26          12 LOAD_CONST               7 (72954)

 27          14 LOAD_CONST               8 (15984)

 28          16 LOAD_CONST               9 (97605)

 29          18 LOAD_CONST              10 (93024)

 30          20 LOAD_CONST              11 (74205)

 31          22 LOAD_CONST              12 (34515)

 32          24 LOAD_CONST              13 (91584)

 33          26 LOAD_CONST              13 (91584)

 34          28 LOAD_CONST              14 (95364)

 35          30 LOAD_CONST              13 (91584)

 36          32 LOAD_CONST               4 (59454)

 37          34 LOAD_CONST              10 (93024)

 38          36 LOAD_CONST              15 (38394)

 39          38 LOAD_CONST              16 (17235)

 40          40 LOAD_CONST              17 (11115)

 41          42 LOAD_CONST               7 (72954)

 42          44 LOAD_CONST               8 (15984)

 43          46 LOAD_CONST              13 (91584)

 44          48 LOAD_CONST              10 (93024)

 45          50 LOAD_CONST               8 (15984)

 46          52 LOAD_CONST              13 (91584)

 47          54 LOAD_CONST              10 (93024)

 48          56 LOAD_CONST               3 (30924)

 49          58 LOAD_CONST              10 (93024)

 50          60 LOAD_CONST              18 (78084)

 51          62 LOAD_CONST               3 (30924)

 52          64 LOAD_CONST              14 (95364)

 53          66 LOAD_CONST              13 (91584)

 54          68 LOAD_CONST               1 (36054)

 55          70 LOAD_CONST              11 (74205)

 56          72 LOAD_CONST               3 (30924)

 57          74 LOAD_CONST              18 (78084)

 58          76 LOAD_CONST              19 (13644)

 59          78 LOAD_CONST              10 (93024)

 60          80 LOAD_CONST              20 (99144)

 61          82 LOAD_CONST               3 (30924)

 62          84 LOAD_CONST              18 (78084)

 63          86 LOAD_CONST              13 (91584)

 64          88 LOAD_CONST              21 (99945)
             90 BUILD_LIST              45 # list of above
             92 STORE_FAST               0 (n) # var[0] = list

 67          94 SETUP_LOOP              82 (to 178) # initialize loop
             96 LOAD_GLOBAL              0 (enumerate) # load enumerate function
             98 LOAD_FAST                0 (n) # load list
            100 CALL_FUNCTION            1 # call enumerate...?
            102 GET_ITER
        >>  104 FOR_ITER                70 (to 176) # start of actual looping, iterate through list
            106 UNPACK_SEQUENCE          2 # unpack for enumeration
            108 STORE_FAST               1 (i) # index
            110 STORE_FAST               2 (x) # value in list

 68         112 LOAD_GLOBAL              1 (int) # load int cast onto stack
            114 LOAD_GLOBAL              2 (str) # load str cast onto stack
            116 LOAD_FAST                0 (n) # push list onto stack
            118 LOAD_FAST                1 (i) # push index onto stack
            120 BINARY_SUBSCR # store list[i] at top of stack (TOS), replacing i
            122 CALL_FUNCTION            1 # call top of stack function --> cast to string
            124 LOAD_CONST               0 (None) # push onto stack
            126 LOAD_CONST               0 (None) # push onto stack
            128 LOAD_CONST              26 (-1) # push onto stack
            130 BUILD_SLICE              3 # build and push slice of first three items on stack, i.e. (None, None, -1) --> equivalent to range(start, stop, step)
            132 BINARY_SUBSCR # list[None:None:-1]...? --> reversed string
            134 CALL_FUNCTION            1 # cast to int
            136 LOAD_FAST                0 (n) # push list onto stack
            138 LOAD_FAST                1 (i) # push index onto stack
            140 STORE_SUBSCR # list[i] = number with digits backwards

# list[i] = list[i] - 999
 69         142 LOAD_FAST                0 (n) # push list onto stack
            144 LOAD_FAST                1 (i) # push index onto stack
            146 DUP_TOP_TWO # duplicate top two references on the stack (i, n)
            148 BINARY_SUBSCR # top of stack = list[i]
            150 LOAD_CONST              23 (999) # push 999 onto stack
            152 INPLACE_SUBTRACT # TOS = list[i] - 999
            154 ROT_THREE # stacK: TOS, TOS1, TOS2 --> TOS1, TOS2, TOS
            156 STORE_SUBSCR # TOS1[TOS] = TOS2

# list[i] = list[i]//432
 70         158 LOAD_FAST                0 (n) # push list onto stack
            160 LOAD_FAST                1 (i) # push index onto stack
            162 DUP_TOP_TWO # duplicate top two references on the stack (i, n)
            164 BINARY_SUBSCR # top of stack = list[i]
            166 LOAD_CONST              24 (432) # push 432 onto stack
            168 INPLACE_FLOOR_DIVIDE # TOS = TOS1//TOS = list[i]//432
            170 ROT_THREE # stacK: TOS, TOS1, TOS2 --> TOS1, TOS2, TOS
            172 STORE_SUBSCR # TOS1[TOS] = TOS2 --> list[i] = list[i]//432
            174 JUMP_ABSOLUTE          104 # return to beginning of loop
        >>  176 POP_BLOCK # pop loop block (end loop)

 72     >>  178 LOAD_CONST              25 ('') # push empty string to stack
            180 STORE_FAST               3 (o) # store '' to var[3]

 73         182 SETUP_LOOP              24 (to 208) # loop
            184 LOAD_FAST                0 (n) # push list to stack
            186 GET_ITER
        >>  188 FOR_ITER                16 (to 206) # actual start of loop
            190 STORE_FAST               4 (p) # store list[i] to var[4]

 74         192 LOAD_FAST                3 (o) # push var[3] to stack
            194 LOAD_GLOBAL              3 (chr) # load chr function
            196 LOAD_FAST                4 (p) # push index to stack
            198 CALL_FUNCTION            1 # call chr function on p
            200 INPLACE_ADD # add p to var[3]
            202 STORE_FAST               3 (o) # var[3] = o
            204 JUMP_ABSOLUTE          188 # return to loop start
        >>  206 POP_BLOCK

 75     >>  208 LOAD_FAST                3 (o) # push var[3] to top of stack
            210 RETURN_VALUE # return top of stack

Now that we’ve reversed the function, we can write a simple Python program to simulate the same steps and get the flag!

a = [36054,55674,30924,59454,53145,70425,72954,15984,97605,93024,74205,34515,91584,91584,95364,91584,59454,93024,38394,17235,11115,72954,15984,91584,93024,15984,91584,93024,30924,93024,78084,30924,95364,91584,36054,74205,30924,78084,13644,93024,99144,30924,78084,91584,99945]

for i in range(len(a)):
    s = str(a[i])
    s = s[::-1]
    a[i] = int(s)
    a[i] -= 999
    a[i] //= 432

print(a)

for i in a:
    print(chr(i), end='')

Running the script gets the flag:

flag{whos_running_python_on_a_mainframe_damn}