Introduction
Find the hidden message! download
Disclaimer
This challenge was made by our very own doskop.
Analysis
- pcap file containing
NNTP
traffic (USENET) - Several files are being transferred and some of those are ‘split up’ in parts.
- data itself is
yEnc
encoded. documentation
The objective for now is to find a way to get the files that are being transferred.
I struggled a bit with tshark
to get those TCP streams out (tshark -r net100.pcap -T fields -e tcp.stream | sort -n | uniq
),
eventually settled with wireshark
to export them. For this write-up, ill use tcpflow
:
~$ tcpflow -r net100.pcap
~$ cat 192* > streams.raw
Now we have a single file containing the 4 TCP streams.
Decoding the data
Before writing our hacky Python script:
- yEnc headers include: filename, filesize
- yEnc headers mark the beginning of some data belonging to a file
- yEnc headers may include an offset/limit range for partial transfers.
For our script we can iterate every line, upon embarking on lines that begin with ybegin
record the proceeding data till yend
-
decode that data, store it in memory and after everything is done - write the files out.
For the decoding of yEnc
data I used the Python library sabyenc.
I used their example script on Github as a starting point.
#!/usr/bin/env python2
import re,sys,sabyenc
data = open(sys.argv[1], "r").readlines()
files = {}
for i in range(0, len(data)):
line = data[i]
if line.startswith("=ybegin"): # beginning of a new yenc file
has_offsets = data[i+1].startswith("=ypart") # check if the second line contains begin/end
headers = { # nntp headers
"begin": 0,
"end": 0,
"size": int(re.search('size=(.\d+?) ', line).group(1))
}
if not headers['size']: raise Exception("could not parse size=")
if has_offsets: # try to parse begin/end
try:
headers['begin'] = int(re.search('begin=(.\d+?) ', data[i+1]).group(1))
headers['end'] = int(re.search('end=(.\d+?)\r\n', data[i+1]).group(1))
except:
print "warning: begin/end could not be correctly parsed"
if not headers['begin']: # sometimes begin turns into None, reset to 0
headers['begin'] = 0
# yencode-decoding using sabyenc - input data includes the 1/2 header lines and the trailing '=yend'
decoded_data, output_filename, crc, crc_yenc, crc_correct = sabyenc.decode_usenet_chunks(
data[i:], headers['size'])
if not crc_correct: raise Exception("faulty checksum")
print "output_filename:", output_filename
print "size:", headers['size']
print "decoded_data length:", len(decoded_data)
if output_filename not in files:
files[output_filename] = []
files[output_filename].append({
"begin": headers['begin'],
"end": headers['end'],
"data": decoded_data
})
print "sorting chunks and writing files."
for output_filename, chunks in files.items():
chunks = sorted(files[output_filename], key=lambda k: k['begin'])
data = "".join([chunk["data"] for chunk in chunks])
open("output/%s" % output_filename, "wb").write(data)
print "written %s" % output_filename
I initially did not sort the data chunks which resulted in not having enough par2 recovery blocks.
par2
We end up with a bunch of .par2
files, which are recovery files.
22:57 $ ls -al ~/hitbctf/net100/output/
total 12752
drwxr-xr-x 2 dsc dsc 4096 Apr 16 22:33 .
drwxr-xr-x 4 dsc dsc 4096 Apr 16 22:33 ..
-rw-r--r-- 1 dsc dsc 40388 Apr 16 22:33 data.tar.bz2.par2
-rw-r--r-- 1 dsc dsc 45576 Apr 16 22:33 data.tar.bz2.vol0000+001.par2
-rw-r--r-- 1 dsc dsc 91048 Apr 16 22:33 data.tar.bz2.vol0001+002.par2
[...]
If we have enough recovery blocks we can use par2
to reconstruct the original data.tar.bz2
file. If anything went wrong in our Python script - we’ll see it in this stage.
~$ par2 r *
Repair is required.
1 file(s) are missing.
You have 1999 recovery blocks available.
Repair is possible.
1999 recovery blocks will be used to repair.
Wrote 10232329 bytes to disk
Repair complete.
After that we can extract files from the archive(s):
~$ bzip2 -d data.tar.bz2
~$ tar -xvf data.tar
~$ cd data
Which gives us 10.000 .dat
files. lets grep for flags ¯\_(ツ)_/¯
~$ strings * | grep -oE "HITB{\w+}"
Well, that’s a lot of matches. Most of them don’t have numbers while flags usually do…
~$ strings * | grep -oE "HITB{\w+}" | grep -E "[0-9]"
1 result; the flag: HITB{1d4dd1ee96694cc44fe685d731f6bd2d}
additional solves
LuckY from eindbazen was able to whip out this one liner:
mkdir troep ; cd troep ; tcpflow -r ../net100.pcap ; uudeview *.bin ; par2repair