I was very excited to hear about this year's SANS Holiday Hack Challenge from a coworker. These challenges are a lot of fun and always a great way to learn some new skills. I have attempted a few such challenges in the past, but this is the first time that I actually had the time and skill necessary to complete the challenge. I certainly had some help from folks in the associated IRC channel but I still learned a TON from this. Here is my journey through the challenge. Santa has been assaulted and kidnapped and now the Dosis children are on a quest to rescue Santa and unravel the sinister plot.

Part 1: A Most Curious Business Card

Based on the hint from the description of this section I decided to indeed take a "closer" look at the business card. I thought that I needed to look IN the image as in hidden data or an embedded file (or some sort of stegonography). After an hour or so of going down that path I decided this was not the right way of going about the task.

I did immediately check the Twitter and Instagram accounts listed but I though that the image itself was going to contain clues to decoding the Twitter messages, which appeared to be basically nonsense. A quick Reddit search pointed me towards looking back at the story for more details and I noticed the "Twime Machine" statement. I easily found the tool on Google and discovered that Twime Machine uses the Twitter API to retrieve a full list of past tweets. The display very quickly revealed that something was there. Zooming out on the page all the way revealed the secret message pretty clearly.

  1. What is the secret message in Santa's tweets?
    Answer to question 1: BUG BOUNTY

Looking at the Instagram account, there is one particular picture that seemed to hold some clues. Briana (my wife) even helped with this one! In the picture there is a cover page for a report on www.northpolewonderland.com, which seemed to be a good place to start. So it was off to the Oracle (there is a companion game for the challenge) to see if I was allowed to scan this server. The Oracle revealed that the site is in scope for downloading files only. Back in the Instagram picture there was a path on the computer screen to SantaGram_v4.2.zip so I checked to see if that was hosted on the website above...and sure enough it was revealing the answer to question 2:

  1. What is inside the ZIP file distributed by Santa's team?
    Answer to question 2: An Android App (.apk file)
    ZIP File

Part 2: Awesome Package Konveyance

Based on clues from two of Santa's elves, I knew that I had to use APKTool and jadx to unpack/de-compile/examine the APK. My Kali instance had APKTool already installed but it was an old version so first I had to update it to get it working. In the end though, nothing I got from APKTool helped me out so I followed the advice from the elves to either use jadx or to simply unzip the APK file.

I unzipped the file first and actually found the answer to question 4 first. I learned that the res/raw directory contains raw files for inclusion in an app and this directory also contained an .mp3 file. The hint to view "Josh Wright's presentation from Hackfest 2016" helped me to figure this out.

  1. What is the name of the audible component (audio file) in the SantaGram APK file?
    Answer to question 4: discombobulatedaudio1.mp3
    Question 4

Konveyance is spelled weird...clue? No, just a fun play on words as far as I could tell.

Continuing to follow the Elves' clues I installed jadx from the Github source and ran jadx-gui (being as this seemed like the easiest initial method). I quickly noticed that within the utility you can search for text in the code. Searching for 'username' and 'password' revealed exactly what I needed.

  1. What username and password are embedded in the APK file?
    Answer to question 3: guest:busyreindeer78

Part 3: A Fresh-Baked Holiday Pi

I followed the elves' advice and read Josh Wrights article about mounting Raspberry Pi images.
Image Mount
The result was a regular Linux file structure. I knew that I would probably need to get the shadow file and crack a few hashes. Looking at the shadow file, I immediately saw the account in question and used the elves' recommended rockyou wordlist. Cracking with John took about 5 minutes and I had my answer.

  1. What is the password for the "cranpi" account on the Cranberry Pi system?
    Answer to question 5: yummycookies
    Password Cracking

And so I was off to see what was behind all the locked doors!

Door #1: Alabaster Snowball's House

