RingZer0-115

Forensics

Ping pong

This time we get a pcap that only contains icmpv6.

If we take a look at a frame we notice that the only difference between them is the checksum and data.

If we look at the data between a request and reply we also notice that we get the same data.

This displays the first 10 frames from the pcap, we can see the the first (request) and the second (reply) both have the same data.

tshark -r 1d807df224db41d7c3808e76c49d4b7a.pcap -Y "frame.number < 11  && frame.number > 0" -T fields -e data.data

62:6d:35:76:64:41:6f:76:55:33
62:6d:35:76:64:41:6f:76:55:33
56:69:64:48:6c:77:5a:53:41:76
56:69:64:48:6c:77:5a:53:41:76
54:47:6c:75:61:77:6f:76:51:6d
54:47:6c:75:61:77:6f:76:51:6d
39:79:5a:47:56:79:49:46:73:77
39:79:5a:47:56:79:49:46:73:77
49:44:41:67:0a:4d:46:30:4b:4c
49:44:41:67:0a:4d:46:30:4b:4c

All the data seems to be in hex. That’s suspicious. We’ll extract all the data from all the icmpv6 packets from one side (since they both send the same data).

tshark -r 1d807df224db41d7c3808e76c49d4b7a.pcap -Y "ipv6.src == 9000:6:3628:e3e3::ee8e" -T fields -e data.data > icmpv6Data  

The data has the “:” delimiter, we’ll need to take that out and merge all the lines together

cat icmpv6Data | tr '\n' ' ' | sed 's/://g' | sed 's/ //g' > mergedIcmpv6Data

We now have all the data in hex. We’ll convert it the hex into ascii.

cat mergedIcmpv6Data | xdd -r -p 

If we look at the data produced we can easily recognize that’s in base64 encoded. We’ll go the hex to ascii then decode the base64 information in a singe line.

cat mergedIcmpv6Data | xxd -r -p | base64 -d > decodedIcmpv6Data

A pdf file

We now have a random file that contains data. If we run file on it we don’t get anything good out of it.

file decodedIcmpv6Data

decodedIcmpv6Data: data

If we open the file with vi, we can take a good guess of what the file is.

The biggest giveaway is the parts that contain objects like the following code snippet.

4 0 obj
<</Type /ExtGState
/CA 1
/ca 1
/LC 0
/LJ 0
/LW 0
/ML 4
/SA true
/BM /Normal
>>
endobj

The first part of the file is missing. File coudn’t identify the file because of the missing header and other valuable information.

There’s valuable information about how PDF files work in the following websites.

https://blog.idrsolutions.com/2013/01/understanding-the-pdf-file-format-overview/#helloworld

https://blog.didierstevens.com/2008/04/09/quickpost-about-the-physical-and-logical-structure-of-pdf-files/

The first thing we could do is to decode the objstreams found in the file.

That will give us an idea how what is on the pdf file.

There’s a useful script that will extract objects and decode them for us.The script if found here.

https://blog.didierstevens.com/programs/pdf-tools/

We can use this tool to extract all object and make them go through the filter that it has been encoded into to get the raw data out of it.

For the sake of this already long write up, we’ll extract the two that we need. One object was interesting and it has the object 10. That file was a TrueType font that had missing characters.

The object we need to solve this are the object 6 and 8

python pdf-parser.py --raw --filter -o 6 decodedIcmpv6Data > dump6
python pdf-parser.py --raw --filter -o 8 decodedIcmpv6Data > dump8

PDF operators and dump6

The dump6 that we extract from the pdf contains a bunch of lines that don’t make much sense.

Those are intructions using pdf operators to contruct how the pdf will look like. Some informations can be found in the following link.

https://github.com/galkahana/HummusJS/wiki/Use-the-pdf-drawing-operators

We can draw the conclusion that the dump6 stream is a text stream. All the lines that contain the operator Tj is a letter.

We’ll keep just the lines with the Tj operator and just keep the number inside the brackets.

