Holiday Hack 2024: Drone Path
Introduction
I’ll take the TTN over to the DMZ and find Chimney Scissorstricks at the bottom:
They have intel on what Wombley’s doing in the toy factory, and need finding an admin password hidden in drone flight logs:
Chimney Scissorsticks
Hey. Psst, over here. Hey, I’m Chimney Scissorsticks.
I’m not liking all the tension brewing between the factions, so even though I agreed with how Wombley was handling things, I get the feeling this is going to end poorly for everyone. So I’m trying to get this data to Alabaster’s side. Can you help?
Wombley’s planning something BIG in that toy factory. He’s not really making toys in there. He’s building an armada of drones!
They’re packed with valuable data from the elves working on the project. I think they hide the admin password in the drone flight logs. We need to crack this to prevent this escalating snowball showdown.
You’ll be working with KML files, tracking drone flight paths. Intriguing, right? We need every detail to prepare for what’s ahead!
Use tools like Google Earth and some Python scripting to decode the hidden passwords and codewords locked in those files.
Ready to give it a go? It’s going to be a wild ride, and your skills might just turn the tide of this conflict!
Drone Path
Challenge
The terminal offers a webpage for the Elf Drone Workshop:
On the menu there’s “Home”, “FileShare”, and “Login”:
“FileShare” offers a KML file to download:
Authenticated Access
KML
A KML file is a format used to show geographical data and works with Google Earth. I’ll upload the file to Google Earth. The KML adds a path over antartica that spells out GUMDROP1:
Access Authenticated Site
Given the elf’s comments about passwords in flight paths, I’ll try this as a password for the site. It doesn’t work for admin, but it does work for the fritjolf user! The page goes to the Elf Drone Workshop Drone Search page (/workshop
):
Alternatively, instead of using this password, the login can be bypassed with a SQL injection. The username “’ or 1=1”;– -“ with any password works to get in:
Authenticated Site Enumeration
In addition to the drone search page there’s an Admin Console, but it requires an unlock code:
There’s a profile page for the currently logged in Elf (more interesting with the correct username and password than the SQLI):
I’ll grab a copy that CSV.
Visualizing CSVs
Preparations-drone-name.csv
The CSV file has 187 columns! I’ll start with the OSD.longitude, OSD.latitude, and OSD.altitude columns to see if I can visualize the data.
The fritjolf-Path.kml
file is an 80-line XML file, where all the coordinate points are in one line towards the bottom:
Each point is lon,lat,alt
and then a space separates points. I’ll make a copy of fritjolf-Path.kml
and change the name at the top:
I’ll use bash
tools to get the points:
oxdf@hacky$ cat Preparations-drone-name.csv | cut -d, -f 6,5,10
OSD.longitude,OSD.latitude,OSD.altitude [ft]
144.8567879816271,-37.42277804382341,19
142.4357677725014,-38.0569169391843,19
143.9329094555584,-37.80217469906655,19
142.2754454646221,-38.0682499155867,19
141.756352258091,-34.52324587244343,19
145.513859306511,-36.74357572393437,19
144.745994150535,-37.89721189352699,19
145.8966329539992,-37.00702150480869,19
oxdf@hacky$ cat Preparations-drone-name.csv | cut -d, -f 6,5,10 | grep -v OSD | tr '\n' ' '
144.8567879816271,-37.42277804382341,19 142.4357677725014,-38.0569169391843,19 143.9329094555584,-37.80217469906655,19 142.2754454646221,-38.0682499155867,19 141.756352258091,-34.52324587244343,19 145.513859306511,-36.74357572393437,19 144.745994150535,-37.89721189352699,19 145.8966329539992,-37.00702150480869,19
Now I can paste that into my new KML file and upload it to Google Earth:
It’s a short trip around Australia. Zooming in on the first point, it looks like an “E”:
Following the line to the next point, it’s an “L”:
All together, it spells “ELF-HAWK”:
ELF-HAWK-dump.csv
Searching on the drone’s page for ELF-HAWK shows another path to a .csv
:
The caps in the second comment suggest I should focus on the LAT and LONG.
I’ll use the same strategy for ELF-HAWK-dump.csv
, making a new KML and getting the points into it. The result in Google Earth is a mess!
Looking around, there are some large block letters in there, and there’s a clear bottom and top:
Looking more closely at the longitude data from ELF-HAWK, I’ll notice at some point the lon data goes above 360:
That’s interesting, as it’s wrapping around the globe and coming back to the same spot. Google Earth seems to handle this by just putting it on the map in the same spot mod 360. It seems like perhaps I should look at the data from just the first pass, where 0 <= lon < 360.
I’ll make a copy of the KML and remove all the point after it goes larger than 360. Starting at the prime meridian (lon === 0, goes through the UK) and going East, there’s a “D”:
Next a lower-case “r”:
The next three are “one”:
I can break the data into five KML files for each lap around the earth and get the password this way.
Python Plot
I’ll work with ChatGPT and Python to get a script that will plot the path of the points on a single plot. I’m going to use a projection onto a map plot to get the spacing right. Unfortunately, these plots only take data from -180 to 720, and my lon data goes up above 1500. I’ll solve the by breaking the result into subplots that are 720 wide each, and splitting the data up into three groups based on which subplot is needed. I can then take the lon value mod 720, plot the value in the correct plot, and show the plots side by side.
The final code looks like:
import csv
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
wrap = 720
with open('ELF-HAWK-dump.csv', newline='') as csvfile:
reader = csv.reader(csvfile)
next(reader) # skip headers
points = [(r[4], r[5]) for r in reader]
longs, lats = list(zip(*(map(float, point) for point in points)))
num_plots = int(max(longs) // wrap) + 1
plot_datas = [[] for _ in range(num_plots)]
for lon, lat in zip(longs, lats):
plot_datas[int(lon//wrap)].append(((lon % wrap), lat))
fig, axes = plt.subplots(1, num_plots, figsize=(10 * num_plots, 6))
if num_plots == 1:
axes = [axes] # Ensure axes is always a list if only one segment
for i, points in enumerate(plot_datas):
ax = axes[i]
segment_lons, segment_lats = zip(*points)
m = Basemap(projection='cyl', llcrnrlat=-60, urcrnrlat=80,
llcrnrlon=0, urcrnrlon=wrap, resolution='l', ax=ax)
x, y = m(segment_lons, segment_lats)
m.plot(x, y, 'o-', markersize=2, color="blue")
ax.set_frame_on(False) # Remove border
# Remove space between subplots
plt.subplots_adjust(left=0, right=1, top=1, bottom=0, wspace=0, hspace=0)
plt.tight_layout()
plt.show()
It generates:
I’m using a wrap of 720, but it’s adjustable. There are some small gaps where the plot switches to a different chart:
But it’s good enough to get the point.
Silver Solve
I’ll enter this password, “DroneDataAnalystExpertMedal”, into the admin panel access form, and it solves the challenge for silver.
Chimney is pleased, but needs more:
Chimney Scissorsticks
Bravo! You’ve tackled the drone challenge and navigated through those KML files like a true expert. Your skills are just what we need to prevent the big snowball battle—the North Pole thanks you!
Well done! You cracked the code from the drones and showed you’ve mastered the basics of KML files. This kind of expertise will be invaluable as we gear up for what’s ahead!
But I need you to dig deeper. Make sure you’re checking those file structures carefully, and remember—rumor has it there is some injection flaw that might just give you the upper hand. Keep your eyes sharp!
The injection flaw is interesting! On originally solving this challenge, I found the SQL injections before finding creds with either fritjolf-Path.kml
or ELF-HAWK-dump.csv
. In fact, it was only while helping someone on the Discord after that I learned about the name ELF-HAWK in the Australia features! Still, this is the path the creators had in mind!
SQL Injection
UNION POC
In addition to the login form there’s an SQL injection in the drone search.
It’s showing all four of the drones!
I’ll try to get a UNION injection and see how many columns the current table has. Sending ' union select 1;-- -
and ' union select 1,2;-- -
returns nothing (the results don’t even update, likely due to a crash). In dev tools, I can see it’s returning 500:
But ' union select 1,2,3;-- -
works!
DB Type
To check for the database type, I’ll try to get the version. Trying @@version
and version()
both return 500 errors. But sqlite_version()
works:
So it’s using SQLite on the backend.
DB Enumeration
I am limited to 50 characters of input, but that’s enough to get all I need from the DB. ' union select sql,2,3 from sqlite_schema;-- -
will show the schema for each table in the database:
I can get the contents of each table pretty easily. I can get all three fields from the drones table at once, but the name is all that’s interesting (' union select name,quantity,'x' from drones;-- -
):
I’ll dump the users with ' union select username,password,1 from users;-- -
:
and ' union select username,bio,1 from users;-- -
:
I’ll get the drone comments with ' union select 1,id,comment from drone_comments;-- -
:
There’s a bunch of information here to dig into:
- According to the drone comments, there’s an activation code hidden in the file
/files/secret/ELF-HAWK-dump.csv
. - Another drone comment mentions the activation code in the data and talks about LONG time and LATTER, suggesting to look into the lat/lon data.
- Another drone comment mentions something about “TRUE carvers” that feels like a hint.
- There’s a list of seven users with hashes that look like MD5.
- The user bio didn’t come back fully via the SQLI (I don’t see the second line of fritjolf’s profile in the injection response).
Gold Solve
There’s a nagging hint from the drone comments:
This is a clue to focus on the TRUE and FALSE values. I’ve only got one sheet with a large data set, ELF-HAWK-dump.csv
. My initial thought is to filter on some binary column, but the problem is, there’s 58 of them (here I use head
and tail
to get the second line because the first is the headers, and then replace comma with newline, and grep
for “TRUE” and “FALSE”, and count the reminaing lines):
oxdf@hacky$ cat ELF-HAWK-dump.csv | head -2 | tail -1 | tr ',' '\n' | grep -e TRUE -e FALSE | wc -l
58
I could try each of them, but that seems…excessive.
Another approach is to look at those TRUE and FALSE as 1s and 0s. I’m going to do the following with the file with bash
:
- Get all the TRUE and FALSE using
grep -o -e TRUE -e FALSE
.-o
says to only return the match, not the entire line, one per line.-e
is used to set multiple things to match one. - Replace TRUE with 1 and FALSE with 0 using
sed
. - Delete all the newlines using
tr
. - Convert from binary to ASCII using
perl
from here.
Putting that together prints out ASCII art:
oxdf@hacky$ cat ELF-HAWK-dump.csv | grep -o -e TRUE -e FALSE | sed 's/TRUE/1/; s/FALSE/0/' | tr -d '\n' | perl -lpe '$_=pack"B*",$_'
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*::::::::::::::::::
:::::::::::::::::::::::::::::::-------------=--------::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::------------------------===-=======--=-::::::::::-:::::::::::::::::
::::::::::::::::::::------------:------------=-====================---:::::::::=+::::::::
:::::::::::::::::------------------------------=====================-------::::::::::::::
::::::::::::::-------------------------------------================:------:::::::::::::::
::::::::::::--------------------------------------==============-::--------:::::::::-::::
::::::::::::-------:--------@+:::::::::--=@--------:===========-::-::----==---:::::::::::
::::-------:::::----------@---::::::---+-==+@--------=========-:--:------=====---::::::::
::::--------::::::-------#--------------=-+@------------===------::-----====--==---::::::
::::-------:-:::::::------@=@=++#+++++@@@@@=-----------------:::--------------==---::::::
::::----------::::=-#-:----**%@+++++++%@@=::::::---%@------:--------:--@-+::-------::::::
::::-----:----:::::::::::--::@@**%@--::::::::::::::--=+@------------@--:::::------@::::::
::::---+@::::::---+@:::::::::#@-@--:::::-:=*=-::-----=+*=*=--------@:--:::::::-----=:::::
::::@-:::-::::::-----=@:-:::@+@%---------------==-==+@@@@@=@------@---------:::::--==+%::
:::#:::::::::::-----=+*@:::%#@#-=---------===++*%@@+@=+*#-+*=@-----#====-----------**-%::
::@--::-:::--:---==++*@-:@=+@=+-@=*+++++++**@#%*@-##**-@##%=#%@@@@#*@###@=+**@*****@@@:::
:::@*=--++++++++**@@@@@@*#@-+%@*=*+****@@@+@***@%@@%%%@-%@*@@@@@@@@@@@@@@%%#%%%@@@@@%::::
:::@@@@@@@++#*####@@@@@@@==---====+##@*%=+@*@*%%@@@@@@@@@@@@@@@=--@+@@@@+@@@@@@@@@@-:::::
::::=*%%%%%%%%%%%@@%@@#@-#*+++++====@-++###@%@*@@@@+@@@@-**+--::::--@@%@%%@%%%%%@@@-:::::
::::---@@@@##@@@@@@@@@--+@%-#+#**+=+++**%@@@@@@@##%**%--:::::::--*----=*@@@@@@@*@@---::::
::::---@@***%%%%@@@@*@-=-+=@#=#%##***##@@@@@#@@*@%%==---:::::::::::----=+---------=--::::
::::----@+=%#@@@=@@-----##@+:-=%@@%##%@@@@@@@@@@@@*+=-----::::::::::::=+*-@:----===--::::
::::---------------------*@##=+@@%@==-+@@@@@@@@@@@-+=---------------===+**--=======-:::::
:::---------------:------%+#%@@@@@#%%%%@@@@#@@@@@@@-+======---------==***#@========-:::::
:::-%-%---------:---------*-*##%@@@@@@@@@@@@@@@@@--=@@-*===++++++++++***@*===++++++=-::::
:::--+---------=-------:-----#==#@%%%@@@@@*@%@@@----@+@@@=***@@@@***@@@@%===++++-++=-::::
:::--------------:::::--------------##-----@@--------@%@#@@%%%%@@@@@@#@=====+++++++=-::::
:::---------------::::::---------------------=====---@@##@@@@@@@@@@@#%#-=====+++++--:::::
:::---======-------------------------=----==========--*=@@%@++*@@%%%@@-======:----==-::::
:::---===============------------------===============-----#@@@@@-----===-::---=====-::::
:::--=============+===--------------===-==================--------======::----=======-:::
:::--================---::::-=======-======================+=====+====::------===+===-:::
:::--===================--:::::====================+====-:---==+++=::-----=======---=-:::
:::--========:===========------:=====================:::-----====:-----==========+===-:::
/ ___/ _ \| _ \| ____\ \ / / _ \| _ \| _ \ _____ ====:-----==========+===-:::
| | | | | | | | | _| \ \ /\ / / | | | |_) | | | | |_____| ====:-----==========+===-:::
| |__| |_| | |_| | |___ \ V V /| |_| | _ <| |_| | |_____| ====:-----==========+===-:::
\____\___/|____/|_____|__\_/\_/__\___/|_| \_\____/ _ _________ ______ _ ____
| ____\ \/ / _ \| ____| _ \_ _|_ _| | | | _ \| |/ / ____\ \ / / ___| / \ | _ \
| _| \ /| |_) | _| | |_) || | | | | | | | |_) | ' /| _| \ V / | / _ \ | |_) |
| |___ / \| __/| |___| _ < | | | | | |_| | _ <| . \| |___ | || |___ / ___ \| _ <
|_____/_/\_\_| __|_____|_|_\_\|_| __|_| \___/|_| \_\_|\_\_____| |_| \____/_/ \_\_| \_\
\ \ / / ____| _ \| \/ | ____| _ \ / \ | | ==========---======++++=+=--+++=-:::
\ \ / /| _| | |_) | |\/| | _| | | | |/ _ \ | | ==========---======++++=+=--+++=-:::
\ V / | |___| _ <| | | | |___| |_| / ___ \| |___ ==========---======++++=+=--+++=-:::
\_/ |_____|_| \_\_| |_|_____|____/_/ \_\_____|==========---======++++=+=--+++=-:::
::::--====+++=---++++++=+========------::::=-:---==============---======++++=+=--+++=-:::
::::--==+++++++==---+++++++++++========-----================++++==-========-++=++====-:::
:::::--====+++++-++--++++++++++=--------=-==============+++---------=====++=+++++::::::::
::::::::======+++=+++=+++++++++++++++=++++===========++++:-------=---=-=----:::::::::::::
::::::::::::::::--=-=======++=++++++++++++++============--------------:::::::::::::::::::
:::::::::::::::::::::::::::------===-==-===-==-----::-:::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Entering the codeword “EXPERTTURKEYCARVERMEDAL” into the admin panel solves gold.
Easter Eggs
Trolls
From the users
table, dumping the hashes into CrackStation breaks two of them:
I had fritjolf’s password from the original KML. But “RumbleInTheJungle” as pip’s password is new. If I log in as pip, their profile is interesting:
He’s one of the trolls that first showed up in 2021 with Jack Frost and were seen most recently at the end of 2023 escorting Jack away.
Dolphin Emulator
In both ELF-HAWK-dump.csv
and Preparations-drove-name.csv
, the RECOVER.aircraftName
is dolphin.exe
. This is likely a reference to the Dolphin Emulator, a GameCube and Wii video game emulator.
Outro
Chimney is pleased!
Chimney Scissorsticks
Absolutely fantastic! I think you found the most difficult path in, from file carving to SQL injection. Not many can do that, but you’ve shown you’re ready for anything the factions throw your way!
Alabaster got the intel:
Alabaster Snowball
Drones? They have drones!? Snowball-dropping drones!? Where is Wombley getting the resources for this tech with so few elves on his side?
What’s that? Chimney gave you this intel, and he’s become a double agent? That’s wonderful! We must be winning some of them over. Hearts and minds, that’s how we’ll triumph.
Wombley is not going to like that we have kept him at bay and prevented him from getting the Naughty-Nice List. The elves have reported that he seems to be preparing for something big.
I told Sparkle to send a distress message to Santa on NASA’s Deep Space Network. I hope he receives it and returns in time before Wombley does something drastic.
Wombley found out that someone is helping Alabaster, and doesn’t trust me:
Wombley Cube
I received intel that we may have a double agent in our ranks. Do you know who it is?
No? Hm… I’m not sure I trust you. I even think it’s likely you’re the culprit. I have my spies’ eyes on you…