SANS Holiday Hacking Challenge

Kringlecon 2018

Mon, 14 Jan 2019


There are alot of reasons to look forward to the holiday season and the annual SANS Holiday Hacking Challenge is no exception. This year they went with a conference theme, where you sign into a virtual world and attend Kringlecon — a mythical conference hosted by santa and his crack team of information security elves. SANS makes things very approachable by giving you smaller terminal challenges to solve in exchange for hints regarding the bigger objectives. This is my writeup on 2018 SANSHHC, aka Kringlecon.


On a personal note, this year was my favorite SANSHHC yet, the variety of challenges and exposure to unfamiliar (to me) technologies was phenomenal. The ASCII art was also a great treat, I was always excited to solve the terminal challenges and see what came out. Hopefully you’re able to take something away from this and use it in your next CTF.

Table of Challenges

We got a little bit of everything with this years SANS Holiday Hacking Challenge, so heres an overview incase there is anything in particular you want to check out.

Title Gist (Objective) Difficulty
1. Essential Editor Skills / Orientation Challenge Vim/HTML 1/5
2. The Name Game / Directory Browsing CMD Injection/ Dir traversal 1/5
3. Lethal ForenseicELFication / De Brujin Sequences Trufflehog / de Brujin Sequence 1/5
4. Stall Mucking Report / Data Repo analysis SMB / Trufflehog 2/5
5. CURLing Master / AD Privelege Discovery cURL / Bloodhound 3/5
6. Yule Log Analysis / Badge Manipulation Windows evtx / SQL injection 3/5
7. Dev Ops Fail / HR Incident Response git / CSV Injection 4/5
8. Python Escape from LA / Network Traffic Forensics Python / Wireshark 4/5
9. Sleighbell Lottery / Ransomware Recovery gdb / Snort / Malware analysis 5/5
10. Santas Vault / Who did it? Music / Story 1/5

Challenge 1

Terminal Challenge 1 : Essential Editor Skills

The first elf we come across, Bushy Evergreen, is next to a terminal that is stuck in VIM and needs our help to get out.


It feels every other time I bring up VIM… someone says they can never figure out how to exit it.

This is an age old debate, so I’ll just say I love VIM, and I’d definitely recommend learning it.

Being able to use a terminal editor effectively is great when you’re dealing with remote Nix systems.

Escape -> :q!

No Editor

Objective 1 : Orientation Challenge

The first objective was a quiz with some SANSHHC history, having done the past two, this wasn’t too bad at all.


Challenge 2

Terminal Challenge 2 : The Name Game

To solve this challenge, determine the new worker’s first name and submit to runtoanswer.

Name Game

The elf dropped a hint relating to command injection and SQLite, from there the path was clear.

In this case the ampersand allowed us to append an additional command spilling the DB and info we wneeded for the solve.

Objective 2 : Directory Browsing

Who submitted (First Last) the rejected talk titled Data Loss for Rainbow Teams: A Path in the Darkness ?

This objective has you go to a Call For Papers site, with the name of the challenge being Directory Browsing I had all I needed upfront.

CFP Site

Immediately going to the website it was sparse and attention was immediately drawn to the URL.

Alright so what if we try to strip the end off?

CFP Directory

That rejected_talks.c1_solve is looking like our target, lets pop it open and use the find function real quick.

CFP Success

CFP Solve

Challenge 3

Terminal Challenge 3 : Lethal ForenseicELFication

Find the first name of the elf of whom a love poem was written. Complete this challenge by submitting that name to runtoanswer.

Alright so to get started I always like to look around the directory and see if anything catches my eye. In this case we’re immediately draw to .viminfo lets spill its contents and see what that’s all about.


We can see Elinore is a name prominently featured here, as if someone removed it from their poem, thus that is our answer.


Objective 3: de brujin sequences

The room is protected by a door passcode. Upon entering the correct passcode, what message is presented to the speaker?

We’re presented with a door sporting a pin made up of a combination containing 4 shapes.


I was fortunate, while clicking around I luckily guessed it, but how do we do this proper?


Well, opening Chromes developer tools -> network tab we can see where the request is being made to validate the pin, from there we can just use some quick pythons to automate some brute forcing action. To be incredibly precise you could read about de brujin sequences and adjust your script accordingly.

import requests
from itertools import product

a = [0, 1, 2, 3]
possible_pins = list(product(a, repeat=4))

for pin in possible_pins:

	attempt = ''
	for thing in pin:
		attempt = attempt + str(thing)

	if 'true' in resp.text:
		print('Found pin {0}'.format(attempt))


