I joined a random team for this CTF. We came in 3rd place.
Solution
We were provided with the below python bytecode and were required to find the flag. I used the documentation for the Python library dis as reference for the bytecodes.
I noticed that there are a few constants defined by the bytecode.
This is then easily converted into Python:
I then examine the following code. POP_JUMP_IF_FALSE
and POP_JUMP_IF_TRUE
are used to control the flow of execution, thus indicating that there is a presence of a loop. Specifically, if i
is not greater than 0
, the program will jump to offset 80
, which is the end of loop, and jumps back to the offset 40
if i
remains greater than 0
.
-
Any
LOAD_FAST
used essentially loads the variable onto the stack. -
LOAD_GLOBAL
: The body of the loop loads thechr
function and theord
onto the stack. -
BINARY_SUBSCR
: pops the loadedi
andencrypted_part
from the stack, accessesencrypted_part[i]
, and pushes the result onto the stack. -
CALL_FUNCTION
: callsord
with the top stack element (the character fromencrypted_part[i]
) and pushes the result (an integer) onto the stack. -
BINARY_XOR
: A XOR operation is then performed , andchr
is then called on this result, and the resulting character is pushed onto the stack. -
INPLACE_ADD
then pops the two stack elements (flag
and result ofchr
), appends the character toflag
, and pushes the updatedflag
back onto the stack. -
STORE_FAST
Stores the updatedflag
from the stack back into the local variableflag
.
The process is then repeated until i > 0
is false, which then breaks out of the loop.
The rest of the bytecode is then repetitive - the program indexes a character from the list chars
, and append them to the flag.
With this information, I was then able to recreate the original code:
The flag is thus btctf{py7h0nS_d0Nt_By7E_d0_tH3y_Dn3fMNDJ3bS}
.