Saved payload as pyc with this script:
import marshal , zlib , base64
open ( 'code.pyc' , 'wb' ) . write ( '03f30d0a5a8cbc52' . decode ( 'hex' ) + zlib . decompress ( base64 . b64decode ( 'eJyNVktv...kLHmeCBQ==' )))
Disassembled the pyc file with uncompyle:
kt@ubuntu:~/ctf/hitcon2016$ uncompyle6 code.pyc
# Python 2.7 (decompiled from Python 2.7)
# Embedded file name: <string>
# Compiled at: 2013-12-26 21:06:50
def main--- This code section failed: ---
1 0 LOAD_GLOBAL 'chr'
3 LOAD_CONST 108
6 CALL_FUNCTION_1 ''
9 LOAD_GLOBAL 'chr'
12 LOAD_CONST 108
15 CALL_FUNCTION_1 ''
18 LOAD_GLOBAL 'chr'
21 LOAD_CONST 97
...
Simulated the string creation with this C# code:
static void HandcraftedPyc ()
{
// Call me a Python virtual machine! I can interpret Python bytecodes!!!
var cmds = File . ReadAllLines ( @"disas.txt" ). Select ( x => Regex . Match ( x , @"(.*?)\s+(.*)" ). Groups . OfType < Group >(). Skip ( 1 ). Select ( g => g . Value ). ToArray ()). ToArray ();
var stack = new Stack < string >();
foreach ( var cmd in cmds )
{
if ( cmd [ 0 ] == "LOAD_GLOBAL" || cmd [ 0 ] == "LOAD_CONST" )
stack . Push ( cmd [ 1 ]);
else if ( cmd [ 0 ] == "CALL_FUNCTION_1" )
{
var arg = stack . Pop ();
var func = stack . Pop ();
if ( func == "'chr'" )
stack . Push ( "" + ( char ) int . Parse ( arg ));
else
Debugger . Break ();
}
else if ( cmd [ 0 ] == "ROT_TWO" )
{
var arg1 = stack . Pop ();
var arg2 = stack . Pop ();
stack . Push ( arg1 );
stack . Push ( arg2 );
}
else if ( cmd [ 0 ] == "BINARY_ADD" )
{
var arg1 = stack . Pop ();
var arg2 = stack . Pop ();
stack . Push ( arg2 + arg1 );
}
else
Debugger . Break ();
}
}
At the end the stack contains one variable, the ‘decrypted’ string. The first code block created the string “Call me a Python virtual machine! I can interpret Python bytecodes!!!”, while the second code block created the flag:
hitcon{Now you can compile and run Python bytecode in your brain!}