Contents

1

TryHackMe - Carnage

I’ve been dealing with packet captures a lot in my day-to-day recently, so I figure while I’ve got some down time this will be a great way to improve my skills and get back into some security blogging!

TLDR - Walk Through

Discover Malicious IP

Filter out the local subnet:

ip.dst != 10.9.23.1/24

You’ll notice there are only a few external IP’s with HTTP requests. If you know we’re looking for a file download to the system, you discover fairly quickly that the only request stream downloading a file is from 85.187.128.24

Date and Time of First HTTP connection

Now, filter for just the malicious IP and sort by time:

ip.dst == 85.187.128.24

You can see the timestamp of the first HTTP packet by clicking it and viewing the frame info.

Zip filename

You can see the filename in the GET request.

Domain hosting the file

The domain hosting the file is listed in the Host header of the HTTP protocol frame information.

Name of file in zip file

To get the next few answers do the following:
- Navigate to the HTTP packet required for the first question
- Right click -> Follow -> HTTP Stream

This will add a filter for the tcp stream number, as well as open a window with the HTTP request/response information.

If you look at the start of the response body in the second request, you’ll notice a string ending with .xls which is the file being delivered within the .zip file.

Name of server

In the same window as the previous step, we can view the headers in the response. The server: XX header contains the answer.

Version of webserver

In the same window as the previous step, we can view the headers in the response. The x-powered-by: XX header contains the answer.

Malicious file download hosts

To get a more clear picture of what’s going on, I enabled address resolution and set my columns as follows:
7

I filtered for TLS traffic, and started looking at the packets around when the first HTTP request started. There were a few clear Domains with heavy traffic, which were the answer. A hint here is the format is very descriptive.

CA

To discover the CA, follow the TCP stream of the previous domain and read the payloads. There is a clear authority. I found the answer format confusing though, it’s just the domain of the authority:
http://<answer>.com

Cobalt Strike Servers

First note that Cobalt Strike uses HTTP, HTTPS and DNS to communicate. Now look at the TCP tab of the communications statics window and start looking for outliers that are similar.

Copy the IP into virustotal and look at the community tab to get the CC servers.

Host header

Add the first IP from previous answer as a filter ip.src == <ip> and look for a http packet. Follow the HTTP stream to get a pop-up window of the http details where you’ll find the host header.

Domains

Turn on host resolution in wireshark, add a column for it, and look at the packets from the IP to get the hostname.

Finding the domain of the next CC server follows the same process.

Post-Infection traffic

If you sort for protocol, and look at the first HTTP requests after the malicious file was downloaded - the domain name is the answer!

Similar, you can see a sequence of the same requests going to that domain, the first 11 chars of that are the next answer.

The length of the packet above, is the next answer. Once again you can follow the TCP stream to observe the Server header for the next answer.

IP Check Questions

Start by filtering for packets coming from the infected machine and heading outside the local subnet:

ip.src == 10.9.23.102 && ip.dst != 10.9.23.0/24

Then, keep removing addresses that were contacted before infection and look through the list until something seems like an outlier.

ip.src == 10.9.23.102 && ip.dst != 10.9.23.0/24 && ip.dst != 51.105.218.222 && ip.dst != 204.79.197.219 && ip.dst != 13.107.42.16 && ip.dst != 20.190.159.135 && ip.dst != 131.253.33.200 && ip.dst != 23.220.255.44 && ip.dst != 20.54.232.160 && ip.dst != 131.253.33.203 && ip.dst != 20.82.218.86

Something that stuck out to me was the Client Hello requests, if we follow that TCP stream we can see it’s contacting the domain api.ipify.org. You’ll notice the stream contains some location information which could be the malware trying to locate where we are.

Now, to filter for DNS queries we can use:

udp.port == 53

Now, let’s look for requests to resolve api.ipify.org and find the first packet - this gets us the correct timestamp for the answer! The domain is of course, api.ipify.org.

Spam mail

To capture the MAIL FROM address, simply remove all filters and search for mail from, the first match contains the answer.

SMTP packets

Navigate to Statistics -> Protocol Hierarchy

The answer is listed under the packet count for SMTP!

Write-up

Alright so we know Eric Fischer opened some sort of malicious word document. The SOC team got a packet capture from the machine for us to analyze.

Setup

To access the pcap file, they have us boot a machine and VNC into it and utilize Wireshark from there. That’s pretty lame, so I’m going to first exfiltrate this pcap file to my own system. I quickly confirmed that ssh is running on the system with systemctl status ssh.

Now, the stupid box doesn’t have copy-paste enabled so I wrote a quick python script to type it into the damn window:

import keyboard, time
time.sleep(5)
keyboard.write("... pub key ...")

Then I put my key into authorized_keys:
2

