RFCLand

Categories: forensics
2020-07-24
by not_really

All RFCs are created equal, right?

Author: DrDinosaur

Files: challenge.pcap

If we browse through the pcap in wireshark, we’ll see lots of base64 being sent and some responses coming back. We should probably first make a list of all that base64 stuff. We’ll export all data like so:

tshark -Tfields -e data -r challenge.pcap | xxd -r -p > out.txt

Essentially, we use -Tfields to print out a list of certain values, -e data to print only data, and -r to read from pcap. The output is in hex though, so we use xxd -r -p to read from the pipe and convert back to text. Then we output that to out.txt.

If we look inside the file it’s going to be a little hard to read since there won’t be any line breaks.

image-20200721211026061

Since the important stuff is in curly braces, we can write a script to only text inside of the {}.

text = open("out.txt", "r").read()
outText = ""

charsUntilStartReading = -1
for c in text:
    if c == "{":
        charsUntilStartReading = 10 # skip {"data": "
    elif c == "}":
        charsUntilStartReading = -1
        outText = outText[:-1] # remove "
        outText += "\n"
    
    if charsUntilStartReading == 0:
        outText += c
    
    if charsUntilStartReading > 0:
        charsUntilStartReading -= 1

open("outfmt.txt", "w").write(outText)

We have lots of base64 so let’s export all of it to files so we can look at it in a hex editor.

import base64

text = open("outfmt.txt", "r").read()
i = 0
for line in text.splitlines():
    open(f"outline_{str(i).zfill(3)}.dat", "w").write(base64.b64decode(line))
    i += 1

Hmm… we seem to get a Invalid base64-encoded string error. Let’s try catch. What could go wrong?

import base64

text = open("outfmt.txt", "r").read()
i = 0
for line in text.splitlines():
    try:
        open(f"outline_{str(i).zfill(3)}.dat", "w").write(base64.b64decode(line))
    except:
        print(f"rip {i}")
    i += 1

Okay… all of them failed. Let’s try adding a = or two. (Yes, I am not proud of this code but it works)

import base64

text = open("outfmt.txt", "r").read()
i = 0
for line in text.splitlines():
    fileName = f"outline_{str(i).zfill(3)}.dat"
    decoded = ""
    passed = False
    try:
        decoded = base64.b64decode(line)
        print(f"pass {i}")
        passed = True
    except:
        try:
            decoded = base64.b64decode(line + "=")
            print(f"pass {i}")
            passed = True
        except:
            try:
                decoded = base64.b64decode(line + "==")
                print(f"pass {i}")
                passed = True
            except:
                print(f"rip {i}")
    if passed:
        open(fileName, "wb").write(decoded)
    i += 1

Let’s use the same trick as Raymonds and print out the headers.

for file in *; do echo $file; xxd $file | head -1; done

There’s too many to list here, but there seem to be more jpeg headers in the first half than in the second. Seems like we need to combine them somehow. Because jpegs are special, you don’t need the whole file to get an idea of what the picture looks like. Let’s take a look by renaming everything to jpeg with for file in *.dat; do mv "$file" "${file%.dat}.jpg"; done or ren *.dat *.jpg on windows.

image-20200721213904124

Hmm, 95 looks like it has text. Let’s see what it says.

outline_095

It’s the flag! But we aren’t able to see the whole image because there’s still more to the file missing. It must be one of those other non jpeg header files we saw, right? Let’s test that by combining all the other base64 lines to this one image.

import base64

text = open("outfmt.txt", "r").read()
firstPart = text.splitlines()[95]
i = 0
for line in text.splitlines():
    fileName = f"outline_{str(i).zfill(3)}.jpg"
    line = firstPart + line
    decoded = ""
    passed = False
    try:
        decoded = base64.b64decode(line)
        print(f"pass {i}")
        passed = True
    except:
        try:
            decoded = base64.b64decode(line + "=")
            print(f"pass {i}")
            passed = True
        except:
            try:
                decoded = base64.b64decode(line + "==")
                print(f"pass {i}")
                passed = True
            except:
                print(f"rip {i}")
    if passed:
        open(fileName, "wb").write(decoded)
    i += 1

Only one of these has more of the message and that’s 106.

outline_106

Okay, let’s do it one more time.

import base64

text = open("outfmt.txt", "r").read()
firstPart = text.splitlines()[95] + text.splitlines()[106]
i = 0
for line in text.splitlines():
    fileName = f"pcapout/outline_{str(i).zfill(3)}.jpg"
    line = firstPart + line
    decoded = ""
    passed = False
    try:
        decoded = base64.b64decode(line)
        print(f"pass {i}")
        passed = True
    except:
        try:
            decoded = base64.b64decode(line + "=")
            print(f"pass {i}")
            passed = True
        except:
            try:
                decoded = base64.b64decode(line + "==")
                print(f"pass {i}")
                passed = True
            except:
                print(f"rip {i}")
    if passed:
        open(fileName, "wb").write(decoded)
    i += 1

Nice, looks like 223 has it.

outline_223

It turns out that this was not the intended way to solve this problem. Let’s go back to wireshark with this newfound knowledge and look at 95, 106, and 223. (Packet no. is 7*index+4, so 669, 746, and 1565)

It’s actually nowhere in the tcp messages but instead in the ipv4 header. Scroll up, open Internet Protocol Version 4, and then Flags. You’ll notice that they all have a reserved bit set (known as the “evil” bit). You can filter by ip.flags.rb == 1 or ip.flags == 0x8000. We can see the 5 packets that send our valid image. Let’s try that for a Full Ultra HD:tm: image.

import base64

text = open("outfmt.txt", "r").read()
base = (text.splitlines()[95] +
        text.splitlines()[106] +
        text.splitlines()[223] +
        text.splitlines()[244] +
        text.splitlines()[245])
open("out.jpg", "wb").write(base64.b64decode(base))

out

Okay, maybe it’s not that quality, but it’s better than that potato image we the first time.

In case you’re interested, here’s the rfc: https://www.ietf.org/rfc/rfc3514.txt