forbiddenBits 2013 Write-Up: Poir

March 21, 2013

The poir challenge was given as a binary file. It’s a “pcap-ng capture file – version 1.0”, so we opened it in wireshark to have a look at the data.
It consists of about 10k pakets, mostly HTTP traffic, some SSDP searches. A closer look revealed: the HTTP pakets are request and responses on a single archive (plus a single google analytics tracking gif), namely “http://urlpush.playmp3.kr/key.7z”.

forbiddenBits 2013: Poir Wireshark

Wireshark dump of poir pcap file.

But they are somewhat special: they all are range request and responses to kind of small ranges (mostly under 100 bytes) and they are in many cases overlapping. The obvious next step was to try to reconstruct the archive file and have a look inside.
With 500 requests and responses each that’s not a task to do by hand. Time for some python automation:
We first needed some kind of library to read the pcap-ng file and parse the pakets to allow us to play around with them. Eventually we used the wonderful scapy library, which supports reading paket dumps and allows us to access the individual protocol layers. Unfortunately scapy cannot read pcap-ng files – only “old” pcaps – so we had to convert it (using wireshark). Furthermore scapy has no builtin protocol support for HTTP, but the interwebz helped out with an implementation for that (was scapy actually has is a plugin support for new protocols/”layers”): scapy-http from github.
So we could start: We used a simple binary buffer to store the file, which was initialized with the first HTTP response, which includes the total file size. For every packet we then added the transferred data to the buffer at the position specified in the Content-Range HTTP header, like this:

def addForPosition(self, posFrom, data):
    posTo = posFrom + len(data)

    for f, t in self.ranges:
        if not ((posFrom < f and posTo < f) or \
          (posFrom > t and posTo > t)):
            fromIdx = max(f, posFrom)
            toIdx = min(t, posTo)
            localFromIdx = fromIdx-posFrom
            localToIdx = toIdx-posFrom

            overlap = toIdx-fromIdx
            if array.array('b', data[localFromIdx:localToIdx]) != self.data[fromIdx:toIdx]:
                return False
    self.data[posFrom:posTo] = array.array('b', data)
    self.ranges.append((posFrom, posTo))
    return True

For safety reasons we also added an additional check to verify that the overlapping data is indeed matching – and it is! That buffer written to disk resulted in a valid 7z archive, containing a single – at a first glance white – png. That was actually the last obstacle on our way to the flag. Via stegsolve we could read the flag: kEy_Is_PIoneer_Of_Invisible_Road_By_BuGeun.

Leave a Reply




Get Adobe Flash player