This is my write-up for the SANS Holiday Hack Challenge 2020.
There are two types of challenges: the main objectives and the extra terminals. In the game they are interleaved since solving terminals give you hints for the main objectives but here I have separated them into two sections.
There are 11 main objectives, or actually 12 if you count the two parts of eleven separately.
Objective 1: Uncover Santa’s Gift List
The first objective is fairly simple. We need to deobfuscate the gift list to see what Josh wants.
Fortunately, the twirl effect that has been applied to the image can be undone. It is porbably possible to do something more sophisticated to get a very clear picture but I simply cropped the image down to just the list and then did a twirl in the opposite direction to get the following result:
Where we can just barely make out what Santa is planning to get Josh, a proxmark.
Objective 2: Investigate S3 Bucket
In this challenge we are tasked to investigate some S3 buckets to find the data from the “Wrapper3000”. We can start by checking out the tips and then run the bucket finder tool.
We find a few buckets but nothing that we have access to. However, if we add “wrapper3000” to our wordlist and try again we do find the bucket of interest. We can then use the tool to download the contents of the bucket.
Inspecting this file we can see it is base64 encoded data. Decoding it gives a zip file which in turns contains a file that has been encoded in multiple layers. By using the appropriate Linux tools in succession, we can decode the data and get the final answer.
Answer: North Pole: The Frostiest Place on Earth
Objective 3: Point-of-Sale Password Recovery
In this challenge we are given an Electron app Windows installer and we need to recover the default password for it.
To make this easier we first install the asar tools via npm. Asar is the archive format used by electron.
We need to extract the actual app data, contained in the “app-64.7z” file, from the installer. This can be done with 7-zip.
This file is itself a 7-zip archive from which we can extract the “app.asar” file. We then use the asar tools to extract the “main.js” file from it.
Looking at the code we find this part containing the password we are looking for.
Objective 4: Operate the Santavator
Throughout the challenges you collect various items as you walk around. These can be used to connect the “circuit” in the Santavator to travel to different floors.
Using the various items it is possible to power the three different colored sockets. My final configuration looked like this:
This allows us to go to any floor except Santa’s office which requires you to activate, or bypass, the fingerprint sensor. This is described in objective 10.
Objective 5: Open HID Lock
After finding the proxmark we can go to (TODO: ELF NAME) and clone their card by bringing up the proxmark console and running the following command.
We can then take this data, go to the locked door in the workshop, bring up the proxmark console again and spoof the card with the following command.
This opens the door and completes the objective.
Objective 6: Splunk Challenge
This challenge requires us to first solve a series of log analysis challenges leading up to the final question which gives us the answer to the objective.
Question 1: How many distinct MITRE ATT&CK techniques did Alice emulate?
Question 2: What are the names of the two indexes that contain the results of emulating Enterprise ATT&CK technique 1059.003?
We can use the following query to tally up the various attacks which are stored in separete indices:
| tstats count where index=* by index
This gives us the answers to the first two questions.
Answer 1: 13
Answer 2: t1059.003-main t1059.003-win
Question 3: One technique that Santa had us simulate deals with ‘system information discovery’. What is the full name of the registry key that is queried to determine the MachineGuid?
Question 4: According to events recorded by the Splunk Attack Range, when was the first OSTAP related atomic test executed?
Let’s search for all entries in the “attack” index containing “ostap” and sort by execution time in ascending order to find the answer.
index=attack ostap | sort + "Execution Time _UTC"
Answer 4:. 2020-11-30T17:44:15Z
Question 5: One Atomic Red Team test executed by the Attack Range makes use of an open source package authored by frgnca on GitHub. According to Sysmon (Event Code 1) events in Splunk, what was the ProcessId associated with the first use of this component?
Question 6: Alice ran a simulation of an attacker abusing Windows registry run keys. This technique leveraged a multi-line batch file that was also used by a few other techniques. What is the final command of this multi-line batch file used as part of this simulation?
Again, we can search the Atomic Red Team repository for “run keys”. This gives us a number of results but the only one also found in the logs, as seen in question 1, is T-1547. Using the descriptions here we can search for “bat” and “CurrentVersion” in the T-1547 index.
This leads us to a bat file called Discovery.bat which we can look up in the GitHub repo and see that it ends with trhe “quser” command.
Answer 6:. quser
Question 7: According to x509 certificate events captured by Zeek (formerly Bro), what is the serial number of the TLS certificate assigned to the Windows domain controller in the attack range?
By searching all the indices for events from bro and looking for events containing “serial” we quickly find the serial of the certificate.
"index=* sourcetype=bro* serial"
Answer 7:. 55FCEEBB21270D9249E86F4B9DC7AA60
With all the regular questions answered, we get a final message with a ciphertext and some hints.
This last one is encrypted using your favorite phrase! The base64 encoded ciphertext is:
It’s encrypted with an old algorithm that uses a key. We don’t care about RFC 7465 up here! I leave it to the elves to determine which one!
The algorithm referenced is RC4. Now we just need the key. Another messages points us in the right direction.
I can’t believe the Splunk folks put it in their talk!
The talk is available on YouTube and jumping to the 18:31 mark we get the phrase “Stay Frosty”. Putting this altogether we can decrypt the ciphertext in Python to get the answer to the objective.
Answer: The Lollipop Guild
Objective 7: Solve the Sleigh’s CAN-D-BUS Problem
The goal of this challenge is to filter out the bad messages Jack is injecting. There are different approaches to this but I started by basically filtering out all messages and then removing one filter at a time to understand which function of the sled corresponds to what messages. The functions are: accelerator, break, steering, lock/unlock and start/stop. By manipulating these functions one at a time we can see that there is a message with ID “19B” corresponding to the lock/unlock function being injected from time to time. The message has value “0000000F2057” which doesn’t match any of the valid values “00000F000000” or “000000000000”. We should therefore filter it out. By going through each of the other functions we can discover thaty message id “080” corresponds to the breaks which seems to have a valid range of 0-100 but we also see valus like “FFFFF8” which can be interpreted as a negative signed number so let’s filter out anything less than 0 with ID 080. These two filters together solve the challenge.
ID 19B Message Equals 0000000F2057
ID 080 Message Less 000000000000
Objective 8: Broken Tag Generator
In this challenge we are presented with a vulnerable web application and we want to leak one of the invironment variables. If we upload an image to the app we observe that it is then served from the following URL:
This smells LFI. Let’s try to access the passwd file to test the hypothesis:
This seems to work. Now we would like to leak the source code of the app to be able to look for other vulnerabilities but we do not know the path to the app. If we try an invalid path however we get a nice error message.
Now with the path to the code we can leak it and start reading through it.
Looking through the code we can see that there is an issue with how uploaded files are handled. The relevant parts of the code are shown below.
The system command which is run in a separate thread takes a filename and uses it directly in the command without proper escaping. If we can control the filename this would be a command line injection vulnerability. However the filenames used in the process_file function are not the ones provided during the upload but the temporary names generated by the web framework. However, the app supports processing uploaded zip files and if the zip file contains images those will be processed using the process_file function using a filename that we control. The call chain will thus look something like this:
There are a few limitations to what names we can use since the “extract” function needs to succeed but taking this into account we can construct the following attack script:
Running this will create a zip file containing a file with a command injection in its name, upload it to the server, wait for the separate thread to finish and then retrieve the outputs.
This gives us the variable we are looking for.
Objective 9: ARP Shenanigans
This challenge tasks us with performing a full Meddler-in-the-Middle attack starting with ARP spoofing and going all the way to getting code execution. We start by looking at the example pcap files provided and what traffic we see on the network.
We see that the host with MAC address 4c:24:57:ab:ed:84 and IP address 10.6.6.35 is looking for IP address 10.6.6.53. Using the provided script as a starting point, we create the following script to use Scapy to respond to the ARP request and claiming that the IP address belongs to our host.
Running this script and observing the network traffic, we can see that after we successfully reply with our ARP spoof packet we get a DNS request sent to us for the host. Again, using the provided script as a base, we can use Scapy to craft a DNS response providing our IP address as the A record of the DNS lookup.
Running both of these scripts and again looking at the traffic we now see an HTTP request incoming to our host requesting a Debian package. We can create our own package containing nothing but a manifest “control” file and a post install “postint” script. The postinst script will be run after the (empty) package has been installed and will give us a reverse shell on the victim host. The two files look like this.
Putting all of this together, we use the first script to ARP spoof the victim tricking it into thinking we are the DNS server. Then we use the second script to reply to the DNS lookup, again replying with our address. Finally, we set up a web server and serve the malicious Debian package on the path requested and once the victim installs the package it will connect a remote shell to our computer. We then use this to fetch the meeting protocol from the server to find out who recused herself from the vote.
Answer: Tanta Kringle
Objective 10: Defeat Fingerprint Sensor
The elevator code can be inspected. Specifically, looking at “app.js” we can find the handler for the santa office button and the “hasToken” function.
This means that by adding the string “besanta” to the “tokens” array, we can bypass the fingerprint sensor. Luckily, the tokens array is in the global scope and is easily accessible so we can simply run this line of code in the browser console and then click the elevator button.
Objective 11: Naughty/Nice List with Blockchain Investigation
This challenge is in two parts. The first step is to predict a nonce and the second one is to figure out how Jack managed to modify the blockchain.
Part 1 - Nonces
The first part is straightforward. The nonces are generated using a Mersenne Twister so by looking at 624 32-bit values, or in this case half as many 64-bit values we can fully recover the internal state and predict the next values. Using the Mersenne Twister Predictor library we can create the following script which reads all the nonces from the blocks and predicts the next. We are specifically looking for the fourth one after the last block.
Running this script gives us the predicted nonce for the fourth block after the last. This is the answer we are looking for.
Part 2 - Altered block
Somehow Jack has managed to alter one of the blocks while keeping the blockchain valid. The suspicious block claims that he has +0xFFFFFFFF nice points and it has a PDF attached containing testimony about how great he is. From the hints we understand that he has used the Unicoll method as described in these slides by Ange Albertini. We are also told that he changed only four bytes which could mean applying the Unicoll method in two different places. Let’s first consider the nice score. What if the sign bit was originally 0 instead of 1? Looking at the layout of the block we see that the sign is in fact stored in the tenth byte of a block which makes it a good candidate for the simple Unicoll setup. Additionally, the tenth byte of the following block is inside the first attachment which seems to be garbage data. This means that by decrementing the the sign bit from 1 to 0 and incrementing the tanth byte of the following block we flip the score from +0xFFFFFFFF to -0xFFFFFFFF without changing the MD5 hash of the block. Now let’s look at the PDF. By extracting the pdf attachment and analyzing the PDF structure we see that there is in fact two “page” objects in the file even though it seems to only contain one page. If we change the catalog entry from pointing to the page with ID 2 to the page with ID 3 and open the PDF file we see completely different contents:
<</Type/Catalog/_Go_Away/Santa/Pages 2 0 R
<</Type/Catalog/_Go_Away/Santa/Pages 3 0 R
Again, it just so happens that this reference is in the tenth byte of a block so by compensating this change with decrementing the tenth byte of the next block we kan perform this change to the PDF while maintaining the same MD5 hash of the block. Below you see the difference between the two blocks.
Both of them will have the same MD5 hash and this is how the attack by Jack was performed. We can use the Python script below to restore the original block calculate the SHA256 hash of it and verify that the blockchain is still valid.
The SHA256 hash of the restored block is the answer we are looking for.
Here I will give a very brief explanation on how to solve the various side terminals in the challenge.
Terminal 1 - Kringle Kiosk
Here we are presented with a menu system written in bash. The goal is to run bash which can be performed with a simple subshell. To get the output immediately we redirect stdout to stderr, otherwise we would have to wait until we exited bash to see any output.
Terminal 2 - Unescape tmux
The goal is to reattach to a running tmux session. We do this by listing all current session and then reattaching to the only session listed.
Terminal 3 - Munchkins
This terminal is an intro to some basic Unix commands such as ls, cat, rm, pwd, history, printenv, chmod, mv, ln, cp, echo, find, ps, netstat, kill and curl. The transcript of all the tasks solved is listed below.
Terminal 4 - Elfcode
Terminal 5 - 33.6kbps
In this challenge we need to mimic a modem. We call the number given to us “756 - 8347” and make the sounds in the correct order. This can be done by finding a recording of a modem dialing up and try to match which sounds the most correct. The result is as follows.
baa DEE brrr
Terminal 6 - Redis Bug Hunt
Here we can use curl to interact with the local web server. We guess that the web root is located at “/var/www/html/”.
It seems that we can run arbitrary commands in Redis. This means that we should be able to get code exection by setting the Redis working directory to “/var/www/html”, setting the name of the database file to “x.php”, storing some PHP code in Redis and finally performing a save to cause Redis to write a file at “/var/html/www/x.php” containing PHP code of our choice.
Using this backdoor we have just created, we can list all the files in the webroot and dump the contents of index.php to find the “bug”.
Terminal 7A - Door
The first challenge we solve by simply running the strings tool on the binary.
Terminal 7B - Lights
If we copy the encrypted password field into the name field and run the program, the decrypted password will be displayed to us. We can then use this to turn on the lights.
Terminal 7C - Vending machine
Here we can create a new password by encrypting a string of all A’s and observing a pattern that repeats after every 8 characters. We can then redo this and encrypt a string of 8 copies of every character to build a lookup table of what a specific character at a specific position encrypts to. We can then use this lookup table to decrypt the original password.
Terminal 8 - Game
First we start a session of the game on the “impossible” difficulty. There we can check the source to find a comment containing the random number that were discarded. By saving them to a file “snowball-values.txt” and running the following Python scripts which uses the Mersenne Twister Predictor library, we find out what our player name actually is.
We then take this value, open a new instance of the game and start a match on the “easy” difficulty using this name. We can now play out the match on easy to figure out where all the forts are located and then trivially win the impossible game.
Terminal 9 - Sort-o-matic
The following regex patterns solves the challenge:
First we take all the messages, sort and count them to find that we are looking for the messages with ID 19B. We then search for them in the logs to find the different message and submit its timestamp as the answer.
Terminal 11 - Scapy Prepper
This terminal is an interactive Scapy tutorial. Each task is about viewing or modifying packets using the Scapy framework. The transcript of the questions and my answers are listed below.
Thanks to SANS for hosting another great edition of the Holiday Hack challenge. These challenges are very nice, especially for beginners as they cover a broad range of topics and there’s almost always something to take away, even for an experienced person. I strongly recommend you to check out the next one if you get the opportunity to.