This article aims at solving the PCAP related questions from the DFIR MONTEREY 2015 Network Forensics Challenge using Squey.
Of course the idea here is not to really solve the challenge as it has been solved numerous times since then, but to see how easier it is to solve it using Squey.
The dataset 2014-11+DFIR+Network+Forensics+Challenge.zip was taken from the Netresec PCAP page.
Note: questions 1 and 4 were not solved because they didn’t involve any PCAP data.
Click on the PCAP
button of the start page, select the provided HTTP
profile, browse the nitroba.pcap
file and then click Process
.
You should now see the selected fields of the PCAP represented as Parallel Coordinates:
On the listing view located on the bottom of the window, right-click on any value of the eth.src
column, select Search for...
, paste the MAC address 00:1f:f3:5a:77:9b
in the Expressions
text field, select Case sensitivity: Does not match case
and click Apply
.
This will instantly filter the packets to display only eth.src == 00:1f:f3:5a:77:9b
:
You can then right-click on the src.ip
column header and select Distinct values
to display the distinct values with their associated count/frequency:
Answer: 169.254.90.183, 192.168.1.64 and 169.254.20.167
Before loading this PCAP file, you will need to create a PCAP profile to select which fields to import in the application.
On the PCAP dialog, select Manage profiles
, click on New profile
, enter something meaningful like FTP
, browse the ftp-example.pcap
file to analyse the protocols it contains and select all the fields you are interested in like :
1eth.dst,eth.src,ip.dst,ip.src,tcp.srcport,tcp.dstport,ftp.request.arg,ftp.response.code,ftp.passive.ip,ftp.passive.port
Save the profile and open the ftp-example.pcap
file with the FTP
profile selected.
Right-click on the ftp.request.arg
column header, select Distinct values
and click on the scenery-backgrounds-6.0.0-1.el6.noarch.rpm
file.
This will display the only packet containing scenery-backgrounds-6.0.0-1.el6.noarch.rpm
as its ftp.request.arg
field.
Right-click on the row index and select Copy line index to clipboard
.
Press the g
key and paste the value 34956
corresponding to our packet.
Scroll-back a few rows until you see on the ftp.response.code
column the value 227
which corresponds to “Entering Passive Mode”.
We can then observe that the destination IP and port are 149.20.20.135:30472.
Right-click on the ip.src
value of the packet containing the file and select Search for this value
, this will only keep packets with this IP as source.
Then right-click on the tcp.dstport
value 30472
and select Search for the value
to add another level of filtering which will keep only packets having our previously selected IP as source and 30472
as TCP destination port.
We can observe that the source IP and port are 192.168.75.29:51851.
Answer: 149.20.20.135:30472 and 192.168.75.29:51851
Create a SMB
PCAP profile containing the following fields:
1eth.dst,eth.src,ip.dst,ip.src,tcp.srcport,tcp.dstport,smb.file,smb.end_of_file
Then import the stark-20120403-full-smb_smb2.pcap
file using the newly created SMB
profile.
Filter the packets containing the text Researched Sub-Atomic Particles.xlsx
in their smb.file
field:
Then display the Distinct values
of the column smb.end_of_file
Answer: 13,625 bytes
Create a custom PCAP profile containing the following fields:
1frame.time,eth.dst,eth.src,ip.dst,ip.src,tcp.srcport,tcp.dstport,data.data
Then import the snort.log.1340504390.pcap
file using the newly created profile.
Displaying the Distinct values
of the data.data
column and scrolling through the values seems to indicate that some of the data remains constant.
But scrolling the 14,228 distinct values to check if this patterns applies to all of them would make our eyes bleed for sure.
Wouldn’t it be nice if we could instead visualize the integrality of the data content and prove it ?
Alright, let’s do that by splitting the data.data
field into the smallest addressable memory units: bytes.
A few lines of Python code will be plenty enough to do that:
1source = squey.source("snort.log.1340504390.pcap")
2data = source.column("data.data")
3for i in range(int(len(data[0])/2)):
4 b=data.view('<U2').reshape(data.shape + (-1,))[:, i]
5 source.insert_column(b.copy(), f"data_byte_{i}")
6str=bytes.fromhex(data[0][8:22]).decode("ASCII")
7print(f"data[4:10]={str}")
Now, it is crystal clear that along all the packets of the dataset, bytes 4 to 10 of the data.data
field are always constant:
Answer: bytes 4 to 10 (zero based), which represent the string “ULQENP2” in ASCII.
There are 4 bytes preceding the static “ULQENP2” string: let’s extract these as a new uint32 integer column using the following Python code:
1import numpy as np
2source = squey.source("snort.log.1340504390.pcap")
3data = source.column("data.data")
4b=data.view('<U8').reshape(data.shape + (-1,))[:, 0]
5b_int=np.vectorize(lambda t: int(t, 16) if t else 0)(b)
6source.insert_column(b_int.copy(), "data_first_4_bytes_as_uint32")
Now, let’s check if we can observe an evolution of this data through time by using a scatter plot.
Wait, it is not evolving through time, it is time.
Answer: A UNIX timesteamp.