Challenge 4

Terminal Challenge 4 : Stall Mucking Report

Complete this challenge by uploading the elf’s report.txt file to the samba share at //localhost/report-upload/

Alright so this challenge references samba, and the only thing on the directory is report.txt.

We can use ps aux to check for running processes, looking for something samba.

PS Aux

From there we can see a line with the name manager, and that looks to be of interest, lets use grep to narrow our results.

We can see the password used and then craft our own command to upload the report using the same.


Objective 4 : Data Repo Analysis

Retrieve the encrypted ZIP file from the North Pole Git repository. What is the password to open this file?

Did you say git repository? Well git tends to retain everything through versioning, which is great… unless you accidentally committed some sort of secret.

Then we can use a tool called Trufflehog to find it. I thoroughly recommend implementing Trufflehog as part of your CI/CD process to help spot accidental secret commits early.

So all we need to do is pull the repository and point Trufflehog at it.


C4 Solve

Challenge 5

Terminal Challenge 5: CURLing Master

Complete this challenge by submitting the right HTTP request to the server at http://localhost:8080/ to get the candy striper started again.

Alright, following that statement they say to checkout /etc/nginx/nginx.conf, if we cat it and take a look… we see a comment helping us narrow down whats important here.

CURL Master Hint

HTTP2 is different, so a quick consult to our CURL documentation gives us a flag to throw in.


After that the output tells us to add a POST and have status=on, no problem just throw it on the end of our CURL command and voila.

Striper Solve

Objective 5 : AD Privelege Discovery

Using the data set contained in this SANS Slingshot Linux image, find a reliable path from a Kerberoastable user to the Domain Admins group. What’s the user’s logon name?

Alright, so if we throw the image into virtualbox and fire up bloodhound the data is already preloaded.

From there I was able to spot a filter that would give us our desired result.


This was pretty sweet, I’d never seen Bloodhound before but being able to visualize all these AD relations was great. Then being able to create attack paths off it sounds even more awesome.

C5 Solve

Challenge 6

Terminal Challenge 6 : Yule Log Analysis

Submit the compromised webmail username to runtoanswer to complete this challenge.

This challenge has a .evtx logfile and a Python script to convert it to something you can grep.

Windows event logs are pretty straight forward and well documented, you can see the standard structure below.


I used targetusername as a filter to narrow results down, then looked at various users until I could identify which was compromised via the log.

Coming back to do this writeup I noticed I didnt take a picture of the exact event that tipped me off. Whoops.

Log solve

Objective 6 : Badge Manipulation

Bypass the authentication mechanism associated with the room near Pepper Minstix. A sample employee badge is available. What is the access control number revealed by the door authentication panel?

Immediately two things become clear.

  1. This is going to be a SQL Injection Challenge
  2. Based on that badge I’m going to have to load it into a QR code.

I’m by no means a SQLi ninja, I just know enough to be dangerous. So lets stick an apostrophe in a QR code and see what happens.

c6 error

{"data":"EXCEPTION AT (LINE 96 \"user_info = query(\"SELECT first_name,last_name,enabled FROM employees WHERE authorized = 1 AND uid = '{}' LIMIT 1\".format(uid))\"): (1064, u\"You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '''' LIMIT 1' at line 1\")","request":false}

From this I understand that we’re injecting our payload into uid, and the DB flavor is MariaDB.

After trying many payloads and trying to think through the backend logic, I felt like I was at an impasse.

I reached out to a DBA friend of mine, JB for some SQL knowledge and he helped me understand what I was missing here.

Before I go ahead show the final payload lets talk about something else I missed here, the added relevance of the employee badge.

If we give the door our employee badge, we get this message {"data":"Authorized User Account Has Been Disabled!","request":false}

They keyword here being disabled. Now proceeding onward, what does our SQLi payload look like?


I really wanted to understand why this was the answer as opposed to something like or '1='1';--.

The logic:

  1. Assuming our SQL roughly evaluates to SELECT first_name,last_name,enabled FROM employees WHERE authorized = 1 AND uid = 'a' or enabled = 1 and ''=' LIMIT 1
  2. dont worry about uid, if we were supposed to manipulate that, then Alabaster Snowball’s QR code would’ve had a UID to look at
  3. so we add the subquery in to bypass the logic, SQLs ordering will execute that first which will cause the conditional to evaluate as true
  4. this allows us to get results back from the query
  5. the limit 1 on the end however means that we only get the first result, and the first results account is disabled
  6. adding enabled=1 allows us to return a result with a passing account