And finally downloaded the pcap file to my system with scp:
3

Finally, I have it opened on my own system and I’m thankful I did because it’s a large capture - 53Mb of packets let’s go.

Malicious IP

First we have to figure out what the malicious IP is, the first thing that comes to mind is an outbound connection to an IP outside the local subnet.

The local gateway appears to be 10.9.23.1 from the ARP requests, and I think from a browser protocol packet I can see the subnet mask is 255.255.255.0. So, my guess is the local network CIDR is 10.9.23.1/24.

I’ll use this to filter out local destination packets.
4

We immediately see the odd http request being sent to 185.106.96.158 which I’ll assume is the malicious remote server.

I then apply that as a filter, and sort by time to obtain the first answer:
5

The first HTTP request is packet number 6326, inspecting it we can see the arrival time in the requested format in the frame data, however this wasn’t the answer… perhaps I’ve got the wrong IP. Let’s backtrack and apply a filter for protocol as well as removing the local subnet.

There is another sequence of HTTP requests being sent to 208.91.128.6, these actually look much more interesting having variable BASE64 payloads:
6

But the first HTTP request in this sequence also wasn’t the answer.

The only other external IP is 85.187.128.241, which happens to be the correct answer. There is a single HTTP packet with this address as the destination and the timestamp is correct.

The request seems rather innocuous, though. It’s a GET request for /incidunt-consequatur/documents.zip. The payloads against the other addresses seem much more suspicious to me! Either way, the new few answers follow pretty easily.

File within the zip file

Now we’re tasked with figuring out what the name of the file within the zip file is. For this I need to change the filter and view the response stream from the remote server with the file payload. The easiest thing to do is follow the request stream from the starting packet. This provides us with a lovely view of the stream data as well.

We can see within the first line of the payload, the filename is presented. It’s fairly easy to recognize due to it’s the .xls extension being present.

We can also see in the stream the name of the remote server in the server header.

Other domains involved

To prune out the other domains involved, I use the following filter:

ip.dst == 10.9.23.102 && ip.src != 10.9.23.0/24

There are four IP’s involved in HTTP communication with the host:
- 85.187.128.24
- 208.91.128.6
- 104.83.124.33
- 185.106.96.158

By checking out a few HTTP packets of each of the others I resolved the domains:
- attirenepal.com
- maldivehost.net
- r3.i.lencr.org -> x1.i.lencr.org
- verisign.com

Following the stream from each of these (Except attirenepal which we already confirmed).

maldivehost.net seems to deliver a file payload in some encoding.

r3.i.lencr.org delivers a certificate with a URL to x1.i.lencr.org contained in it?

To get a more clear picture of what’s going on, I enabled address resolution and set my columns as follows:
7

I filtered for TLS traffic, and started looking at the packets around when the first HTTP request started. There were a few clear Domains with heavy traffic.

Discovering Cobalt Strike Servers

Cobalt strike communicates with HTTP, HTTPS and/or DNS.

So, going through each IP involved in HTTP, HTTPS and DNS traffic and checking virus total should let us know if any are detected as cobalt strike CC.

I looked through HTTP traffic first, and the one sending those weird BASE64 requests turned out to indeed be a CC server.

I then looked at the Conversation menu under statics, and at the TCP tab.

I looked at the known CC server and searched for similar subnets or behavior as the known bad actor IP and discovered the other one fairly quickly.

The remainder of questions come pretty easily, I wrote some details in the walk through if you need it.

IP Check API call

The question states we’re looking for an API call from the infected machine containing their IP to some remote server to ‘check’ it.

This is the filter I used:

ip.src == 10.9.23.102 && ip.dst != 10.9.23.0/24

Then, after the time of downloading the file I started to filter out any IP’s that were contacted beforehand. I ended up with this:

ip.src == 10.9.23.102 && ip.dst != 10.9.23.0/24 && ip.dst != 51.105.218.222 && ip.dst != 204.79.197.219 && ip.dst != 13.107.42.16 && ip.dst != 20.190.159.135 && ip.dst != 131.253.33.200 && ip.dst != 23.220.255.44 && ip.dst != 20.54.232.160 && ip.dst != 131.253.33.203 && ip.dst != 20.82.218.86

Something that sticks out to me are the Client Hello requests, if we follow that TCP stream we can see it’s contacting the domain api.ipify.org.

Now, filtering for DNS queries we can use:

udp.port == 53

Now, let’s look for requests to resolve api.ipify.org and find the first packet - this gets us the correct timestamp for the answer!

Spam mail

To capture the MAIL FROM address, simply remove all filters and search for mail from.

To see how many SMTP packets there were, we can simply navigate to Statistics -> Protocol Hierarchy and get the number of SMTP packets!

Directory
$ cd content && tree