grep -i "Tj" dump6 | cut -c 2,3,4,5 > cleanDump6

Now we need to understand how pdfs take the code from the Tj line and maps it to a cmap table that links the code to a character. There’s more information about it in the following links.

https://blog.idrsolutions.com/2012/05/understanding-the-pdf-file-format-embedded-cmap-tables/

http://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5014.CIDFont_Spec.pdf

The table can be found in the dump8 file

Cmap and dump8

We got the cmap table that we need to be able to take the code from the dump6 and match it to the correspondant unicode character.

If we look at the table.

cat dump8 

...
10 beginbfchar
<0003> <0020>
<000C> <0041>
<0014> <0049>
<0017> <004C>
<001D> <0052>
<001F> <0054>
<0056> <003A>
<0059> <003D>
<016F> <002C>
<0170> <002E>
endbfchar
6 beginbfrange
<0005> <0007> <0033>
<000E> <0011> <0043>
<0019> <001A> <004E>
<0026> <0035> <0061>
<0037> <003C> <0072>
<003E> <003F> <0079>
endbfrange
...

We can see that the code 0003 is mapped to the unicode character with the value 20.

The same goes with 000C is mapped to unicode(41) which is the letter A.

If we look at the first 5 lines of our cleaned up dump6.

head -n 5 cleanDump6

0059
0059
0059
0059
0003

So if we follow the cmap table the code 0059 is unicode(003D) or the letter “=” and 0003 is unicode(0020) which is a space.

So the text stream starts with “==== “. The problem is that the text stream is actually pretty long.

wc -l cleanDump6

304 cleanDump6

We got 304 characters. So i created a python script for it.

The script is VERY FAR from being good code. BUT IT DOES WORK!

The script reads both files (dump8 and cleanDump6), create a dictionary to map all the codes in the cmap table to their respective value in unicode. After that it compares the values in the cleanDump6 and writes the correspondant value in the variable convertedTextStream then prints it.

import re

def read_file(filepath):
    with open(filepath, 'r') as read:
        return read.read()

cmap = read_file('dump8')
textStream = open('cleanDump6')
convertedTextStream = ""
cmap_dict = {}

# Strip all <>
def stripExtra(list):
    stripedString = ""
    for i in list:
        stripedString += i.replace(">","").replace("<","") + "\n"
        
    return stripedString

bfChar = re.findall("^<....> <....>$",cmap, flags= re.MULTILINE )
bfRange = re.findall("<....> <....> <....>",cmap )

bfCharCleaned = stripExtra(bfChar).split("\n")
bfRangeCleaned = stripExtra(bfRange) .split("\n")

# Creating Cmaps dictionary
for i in range(0,len(bfCharCleaned)):
    cmap_values= bfCharCleaned[i].split()
    try:
        cmap_dict[hex(int(cmap_values[0],16))]=hex(int(cmap_values[1],16))
    except:
        pass

for i in range(0,len(bfRangeCleaned)):
    cmap_values= bfRangeCleaned[i].split()
    try:
        nbRange = int (cmap_values[1],16) - int (cmap_values[0],16)
        for y in range(0,nbRange+1):
            code = (int(cmap_values[0],16) + y)
            codeuni = (int(cmap_values[2],16) + y)
            cmap_dict[hex(code)] = hex(codeuni)
        
    except:
        pass

# Compare textStream to cmap dictionary
for i in textStream:
    try:
        convertedTextStream += cmap_dict[hex(int(i,16))][2:]
    except:
        pass

print convertedTextStream.decode("hex")

textStream.close()

The result is:

==== CONFIDENTIAL====Comrade Rausczek, our honorary allies have found the source of the leaks. This person is currently under protection of the Demokratik Republik of Auskev, but we are working diplomatically to resolve the matter.Flag: sasdhbdsahbdsadsabbjbdsavdsae333445rddssaazssd==== CONFIDENTIAL====

The flag is sasdhbdsahbdsadsabbjbdsavdsae333445rddssaazssd