RingZer0-115 - Ping Pong
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
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