Hey everyone! This write up is going to cover all the tricks needed to work through the “Adversary TTP Analysis” track presented in the Red Team Village Mayhem 2020 CTF! I really liked this set of challenges and recommend everyone run through this because it really covers some common challenges often associated with pcap analysis as well as some I haven’t ran into before!
This was the first outing of the Hackers N' Hops CTF team which we put together just days before the event. We were unorganized but ultimately we all had a blast and finished with a respectable 4th place finish amongst 150 active teams (over 200 were actually registered).
So before we dive right in, let’s take a look at some of the questions we’re trying to answer for the CTF. Each question was worth 50 points making this a 500 point track.
- What tool is being used to perform encrypted communications?
- Provide the sha1sum of the tool used to perform encrypted communications.
- What port is the encrypted communications being sent over?
- Provide the sha1sum of the combined certificate/private key file (PEM format) used by the tool to encrypt communications.
- Decrypt the ssl traffic of the largest conversation.
- What ports are being knocked?
- How many knocks were sent out?
- How many targets were knocked on?
- What is the average time between the 1st and 2nd knocks?
- What was the average time between the 2nd and 3rd knocks?
This track of challenges were completed while enjoying a delicious Tangerine Express IPA by Stone Brewing Co.!
Before we start you’re going to want to download the .pcap file called ‘apt-capture.pcap’ which you can download from https://ewhitehat.com/?mdocs-file=649. For the most part, we’re going to be working exclusively with Wireshark. I will be using 2 tools that come default with most Linux distro’s when it comes time to reconstruct a file extracted from the pcap. These tools are xxd and sha1sum. I’m sure there’s probably a windows equivalent for both of these, but I’m not going to cover any of it.
Once we fire up wireshark and open the ‘apt-capture.pcap’ we’re presented with a very realistic capture and the first major hurdle becomes clear… Where’s the APT traffic? This capture is filled with activity commonly seen across an enterprise wire to include email, ftp, etc. It’s a lot of noise to cut through to find our suspect.
The method I used to find our nefarious goon was to look for baseline anomalies in the pcap. “Well, Cylent, what the heck does that mean”? Well, it means that I want to see if I can identify the common services running on the victim network and see if there is anything that stands out to me. To do this I first want to add a new column that isn’t displayed by default in wireshark and that is the destination port. Right click on any of the column headers and select Column Preferences.
Next click the plus icon to add a column.
Finally, enter tcp.dstport in the ‘Fields’ field (you can also change the ‘Title’ field if you’d like) and click ok.
Next we’re going to clean up some of the noise by filtering only the SYN packets. The filter for this is tcp.flags.syn == 1 && tcp.flags.ack == 0
Now, click on the new column header we added to sort the pcap by the destination port. From here you will see a lot of seemingly normal traffic. In this case, normal traffic is defined as ‘many to one’ communications. In other words, multiple host devices are accessing services hosted by singular devices. However as you scroll through, familiarizing yourself with what is “normal” you may see something that pops out at you…
In the above picture, you can see some many to one communication then we notice some one to many traffic as well. This doesn’t necessarily mean this is out suspect but it’s certainly worth looking into.
Since I have an IP address I’d like to investigate I like to ask 3 general questions. Who is talking to this IP, Who is this IP trying to talk to and finally Who is this IP successfully talking too.
Who’s talking to who?
To find out who is talking to our suspect IP address, I look to all SYN/ACK packets that the suspect is sending. As many of you know, a 3 way handshake (the exchange of packets that initiate a TCP connection) consists of a SYN packet generated by the client, followed by a SYN/ACK packet by the server and followed by and ACK packet and any subsequent data by the client once more. With that in mind, if our IP EVER sends a SYN/ACK packet then it means that it is running some sort of service that another computer would like to communicate with.
In wireshark the filter to identify this traffic is
ip.src == 10.1.30.11 && tcp.flags.syn == 1 && tcp.flags.ack == 1
In the picture below you can see the filter as well as the results; a few SSH connections from 10.1.40.80.
Since this is all SSH traffic there’s not much else we can do with it, but it does reveal that our suspect isn’t likely to be a traditional enterprise server since it’s only serving a very small amount of ssh connections… Getting fishier.
The next question: Who is my suspect trying to talk to? This question is going to be answered by looking exclusively at the SYN packets generated by our suspect. This filter is very good at identifying port scanning attempts as well. The filter is
Ip.src == 10.1.30.11 && tcp.flags.syn == 1 && tcp.flags.ack == 0
If you’re still sorted by the destination port (recommended) you should now be able to see that our suspect machine doesn’t seem to talk to very many devices and it also exclusively talks on very uncommon ports; 31001, 32001, 33001, 34001, 8443 and 31337 (Note, anytime you see port 31337, investigate it, especially in a CTF)… Getting EVEN FISHIER!
The final question we have is who is the IP successfully talking too. This question is different than the last because just this one will tell us who is responding to our potential malicious machine. This time we’re looking for SYN/ACK packets sent TO our suspect. This filter is as follows
Ip.dst == 10.1.30.11 && tcp.flags.syn == 1 && tcp.flags.ack ==1
The results here show that our suspect machine only makes 3 type of connections; 31001, 31337 and 8443. The majority of these connection are made to 10.1.10.120!
There! Using just 1 basic filter with slight modifications we just got some great information and it’s time to dig in on some of this traffic!
Let’s examine a sample of each port the suspect likes to talk to using the Follow TCP Stream capability of Wireshark. Right click on one of the packets and hover over “Follow”. Now click the “TCP Stream” option. (Examine the traffic and sample the next on your own).
You should have sampled each of the ports now so what did we find? Well if we’re working on the same pcap then you should have found that 31001 traffic is a clear text shell interaction! Next, 8443 was encrypted, we’ll come back to that later. Finally, 31337 appears to be some type of file transfer.
Go ahead and examine each of the file transfers. One of these files is an executable (it starts with .ELF); we’ll be coming back to that in a bit. The other two files seem very interesting. One is an RSA public key (not very useful on its own so let’s skip that) and the other is the same public key as well as its companion private key! (Quick note: a public key and private key in this arrangement is known as a ‘.pem’ file). Go ahead and copy that .pem data into a file of your own. If you run the Linux command ‘sha1sum’ on that new file you’ve just solved one of our questions (Give yourself 50 points)!
Next let’s dig into these plain text shell conversations. Go ahead a follow the TCP streams… I’ll wait…
You should have noticed that the conversation with .120 was a little more in-depth than the others. For the most part we just see some user, process and network enumeration but with .120, our malicious actor does something really odd… They transfer a file called socat, then create an RSA key pair using openssh and finally (using socat) they open an ssl connection on the machine using port 8443! You can now answer two more challenges: what tool is used for encrypted communications and what port is used (+100).
Now let’s see what is happening in the encrypted traffic shall we?
Decrypting SSL (TLS 1.2 or below) using Wireshark and an RSA Key
If you didn’t know Wireshark could do this, be sure to put it in your toolbox after reading!!
First, we want to copy the private key out of our .pem file and into its own key file (Wireshark may accept the .pem file as is but I didn’t test it so we’re doing this MY WAY!). Next we want to open up the Wireshark preferences by going to “Edit > Preferences”.
When the window opens up, expand the protocol section by clicking the arrow next to it. Scroll down until you get to the TLS option. Select the option then click the “Edit…” button next to RSA keys list. Click the “+” button to add a new RSA key. There are only 2 fields you’re really going to need to use for this challenge which are Port, with should be set to 8443 and Key File which you should point to our private key file.
NOTE: Other online resources will have you select SSL instead of TLS. SSL was not an option in my Wireshark and may not be in yours either! If you don’t have an SSL option this is the method for you!
Now, all we need is a TLS 1.2 packet that’s part of our 8443 traffic. The method I used to find this is to change my filter to
Ip.src == 10.1.30.11 && tcp.dstport == 8443
Looking at the ‘Protocol’ column, right click one labeled as ‘TLS 1.2’ and hover over ‘Follow’. You should now see a new option available called ‘TLS Stream’.
And there we have it! Decrypted traffic and a flag (+50)!
Extracting and reconstructing the .ELF file
Now let’s rebuild the socat file and get some more points.
Go back and follow the 31337 tcp stream that contained the .ELF file. On the bottom of the follow page, use the dropdown menu to select “RAW”. The text should have changed to something completely unreadable. Right click the text and “select all” and copy the data (you can also just save the data off this way, but I’m just used to the copy and paste method).
Create a new file (I called mine socat.hex) and paste the data into the new file. If you did the copy and paste method you may now get up and grab yourself a frosty beverage, this will take a minute.
Once the file is done pasting and saved off it’s time to convert the file into an executable binary. To do this we use the built in Linux tool xxd! Using the command xxd –r –p socat.hex socat gives us our binary file which can now be hashed using ‘sha1sum’ and we have earned ourselves another 50 points!
Port Knocking and Timing!
First things first, we need to identify what ports are being knocked on! Thankfully we already found that answer earlier when we asked the questions “Who is our suspect trying to talk too” and “Who is our suspect successfully talking to”. There was a discrepancy in data here, where are suspect sent SYN packets to ports 8443, 31001, 31337, 32001, 33001 and 34001 but only received SYN/ACK packets back from 8443, 31001 and 31337… Well what about the other 3?
If we look at the traffic holistically with the filter ip.src == 10.1.30.11 and sort by either the packet number of time columns, we’ll see that before our APT actor first sends a SYN to 34001, then 33001, then 32001 before sending actual data to 31001. This pattern repeats itself for multiple hosts! In fact, if you count up the number of unique hosts this happens to then you just earned yourself 50 points and another 50 if you count the total number of knocks!
This means that 34001, 33001, and 32001 are knock knock ports! Give yourself another 50 points! (now in the CTF however, the actual flag had these ports reversed so if anyone missed this flag because of this, I feel for you, it almost got me too).
Finally, we’ve made it to the last 2 questions… Knock timing. Calculating knock timing can be relevant in the real world as some knock knock servers can add a time factor into the combination sequence! This was a new one for me though so I had to do some searching before finding a method that would work and without requiring a LOT of manual math.
First I started by isolating the first and second port knocks in the sequence by using the filter
Ip.src == 10.1.30.11 && (tcp.dstport == 34001 || tcp.dstport == 33001)
Now it’s CRUCIAL that you sort the output by either packet number or time! If you don’t, then you’ll end up with a bad result. Starting at the very first result (which should be a 34001) right click the row and select Set/Unset Time Reference (Shortcut Ctrl+T).
Do this to every OTHER (alternate) packet. In the end you should have marked each packet destined for 34001.
Now time for math! Using a calculator (or some spreadsheet application too I guess) add all the visible values together then divide by 11 and give yourself 50 points!!
The final 50 points just involves doing the same procedure to calculate the average time between the second and third port knock.
If you made it this far thanks for sticking with me! I tried to keep this write up highly descriptive so it can be used by people of all skill levels. Did I breeze by something that you think needs more detail or is this just way too long? Let me know so I can deliver better content to you in the future. Cheers!