[CTF Series #8] FlareOn6 wopr PythonInMemory

GhouLSec
5 min readOct 2, 2019

--

This is the another interesting flareon challenge for me as it involves python memory, python debugger and maths solver library. Given a wopr.exe executable which requires user to enter some command and by given a correct launching code, flag was given.

Initial Interface of wopr.exe

Main steps involved:

  • Determine the type of executable and compiler used
  • Extract the executable using suitable tools
  • Using memory forensic tools to find out the hidden code
  • Using python debugger (pdb) to get the correct value that found in the compare string function
  • Using maths solver tools to solve the linear XOR equation
  • Enter launch code (Flag Get!)

Determine the type of executable and compiler used

In CFF explorer, it found that the executable file is compiled using python2exe program as there have some python related strings (python37.dll & *.pyd etc.) in the hex view.

Hex View of the wopr.exe

Extract the executable using suitable tools

Using this tool to unpack the python exe.

cmd: python pyinstxtractor.py wopr.exe

Go into extracted folder and decompile the entry point of the python files (in this case pyiboot02_cleanup) using this link.
*Manual Decompilation check here.
Before put the file into the decompiler, rename and add .pyc extention into it. The pyc decompiled code:

From the code above, the pointer of print() and exec() was changed. So, all the print() function actually is exec(). Hmm so simple obfuscation. 🐱‍👤

The io.BytesIO() will read and write data within the memory bytestream buffer. Therefore, i cannot simply using the print() to read the value in memory and trace it. 😪

Then continue analysis, I saw something interesting in exec(lzma.decompress()) and it will cause error when i run it.

...
leg = io.BytesIO()
...
print((lzma.decompress(fire(eye(__doc__.encode()), bytes([i]) + BOUNCE), format=lzma.FORMAT_XZ)))
...

However, the exec() will leave a trace in the memory dump when it execute some something. So, I execute the code and record the memory dump using the dumpIt.exe (Explaination here)

Using DumpIt to create dump file

Then, using volatility to run pslist to find out the child wopr.exe process as the main code mostly running those library loading stuffs.

vol.py -f “WIN-7F8FIFSQEEB-20191002–131743.raw” — profile=”Win8SP0x64" pslist

After identified the PID of the wopr.exe, run the volatility memdump to dump out the relevent child wopr.exe process and the compressed code was found.

vol.py -f “WIN-7F8FIFSQEEB-20191002–131743.raw” — profile=”Win8SP0x64" memdump -p 3396 -D .

This linear xor equation catched my eyes as this is the launch code need to get the flag.

b[0] = x[2] ^ x[3] ^ x[4] ^ x[8] ^ x[11] ^ x[14]
b[1] = x[0] ^ x[1] ^ x[8] ^ x[11] ^ x[13] ^ x[14]
b[2] = x[0] ^ x[1] ^ x[2] ^ x[4] ^ x[5] ^ x[8] ^ x[9] ^ x[10] ^ x[13] ^ x[14] ^ x[15]
b[3] = x[5] ^ x[6] ^ x[8] ^ x[9] ^ x[10] ^ x[12] ^ x[15]
b[4] = x[1] ^ x[6] ^ x[7] ^ x[8] ^ x[12] ^ x[13] ^ x[14] ^ x[15]
b[5] = x[0] ^ x[4] ^ x[7] ^ x[8] ^ x[9] ^ x[10] ^ x[12] ^ x[13] ^ x[14] ^ x[15]
b[6] = x[1] ^ x[3] ^ x[7] ^ x[9] ^ x[10] ^ x[11] ^ x[12] ^ x[13] ^ x[15]
b[7] = x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[8] ^ x[10] ^ x[11] ^ x[14]
b[8] = x[1] ^ x[2] ^ x[3] ^ x[5] ^ x[9] ^ x[10] ^ x[11] ^ x[12]
b[9] = x[6] ^ x[7] ^ x[8] ^ x[10] ^ x[11] ^ x[12] ^ x[15]
b[10] = x[0] ^ x[3] ^ x[4] ^ x[7] ^ x[8] ^ x[10] ^ x[11] ^ x[12] ^ x[13] ^ x[14] ^ x[15]
b[11] = x[0] ^ x[2] ^ x[4] ^ x[6] ^ x[13]
b[12] = x[0] ^ x[3] ^ x[6] ^ x[7] ^ x[10] ^ x[12] ^ x[15]
b[13] = x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7] ^ x[11] ^ x[12] ^ x[13] ^ x[14]
b[14] = x[1] ^ x[2] ^ x[3] ^ x[5] ^ x[7] ^ x[11] ^ x[13] ^ x[14] ^ x[15]
b[15] = x[1] ^ x[3] ^ x[5] ^ x[9] ^ x[10] ^ x[11] ^ x[13] ^ x[15]
if b != h:

However, we need to get the correct h value as the h value is depends on the

trust = windll.kernel32.GetModuleHandleW(None)

since the base pointer of kernel32.dll is different from the binary and our machine, so we cannot just simply run it the get the h value.

Using python debugger (pdb) to get the correct value that found in the compare string function

Since the base pointer of kernel32.dll is different from the binary and our machine, so we cannot just simply run it the get the h value. Here, I’m using the python debugger (pdb) to get the correct h value.

Steps taken in picuture above:

  • Set Breakpoint in CreateProcessW
  • Run until the breakpoint
  • Go to temp file created (most of the python file will drop this in temp file with _MEI<random num>)
  • Go into this -> __init__.py and paste the code from memory with pdb.set_trace()
  • Continue the process in debugger.
  • Step few time and then h value get.
Correct h value

Using maths solver tools to solve the linear XOR equation

To solve the linear XOR equation? Easy, use z3 Solver 🙌

Solver script

Launch code get. Now just play around with the wopr.exe and insert the launch code then the flag is on your hands now 🐱‍🚀. Done~

Flag !!!

Correct me if something is incorrect. 😬

Reference

https://hshrzd.wordpress.com/2018/01/26/solving-a-pyinstaller-compiled-crackme/
https://docs.python.org/3/library/pdb.html
https://github.com/Z3Prover/z3
https://www.fireeye.com/content/dam/fireeye-www/blog/pdfs/FlareOn6_Challenge7_Solution_WOPR.pdf

--

--

GhouLSec
GhouLSec

No responses yet