It took me a while to figure out the initial steps on this one. I immediately thought I was going to have to find a privilege escalation vulnerability to bypass the limited permissions the scratchy user had. Some hints about reading man pages for sudo got me going in the right direction using sudo -l to list available sudo commands (sudo access to strings and tcpdump via 'itchy') and finding the first portion of the passphrase was fairly straightforward. I read the whole .pcap and looked (grep'd) for keywords and headers and was able to boil it down to a specific set of packets sudo -u itchy tcpdump -r out.pcap dst port 52102 -X revealing the first part of the password "santasli".
passphrase part 1

The second half of the passphrase was pretty much known at this point but I wanted to figure out the right way to find it. I spent over an hour trying to cut the pcap (revealed a binary file was returned to the request for secondhalf.bin), decode the output from strings, and extract the binary file. This got me nowhere. Continued hints about man pages led me to the strings --encoding option. I tried this once and must of missed one of the encoding types because it did not originally work and I moved on. More hints to look at man pages made me try again and I finally found what I was looking for.

Part 2

Answer: santaslittlehelper

On to door #2

Door #2: Train

This was perhaps the easiest challenge for me so far. After connecting to the train console it is clear you are in some sort of train control program that you are unable to get out of. reading the HELP file revealed a hint where the author says 'unLESS you know something I don't'. The 'less' hint was all I needed for a quick Google search on how to execute shell commands from within less !cat Train_Console. I quickly found the actual Train_Console program file and was able to read the password right out of the first few lines. Using this password I was able to activate the train, which turns out to be a time machine. I was transported back to 1978 North Pole where the elves' puns are worse, there are a few Netwars coins and the remaining two locked doors that I do not have the password for yet.
Train Console

Door #3: Stairs

This one was also not bad. I started by searching the file structure for a few keywords like pass, password, and a few Christmas words. This didn't work, so then I started searching for specific file types and started with *.txt and immediately found what I was looking for. Getting there was a pain though as figuring out what to escape and what not to escape in the directory names was difficult. I ended up just using a splat to get there. And inside that door...another terminal :(

Door #4: Stable

This one was a Wumpus game that would give you the password if you won. Wumpus is a game where you are in a cave and have to move around and avoid falling in holes and getting eaten by the Wumpus. The game said you could cheat but I could not figure out a quick method to do this so I played the game and eventually won. Just a NetWars coin in there using the game given password WUMPUS IS MISUNDERSTOOD.

Door #5: Inside Door #3 (Santa's Office?)

Well this one was positively delightful. I was presented with the WOPR interface from War Games. I tried playing around with it but it turns out the program wanted only the exact input from the movie with proper punctuation and capitalization. Following that, I was given the key to a secret bookshelf in Santa's office. Nowhere to go in there, so I headed back to 1978 since I had unlocked all other doors AND I FOUND SANTA in his own reindeer dungeon.

War Games

  1. How did you open each terminal door and where had the villain imprisoned Santa?
    ==Answer to Question 6
    Door #1: sudo for scratchy had been configured to allow him to run strings and tcpdump as itchy (the owner of the PCAP file). Using those commands I was able to find the full password.
    Door #2: Using the built in functionality of strings I was able to execute shell commands to explore the file system and train program to find the password.
    Door #3: Using find commands and understanding escapes, hidden, and oddly named directories was key here.
    Door #4: Simply played the game here. I'm sure there was a way to cheat but I figured playing would be quicker given my knowledge level.
    Door #5: Quoted War Games verbatim and got the password quickly on this one. ==

Santa was imprisoned in the Dungeon Room (DFER) but you had to go to 1978 to get him.

Part 4: My Gosh... It's Full of Holes

This part took me a while to even get started. I had to figure out how exactly to get Android SDK and an emulator up and running so that I could analyze the SantaGram app. The new hotness is Android Studio which includes all parts (Studio, SDK, emulator) but most guides out on the internet are not yet up to date for this tool. Some diligent Googling got me where I needed to be. So I got my emulator up and running to start my testing emulator -avd nougat -debug socket -http-proxy

Exception Server

The app immediately threw an exception but since I was running everything through Burp I was able to capture the POST to ex.northpolewonderland.com/exception.php. After getting clearance from from the Oracle to attack this box, I ran an NMAP scan to see what I was dealing with. I saw open SSH and the HTTP port but I didn't have much to go on. Going back to Burp I further examined the POST and the response. The response returns a .php file with the details of the crash. From here, I figured I need to manipulate the POST request and after some playing around, found that there are two POST operations: WriteCrashDump and ReadCrashDump.

From here, I followed the Elf recommended article from Jeff McJunkin on working with PHP local file inclusion vulnerabilities. I tried a few times to get remote files from the system to no avail. Jeff's article mentioned getting the page code directly using the PHP interpreter's base64 encoding method. Using the Burp Repeater, I was able to get exactly what I needed. I decoded the base64 response and downloaded my newest Discombobulated Audio File.
Burp PHP Interpreter
File Location

Ad Server

One of the Elves' hints mention that strings.xml files are a great place to look for hidden data in APKs. Searching the smali directory that I was able to extract by unzipping the APK, I found many strings.xml files, but one in particular (res/values/strings.xml) had four additional northpolewonderland.com servers listed that I did not know about before. They were the ad server, the dungeon server, the dev server, and the analytics server. I started with the ad server. Capturing a bit of traffic in Burp, I quickly saw references to Meteor and remembered the hinted article by Tim Medin about exploiting Meteor. Using his recommended approach of using Tampermonkey, Tim's Meteor Miner script, and some basic Javascript in the Chrome console, I was able to find an interesting collection called "quotes". After working through some syntax errors for a while, I was finally able to access this collection, and sure enough, one of the quotes was a path the the next audio file.
Ad Server

Debug Server

This one was pretty fun to begin with, frustrating to figure out, and positively maddening when I found my error. I started off using the hinted video on manipulating and re-signing Android apps. Joshua Wright gave a few good places to look for interesting artifacts in apps, and sure enough, the strings.xml file revealed more than the additional app infrastructure, it also revealed the variable name where the dev URL was used <string name="debug_data_collection_url">http://dev.northpolewonderland.com/index.php</string>. Using JadX I was able to search for the string in the code and traced it back to the EditProfile.smali function and found that dev data was only sent if the debug_data_enabled value was set to true. I found this also in the strings file. After a few hours of trying to edit the IF statement in the EditProfile.smali function, I finally realized I could just change the value of the debug_data_enabled variable. Using what I learned from Joshua Wright and the previous few hours of work on the smali file, I was able to rebuild the APK, sign it, load it, and based on what I saw in the code, create a new account to trigger the debug traffic.

I captured this traffic with Wireshark and found the structure of the POST and the return data. This is where it got really frustrating, I knew I had to edit a parameter and immediately saw the "verbose":false parameter returned. Simple enough, set it to true on the post and see what happens. Nothing new so I spent hours going down a different road only to find that I had my syntax wrong, I put true in quotes and should not have. Once I finally realized this (post Christmas Eve Family Meal), I got exactly what I had expected in the first place. This one was a ton of fun on the Android App side and just frustrating on the web side.
Dev Server Audio

Analytics Server #1

A few of the other challenges taught me to keep digging in the APK and to search for terms associated with the information found in the strings.xml file. So for this one, I found the parameter for the analytics server in the strings.xml file so decided to search for some of those terms in the APK using JadX. The search VERY quickly revealed a username and password that I SWEAR I had seen before but apparently did not understand what they were for at the time. Well the time was now. Logging in with those creds got me to a landing page that had a link to an MP3, easy enough!
Analytics #1

Analytics Server #2

Out the gate, this one was by far the most frustrating, involved, and educational of all the challenges up to this point. This one took a LOT of steps and a lot of knowledge. I required hints from some other folks so thanks to dezz0 for his help. As with each host, I started this one with an NMAP scan with the -sC option per a hint from one of the elves. NMAP was nice enough to immediately reveal a hidden Git repo hosted publicly on the server. A few attempts at using git commands to clone or copy the repo did not produce anything useful. Seeing as I was able to navigate the Git file structure though, I figured wget would be a good option here. Researching the recursive wget options revealed that it only goes down 5 levels by default and there were definitely places where this file structure went deeper. Using the 'l 10 option, I made sure that I got all the files I needed wget -r -l 10 analystics.northpolewonderland.com/.git/ (that last slash is truly important I found after further testing in order to get all the files). Once I had downloaded (cloned) the repo, I started exploring the files without much success. I figured the repo had to be there for a reason so I was missing something. Finally at this point I started treating the repo as a true repo, as in finding out the status of the repo, as in git status...PAY DIRT! I found the files I was looking for. Doing git checkout *.php got me going on analysis of the analytics server by restoring all of the deleted files.
git stats

Looking through the files, I was able to find the function that created the cookie value for users. I used that logic to construct my own cookie for the administrator user who I saw referenced throughout the files. It took a while to figure out all the dependencies, but persistence was key here.

Logging in as administrator (by editing my cookie values through Burp) revealed a new page that I had access to: Edit. Now I knew that I was able to view, save, and edit queries. Some hints got me looking specifically at the code for edit.php, query.php, and view.php. I so badly wanted to find some straightforward SQL Injection but all the parameters input from the user were properly escaped. In view.php I saw that it would output a query parameter and below it, the results of said query. Edit.php when rendered in the web browser did not provide a method to update the query of a saved report just the name and description. The code to query.php revealed that when a query is saved, the parameters that are written are id, name, description, and query. Query was not an available field in the edit tool. Using Burp though, I was able to edit that parameter regardless (see first line below).
Burp query

I immediately queried the audio table because the code for that PHP was interesting and revealed that it would only provide audio files to a guest. With the query above I discovered the file that I needed but could not immediately access it due to the logic in the getaudio file.
Audio Table

I spent about a full day and a half trying to find a way to get around the logic using different queries and trying to get PHP injected to mimic the internal logic of getaudio.php to no avail. I knew I had to somehow access the file that was loaded in the database but could not find a way to do it. Finally, the pivotal moment, "everyone is doing the same thing I am, why don't I query the full 'reports' table and see what other queries people have been submitting." And that was the nail in the coffin, I found exactly what I was looking for, a query that forced the database to print the mp3 file as a base64 encoded string SELECT TO_BASE64(mp3) FROM audio where ``username``='administrator'. I was able to grab this, decode it, and write it to a playable audio file base64 -d discombobulatedaudio7.b64 > discombobulatedaudio7.mp3. Whew! What a challenge that one was.

Dungeon Server

I already had the offline version of the Dungeon game from one of the Elves so I had been poking around with that but had not done much dedicated analysis. Running strings on the game executable revealed some commands that looked like they were some sort of control commands. Using that as a guide, I was able to find a great online run-down of Zork and how to use these commands to get what I wanted/needed Zork Walkthrough
Dungeon Strings

Using these commands, I was able to get to the end of the game, figure out what the Elf wanted in return for a secret (Gold Card), and get the clue. But in the offline version, the clue was simply to play the online version.

Based on an NMAP scan I had initially done against the Dungeon server, I saw an open Port 11111 and the NMAP data that came back looked like a banner grab that included words like Dungeon. I tried Telneting to the port and sure enough, the Dungeon game was being hosted on port 11111. But I was unable to do anything with the game, every command was answered with "I don't understand that." Finally I got the hint from PantsFantastico that Telnet would probably not work, so I tried NetCat and was immediately able to complete my quest (after a full day of trying Telnet). The GDT commands worked as expected and this time, the Elf gave me a better clue.
Elf Clue

After emailing Peppermint, I had all the audio files and was off to figure out their hidden message.

  1. For each of those six items, which vulnerabilities did you discover and exploit?
    ==Answer to Question #7
  • Mobile Analytics Server (with creds): Found creds in the APK, able to login as guest.
  • Dungeon Game: Used GDT commands to go straight to end of game. Online version was revealed with nmap scan.
  • Debug Server: Had to edit and repackage the APK to send debug data, then modify that traffic to return verbose data, which listed the audio file.
  • Banner Ad Server: Looking at the page source, I saw that it was using Meteor. Used MeteorMiner to find the audio file.
  • Uncaught Exception Handler Server: Used PHP local file inclusion to return the actual page PHP source by modifying the JSON data being send in the POST.
  • Mobile Analytics Server (post authentication): Able to edit the saved queries using the Edit page, then used the View page to view the results of the query. Page source form Git repo revealed the audio table. Also able to view all other queries for hints on how to actually get the audio. ==
  1. What are the names of the audio files you discovered from each system above?
    Answer to question 8

Part 5: Discombobulated Audio

Not much to say here other than a few hours playing around with the audio in Audacity. For a while I thought it was a song, then I thought it was some other random words, and finally, I got it. I started typing the words I could fully understand into Google and ended up with a Dr. Who quote: "Father Christmas, Santa Claus. Or, as I've always known him, Jeff." For the password to the last door I tried Jeff, different variations on Dr. Who, and finally the full phrase.

The villain was Dr. Who all along. And he would have succeeded if it hadn't been for us silly kids.

  1. Who is the villain behind the nefarious plot.
    Answer to question 9: Dr. Who

  2. Why had the villain abducted Santa?
    Answer to question 10: He thought he could use Santa's maigc to stop the 1978 Star Wars Christmas Special from ever happening and dooming the world to it's existence.

This was a ton of fun. Thanks to the SANS team for putting this on.