Tags: forensics 

Rating: 5.0

[email protected]:/app$ ps aux | grep python
lost-fi+ 6 0.0 0.1 21908 2772 ? S 12:09 0:00 python2 /app/challenge.py

My first approach was to look for a pyc still somewhere resident in `/proc/$PID/fd/$FD`, but alas, I had no luck. Yet, the python program was still running and hitherto still in memory.

A month ago I remember reading on HackerNews a gist about [how to recover lost Python source code if it's still resident in-memory](https://gist.github.com/simonw/8aa492e59265c1a021f5c5618f9e6b12). I tried it with varying degrees of success, but there were some missing dependencies so I'll report the full install procedure below:

[email protected]:/app$ virtualenv pyrasite
[email protected]:/app$ pyrasite/bin/pip install pyrasite
[email protected]:/app$ pyrasite/bin/pip install uncompyle6
[email protected]:/app$ pyrasite/bin/pyrasite-shell $(pgrep -f "python")

You can now use several [payloads](https://github.com/lmacken/pyrasite/tree/master/pyrasite/payloads).
If you want to extract the source, you'll need [meliae](https://github.com/isaacl/meliae), a python memory analysis tool. On the challenge box I had problems while executing `pyrasite/bin/pip install meliae` so I resorted to manually downloading and compiling the source:

[email protected]:/app$ pip install Cython
[email protected]b7:/app$ pyrasite/bin/pip install --download="." meliae
[email protected]:/app$ tar -zxvf meliae-0.4.0.tar.gz ; rm meliae-0.4.0.tar.gz; cd meliae-0.4.0/ ;
[email protected]:/app/meliae-0.4.0$ python ./setup.py install

and then, when the attached python shell popped:

>>> import uncompyle6
>>> import sys
>>> uncompyle6.main.uncompyle(
>>> 2.7, x.func_code, sys.stdout
>>> )

# Embedded file name: /app/challenge.py
return ''.join((chr(ord(c) ^ ord(k)) for c, k in izip(base64.decodestring(a), cycle(b))))


We also used `globals()` to get the `c` var:


Decoding c and using this [xor cracker](https://wiremask.eu/tools/xor-cracker/) lead us to the source of `/app/challenge.py`:

import socket
import sys
from itertools import cycle

def fail():
printf("You have failed")

def done():
printf("Well done")

def func():
global x
global k
x=lambda s,t:"".join(chr(ord(a)^ord(b)) for a,b in zip(s,cycle(t)))

def backdoor():

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("", 666))

if __name__ == "__main__":

In the `backdoor` function, xoring the base64-decoded `data` var ("Hj4GKR53QQAzKmEjRD40O1sjGAo4VE0YUxgI") with `k` ("WpUhe9pcVu1OpGklj") gives us the flag, which decodes to `INSA{N1ce_Pl4y_W1th_P1th0N}`.

Original writeup (http://pequalsnp-team.github.io/writeups/FOR-225-Lost-File).