2024 Holiday Hack Challenge - Prologue
A orientation of the HHC universe, followed up by the Prologue objectives of the 2024 HHC!
A new Holiday season means... a new Holiday Hack Challenge! I've completed the challenges each of the past two years. This year's is slightly different, in that the solutions are allowed to be posted this year earlier than year's past - 7 days after each challenge release date. You can read more about that in the previous blog post. Since this section is the Prologue, it's been released on November 14th.
Unofficial HHC "Orientation"
First visit this year's website, register/login to your account. If you've never done Holiday Hack Challenge before, we'll cover the initial orientation once you've created an account and login. Slightly confusing since each year has an actual "Orientation", but this unofficial one is meant to get you situated with the HHC universe.
Important Landmarks & UX
To do a quick summary of the game interface, you can move your avatar around by using the arrow keys, or clicking your mouse in the direction you want your character to move. Upon first logging into the game you'll notice a few key features we'll cover here:
On the left-hand side of the screen is the toolbar, which includes the following buttons:
- Story - Tells the story of the entire HHC. You'll notice this helps explain the overarching theme of the challenge, and is constantly updated as you progress through the challenges.
- Map - A layout of the locations. You can click on the locations as you discover them to quickly teleport to locations to save yourself time. It's a balance between playing the game, and still having time to shop for Christmas presents.
- Objectives - these will summarize the specific challenge you need to complete. It usually includes the who, what, and where. Helps to check these if you are unsure where to go next. An incomplete challenge has a greyed out trophy next to it, while a completed objective has a trophy. Be aware there are some challenges that require you to complete them on an external website and to submit a flag in this section. The difficulty rating is on a scale of 1 to 5 snowflakes. Don't be discouraged, even if you face a more difficult challenge, try it out, and be sure to use the Discord channel as a resource for help. Also new this year - the ability to use Story Mode, and skip objectives! For those who might not be interested in completing a challenge for whatever reason.
- Conversations - as you progress through the game, you'll meet characters who will explain both the objectives you'll need to complete, hints of how to solve objectives and more. This tab has the shortcut to the entire transcript of anyone you talk to in the event you accidentally speed click past a conversation.
- Hints - A condensed list of hints, of who said it, what challenge it pertains to, and what the actual hint may be. Some hints are more direct than others, but nonetheless will help you out.
- Achievements - This one is fairly straight forward...
Additionally, two other things to note:
- Raspberry Pis - these are the computer interfaces, typically used to complete a challenge. Use these after speaking to the key characters, typically standing next to them... which brings up...
- Key Characters - These are the avatars who have their names in holiday green text. Be sure to interact with these people, as they'll tell you about objectives, give hints, and help explain the story of this year's HHC!
2024 HHC - Prologue
To start the prologue, click on the Story button, which instructs you to "Talk to Jingle, Angel and Poinsettia about their challenges". Click on the Go to Prologue button, which should bring you to a new location.
Objective: Holiday Hack Orientation
Tasks to Jingle Ringford. Click through the conversation. You will learn that you can click on the snowball that your avatar holds, which is a shortcut to bring up the toolbox mentioned earlier.
Walkthrough
Click on the Raspberry Pi, and click on the upper pane, type in the word answer
and hit Enter
. Objective Complete!
Objective Takeaways
- Get acclimated to the interface
- Two new objectives appear: "Elf Connect" and "Elf Minder 9000"
Objective: Elf Connect - Gold
On the same island where you spoke with Jingle Ringford, move to the northeast, and you'll find Angel Candysalt. He has a game he needs you to help beat, specifically topping the high score of 50,000. It's similar to the New York Times' Connections game, but more vulnerable! The max score should be 1,600 but someone topped 50,000.
Walkthrough
Click on the Raspberry Pi to start the game - an important first step! Open Developer Tools - in Firefox, this can be done by clicking CTRL + SHIFT + I
. The game loads as an iframe
inside the browser. Use the Inspector tab to find the Javascript inside the iframe
. To solve the challenge, we are interested in this block of code, starting on line 202:
function checkSelectedSet(scene) {
let selectedIndices = selectedBoxes.map(box => box.index);
selectedIndices.sort((a, b) => a - b);
let isCorrectSet = false;
let matchedSetIndex = -1;
for (let i = 0; i < correctSets.length; i++) {
if (JSON.stringify(selectedIndices) === JSON.stringify(correctSets[i])) {
isCorrectSet = true;
matchedSetIndex = i;
break;
}
}
if (isCorrectSet) {
completedSets.push(matchedSetIndex);
positionCompletedSets();
disableCompletedSet(matchedSetIndex); // Disable interaction on the completed set
shuffleRemainingRows();
// Update score by 100 points
score += 100;
scoreText.setText('Score: ' + score);
// Add high-score board
if (score > 50000) {
highScoreText.setText('High Score: ' + score);
emitter.explode(20);
submitAction(2);
displaySuccessMessage('Great Job Hacker! Elf Connect Complete and Hacked!', function () {
});
}
Specifically, we want the score
to be greater than 50,000. In order to do that, we need the isCorrectSet
to flip from false
- as defined in line 206 of the original code, or line 4 in the code snippet above - to true
. In order to do that, we must match 4 of the squares in the game.
Before we do that, we should alter our score. Within the Web Developer Tools, click on the Console tab. Type in: score += 50001
and hit Enter. Next, back within the game in the browser, match 4 of the tiles of your choosing. You can go with the reindeer of Blitzen, Comet, Vixen, and Prancer for this example.
VICTORYYYY!!!!! You should receive a prompt that you've completed the objective successfully.
Objective Takeaways
Use Developer Tools in a browser of your choosing, to analyze JavaScript and use the console to set the new high score!
Objective: Elf Connect - Silver
After completing the entire Prologue, I realized I didn't complete the Silver level. This was as simple as playing the game by itself and winning. For those Connections aficionados, you might get away with it. Instead, looking at the same source code mentioned in the Gold solution, I pulled together a quick python script. The words for each level were stored in a dictionary (wordSets
), and the pairs were specified in the correctSets
array.
#! /usr/bin/env python3
wordSets = {
1: ["Tinsel", "Sleigh", "Belafonte", "Bag", "Comet", "Garland", "Jingle Bells", "Mittens", "Vixen", "Gifts", "Star", "Crosby", "White Christmas", "Prancer", "Lights", "Blitzen"],
2: ["Nmap", "burp", "Frida", "OWASP Zap", "Metasploit", "netcat", "Cycript", "Nikto", "Cobalt Strike", "wfuzz", "Wireshark", "AppMon", "apktool", "HAVOC", "Nessus", "Empire"],
3: ["AES", "WEP", "Symmetric", "WPA2", "Caesar", "RSA", "Asymmetric", "TKIP", "One-time Pad", "LEAP", "Blowfish", "hash", "hybrid", "Ottendorf", "3DES", "Scytale"],
4: ["IGMP", "TLS", "Ethernet", "SSL", "HTTP", "IPX", "PPP", "IPSec", "FTP", "SSH", "IP", "IEEE 802.11", "ARP", "SMTP", "ICMP", "DNS"]
}
correctSets = [
[0, 5, 10, 14], # Set 1
[1, 3, 7, 9], # Set 2
[2, 6, 11, 12], # Set 3
[4, 8, 13, 15] # Set 4
]
for key in wordSets:
print(f"Round {key}:")
for grouping, indices in enumerate(correctSets, start=1):
group_words = [wordSets[key][i] for i in indices]
print(f" Grouping {grouping} - {', '.join(group_words)}")
print()%
Running the script (answers.py
) yields the results which you can then easily click through.
python3 answers.py
Round 1:
Grouping 1 - Tinsel, Garland, Star, Lights
Grouping 2 - Sleigh, Bag, Mittens, Gifts
Grouping 3 - Belafonte, Jingle Bells, Crosby, White Christmas
Grouping 4 - Comet, Vixen, Prancer, Blitzen
Round 2:
Grouping 1 - Nmap, netcat, Wireshark, Nessus
Grouping 2 - burp, OWASP Zap, Nikto, wfuzz
Grouping 3 - Frida, Cycript, AppMon, apktool
Grouping 4 - Metasploit, Cobalt Strike, HAVOC, Empire
Round 3:
Grouping 1 - AES, RSA, Blowfish, 3DES
Grouping 2 - WEP, WPA2, TKIP, LEAP
Grouping 3 - Symmetric, Asymmetric, hash, hybrid
Grouping 4 - Caesar, One-time Pad, Ottendorf, Scytale
Round 4:
Grouping 1 - IGMP, IPX, IP, ICMP
Grouping 2 - TLS, SSL, IPSec, SSH
Grouping 3 - Ethernet, PPP, IEEE 802.11, ARP
Grouping 4 - HTTP, FTP, SMTP, DNS
Objective: Elf Minder 9000
The objective asks to assist Pointsetta McMittens with playing a game of Elf Minder 9000. Depart Angel Candysalt, and continue to move northeast, past the vendor booths, and you'll run into Pointsetta.
Be sure to read the instructions on how to play the game. You could use the lessons that we'll cover shortly to play the earlier lessons. However, I just treated it like the game it is, and goofed around admittedly. It was fun to play as is! Your score is not pertinent to advancing levels. You just need to collect all the boxes before time expires.
However, once you complete each of the 12 levels, you'll be given access to a special level A Real Pickle. Let's cover a few important things first.
Walkthrough - A Real Pickle
Before we dive into solving the challenge, we can cover a few miscellany items.
Gameplay
A few important facts to cover about the game:
- Your main objective is to collect all the crates, by drawing a path for the elf.
- Once all crates are collected, get to the checkered flag before time expires.
- Tunnels can teleport the elf, and come in pairs. You can only dig one tunnel per level.
- Springs - when stepped on, they launch the elf in the current direction of travel. If there isn't a path in that direction, the elf will skip the spring. The GUI limits you to two springs
There are apparently ways to use more springs than what is provided. However, I didn't pursue that for this solution. In my testing, I saw the ability to add more springs to the board. But that's about as far as I got, and given the lack of necessity to get the final solution, moved on.
- Sizzling sand makes you move faster when you move through it, and sleeping crabs make you move slower when you walk in a cell adjacent to it.
Developer Tools - GUI
You can play the game inside the HHC, or you can open the page in a new tab. To do so, open Developer Tools in your browser. We previously covered the command shortcut to do so, but for those more GUI-forward, (in Firefox):
- Click the Hamburger Button in the upper right hand corner of Firefox
- Click More Tools
- (Not pictured) Click Developer Tools.
To open the game in a new window, use the Inspector tab to look at the HTML. Expand the sections of the HTML to (1) find the iframe
with a title="challenge"
. Right click on the code, and (2) Select Open Link in New Tab.
This doesn't help solve the challenge in any way, purely aesthetics, and makes it a bit easier to work with. It'll limit the HTML you're inspecting to just the game - rather than the game inside the HHC HTML overall.
Download/Open the Javascript
Looking at the HTML in the new tab, we are presented with the following by default:
<body>
<div class="container">
<script src="chance.min.js"></script>
<script src="levels.js?"></script>
<script src="guide.js"></script>
<script src="game2.js"></script>
</body>
This gives us a hint of how the game is running. You can enumerate each of those files by appending the filename to the website. We will focus on the guide.js.
Game Functionality - Grid Layout
The game is played on a 6 x 5 grid - that's 6 cells across, by 5 cells vertically - to the human eye. However, it's more important to look at the game setup, which should be looked at a 12 x 10 grid. Instead of thinking like you're in Quadrant 1 a Cartesian Plane (apologies for everyone who hated high school math and just bailed), the start of the grid is in the upper left hand corner, with the X axis (orange numbers) incrementing as you move to the right, and the Y axis (blue numbers) incrementing as you move down.
Game Functionality - segments
and entities
Lets pivot from from the front end, to the back end - i.e the code - to look at how it functions. Many different portions of the code reference both segments
, and entities
. This.segments
in the code, and game.segments
in the Developer Tools Console, is an array which refers to the various pieces of the Path that are drawn by the player. Before a board is modified by the player (i.e. drawing a path), this array is empty. As a player draws the path, the array is populated in the order in which the line was drawn. Segments
are typically in a 2 dimensional array, where each inner array includes a pair of two numbers. Each inner array is the start of the segment, as the first 2 digit array, and the end of the segment as the second 2 digit array. The inner arrays are in the layout of [ orange-number , blue-number]
using the color coding from the picture above. If your first line drawn using the Path tool was from the start flag to one location directly to the right, it would appear in game.segments
as [[1,1],[2,1]]
.
Entities
(this.entities
and game.entities
) is an array which refers to the objects placed on the board. This includes all 7 Entity Types - which are mentioned in the first 24 lines of code. This is another 2-dimensional array. However, the inner array includes 3 numbers - in the syntax of [ orange-number, blue-number, EntityTypesRef[Number]]
- where the Entity type number pertains to the type of object located at that coordinate (0 = start, 1 = end, 2 = crate, 3 = blocker, 4 = hazard, 5 = steam, 6=portal, 7 = spring). For instance, in the picture above, there was a start flag in the coordinate of [1,1]
, so the item would appear in the game.entities
array as [1 , 1, 0]
.
Its important to grasp these concepts, as well as the grid layout, as we'll be manipulating these soon.
Game Functionality - getSpringTarget
Another important code block starts on line 266 of guide.js and is pasted below for easy reference.
I provided my own comments in this code below, prepended by ZTNote:
. It's important, as there was already a comment left in the code, that is of interest to us.
getSpringTarget(springCell) {
const journey = this.hero.journey; // ZTNote: the current path the elf is on
const dy = journey[1][1] - journey[0][1]; // ZTNote: vertial direction elf is moving
const dx = journey[1][0] - journey[0][0]; // ZTNote: horizonatl direction the elf is moving
let nextPoint = [ springCell[0], springCell[1] ]; // ZTNote: where the elf is going next
let entityHere;
let searchLimit = 15; // ZTNote: setting ceiling for search to avoid doom loop
let searchIndex = 0;
let validTarget;
do {
searchIndex += 1;
nextPoint = [ nextPoint[0] + dx, nextPoint[1] + dy ]; // general direction of where they are going
// Note: locations of Portals, and Springs
entityHere = this.entities.find(entity =>
~[
EntityTypes.PORTAL,
EntityTypes.SPRING,
].indexOf(entity[2]) &&
searchIndex &&
entity[0] === nextPoint[0] &&
entity[1] === nextPoint[1]);
// ZTNote: exit code if Index = 15
if (searchIndex >= searchLimit) {
break;
}
validTarget = this.isPointInAnySegment(nextPoint) || entityHere;
} while (!validTarget);
if (this.isPointInAnySegment(nextPoint) || entityHere) {
// ZTNote: If the next point the elf is moving to is a location of another spring/tunnel
// ZTNote: Then send elf to the *very first* line drawn in segments
if (entityHere) return this.segments[0][0]; // fix this
return nextPoint;
} else {
return;
}
}
This code is intended to provide a location for where the Spring should land the elf once stepped on. The particular line of interest in the original code is line 298:
if (entityHere) return this.segments[0][0]; // fix this
The comment indicating, this is a problem for the game logic. Summarizing the rest of the function, it takes into consideration where the elf is and what direction they are traveling. If the location where the spring/portal is going to send the elf is another spring/portal, send the elf back to the very first entry in segments
.This would mean the elf would be returned to the very first line drawn by the player.
Solution - Board Setup
From here on out, it goes from understanding the gameplay and theory of how to win, to implementing a solution to win the level. I can't emphasize this enough - there is more than one way to beat the level. In fact, I even heard rumblings on the discord of folks solving the level without using the game console. Tinker around and find alternative ways! But we'll cover the way I found to be most direct.
The grid from above is again copied for easy reference.
Setup the board by placing the items in the followinglocations:
- Tunnel #1 -
[3,1]
- Tunnel #2 -
[3,2]
- Spring #1 -
[9,3]
(for starters) - Spring #2 -
[9, 7]
(for starters)
Next, draw your path taken by the elf. The MOST important thing to do is draw the line to the FINISH flag first. Draw it from [10,9]
--> [11,9]
. When you draw your line, assume the springs will move over 1 spot to the left for each - to [8,3]
and [8,7]
. Draw a line through the tunnels, to the spring, then a left, over the rock, an down to collect the boxes before then going through the spring and up 1 spot, like below:
For a quick summary:
- Place Tunnel #1
- Place Tunnel #2
- Place Spring #1
- Place Spring #2
- MOST IMPORTANT STEP - Begin drawing path here, to the finish flag.
- Draw rest of the path, starting at the beginning
- Continue drawing the path, note the left turn after the spring
- Continue drawing the path
- Last part of the path to draw, being sure there is only one line going upward from Spring #2.
Prior to running the game, run this in the Developer Tools Console.
// move spring #1 one spot to the left
game.entities[22] = [8,3,7]
// move spring #2 to be vertically aligned with spring #1
game.entities[23] = [8,6,7]
//move the vertical line last added one spot to the left
game.segments[20] = [[8,6],[8,7]]
Making those adjustments, shows a more logical path to success. The changes below are in the purple boxes.
Click the Start Button - aka the neon green elf in the right hand side of the toolbar. And... VICTORY!!!!!
Navigate back to the Holiday Hack website, log back in if it's been a while 😉, and see you've passed the objective!
Why This Solution Works
The majority of the solution is using the regular rules of the game to solve the level. It's the last few changes implemented in the console.
- Firstly, we make the jump over the rock to the crate in the second row, thanks to moving the spring over one spot to the left. In normal game play/just by using the GUI, this isn't feasible.
- Secondly, and most importantly - the second spring must move to be aligned in order to hit the
if(entityHere)
logic, the next cell on the path for the elf after taking the spring, must be another spring. - Lastly, we must move the line so our elf continues on the path and can reach the second spring.
Objective Takeaways
The objective gave us some exposure to JavaScript code review and understanding how to abuse a game's logic and win! We reviewed documentation to understand the intended functions of the game, as well as the code itself to identify logic flaws. Additionally, we continued our exposure to using the browser Developer Tools to interact with the game.
Prologue Conclusion
This wraps up all the objectives in the Prologue of the 2024 Holiday Hack Challenge. If you navigate to your Story tab, you should see "ACT I" now available, and the Go to Act I button which will teleport you to the next level. I'll release those in a separate post, 7 days after Act I opens. Stay tuned for all 3 Act's of the HHC!