C6 Granted

C6 Solve

Challenge 7

Terminal Challenge 7 : Dev Ops Fail

This one is succinct, and similar to the Trufflehog challenge being git is the culprit. Except this time we get no Trufflehog, what do we do??

We use Git. git help -> git log (Identify commit to examine) -> git diff _commit_


TC7 ii

TC7 iii

TC7 iv

Objective 7 : HR Incident Response

Santa uses an Elf Resources website to look for talented information security professionals. Gain access to the website and fetch the document C:\candidate_evaluation.docx. Which terrorist organization is secretly supported by the job applicant whose name begins with “K”?

Web challenges are always fun and the hints all point to this one being a csv injection. Looking at the site we see a nice form with a file upload.

O7 Site

At this point Im not sure what my csv injection should be, so I try my favorite approach — poking around the site and seeing what I find


Oh alright, armed with this fresh knowledge lets make a super simple payload.csv

O7 i

Submitting this triggers a file download of the aforementioned candidate_evaluation.docx.

O7 ii

O7 iii

Challenge 8

Terminal Challenge 8 : Python Escape from LA

To complete this challenge, escape Python and run ./i_escaped

This one has an accompanying talk so I watched that to learn how to get this one done.

Escaping Python Shells

Py Esc

In the talk he was implementing a black list on the python shell and demonstrating creative ways to circumvent it.

I like Python so I thought Id try some other creative ways to get around it.

The first thing that came to mind was base64 encoding for a filter bypass


Next someone had mentioned I should look up the globals function in the Python standard library. If its not blacklisted then we can use it to overwrite the global variable containing the blacklisted function names.


Looks line restricted terms is what we want to overwrite, lets give it a go.

Globals exec

Objective 8 : Network Traffic Forensics

Santa has introduced a web-based packet capture and analysis tool to support the elves and their information security work. Using the system, access and decrypt HTTP/2 network activity. What is the name of the song described in the document sent from Holly Evergreen to Alabaster Snowball?

Armed with my new found knowledge of HTTP/2 from the CURL master challenge, and the hints from the Python Escape I was feeling ready to tackle this one.

I also don’t do alot with Wireshark so I’m excited to get some more time in using it.

Well heres the site. When you sign in and poke around it has a nice UI, but that’s not what we’re here for. It gives us our PCAP file but its encrypted.

C8 Site

So what do we do? Directory traversal is easy, lets start there. The app is snappy so we’ll look for something associated with those kinds of web frameworks.

C8 Error

Boy do I love a good error message. A quick Google and it looks like we’re working with NPM/Node.

A comment line in the HTML of the site mentions rushing into production and accidentally including dev code…

C8 App

Look at that, the source code! Not to mention, if our goal is to decrypt then seeing server.key is looking promising.

…But its not, its a red herring. They’re trying to draw our eyes away. If we look above the variables dev_mode and key_log_path start to look interested. Dev mode is set to true (Because its dev code remember? How fortunate.), so that means we can reach it. Lets throw SSLKEYLOGFILE onto the end of our URL.


Another error message… but at least we can clearly see the next breadcrumb. Some more mild fiddling around with the URL and we finally get.


Sweet, the key! Now we can download it, and feed it to Wireshark to decrypt our HTTP/2 traffic. The SANS videos accompanying Kringlecon helped me understand more about Wireshark and its filters, making this much easier.


Well I don’t see any indication of an attachment in this PCAP, but finding some credentials gives me a new direction. What if we try to log into Alabaster Snowballs account using them?

Logged in

I was wondering why have us login, and I thought some of the text on that login screen was phrased interestingly.

Moving on, from here we can download the PCAP, open it, and see it’s not encrypted. Not only that, but it’s easy to scroll through and see where the email begins as a Follow TCP Stream. So if we just right click Follow Stream we’re rewarded with this.


Look, Base64! We can wrangle that with a few lines of Python to dump it out into a file. Opening the file I see the word PDF, so I immediately close it, save it as .pdf and reopen it.

Decoded Stream

Seeing the PDF open with nothing wrong was pretty awesome, I’d never pulled an attachment out of Wireshark like this before.

C8 Solve

Challenge 9

Terminal Challenge 9 : Sleigh Bell Lottery

Complete this challenge by winning the sleighbell lottery for Shinny Upatree.

Descriptive right? Theres a little lottery binary, objdump, and GDB in the directory, chances are we need to call a function.

Most of the terminal challenge have been simple so far, so lets treat this one the same way.

