Thanks to Deroko and some ARTeam members to play with CLGT. Below is the write up by Deroko posted on http://www.xchg.info/wiki/index.php?title=CodeGate2012_bin500

CodeGate2012 bin500

Challenge: Seeing that it is not all.
Link to challenge: http://deroko.phearless.org/codegate2012/bin/bin500.zip

This binary is double ReWolf vm, and python script for modified Olly by Immunity.

Script which comes with binary uses marshal.loads to load already compiled pyc code which was produced with marshal.dump

To get .pyc back we need to make some modification to our script:

Modifiedscript.png

Now C:test.pyc will have dump of python bytecode.

If you look carefully through script, some strings might look like a clue:

readMemory
getRegs
EIP
Nice work, Key1 :
But, Find Next Key!
Nice work, Key2 :
Input Key : Key1 + Key2
Nothing Found ...

So this script will probably try to read from current EIP some bytes (readMemory + EIP are good hint), and make key out of it. After modifying test.pyc to have proper layout:

00000000  03 f3 0d 0a dc dd e2 4c  63 00 00 00 00 00 00 00  |.......Lc.......|
00000010  00 02 00 00 00 40 00 00  00 73 22 00 00 00 64 00  |.....@...s"...d.|
00000020  00 64 01 00 6c 00 00 5a  00 00 64 02 00 84 00 00  |.d..l..Z..d.....|

Which is actually 4 bytes for python signature4 bytes for timestamp +marshal.dump() data we get .pyc file which we can decompile.

For sake of this solution, we will use some simple program to dump python byte-code, and one I found here:http://nedbatchelder.com/blog/200804/the_structure_of_pyc_files.html

After disassembling binary with this python script we get (I cut not important parts):

             15 LOAD_ATTR                2 (readMemory)
             18 LOAD_CONST               1 (4237456)
             21 LOAD_CONST               2 (80)
             24 CALL_FUNCTION            2

So from address 40A890 it will read 80 bytes and keep it in internal buffer.

Now comes interesting part when it actually gets keys:

 19          54 LOAD_FAST                4 (regs)
             57 LOAD_CONST               3 ('EIP')
             60 BINARY_SUBSCR
             61 LOAD_CONST               4 (4273157)
             64 COMPARE_OP               2 (==)
             67 POP_JUMP_IF_FALSE      161

and

 23     >>  161 LOAD_FAST                4 (regs)
            164 LOAD_CONST               3 ('EIP')
            167 BINARY_SUBSCR
            168 LOAD_CONST              15 (4278021)
            171 COMPARE_OP               2 (==)
            174 POP_JUMP_IF_FALSE      276

If you look at out.txt (in attachment) you may also see what’s read from where as this python script is not complicated, and python byte code is quite easy to understand.

So just set EIP to be 413405 and run script, and you will get 1st key. Then set EIP to be 414705 and run scrip again. If you did, everything correct you should see in Log of Immunity Debugger this:

Key.png

So final key is Never_up_N3v3r_1n

Greetings

I would like to say tnx to my ARTeam mates, vnsecurity guys, and rd , and of course to superkhung for listening to my random blabing on skype during CTF :)

Author

deroko of ARTeam