Blog


Kringlecon 2 Turtle Doves (2019)

Jan 14, 2020 | 55 minutes read

Tags: holidayhack, python, powershell

Welcome to my write-up of the SANS Holiday Hack 2019 aka Kringlecon 2 Turtle Doves. The holiday hack is something I look forward to every year, doubly so with the new online convention format they’ve adopted. This year was focused primarily on the defensive side of the house, which is outside the norm for me. That being said, I strongly suspect there are cleaner/cleverer ways of performing some of these tasks (Splunk comes to mind), but below outlines how I was able to solve each terminal challenge and badge objective. Let’s jump in!


Terminal Challenges

Escape ed Challenge

The Escape ed Challenge can be found in the Train Station beside Bushy Evergreen.

Helpful Resources

Actually Using ed

Bushy Evergreen - Initial

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.

Problem

To complete this challenge, we need to exit the ed editor.

                  ........................................
               .;oooooooooooool;,,,,,,,,:loooooooooooooll:
             .:oooooooooooooc;,,,,,,,,:ooooooooooooollooo:
           .';;;;;;;;;;;;;;,''''''''';;;;;;;;;;;;;,;ooooo:
         .''''''''''''''''''''''''''''''''''''''''';ooooo:
       ;oooooooooooool;''''''',:loooooooooooolc;',,;ooooo:
    .:oooooooooooooc;',,,,,,,:ooooooooooooolccoc,,,;ooooo:
  .cooooooooooooo:,''''''',:ooooooooooooolcloooc,,,;ooooo,
  coooooooooooooo,,,,,,,,,;ooooooooooooooloooooc,,,;ooo,
  coooooooooooooo,,,,,,,,,;ooooooooooooooloooooc,,,;l'
  coooooooooooooo,,,,,,,,,;ooooooooooooooloooooc,,..
  coooooooooooooo,,,,,,,,,;ooooooooooooooloooooc.
  coooooooooooooo,,,,,,,,,;ooooooooooooooloooo:.
  coooooooooooooo,,,,,,,,,;ooooooooooooooloo;
  :llllllllllllll,'''''''';llllllllllllllc,


Oh, many UNIX tools grow old, but this one's showing gray.
That Pepper LOLs and rolls her eyes, sends mocking looks my way.
I need to exit, run - get out! - and celebrate the yule.
Your challenge is to help this elf escape this blasted tool.

-Bushy Evergreen

Exit ed.

1100

Solution

ed is a line editor that predates vi. Luckily exiting it is even easier than vi! Simply type q and hit enter to solve the challenge.

escape-ed

Bushy Evergreen - Solved

Wow, that was much easier than I’d thought. Maybe I don’t need a clunky GUI after all! Have you taken a look at the password spray attack artifacts? I’ll bet that DeepBlueCLI tool is helpful. You can check it out on GitHub. It was written by that Eric Conrad. He lives in Maine - not too far from here!

Frosty Keypad Challenge

The Frosty Keypad Challenge can be found in the The Quad beside Tangle Coalbox.

Helpful Resources

Python Sieve of Eratosthenes

Tangle Coalbox - Initial

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.

Problem

Given what we know from Tangle Coalbox, we can examine the keypad itself and see that the numbers 1, 3, and 7 make up the code. We can tell that we need to find a 4-digit prime number.

keypad-challenge

Solution

In order to generate prime numbers, I grabbed a sieve of eratosthenes implementation in python and added logic to filter out primes that included all of the numbers that were visibly worn on the keypad. I then filtered those to include only primes that had at least one repeating number.

 1def primes_sieve2(limit):
 2    """ https://stackoverflow.com/questions/3939660/sieve-of-eratosthenes-finding-primes-python """
 3    a = [True] * limit                          # Initialize the primality list
 4    a[0] = a[1] = False
 5
 6    for (i, isprime) in enumerate(a):
 7        if isprime:
 8            yield i
 9            for n in range(i*i, limit, i):     # Mark factors non-prime
10                a[n] = False
11
12for prime in primes_sieve2(10000):
13    prime = str(prime)
14    if '1' in prime and '3' in prime and '7' in prime:  # contains all our numbers
15        if any(prime.count(x) == 2 for x in '137'):  # one of them repeats
16            print(prime)
python3 prime-sieve.py 
══════════════════════

1373
1733
3137
3371
7331

I took the results and manually tried them since there were only 5. 7331 was the correct prime.

keypad-done

Tangle Coalbox - Solved

Yep, that’s it. Thanks for the assist, gumshoe. Hey, if you think you can help with another problem, Prof. Banas could use a hand too. Head west to the other side of the quad into Hermey Hall and find him in the Laboratory.

Graylog Challenge

The Graylog Challenge can be found in the Dorm beside Pepper Minstix.

Helpful Resources

Graylog Search Documentation

Pepper Minstix - Initial

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.

Problem

There are 10 fields in the incident response report, we need to use Graylog searches to answer all 10 questions. Upong logging in, we’re presented with the search interface.

graylog-search

Our goal is to correctly complete the incident response report.

Solution

Question 1

Minty CandyCane reported some weird activity on his computer after he clicked on a link in Firefox for a cookie recipe and downloaded a file. What is the full-path + filename of the first malicious file downloaded by Minty?

Search: minty AND _exists_:TargetFilename

Answer: C:\Users\minty\Downloads\cookie_recipe.exe

Message: https://graylog.elfu.org/messages/graylog_0/5f9c3021-1b70-11ea-b211-0242ac120005

Question 2

The malicious file downloaded and executed by Minty gave the attacker remote access to his machine. What was the ip:port the malicious file connected to first?

Search: cookie_recipe.exe AND _exists_:DestinationIp

Answer: 192.168.247.175:4444

Message: https://graylog.elfu.org/messages/graylog_0/5c93f930-1b70-11ea-b211-0242ac120005

Question 3

What was the first command executed by the attacker (answer is a single word)?

Search: I used “show surrounding messages (5 minute window)” on the answer to Question 2 and found the whoami command being run shortly after.

graylog-5-min-surround

Answer: whoami

Message: https://graylog.elfu.org/messages/graylog_0/5c969140-1b70-11ea-b211-0242ac120005

Question 4

What is the one-word service name the attacker used to escalate privileges?

Search: _exists_:CommandLine AND minty and cookie_recipe.exe

Answer: Webexservice

Message: https://graylog.elfu.org/messages/graylog_0/5d312390-1b70-11ea-b211-0242ac120005

Question 5

What is the file-path + filename of the binary ran by the attacker to dump credentials?

Search: minty AND cookie_recipe2

Answer: C:\cookie.exe

Message: https://graylog.elfu.org/messages/graylog_0/5d97d4a1-1b70-11ea-b211-0242ac120005

Question 6

The attacker pivoted to another workstation using credentials gained from Minty’s computer. Which account name was used to pivot to another machine?

Search: EventID:4624

Answer: alabaster

Question 7

What is the time ( HH:MM:SS ) the attacker makes a Remote Desktop connection to another machine?

Search: source:"elfu\-res\-wks2" AND AccountName:alabaster

Compared the logontype of all the Messages, finding an outlier

Answer: 06:04:28

Message: https://graylog.elfu.org/messages/graylog_0/6c638510-1b70-11ea-b211-0242ac120005

Question 8

The attacker navigates the file system of a third host using their Remote Desktop Connection to the second host. What is the SourceHostName,DestinationHostname,LogonType of this connection? (submit in that order as csv)

Search: EventID:4624

Answer: elfu-res-wks2,elfu-res-wks3,3

Question 9

What is the full-path + filename of the secret research document after being transferred from the third host to the second host?

Search: ParentProcessImage:C\:\\Windows\\Explorer.EXE

Answer: C:\Users\alabaster\Desktop\super_secret_elfu_research.pdf

Message: https://graylog.elfu.org/messages/graylog_0/5f9cf370-1b70-11ea-b211-0242ac120005

Question 10

What is the IPv4 address (as found in logs) the secret research document was exfiltrated to?

Search: _exists_:DestinationHostname

Answer: 104.22.3.84

Message: https://graylog.elfu.org/messages/graylog_0/5f9e04e0-1b70-11ea-b211-0242ac120005

Report Complete

incident-reported

Pepper Minstix - Solved

That’s it - hooray! Have you had any luck retrieving scraps of paper from the Elf U server? You might want to look into SQL injection techniques. OWASP is always a good resource for web attacks. For blind SQLi, I’ve heard Sqlmap is a great tool. In certain circumstances though, you need custom tamper scripts to get things going!

Smart Braces Challenge

The Smart Braces Challenge can be found in the Student Union beside Kent Tinseltooth.

Kent Tinseltooth - Initial

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.

Problem

The challenge begins with a little back and forth between Kent and his “inner voice”.

iot-motd

Upon viewing /home/elfuuser/IOTteethBraces.md, we see the following information about how the firewall should be configured.

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

If you know iptables, this challenge is pretty straightforward. I saved the policies for last just in case, but other than that, the challenge was simply to implement the given rules.

elfuuser@9abe25fa92c2:~$ sudo iptables -A INPUT -j ACCEPT -m state --state RELATED,ESTABLISHED
elfuuser@9abe25fa92c2:~$ sudo iptables -A OUTPUT -j ACCEPT -m state --state RELATED,ESTABLISHED
elfuuser@9abe25fa92c2:~$ sudo iptables -A INPUT -j ACCEPT -s 172.19.0.225 -p tcp --dport 22
elfuuser@9abe25fa92c2:~$ sudo iptables -A INPUT -j ACCEPT -s 172.19.0.225 -p tcp --dport 22
elfuuser@9abe25fa92c2:~$ sudo iptables -A INPUT -j ACCEPT -p tcp --dport 21   
elfuuser@9abe25fa92c2:~$ sudo iptables -A INPUT -j ACCEPT -p tcp --dport 80
elfuuser@9abe25fa92c2:~$ sudo iptables -A OUTPUT -j ACCEPT -p tcp --dport 80
elfuuser@9abe25fa92c2:~$ sudo iptables -A INPUT -j ACCEPT -i lo
elfuuser@9abe25fa92c2:~$ sudo iptables -P INPUT DROP          
elfuuser@9abe25fa92c2:~$ sudo iptables -P OUTPUT DROP
elfuuser@9abe25fa92c2:~$ sudo iptables -P FORWARD DROP
elfuuser@9abe25fa92c2:~$ sudo iptables -A INPUT -j ACCEPT -p tcp --dport 80

Kent TinselTooth: Great, you hardened my IOT Smart Braces firewall!

Kent Tinseltooth - Solved

Oh thank you! It’s so nice to be back in my own head again. Er, alone. By the way, have you tried to get into the crate in the Student Union? It has an interesting set of locks. There are funny rhymes, references to perspective, and odd mentions of eggs! And if you think the stuff in your browser looks strange, you should see the page source… Special tools? No, I don’t think you’ll need any extra tooling for those locks. BUT - I’m pretty sure you’ll need to use Chrome’s developer tools for that one. Or sorry, you’re a Firefox fan? Yeah, Safari’s fine too - I just have an ineffible hunger for a physical Esc key. Edge? That’s cool. Hm? No no, I was thinking of an unrelated thing. Curl fan? Right on! Just remember: the Windows one doesn’t like double quotes. Old school, huh? Oh sure - I’ve got what you need right here… … And I hear the Holiday Hack Trail game will give hints on the last screen if you complete it on Hard.

Linux Path Challenge

The Linux Path Challenge can be found in Hermey Hall beside SugarPlum Mary.

SugarPlum Mary - Initial

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:

  • Do the words in green have special significance?
  • How can I find a file with a specific name?
  • What happens if there are multiple executables with the same name in my $PATH?

Problem

SugarPlum Mary needs us to run the ls command in the home directory.

path-motd

Solution

I used type -a to find the real ls. After that, a call to the real ls’s absolute path will accomplish the task.

elf@2cc3ac9c0345:~$ type -a ls
ls is aliased to `ls --color=auto'
ls is /usr/local/bin/ls
ls is /bin/ls
elf@2cc3ac9c0345:~$ /bin/ls -al
total 52
drwxr-xr-x 1 elf  elf   4096 Dec  8 14:19 ' '
drwxr-xr-x 1 elf  elf   4096 Dec  8 14:19  .
drwxr-xr-x 1 root root  4096 Nov 21 19:46  ..
-rw-r--r-- 1 elf  elf    220 Apr 18  2019  .bash_logout
-rw-r--r-- 1 elf  elf   3596 Dec 15 23:27  .bashrc
-rw-r--r-- 1 elf  elf  13838 Nov 21 19:46  .elfscream.txt
-rw-r--r-- 1 elf  elf    807 Apr 18  2019  .profile
-rw-r--r-- 1 elf  elf    401 Nov 21 19:46  rejected-elfu-logos.txt

Loading, please wait......
You did it! Congratulations!

SugarPlum Mary - Solved

Oh there they are! Now I can delete them. Thanks! Have you tried the Sysmon and EQL challenge? If you aren’t familiar with Sysmon, Carlos Perez has some great info about it. Haven’t heard of the Event Query Language? Check out some of Ross Wolf’s work on EQL or that blog post by Josh Wright in your badge.

Mongo Pilfer Challenge

The Mongo Pilfer Challenge can be found in the NetWars room beside Holly Evergreen.

Helpful Resources

MongoDB Cheat Sheet

Holly Evergreen - Initial

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!

Problem

For this challenge, we need to find a solution inside the mongo database.

mongo-motd

Solution

We begin by connecting to the server and getting a list of the databases along with their collections.

elf@63fb671377cc:~$ mongo --port 12121
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:12121/
MongoDB server version: 3.6.3
Welcome to the MongoDB shell.
-------------8<-------------
> show dbs
admin  0.000GB
elfu   0.000GB
local  0.000GB
test   0.000GB
> use elfu
switched to db elfu
> show collections
bait
chum
line
metadata
solution
system.js
tackle
tincan

Seeing the solution collection in the elfu database, let’s exit the mongo shell to dump the information to disk.

mongodump --port 12121 --db=elfu --collection=solution --out .
2019-12-27T14:18:50.105+0000    writing elfu.solution to 
2019-12-27T14:18:50.106+0000    done dumping elfu.solution (1 document)
elf@63fb671377cc:~$ cat elfu/solution.bson
You did good! Just run the command between the stars: ** db.loadServerScripts();displaySolution(); **
elf@63fb671377cc:~$ 

Now we just need to get back into the shell to run the commands specified in the dump.

> use elfu
> db.loadServerScripts();
> displaySolution();

After running displaySolution(), we’re presented with an ascii-art tree!

mongo-complete

Holly Evergreen - Solved

Woohoo! Fantabulous! I’ll be the coolest elf in class. On a completely unrelated note, digital rights management can bring a hacking elf down. That ElfScrow one can really be a hassle. It’s a good thing Ron Bowes is giving a talk on reverse engineering! That guy knows how to rip a thing apart. It’s like he breathes opcodes!

Nyanshell Challenge

The Nyanshell Challenge can be found in the Speaker UNpreparedness Room beside Alabaster Snowball.

Alabaster Snowball - Initial

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?

Problem

nyan-motd

Our goal in this challenge is to login as the user alabaster_snowball with a bash prompt. The default shell is currently set to a nyancat animation.

nyan-shell

Solution

sudo -l shows us that we can run the chattr command as root.

elf@952a6c723edd:~$ sudo -l
Matching Defaults entries for elf on 952a6c723edd:
    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 952a6c723edd:
    (root) NOPASSWD: /usr/bin/chattr

We can also check out the default shell for our target user by inspecting /etc/passwd

elf@952a6c723edd:~$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
-------------8<-------------
alabaster_snowball:x:1001:1001::/home/alabaster_snowball:/bin/nsh

/bin/nsh is presumably the nyancat shell. We can inspect the extended attributes with lsattr.

elf@952a6c723edd:~$ lsattr /bin/nsh
----i---------e---- /bin/nsh

The i returned from lsattr means that nsh has the immutable flag set. We should also check our permisssions.

elf@952a6c723edd:~$ ls -al /bin/nsh
-rwxrwxrwx 1 root root 75680 Dec 11 17:40 /bin/nsh

So, anyone can write over the shell, if the immutable flag is removed. Let’s remove the immutable flag and then cat /bin/bash over /bin/nsh.

elf@952a6c723edd:~$ sudo /usr/bin/chattr -i /bin/nsh
elf@952a6c723edd:~$ cat /bin/bash > /bin/nsh

Finally, we can login to the target user and claim our victory.

nyan-complete

Alabaster Snowball - Solved

Who would do such a thing?? Well, it IS a good looking cat. Have you heard about the Frido Sleigh contest? There are some serious prizes up for grabs. The content is strictly for elves. Only elves can pass the CAPTEHA challenge required to enter. I heard there was a talk at KCII about using machine learning to defeat challenges like this. I don’t think anything could ever beat an elf though!

Holiday Hack Trail Challenge

The Holiday Hack Trail Challenge can be found in the Dorm beside Minty Candycane.

Helpful Resources

Web Apps: a Trailhead

Minty Candycane - Initial

Hi! I’m Minty Candycane! I just LOVE this old game! I found it on a 5 14” 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!

Problem

In this challenge, our task is to win the Holiday Hack Trail game by hacking it. The difficulty level increases the game’s difficulty along with how hard it is to hack. We’ll cover easy and hard difficulty. The only difference in going from easy to medium is that the GET parameters are moved to POST parameters. Since we’ll have to alter the POST parameters in hard, we won’t bother with medium.

hht-motd

Solution - easy

The crux of each solution is to provide an unexpected value to the distance parameter. Altering the distance will bring us to the end of the trail with all of our supplies in tow and people still alive (no dysentary!).

We begin by seleting easy as the difficulty which brings us to the Purchase Supplies page shown below.

hht-easy-purchase

After pressing the buy button, we’re brought to the game’s primary interface where we notice the distance parameter with a value of 0.

hht-easy-after-go

From here, we can simply change the value of distance from 0 to 7999 and press Enter (pressing the Go button will produce different results).

hht-easy-7999

After that, we see on the next screen that we only have a distance of 1 left to cover.

hht-easy-1

From here, we can press Go and collect our Achivement.

hht-easy-win

Solution - hard

The key differences when attempting the game on hard are

  1. The parameters are sent in the body of a POST request instead of GET
  2. There is a parameter named hash that contains a value the server uses to verify the values it receives (shown at the bottom of the image below)

hht-hard-hash

We can begin by seeing if the hash is a known value or not with hashcat. Due to the length of the hash, md5 is a likely guess for the algorithm used.

hashcat -m 0 /tmp/a /wordlists/seclists/Passwords/Leaked-Databases/rockyou.txt
══════════════════════════════════════════════════════════════════════════════

bc573864331a9e42e4511de6f678aa83:1626            
                                                 
Session..........: hashcat
Status...........: Cracked
Hash.Type........: MD5
Hash.Target......: bc573864331a9e42e4511de6f678aa83
Time.Started.....: Sat Dec 28 11:23:38 2019 (0 secs)
Time.Estimated...: Sat Dec 28 11:23:38 2019 (0 secs)
Guess.Base.......: File (/wordlists/seclists/Passwords/Leaked-Databases/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 29050.3 kH/s (3.32ms) @ Accel:1024 Loops:1 Thr:64 Vec:1
Recovered........: 1/1 (100.00%) Digests, 1/1 (100.00%) Salts
Progress.........: 1966080/14344384 (13.71%)
Rejected.........: 0/1966080 (0.00%)
Restore.Point....: 0/14344384 (0.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidates.#1....: 123456 -> bragg426
Hardware.Mon.#1..: Temp: 41c Fan:  0% Util:  3% Core:2025MHz Mem:6801MHz Bus:16

Started: Sat Dec 28 11:23:35 2019
Stopped: Sat Dec 28 11:23:39 2019

Surprisingly, the hash cracks and we see the value is 1626. We can verify this my running the command below.

echo -n 1626 | md5sum
═════════════════════

bc573864331a9e42e4511de6f678aa83  -

Now that we know the value of the hash, the next step is to determine where the value of 1626 came from. If we add up all the values in the inventory, the current month, and the current day we arrive at 1626!

  • money - 1500
  • distance - 0
  • day - 1
  • month - 9
  • reindeer - 2
  • runners - 2
  • ammo - 10
  • meds - 2
  • food - 100

If we watched the associated talk, we would see the majority of the hashing code starting at around 5:05 in the video.

In order to complete the challenge, we’ll need to change the distance value to 7999

htt-hard-distance

Then we’ll recalculate the hash

echo 1626 + 7999 | bc | tr -d '\n' | md5sum
═══════════════════════════════════════════

a330f9fecc388ce67f87b09855480ca3  -

Next, we’ll change the hash value to what we just calculated.

htt-hard-hash

Finally, we press Go and claim our hard-mode victory!

htt-hard-complete

Minty Candycane - Solved

You made it - congrats! Have you played with the key grinder in my room? Check it out! It turns out: if you have a good image of a key, you can physically copy it. Maybe you’ll see someone hopping around with a key here on campus. Sometimes you can find it in the Network tab of the browser console. Deviant has a great talk on it at this year’s Con. He even has a collection of key bitting templates for common vendors like Kwikset, Schlage, and Yale.

Xmas Cheer Laser Challenge

The Xmas Cheer Laser Challenge can be found in the Laboratory beside Sparkle Redberry.

Sparkle Redberry - Initial

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!

Problem

Our task for this one is to find all of the real laser settings sprinkled throughout a small PowerShell ctf. This was my favorite terminal challenge and in my top 3 for all of kringlecon.

laser-motd

We can view the settings that we’ll need to be on the lookout for by running the command below

(Invoke-WebRequest -Uri http://localhost:1225/).RawContent
══════════════════════════════════════════════════════════

----------------------------------------------------
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
----------------------------------------------------

We’ll need to keep an eye out for the following settings

  • refraction
  • temperature
  • angle
  • gas mixture percentages

Solution

We begin by examining the contents of callingcard.txt

Get-Content ../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 statement about hist’ry suggests that we look at the command line history.

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 com…

The seventh entry contains a GET request that specifies angle=65.5! That was quick. Let’s make a note of that value for later use. Additionally, the ninth entry is interesting, let’s expand it so we can view everything.

history -id 9 |select -ExpandProperty commandline -verbose
══════════════════════════════════════════════════════════

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.

Our last clue seems to point to environment variables, let’s take a look.

cd env:
get-childitem
═════════════

-------------8<-------------
riddle                         Squeezed and compressed I am hidden away. Expand me from …
-------------8<-------------

Once again, we need to expand the value associated with the riddle environment variable.

Get-ChildItem ./riddle | select -ExpandProperty value
═════════════════════════════════════════════════════

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.

The clue this time is pretty straightforward; we need to recursively sort the contents of /etc/ by the LastWriteTime.

Get-ChildItem -Recurse -Path /etc | sort -Property LastWriteTime 
════════════════════════════════════════════════════════════════

-------------8<-------------
Directory: /etc/apt
Mode                LastWriteTime         Length Name
----                -------------         ------ ----
--r---          12/17/19  1:08 AM        5662902 archive

We can make a scratch folder from which to work in /tmp/ then uncompress the archive there.

cd /tmp
new-item -itemtype directory -name stuff
cd stuff
expand-archive /etc/apt/archive

Let’s examine the contents of our new archive.

gci -recurse
════════════

    Directory: /tmp/stuff
Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----          12/29/19  1:16 PM                archive
    Directory: /tmp/stuff/archive
Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----          12/29/19  1:16 PM                refraction
    Directory: /tmp/stuff/archive/refraction
Mode                LastWriteTime         Length Name
----                -------------         ------ ----
------           11/7/19 11:57 AM            134 riddle
------           11/5/19  2:26 PM        5724384 runme.elf

Now, we can run the binary inside to receive our second setting (refraction?val=1.867)!

chmod +x ./runme.elf ; ./runme.elf
══════════════════════════════════
refraction?val=1.867

Finally, we check out our next clue.

gc riddle
Very shallow am I in the depths of your elf home. You can find my entity by using my md5 identity:

25520151A320B5B0D21561F92C8F6224

Based on our last clue, we’ll need to hash the files in our home directory and find the one that matches what was in the riddle.

gci -recurse -file | %{ if ((Get-FileHash -Algorithm MD5 $_.fullname).hash -eq '25520151A320B5B0D21561F92C8F6224') {$_.fullname} }
═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════

/home/elf/depths/produce/thhy5hll.txt

Now that we’ve identified the file, we can check the contents where we’ll find the setting temperature?val=-33.5!

gc /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 ill require Piping all the FullName's to Sort Length.

Another recursive search; this time we’re sorting on the length of the filename.

gci -recurse -path ./depths/ | select -ExpandProperty fullname | sort -Property Length
══════════════════════════════════════════════════════════════════════════════════════

-------------8<-------------
/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

Once found, we can check the contents of the file for our next clue.

gc /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.

Our clue now tells us that we need to kill a few processes in a specific order, and then check out what appears to be a file path. First, let’s check out the currently running processes.

Get-Process -IncludeUserName
════════════════════════════

     WS(M)   CPU(s)      Id UserName                       ProcessName
     -----   ------      -- --------                       -----------
     28.87     1.15       6 root                           CheerLaserServi
    120.02     3.82      31 elf                            elf
      3.37     0.03       1 root                           init
      0.74     0.00      24 bushy                          sleep
      0.86     0.00      26 alabaster                      sleep
      0.77     0.00      28 minty                          sleep
      0.75     0.00      29 holly                          sleep
      3.47     0.00      30 root                           su

Next, we’ll kill the processes in the specified order.

Stop-Process -id 24 
Stop-Process -id 26
Stop-Process -id 28
Stop-Process -id 29

With that complete, we can check out the file that should have appeared at /shall/see.

gc /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 of the lonely unique event Id.

First of all, we’ll need to locate the eventlog.

gci -recurse /etc | %{ if ($_.extension -eq ".xml") {$_.fullname}}
══════════════════════════════════════════════════════════════════

/etc/systemd/system/timers.target.wants/EventLog.xml

With that done, we can group all of the Ids.

$doc = [xml](gc /etc/systemd/system/timers.target.wants/EventLog.xml)
$doc.Objs.Obj.Props.I32 | where N -eq "Id" | select -ExpandProperty "#text" | group       
═══════════════════════════════════════════════════════════════════════════════════

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

We can see that there is only unique Id is 1. We can use that information to “grep” out the surrounding information to find the values for our - gas mixture percentages.

gc /etc/systemd/system/timers.target.wants/EventLog.xml | Select-String '<I32 N="id">1' -Context 10,150
═══════════════════════════════════════════════════════════════════════════════════════════════════════

-------------8<-------------
<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>
-------------8<-------------
Arm ‘ze Laser!

Now that we have all of our values, we just need to make the api requests outlined earlier.

  1. turn laser off (GET)
  2. change refraction (GET)
  3. change temperature (GET)
  4. change angle (GET)
  5. change gaseous elements (POST)
  6. turn laser on (GET)
  7. check laser output

Here’s what those requests (with their responses) look like in practice.

(Invoke-WebRequest -Uri http://localhost:1225/api/off).RawContent
═════════════════════════════════════════════════════════════════

Christmas Cheer Laser Powered Off
(Invoke-WebRequest -Uri http://localhost:1225/api/refraction?val=1.867).Rawcontent
══════════════════════════════════════════════════════════════════════════════════

Updated Lense Refraction Level - Check /api/output if 5 Mega-Jollies per liter reached.
(Invoke-WebRequest -Uri http://localhost:1225/api/temperature?val=-33.5).Rawcontent
═══════════════════════════════════════════════════════════════════════════════════

Updated Laser Temperature - Check /api/output if 5 Mega-Jollies per liter reached.
(Invoke-WebRequest -Uri http://localhost:1225/api/angle?val=65.5).Rawcontent
════════════════════════════════════════════════════════════════════════════

Updated Mirror Angle - Check /api/output if 5 Mega-Jollies per liter reached.
$params = @{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 $params).Rawcontent
════════════════════════════════════════════════════════════════════════════════════════════

Updated Gas Measurements - Check /api/output if 5 Mega-Jollies per liter reached.
(Invoke-WebRequest -Uri http://localhost:1225/api/on).RawContent            
════════════════════════════════════════════════════════════════

Christmas Cheer Laser Powered On
(Invoke-WebRequest -Uri http://localhost:1225/api/output).Rawcontent
════════════════════════════════════════════════════════════════════

Success! - 6.13 Mega-Jollies of Laser Output Reached!

There we have it. Definitely a good challenge!

Sparkle Redberry - Solved

You got it - three cheers for cheer! For objective 5, have you taken a look at our Zeek logs? Something’s gone wrong. But I hear someone named Rita can help us. Can you and she figure out what happened?

Zeek JSON Analysis Challenge

The Zeek JSON Analysis Challenge can be found in the Sleigh Workshop beside Wunrose Openslae.

Helpful Resources

jq Basic Filters

Wunrose Openslae - Initial

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!

Problem

Based on the hint from Wunrose, we should be looking at the logs and trying to figure out which one has the longest connection.

zeek-motd

Solution

Luckily, parsing JSON is pretty simple with jq. Using that in conjunction with some commandline-fu gets us the longest connection.

cat conn.log | jq .duration | sort -n | grep -v null | tail -1
══════════════════════════════════════════════════════════════

1019365.337758

Now that we know the longest connection’s value, we can view it with the command below.

grep 1019365.337758 conn.log | 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
}

After that we need to execute the runtoanswer command to submit our response.

zeek-complete

Wunrose Openslae - Solved

That’s got to be the one - thanks! Hey, you know what? We’ve got a crisis here. You see, Santa’s flight route is planned by a complex set of machine learning algorithms which use available weather data. All the weather stations are reporting severe weather to Santa’s Sleigh. I think someone might be forging intentionally false weather data! I’m so flummoxed I can’t even remember how to login! Hmm… Maybe the Zeek http.log could help us. 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. I’ll bet if you pick through, you can find some naughty data from naughty hosts and block it in the firewall. If you find a log entry that definitely looks bad, try pivoting off other unusual attributes in that entry to find more bad IPs. The sleigh’s machine learning device (SRF) needs most of the malicious IPs blocked in order to calculate a good route. Try not to block many legitimate weather station IPs as that could also cause route calculation failure. Remember, when looking at JSON data, jq is the tool for you!

Badge Objectives

Now that we’ve stepped through all of the terminal challenges, we’ll shift gears and work through the Badge Objectives.

0 - Talk to Santa in the Quad

Objective > Enter the campus quad and talk to Santa.

It doesn’t get much simpler than this, and it’s probably one of the first things any of us did during kringlecon.

santa-quad

1 - Find the Turtle Doves

Objective > Find the missing turtle doves.

The turtle doves can be found in the Student Union, where Kent Tinseltooth and the Smart Braces challenge reside.

turtle-doves

2 - Unredact Threatening Document

Objective > 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 can be found in upperleft corner of the quad.

letter-location

By simply highlighting the text, we can see the contents.

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 Confidential
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
Confidential
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

Answer: DEMAND

3 - Windows Log Analysis: Evaluate Attack Outcome

Objective > 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.

Hint > Wow, that was much easier than I’d thought. Maybe I don’t need a clunky GUI after all! Have you taken a look at the password spray attack artifacts? I’ll bet that DeepBlueCLI tool is helpful. You can check it out on GitHub. It was written by that Eric Conrad. He lives in Maine - not too far from here!

The hint from Bushy Evergreen points us to a tool called DeepBlueCLI. We can use this tool to quickly solve this particular challenge.

After downloading the zip to a Windows VM, we can run the PowerShell script against the provided event log.

.\DeepBlue.ps1 .\Security.evtx | ConvertTo-Html > analysis.html

When we open up the resulting html file, we notice that there are a lot of failed login attempts for a lot of users. Almost all of the users have 77 failed logins, except for one. The user supatree has only 76 failed logins, suggesting that the 77th succeeded.

b3-supatree

Answer: supatree

4 - Windows Log Analysis: Determine Attacker Technique

Objective > 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.

Hint > Oh there they are! Now I can delete them. Thanks! Have you tried the Sysmon and EQL challenge? If you aren’t familiar with Sysmon, Carlos Perez has some great info about it. Haven’t heard of the Event Query Language? Check out some of Ross Wolf’s work on EQL or that blog post by Josh Wright in your badge.

After downloading the zip and extracting it, we can begin our search by finding the lsass entry with the following command.

jq '.[] | select(.parent_process_name | length > 0) | select(.parent_process_name | startswith("lsass"))' sysmon-data.json 
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════

{
  "command_line": "C:\\Windows\\system32\\cmd.exe",
  "event_type": "process",
  "logon_id": 999,
  "parent_process_name": "lsass.exe",
  "parent_process_path": "C:\\Windows\\System32\\lsass.exe",
  "pid": 3440,
  "ppid": 632,
  "process_name": "cmd.exe",
  "process_path": "C:\\Windows\\System32\\cmd.exe",
  "subtype": "create",
  "timestamp": 132186398356220000,
  "unique_pid": "{7431d376-dedb-5dd3-0000-001027be4f00}",
  "unique_ppid": "{7431d376-cd7f-5dd3-0000-001013920000}",
  "user": "NT AUTHORITY\\SYSTEM",
  "user_domain": "NT AUTHORITY",
  "user_name": "SYSTEM"
}

Now, we can assume that if the lsass process was used to dump domain creds, the tool run should be a child process of lsass. That means we should look for any entries with a PPID of 3440 (lsass’s PID).

jq '.[] | select(.ppid == 3440)' sysmon-data.json 
════════════════════════════════════════════════

{
  "command_line": "ntdsutil.exe  \"ac i ntds\" ifm \"create full c:\\hive\" q q",
  "event_type": "process",
  "logon_id": 999,
  "parent_process_name": "cmd.exe",
  "parent_process_path": "C:\\Windows\\System32\\cmd.exe",
  "pid": 3556,
  "ppid": 3440,
  "process_name": "ntdsutil.exe",
  "process_path": "C:\\Windows\\System32\\ntdsutil.exe",
  "subtype": "create",
  "timestamp": 132186398470300000,
  "unique_pid": "{7431d376-dee7-5dd3-0000-0010f0c44f00}",
  "unique_ppid": "{7431d376-dedb-5dd3-0000-001027be4f00}",
  "user": "NT AUTHORITY\\SYSTEM",
  "user_domain": "NT AUTHORITY",
  "user_name": "SYSTEM"
}

There we have it, ntdsutil was used to dump the creds.

Answer: ntdsutil

5 - Network Log Analysis: Determine Compromised System

Objective > 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.

Hint > You got it - three cheers for cheer! For objective 5, have you taken a look at our Zeek logs? Something’s gone wrong. But I hear someone named Rita can help us. Can you and she figure out what happened?

This objective was another of the type “run the tool -> get the results”. The tool in this case was RITA. Unfortunately, the real challenge lay in actually getting the software to run. I tried on ubuntu 19.04, 18.04, and kali (both manual install and docker). None of them worked. Browsing the documentation, there is a snippet that mentions Ubuntu 16.04 works the best for RITA. I ended up downloading a 16.04 ISO and spinning it up for this challenge.

After getting the software up and running, an html report is generated by RITA. All we need to do is click on the Beacons tab and grab the source IP as it’s the one that has been infected.

rita-5-output

Answer: 192.168.134.130

6 - Splunk

Objective > 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.

Once we login to the splunk interface, we’re greeted with a chat window on the side. If you’re like me and not at all familiar with Splunk, this was a great way to walk through the exercise. For each step, there is a new hint in the chat window from Alice Bluebird.

splunk-chat

There is only one question that needs to be answered for the badge, but the optional questions help you get to the one that matters. Since there are hints at each step from Alice, we’ll only cover how to utilize those hints in the search interface of Splunk.

Question 1

What is the short host name of Professor Banas’ computer?

Search: cbanas

Answer: sweetums

Question 2

What is the name of the sensitive file that was likely accessed and copied by the attacker? Please provide the fully qualified location of the file. (Example: C:\temp\report.pdf)

Search: santa

Answer: C:\Users\cbanas\Documents\Naughty_and_Nice_2019_draft.txt

Question 3

What is the fully-qualified domain name(FQDN) of the command and control(C2) server? (Example: badguy.baddies.com)

Search: sourcetype=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational powershell EventCode=3 Interesting Field: DestinationHostname

Answer: 144.202.46.214.vultr.com

Question 4

What document is involved with launching the malicious PowerShell code? Please provide just the filename. (Example: results.txt)

This question is a multi-step process that begins with a search given to us by Alice.

  • Search-1: index=main sourcetype="WinEventLog:Microsoft-Windows-Powershell/Operational" | reverse
  • Time-Pivot: +/- 5 seconds (on first entry)
  • Search-2: index=main
  • Interesting Field: ProcessId -> 6268
  • Remove Time-Pivot
  • Search-3: sourcetype=WinEventLog EventCode=4688 process_id=0x187c (search in all records)

Answer: 19th Century Holiday Cheer Assignment.docm

Question 5

How many unique email addresses were used to send Holiday Cheer essays to Professor Banas? Please provide the numeric value. (Example: 1)

Search:

index=main sourcetype=stoq | 
  table _time results{}.workers.smtp.to results{}.workers.smtp.subject | 
  search results{}.workers.smtp.subject="Holiday Cheer Assignment Submission"

Answer: 21

Question 6

What was the password for the zip archive that contained the suspicious file?

Search:

index=main sourcetype=stoq | 
  table _time results{}.workers.smtp.from results{}.workers.smtp.body | 
  search results{}.workers.smtp.body="*password*"

Answer: 123456789

Question 7

What email address did the suspicious file come from?

Search: Same as above Answer: bradly.buttercups@eifu.org

Challenge Question

The query below is given to us and shows us full file paths. The last hint from Alice is below

Last thing for you today: Did you know that modern Word documents are (at their core) nothing more than a bunch of .xml files?

Using the given search string and the hint, we find the full file path to core.xml.

index=main sourcetype=stoq  "results{}.workers.smtp.from"="bradly buttercups <bradly.buttercups@eifu.org>" | 
  eval results = spath(_raw, "results{}") |
  mvexpand results | 
  eval path=spath(results, "archivers.filedir.path"), filename=spath(results, "payload_meta.extra_data.filename"), fullpath=path."/".filename | search fullpath!="" | 
  table filename,fullpath

Full Path: /home/ubuntu/archive/f/f/1/e/a/ff1ea6f13be3faabd0da728f514deb7fe3577cc4/core.xml

Armed with the full path, we can click on the File Archive tab and drill down until we eventually reach this folder.

Once we’ve reached the folder, we can download the only file in there and examine the contents, revealing the message!

splunk-message

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

Nice! All done with this one.

splunk-complete

7 - Get Access To The Steam Tunnels

Objective > 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.

Hint > You made it - congrats! Have you played with the key grinder in my room? Check it out! It turns out: if you have a good image of a key, you can physically copy it. Maybe you’ll see someone hopping around with a key here on campus. Sometimes you can find it in the Network tab of the browser console. Deviant has a great talk on it at this year’s Con. He even has a collection of key bitting templates for common vendors like Kwikset, Schlage, and Yale.

Helpful Resources > Deviant Ollam, Optical Decoding of Keys | KringleCon 2019

To act on the hint, we need to find the person with the key. That person is none other than Krampus! He can be found in Minty’s Dorm Room which is accessed from the Dorm. Whenever we enter the room, he wanders off behind a locked door. We can use our browser’s dev tools (network tab) in order to find the URL that was used to load his avatar (https://2019.kringlecon.com/images/avatars/elves/krampus.png).

krampus

After we save the image to disk, we can use GIMP to rotate krampus and focus in on his key.

horiz-krampus

I’m fairly certain the intended solution was to overlay the image of the key with the Schlage template from Mr. Ollam. However, I had success with making a few logical assumptions about the bit depth. Those assumptions are outlined below

  • made an assumption that the first bitting value was 1
  • the next appeared to be double the depth of the first, so used a value of 2
  • next was same as previous
  • made an assumption that this value was 4
  • another 2
  • and a 0 (no cut was used)

My first attempt was incorrect. I then tried incrementing my assumption of 4 to 5 and the door opened (yes, i know i was pretty lucky… lol).

correct bitting code: 122520

After we make our way through the steam tunnels, we run find Krampus. His dialogue contains the answer to this objective.

Krampus Dialogue (Steam Tunnels)

Hello there! I’m Krampus Hollyfeld. I maintain the steam tunnels underneath Elf U, Keeping all the elves warm and jolly. Though I spend my time in the tunnels and smoke, In this whole wide world, there’s no happier bloke! Yes, I borrowed Santa’s turtle doves for just a bit. Someone left some scraps of paper near that fireplace, which is a big fire hazard. I sent the turtle doves to fetch the paper scraps. But, before I can tell you more, I need to know that I can trust you. Tell you what – if you can help me beat the Frido Sleigh contest (Objective 8), then I’ll know I can trust you. The contest is here on my screen and at fridosleigh.com. No purchase necessary, enter as often as you want, so I am! They set up the rules, and lately, I have come to realize that I have certain materialistic, cookie needs. Unfortunately, it’s restricted to elves only, and I can’t bypass the CAPTEHA. (That’s Completely Automated Public Turing test to tell Elves and Humans Apart.) I’ve already cataloged 12,000 images and decoded the API interface. Can you help me bypass the CAPTEHA and submit lots of entries?

Answer: Krampus Hollyfeld

8 - Bypassing the Frido Sleigh CAPTEHA

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

Hint > Who would do such a thing?? Well, it IS a good looking cat. Have you heard about the Frido Sleigh contest? There are some serious prizes up for grabs. The content is strictly for elves. Only elves can pass the CAPTEHA challenge required to enter. I heard there was a talk at KCII about using machine learning to defeat challenges like this. I don’t think anything could ever beat an elf though!

Helpful Resources Chris Davis, Machine Learning Use Cases for Cybersecurity | KringleCon 2019

This was a really fun challenge for me. I love Python and enjoyed studying machine learning in the past. While the objective may have seemed daunting at first, the amount of custom code needed to solve the challenge was pretty minimal. The steps to complete the challenge are outlined below.

Assumption: You’ve already downloaded the images and Python script

Create a project directory

mkdir kringlecon-machine-learning 
cd kringlecon-machine-learning

Create a Python virtual environment (i like pipenv but it’s dealer’s choice)

pipenv install setuptools tensorflow==1.15 tensorflow_hub requests numpy

Clone the github repo

git clone https://github.com/chrisjd20/img_rec_tf_ml_demo.git

Create an images directory and untar the 12,000 images into the new directory

mkdir images
tar xvf capteha_images.tar.gz -C images/

Run retrain against the images directory

cd img_rec_tf_ml_demo
python retrain.py --image_dir ../images/

Move the resulting graph/labels file from /tmp/retrain_tmp to the project directory

mv /tmp/retrain_tmp/output_* .

Next, we can grab the functions from predict_images_using_trained_model.py and add them to the capteha_api.py script so we can use them as part of our solution. After which we can alter the predict_image function to return a dictionary and remove unnecessary args from the function call.

23def predict_image(sess, image_bytes, labels, input_operation, output_operation):
24    image = read_tensor_from_image_bytes(image_bytes)
25    results = sess.run(output_operation.outputs[0], {
26        input_operation.outputs[0]: image
27    })
28    results = np.squeeze(results)
29    prediction = results.argsort()[-5:][::-1][0]
30    return {'prediction':labels[prediction].title(), 'percent':results[prediction]}

We’ll need to change the variable yourREALemailAddress to a real email (line 65). We’ll also need to change the graph and label variables to point to the files created by running retrain.py (line 6667).

With all of that complete, we need to add the logic for using the model to predict images sent by the server as part of the

64    # begin my code
65    yourREALemailAddress = "epibar052@gmail.com"
66    graph = load_graph('output_graph.pb')
67    labels = load_labels("output_labels.txt")
68
69    input_operation = graph.get_operation_by_name("import/Placeholder")
70    output_operation = graph.get_operation_by_name("import/final_result")
71    sess = tf.compat.v1.Session(graph=graph)
72
73    selected_images = list()
74
75    for image in b64_images:
76        binary_img = base64.b64decode(image.get('base64'))
77        predicted = predict_image(sess, binary_img, labels, input_operation, output_operation)
78        if predicted.get('prediction') in challenge_image_types:
79            selected_images.append(image)
80    
81    b64_images = selected_images
82    # end my code

If all went well, we should see an email sent to the email address we added on line 65. The code received is the answer to this objective!

contest-win

Answer: 8Ia8LiZEwvyZr2WO

9 - Retrieve Scraps of Paper from Server

Objective > 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.

Hint (Krampus) > You did it! Thank you so much. I can trust you! To help you, I have flashed the firmware in your badge to unlock a useful new feature: magical teleportation through the steam tunnels. As for those scraps of paper, I scanned those and put the images on my server. I then threw the paper away. Unfortunately, I managed to lock out my account on the server. Hey! You’ve got some great skills. Would you please hack into my system and retrieve the scans? I give you permission to hack into it, solving Objective 9 in your badge. And, as long as you’re traveling around, be sure to solve any other challenges you happen across.

Hint (Pepper Minstix) > That’s it - hooray! Have you had any luck retrieving scraps of paper from the Elf U server? You might want to look into SQL injection techniques. OWASP is always a good resource for web attacks. For blind SQLi, I’ve heard Sqlmap is a great tool. In certain circumstances though, you need custom tamper scripts to get things going! …

Helpful Resources https://www.foregenix.com/blog/testing-problematic-authorisation-tokens-with-burp

This was another challenge where we won’t take the intended (tamper script) route. Instead, we’ll use BurpSuite’s macro capability to grab a new CSRF token for each new injection request.

First, we’ll need to find the injection point. Browsing around the site manually leads us to the email form located at https://studentportal.elfu.org/check.php.

vuln-form-9

Then, we’ll a send normal request to the site while proxying our broswer through Burp. With that done, we can right-click on the request itself in the HTTP history tab to save the request to disk. Saving the request (known forevermore as request.burp) to disk will make it easier for us to craft our sqlmap command.

Speaking of sqlmap commands, let’s try to run sqlmap against what we believe to be the injection point.

sqlmap -l request.burp --tables --batch --proxy=http://127.0.0.1:8080
═════════════════════════════════════════════════════════════════════

-------------8<-------------
GET parameter 'token' appears to hold anti-CSRF token. Do you want sqlmap to automatically update it in further requests? [y/N]
-------------8<-------------

The above command fails, specifically there are messages about a anti-CSRF token named token. Looking back in our HTTP history in Burp, we should see a GET request to /validator.php right before the GET request to /application-check.php.

sqli-validator

It seems as though we’ll need a new token for each request to /application-check.php we want to send. Knowing that, let’s setup burp to auto request the token for us via a macro!

We’ll begin by adding a session rule. > project options -> sessions -> session handling rules -> add

add-session-rule

Next, we’ll add a rule handler that runs a macro based on certain criteria. > rule actions -> add -> run a macro

run-a-macro

Then, we’ll select the request we made to /validator.php > session handling action editor -> add -> select /validator.php get request

macro-recorder

After that, we need to tell burp how to recognize the token by defining it as a custom parameter. Since the token is the only thing in the response body, we can simply write a regex to capture everything and excluse the HTTP headers from the search.

  • configure macro item -> add
  • extract from regex group -> highlight token value -> give Parameter name a value of token
  • check exclude HTTP headers

custom-param

Back in the session rule editor, we need to select the Scope tab and then select Use suite scope (we’ll set this up next). > click Use suite scope

session-rule-scope

Now we can click on the Target tab and the Scope subtab to set our scope. > configure suite scope

suite-scope

With all of that complete we can run a command to view the tables in the database.

sqlmap -l request.burp --tables --batch --proxy=http://127.0.0.1:8080
═════════════════════════════════════════════════════════════════════

-------------8<-------------

Database: elfu                              
[3 tables]
+---------------------------------------+
| applications                          |
| krampus                               |
| students                              |
+---------------------------------------+

-------------8<-------------

We see the elfu database and its associated tables, nice! Let’s run another command to dump their contents.

sqlmap -l request.burp --dump -D elfu --batch --proxy=http://127.0.0.1:8080
═══════════════════════════════════════════════════════════════════════════

-------------8<-------------

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

-------------8<-------------

Browsing to the URLs below, we see the scraps of paper that Krampus uploaded.

Specifically, combining this piece and this piece gives us the answer to the objective.

Answer: Super Sled-o-matic

10 - Recover Cleartext Document

Objective > 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.

Hint > Woohoo! Fantabulous! I’ll be the coolest elf in class. > On a completely unrelated note, digital rights management can bring a hacking elf down. > That ElfScrow one can really be a hassle. > It’s a good thing Ron Bowes is giving a talk on reverse engineering! > That guy knows how to rip a thing apart. It’s like he breathes opcodes!

Helpful Resources Ron Bowes, Reversing Crypto the Easy Way | KringleCon 2019

We’re not going to go into too much depth with this one. I strongly recommend watching the talk above. It covers exactly what needs to be done in order to solve the challenge and has a lot of good information in it as well. The overall goal for this one is to decrypt the supplied PDF using some reverse engineering tips given by Mr. Bowes.

We start off by downloading the 3 files below - elfscrow.exe - elfscrow.pdb - ElfUResearchLabsSuperSledOMaticQuickStartGuideV1.2.pdf.enc

Examining the .exe in IDA, we should notice a few things

If we google the value of the LCG constant, we arrive at this code, which we’ll use as the base for our decrypter. The objective tells us that the document was encrypted somewhere within a 2-hour window. Since the seed for the LCG is time-based, we can iterate from the start time to the end time in order to try all of the potential seeds that were used during encryption.

The modified version of the code we found (below) attempts to decrypt the PDF. After attempting decryption with the given seed, it runs the file command against the result. If file says that the file is a PDF instead of data, we’ve found the correct seed!

There was one thing that took a while to figure out. We needed to add c.padding = 0 as part of the decrypt function. Without this line the code threw in final: bad decrypt (OpenSSL::Cipher::CipherError) errors when attempting to decrypt (shown on line 43).

 1# https://rosettacode.org/wiki/Linear_congruential_generator#Ruby
 2#
 3# We know that it was encrypted on December 6, 2019, between 7pm and 9pm UTC.
 4# 
 5
 6require 'openssl'
 7module LCG
 8  module Common
 9    # The original seed of this generator.
10    attr_reader :seed
11 
12    # Creates a linear congruential generator with the given _seed_.
13    def initialize(seed)
14      @seed = @r = seed
15    end
16  end
17 
18  # LCG::Microsoft generates 15-bit integers using the same formula
19  # as rand() from the Microsoft C Runtime.
20  class Microsoft
21    include Common
22    def rand
23      @r = ((214013 * @r + 2531011) & 0x7fff_ffff) 
24      return @r >> 16
25    end
26  end
27end
28
29# begin my code 
30def genkey(seed)
31    lcg = LCG::Microsoft.new(seed)
32    key = ""
33    1.upto(8) do
34        key += (lcg.rand() & 0x0ff).chr 
35    end
36    return key
37end
38
39def decrypt(data, key)
40    c = OpenSSL::Cipher::DES.new('CBC')
41    c.decrypt
42    c.padding = 0  # had to add this to bypass "in `final': bad decrypt (OpenSSL::Cipher::CipherError)"
43    c.key = key
44    return (c.update(data) + c.final())
45end
46
47infile = File.open("ElfUResearchLabsSuperSledOMaticQuickStartGuideV1.2.pdf.enc", "rb")
48data = infile.read
49
50# 1575658800 <- start time for encryption window
51# 1575666000 <- end time
52(1575658800..1575666000).each do |n|
53    seed = n
54    key = genkey(seed)  # create key from time seed
55
56    decrypted = decrypt(data, key)  # attempt decrypt
57
58    File.open("decrypted.pdf", "w") { |f| f.write decrypted }  # write potentially decrypted contents to disk
59
60    # check if what was written to disk is "data" (not decrypted) or "PDF document" (decrypted)
61    r = IO.popen("file decrypted.pdf")
62    resp = r.gets
63    if resp.include? "PDF document"
64        puts("Found a solution; check decrypted.pdf")
65        puts("seed: #{seed}")
66        break
67    end
68end

Running the code above yields a solution.

ruby cracker.rb
Found a solution; check decrypted.pdf
seed: 1575663650

We can open up decrypted.pdf and look for the answer to the objective.

crypto-complete

Answer: Machine Learning Sleigh Route Finder

11 - Open the Sleigh Shop Door

Objective > Visit Shinny Upatree in the Student Union and help solve their problem. What is written on the paper you retrieve for Shinny? > For hints on achieving this objective, please visit the Student Union and talk with Kent Tinseltooth.

Hint > Oh thank you! It’s so nice to be back in my own head again. Er, alone. > By the way, have you tried to get into the crate in the Student Union? It has an interesting set of locks. > There are funny rhymes, references to perspective, and odd mentions of eggs! > And if you think the stuff in your browser looks strange, you should see the page source… > Special tools? No, I don’t think you’ll need any extra tooling for those locks. > BUT - I’m pretty sure you’ll need to use Chrome’s developer tools for that one. > Or sorry, you’re a Firefox fan? > Yeah, Safari’s fine too - I just have an ineffible hunger for a physical Esc key. > Edge? That’s cool. Hm? No no, I was thinking of an unrelated thing. > Curl fan? Right on! Just remember: the Windows one doesn’t like double quotes. > Old school, huh? Oh sure - I’ve got what you need right here… > … > … > And I hear the Holiday Hack Trail game will give hints on the last screen if you complete it on Hard.

This challenge revolves around the use of developer tools in browsers. When we brosed to the challenge site, we’re presented with a series of locks. Each lock has a small challenge to solve involving the user of broswer developer tools. We’ll be completing this challenge using Firefox.

Note: Most of the answers change every time the page is loaded; your answers will differ from those shown here.

Lock 1

You don’t need a clever riddle to open the console and scroll a little.

We need to open the console tab and scroll up

lock-1

Lock 2

Some codes are hard to spy, perhaps they’ll show up on pulp with dye?

For this one, we can toggle the print media button, which can be found in the upper right corner of the inspector tab beside :hov, .cls, and + (bottom right of the image below).

lock-2

Lock 3

This code is still unknown; it was fetched but never shown.

This time, we can view the network tab and look for a fetch in the Cause column. Hover over the row and the code will appear.

lock-3

Lock 4

Where might we keep the things we forage? Yes, of course: Local barrels!

The next clue points us to our browser’s Local Storage. Click on the Storage tab then Local Storage on the left hand side for the answer.

lock-4

Lock 5

Did you notice the code in the title? It may very well prove vital.

Here, we can simply type document.title into the console for the answer.

lock-5

Lock 6

In order for this hologram to be effective, it may be necessary to increase your perspective.

For this clue, we’ll need to manipulate the CSS of the hologram.

  • Find the <div class="hologram"> element in the Inspector tab
  • Under CSS Rules tab (right hand panel), uncheck the box marked perspective

lock-6

Lock 7

The font you’re seeing is pretty slick, but this lock’s code was my first pick.

We can view the fonts using the Style Editor tab. The one we’re looking for is the one marked <inline style sheet #4> in the left hand panel.

lock-7

Lock 8

In the event that the .eggs go bad, you must figure out who will be sad.

First, we’ll need to find .eggs in the Inspector tab. We can accomplish that by hitting ctrl+f and entering .eggs.

lock-8-1

Once there, we see that there is an event handler for this element. Let’s click the event button beside the element. Doing so reveals the answer.

lock-8

Lock 9

This next code will be unredacted, but only when all the chakras are :active.

To accomplish this one, we’ll need to set the :active attribute on all of the .chakra elements. This only works one element at a time. Taking note of what pops up after each one is set to active gives us the answer (one is shown below, ressulting in N6).

lock-9

Lock 10

Oh, no! This lock’s out of commission! Pop off the cover and locate what’s missing.

This one was trickier than any of the others. The first part is pretty simple though. In order to remove the cover, we can just change the class name associated with the lock.

lock-10-0

After that, the cover is removed and we can see the code inside the case.

lock-10-1

Unfortunately, we can’t press the Unlock button. The button has a disabled attribute that we can remove though.

lock-10-2

After removing it, we can enter the code and try to unlock the lock. Once it fails, we can check the console to see an odd error message.

Error: "Missing macaroni!"
    317784542493 https://sleighworkshopdoor.elfu.org/client.js/82a939a6-6215-463a-9823-0c7f4a16fdbf:1

We can go back to the Inspector tab and search for macaroni to find an element with a component class along with a macaroni class. Let’s move the component down into the lock by dragging it into position.

lock-10-3

If we attempt to unlock again, we’re presented with another error message.

Error: "Missing cotton swab!"
    317784542493 https://sleighworkshopdoor.elfu.org/client.js/82a939a6-6215-463a-9823-0c7f4a16fdbf:1

We can repeat the same process with the cotton swab that we did with the macaroni. Alternatively, we can just search for all .components and move them into place all at once. Either way, we need three components to be inside the lock for it to function. With those in position, we’re succesful in unlocking the final lock!

lock-10

Once the final lock is open, we see who the real villian is and can solve this objective.

the-villian

Answer: The Tooth Fairy

12 - Filter Out Poisoned Sources of Weather Data

Objective > Use the data supplied in the Zeek JSON logs to identify the IP addresses of attackers poisoning Santa’s flight mapping software. Block the 100 offending sources of information to guide Santa’s sleigh 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.

Hint > That’s got to be the one - thanks! > Hey, you know what? We’ve got a crisis here. > You see, Santa’s flight route is planned by a complex set of machine learning algorithms which use available weather data. > All the weather stations are reporting severe weather to Santa’s Sleigh. I think someone might be forging intentionally false weather data! > I’m so flummoxed I can’t even remember how to login! > Hmm… Maybe the Zeek http.log could help us. > 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. > I’ll bet if you pick through, you can find some naughty data from naughty hosts and block it in the firewall. > If you find a log entry that definitely looks bad, try pivoting off other unusual attributes in that entry to find more bad IPs. > The sleigh’s machine learning device (SRF) needs most of the malicious IPs blocked in order to calculate a good route. > Try not to block many legitimate weather station IPs as that could also cause route calculation failure. > Remember, when looking at JSON data, jq is the tool for you!

Our goal here is to determine malicious IP addresses based on attacks captured in the provided http.log. Once again, we’re going to ignore the hint, at least insofar as it talks of using jq. We’re going to write a python script to handle the heavy lifting. First though, we need to find the creds to login. The recovered document from badge objective #10 says that the default creds are found in the readme within the git repo.

def-creds-in-git

We can try a few logical things, such as git.elfu.org or https://srf.elfu.org/.git, though both fail. Another potential solution is that they’re hosting the site directly from the repo itself. To test that theory, we can try things like https://srf.elfu.org/README which also doesn’t work. Fear not! Attemping https://srf.elfu.org/README.md leads to a win.

def-creds

So, the creds to the site are

admin
924158F9522B3744F5FCD4D10FAC4356

Using those and logging in brings us to the home page

srf-home

Our objective is primarily concerned with the firewall interface

12-firewall

We’ll need to add any malicious IPs to the deny list here after we find them. As stated previously, we’ll be scripting out the solution. The initial piece of our code to identify bad traffic is shown below.

 1#!/usr/bin/env python3
 2import json
 3from pathlib import Path
 4from collections import defaultdict
 5
 6contents = json.loads(Path("http.log").read_bytes())
 7
 8dirty_strings = {
 9    "select ",
10    "select/*",
11    "select+",
12    "<script",
13    "/etc/passwd",
14    "()",
15}
16
17found_entries = list()
18
19results = defaultdict(set)
20
21for entry in contents:  # http.log contents
22    for ds in dirty_strings:  # dirty string that identifies an attack
23        for field in entry.values():  # each field in an entry (i.e. ts, uid, method, host, uri, etc...)
24            if ds in str(field).lower():
25                print(f"{entry.get('id.orig_h')}: {field} found {ds}")
26                found_entries.append(entry)
27                results[entry.get('id.orig_h')].add(field)

The general idea is that we’ll iterate over each log entry, and then iterate again over each field of each log. Inside each field, we’re going to look for a string that is indicative of each attack. In our case, Wunrose tells us to be on the lookout for XSS, LFI, SQLi, and “shell stuff”. Shell stuff happens to mean shellshock attacks in these logs. The above code is enough to identify all of those attacks.

With the attacks found, after some examination, we notice that there are oddities in the User-Agent strings sent along with these attacks. The most obvious is probably Metasploit, but there are others such as Goglebot, random misspellings, versions of operating systems / software that doesnt exist, etc…

Knowing that we’ll grab all of the User-Agents from the malicious entries, iterate over the entire log file again and identify any other IPs that are using the same User-Agents as those that are definitely sending attacks. The code to accomplish that is shown below.

29user_agents = [x.get('user_agent') for x in found_entries]
30dirty_strings.update(set(user_agents))
31
32for entry in contents:
33    for ds in dirty_strings:
34        if ds in entry.get('user_agent'):
35            print(f"{entry.get('id.orig_h')}: {field} found {ds}")
36            found_entries.append(entry)
37            results[entry.get('id.orig_h')].add(field)
38
39print(f"found {len(results)} results")
40print(','.join(ip for ip in results.keys()))

Running the entire script results in the below output.

./ingest.py
═══════════

found 94 results
42.103.246.250,56.5.47.137,19.235.69.221,69.221.145.150,42.191.112.181,48.66.193.176,49.161.8.58,84.147.231.129,44.74.106.131,106.93.213.219,2.230.60.70,10.155.246.29,225.191.220.138,75.73.228.192,249.34.9.16,27.88.56.114,238.143.78.114,121.7.186.163,106.132.195.153,129.121.121.48,190.245.228.38,34.129.179.28,135.32.99.116,2.240.116.254,45.239.232.245,102.143.16.184,230.246.50.221,131.186.145.73,253.182.102.55,229.133.163.235,23.49.177.78,223.149.180.133,187.178.169.123,116.116.98.205,9.206.212.33,28.169.41.122,68.115.251.76,118.196.230.170,173.37.160.150,81.14.204.154,135.203.243.43,186.28.46.179,13.39.153.254,111.81.145.191,0.216.249.31,31.254.228.4,220.132.33.81,83.0.8.119,150.45.133.97,229.229.189.246,227.110.45.126,61.110.82.125,65.153.114.120,123.127.233.97,95.166.116.45,80.244.147.207,168.66.108.62,200.75.228.240,42.103.246.130,118.26.57.38,42.127.244.30,217.132.156.225,252.122.243.212,22.34.153.164,44.164.136.41,203.68.29.5,97.220.93.190,158.171.84.209,34.155.174.167,104.179.109.113,66.116.147.181,140.60.154.239,50.154.111.0,92.213.148.0,31.116.232.143,126.102.12.53,187.152.203.243,37.216.249.50,250.22.86.40,231.179.108.238,103.235.93.133,253.65.40.39,142.128.135.10,226.102.56.13,185.19.7.133,87.195.80.126,148.146.134.52,53.160.218.44,249.237.77.152,10.122.158.57,226.240.188.154,29.0.183.220,42.16.149.112,249.90.116.138

The list of IPs is able to be copy/pasted into the SRF in order to block all the bad IPs we found. After doing so, we see the RID that answers #12’s objective.

firewall-complete

Answer: 0807198508261964

The End

After submitting the 12th challenge and walking through the door that opens after, we can proceed to the Bell Tower. At the top of the Bell Tower, we reach the end of the story! Santa and Krampus congratulate/thank us and the Tooth Fairy grumbles.

12-done

If you moved up beside Santa, you may have noticed a letter on the ground. It seems to hint at next year’s adventure!

2020-badguy

I hope you enjoyed this write-up or at least found something useful. Drop me a line in chat @ NetSec Focus / Twitter / etc…


comments powered by Disqus