First we’ll use objdump to look at the functions in the binary and see if any jump out at us.


It does get much more apparent than that, so how do we call it?

Since we were provided with GDB we can just place a breakpoint at main then jump to the winwinwin function.


Pretty straight forward, a great introductary challenge for GDB if you’re not familiar with it already.

Sadly this is the last piece of ASCII art, I thoroughly enjoyed them all and could’ve easily spent a whole post admiring the art they put into this.


Obective 9

For me Challenge 9 was a doozy, both for introducing me to new concepts, and challenging my understanding of existing ones.

Obective 9.1 : Catch the Malware

Assist Alabaster by building a Snort filter to identify the malware plaguing Santa’s Castle.

They provide us a snort terminal to input our answer onto, and some PCAPs with traffic to analyze. More Wireshark action!


Immediately we notice quite a few things going on here.

  1. They DNS queries with malicious traffic all have hex strings at the start
  2. The DNS names are dynamic
  3. The content size of the packets containing the malicious code is apparent
  4. Decoding the malicious packets TXT segment shows us the malware transmitting its source


Neat but we cant block based on the hex body, or the packet size, or the DNS names because then we may shun legit traffic.

So what does that leave? Upon closer inspection you’ll notice that all the DNS names begin with that same hex string, we can use that!

I’ve not done anything with Snort outside of studying for cert exams so writing a rule was new to me. After reading a few sites it became apparent that we would need to use Content as our blocker, and a kind person recommended I convert the hex string to bytes for this.

After doing that we windup with the following rule.




I’ve been alternating between turning the answers ingame, and on that static site you see, when we give it the terminal output from the above it gives us the Word document for the next challenge.


Obective 9.2 : Identify the Domain

Using the Word docm file, identify the domain name that the malware communicates with.

Analyzing Powershell Malware

Using the awesome Kringlecon talk on Powershell Malware analysis we have our base of knowledge to work through this.

Lets get started, first thing we need to do is extract the Macro from the Doc that is calling the powershell code that has the virus.


There’s our Macro alright but its heavily obfuscated, if we just drop the iex() function from the code we can pipe the deobfuscated string to standard output.


Well that URL certainly looks like it could be the domain the malware communicates with, lets try that out.


Obective 9.3 : Stop the Malware

Identify a way to stop the malware in its tracks!

Wannacookie is a clear name play on that nasty wannacry malware, so we know theres a killswitch involved!

If we slightly modify the dropper code by removing things like iex() and then execute it, it’ll reward us with the source.


Sweet we have source code now! Sadly its a single line, so from here I had to drop it into Powershell ISE and prettify it back into something human readable.

After we do that, we have alot of type conversion functions, some encryption functions, and a main function called wanc.

The first line of wanc has an interesting string that it attempts to resolve on the next line in a conditional, a prime suspect for our killswitch domain.

What we’ll wanna do is set a breakpoint on the following line then manually run that string through its decoder functions so we can examine the output.

Found the domain

They provide us a fun little ‘Ho-Ho Daddy’ domain registrar, so lets go try our string there.


Slightly different from the Powershell reversing video, but obvious enough to get us moving forward.

Objective 9.4 : Recover Alabaster’s Password

Recover Alabaster’s password as found in the the encrypted password vault.

This challenge was ranked the hardest and rightfully so, you need a firm grasp on the concepts of encryption to tackle this one.

We can see by analyzing the functions in the Malware that they are implementing asymmetric encrpytion.

What is asymmetric encryption?

The two actions we want to hone in on are:

  • Create a private key for just that user, this would be the unique one the malware authors give upon payment.
  • Encrypt the private key using the private key from their C&C server

We’ll want to do the opposite. We already have our source code from 9.3, what does 9.4 give us?

This challenge supplies us with a memory dump of the program and an encrypted DB — alabasters-passwords.elfdb.wannacookie .

The memory dump is relevant becuse the private key is generated with random bytes, so we’ll need to fish the exact key used out of the dump using Power dump

In order to narrow the search critera out of all the 11000 variables, I put a break point in the malware and just grabbed the length of p_k_e_k, the encrypted private key that was used to encrypt the elfdb.


Sweet, now lets run a length match in Power dump against the powershell memory dump.


We’re lucky to have gotten one result back, this makes things much easier for us.


Alright, so now we have the solution, but its unusable since it’s encrypted. We’ll need to get the asymmetric encryption pieces in order to decrypt it.

Immediately one thing stands out, we have to change our computers WORKGROUP to KringleCastle or the program wont continue to execute.

Moving past that, I noticed another hex string a function called godns() containing a hex string. Decoded the string evaluates to server.crt.

A quick breakpoint, a function call… and we’re rewarded with our server.crt, the first half of the asymmetric pair.


Awesome, now all we need is a private key. Maybe the attackers didn’t secure their infrastructure and we can leak the private key the same way, just with a hex encoded string containing a value of server.key.

Private key

With both pieces of the puzzle, now comes the hard part. We need to combine them together into a certificate, and then import the certificate and use it to decrypt the p_k_e_k to then decrypt the database.

Fortunately a fellow with kringlecon attendee with the handle marlas linked me these two pages which helped me get everything assembled together. I’ve worked with certificates on Linux systems but on Windows in Powershell this is new territory.

How to create a PFX Certificate

Using a PFX Certificate in powershell

I lined out what I felt was a good decryption function. I made a slight mistake when I copy pasted the script, so for a while I was spinning in circles. I didn’t notice a syntax error I made earlier since the function e_d_file hadn’t been called until now.

function p_k_d($pkek){
    $PFXPath = 'C:\Users\user\power_dump\cert.pfx'
    $PFWPassword = 'lol'
    $PFX = New-Object -TypeName 'System.Security.Cryptography.X509Certificates.X509Certificate2Collection';
    $PFX.Import($PFXPath, $PFWPassword, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet);
    $cert_bytes = $(H2B $pkek)
    $decKey = $PFX.PrivateKey.Decrypt($cert_bytes, $true);
    return $decKey

function eat_cookies{
    $pkek = '3cf903522e1a3966805b50e7f7dd51dc7969c73cfb1663a75a56ebf4aa4a1849d1949005437dc44b8464dca05680d531b7a971672d87b24b7a6d672d1d811e6c34f42b2f8d7f2b43aab698b537d2df2f401c2a09fbe24c5833d2c5861139c4b4d3147abb55e671d0cac709d1cfe86860b6417bf019789950d0bf8d83218a56e69309a2bb17dcede7abfffd065ee0491b379be44029ca4321e60407d44e6e381691dae5e551cb2354727ac257d977722188a946c75a295e714b668109d75c00100b94861678ea16f8b79b756e45776d29268af1720bc49995217d814ffd1e4b6edce9ee57976f9ab398f9a8479cf911d7d47681a77152563906a2c29c6d12f971'
    $dec_key = (p_k_d($pkek));
    $DBFile = 'C:\Users\user\power_dump\alabaster_passwords.elfdb.wannacookie'
    (e_d_file $dec_key, $DBFile, $false);

The extension is .elfdb and not knowing any elves, I opted to open it in N++ because I am not sure what else to use..

Decypted Elfdb

Oh, thats what else Im going to open it with, SQLite.

DB Clean

Fortunately they didnt fill this with alot of data and we have our answer immediately.


Challenge10 : Santa’s Vault

That password looks alot like musical notes… and there’s a piano on the wall.


Not only that, but the PDF we got from the TCP Stream earlier mentioned the key of D.

Lets throw this all together in an online music transposer, and I’m not sure what key to start with so we’ll use the default of E.


E was the right key to start with! With that, we’ve completed all the challenges we need to finish Kringlecon.


Objective 10 : Who did it?

Who was the mastermind behind the whole KringleCon plan?


Santa reveals he did this all for us.

I actually answered this one before I found got through the piano door, I gave it a guess. Trying “Santa” as a guess kind of felt like trying “password” but it worked! My second lucky guess in this writeup.


This was the first SANS Holiday Hacking Challenge I’ve completed. It felt really great for so many technical concepts to come together in accomplihing these objectives. I learned an immense amount and had the opportunity to hone some existing skills with practice. Not to mention, that ASCII art was pretty sweet.

I get asked regularly by people how to learn or get better at InfoSec type skills.

CTFs like this SANSHHC are the place to do just that. Especially with the Holiday Hack challenge; SANS provides you so much information, challenges to pit it against, and an environment to mingle with other like minded people. Thats a solid environment to learn in as opposed to trudging through youtube videos and documentation, if you say you want to learn but don’t take advantage of these opportunities then you’re missing out. Don’t worry if you aren’t sure where to start, just jump into the CTF and see what it asks of you.

In the end it’s all just learning and practice, which was Kringlecons gift to us all along this holiday season.

Anthony Laiuppa

If you have any feedback feel free to @ me on twitter, Im always looking to learn. -AL