Welcome to Part II of the Sans Holiday Hack 2018 Walkthrough! In this post, I'll go through questions 4 through 6 and their associated terminal challenges. If you missed Part I or would like to refer back to it for anything, you can find it here.
Let's get started!
Question 4
"Retrieve the encrypted ZIP file from the North Pole Git repository. What is the password to open this file? For hints on achieving this objective, please visit Wunorse Openslae and help him with Stall Mucking Report Cranberry Pi terminal challenge."
The Git repository can be found here.
Optional - talk to Wunorse Openslae and complete his terminal challenge. Wunorse is located on the ground floor of the castle, in the right hallway past Bushy Evergreen.
Hi, I'm Wunorse OpenslaeClick on the terminal to start the challenge!
What was that password?
Golly, passwords may be the end of all of us. Good guys can't remember them, and bad guess can guess them!
I've got to upload my chore report to my manager's inbox, but I can't remember my password.
Still, with all the automated tasks we use, I'll bet there's a way to find it in memory...
![]() |
| Terminal challenge prompt |
Looks like we need to recover the password in order to upload the file report.txt to the samba share. The file is located in the current directory, which you can see if you run ls.
Wunorse mentioned something about finding the password in memory, so let's see what happens when we run "ps aux".
![]() |
| Looking for running processes |
The output on the right looks a bit cut off from long commands. Let's re-run the command, but pipe the output to less so we can see the entire output.
![]() |
| Full ps output |
Much better. The command of interest here is:
sudo -u manager /home/manager/samba-wrapper.sh --verbosity=none --no-check-certificate --extraneous-command-argument --do-not-run-as-tyler --accept-sage-advice -a 42 -d~ --ignore-sw-holiday-special --suppress --suppress //localhost/report-upload/ directreindeerflatterystable -U report-uploadIt looks like the command ran a wrapper shell script for samba (probably by running the smbclient command). Ignoring the bogus arguments (and the Hitchhiker's Guide reference), we can see some interesting arguments:
- //localhost/report-upload/, which is the samba share that we want to upload report.txt to.
- report-upload, which is most likely the username, given the associated -U flag
- directreindeerflatterystable, which is most likely the password if we're following the typical smbclient syntax.
Let's try out our password guess using the smbclient command and see if it works:
smbclient //localhost/report-upload/ \
-U report-upload \
directreindeerflatterystable
![]() |
| Testing the credentials. |
It worked! Now we just need to put the local file report.txt onto the share.
Run "put report.txt" and enjoy the success message!
![]() |
| Placing the file! |
Talk to Wunorse again to receive the hints for Question 4.
Thank goodness for command line passwords - and thanks for your help!Given that we're looking for the password for an encrypted zip file from a Git repository, this Trufflehog tool sounds like the perfect way to find a password left in the repo.
Speaking of good ways to find credentials, have you heard of Trufflehog?
It's a cool way to dig through repositories for passwords, RSA keys, and more.
I mean, no one EVER uploads sensitive credentials to public repositories, right? But if they did, this would be a great tool for finding them.
But hey, listen to me ramble. If you're interested in Trufflehog, you should check out Brian Hostetler's talk!
Have you tried the entropy=True option when running Trufflehog? It is amazing how much deeper it will dig!
Go ahead and download the source code for the repository and find the zip file. "find /path/to/unzipped/folder -name *.zip" should give you the zip file name (schematics/ventilation_diagram.zip).
Let's find this password. You can find and install Trufflehog using https://github.com/dxa4481/truffleHog. Once it's installed, let's run it using the entropy=True argument and the git url https://git.kringlecastle.com/Upatree/santas_castle_automation
Start sifting through the output. It looks like some RSA private keys and change IDs were flagged for high entropy. However, some commits were flagged near the bottom of the output, and these might be what we're looking for.
If I had to take an educated guess, I'd say that "Yippee-ki-yay" is the password to the zip file. And sure enough, that password works! Submit it as an answer to Question 4, and let's move on to the next objective.
Question 5
"Using the data set contained in this SANS Slingshot Linux image, find a reliable path from a Kerberoastable user to the Domain Admins group. What’s the user’s logon name (in [email protected] format)? Remember to avoid RDP as a control path as it depends on separate local privilege escalation flaws. For hints on achieving this objective, please visit Holly Evergreen and help her with the CURLing Master Cranberry Pi terminal challenge."
The Linux image can be downloaded here (note that this file is about 1.4GB)
Optional - Talk to Holly Evergreen and complete her terminal challenge for hints. Holly is on the ground floor in the left hallway, past Toy Soldier 6.
Oh that Bushy!Click on the terminal to start the challenge.
Sorry to vent, but that brother of mine did something strange.
The trigger to restart the Candy Striper is apparently an arcane HTTP call or 2.
I sometimes wonder if all IT folk do strange things with their home networks...
![]() |
| Terminal challenge prompt |
Let's look at /etc/nginx/nginx.conf first to see what kind of HTTP request we need to send.
![]() |
| snippet of nginx configuration file. |
curl --http2-prior-knowledge \
http://localhost:8080
![]() |
| curl command and output |
Excellent, we got some HTML back! In order to turn on Candy Striper, we need to send a POST request to the same URL with the "status=on" parameter. Let's craft a curl request for that:
curl --http2-prior-knowledge \The --data option will send the "status=on" data in a POST request. Run the command and enjoy the ASCII art!
--data "status=on" \
http://localhost:8080
Exit the terminal and talk to Holly to get the hints for Question 5.
Unencrypted HTTP/2? What was he thinking? Oh well.You can find the tool here
Have you ever used Bloodhound for testing Active Directory implementations?
It's a merry little tool that can sniff AD and find paths to reaching privileged status on specific machines.
AD implementations can get so complicated that administrators may not even know what paths they've set up that attackers might exploit.
Have you seen anyone demo the tool before?
Fire up a virtualization tool that can handle .ova files and import the .ova image from the link in Question 5. Note: I found that my import tried to automatically set the VM to 32-bit Debian, which didn't start properly. I changed it to 64-bit Debian, and it worked.
Start the VM when it's ready. You'll see BloudHound available for us on the desktop. Go ahead and run it. The window should look similar to the below screenshot:
![]() |
| opening BloodHound |
It looks like the default view lists users who are members of the Domain Admins group. We want to find a path from the Kerberoastable user to the Domain Admins group, without using RDP as a control path.
On the upper left corner, by the search box, click the 3-bar button to open a menu.
Select "Queries" to find a list of pre-built queries that we can try out. The query labeled "Shortest Paths to Domain Admins from Kerberoastable Users" sounds promising. Click on it, and then select "DOMAIN [email protected]" as the Domain Admin group to target.
![]() |
| Pre-set queries |
Our BloodHound view should have changed - you should now see a single path from user [email protected] to user [email protected], who is a member of the Domain Admins group.
![]() |
| Query results. |
Looking at the path edges, we see that [email protected] is a member of the [email protected] group, which is admin to [email protected], and [email protected] has a session on [email protected]. None of the edges uses RDP, so we can say this path is stable. Let's submit "[email protected]" as the answer to the objective!
Question 6
"Bypass the authentication mechanism associated with the room near Pepper Minstix. A sample employee badge is available. What is the access control number revealed by the door authentication panel? For hints on achieving this objective, please visit Pepper Minstix and help her with the Yule Log Analysis Cranberry Pi terminal challenge."
Optional - speak with Pepper Minstix and complete her terminal challenge. Pepper is far down the right hallway of the second floor - go past Tangle Coalbox and the Speaker Unpreparedness Room and turn the corner.
Hi, I'm Pepper Minstix.
Have you heard of password spraying? It seems we've been victim.
We fear that they were successful in accessing one of our Elf Web Access accounts, but we don't know which one.
Parsing through .evtx files can be tricky, but there's a Python script that can help you convert it into XML for easier grep'ing.
Click on the terminal to start Pepper's challenge.
![]() |
| Terminal challenge prompt. |
Let's run the provided Python script to turn the ho-ho-no.evtx file into an XML file. Run the command "evtx_dump.py ho-ho-no.evtx > logs.xml". The command will take some time. When it's done, we can start digging!
The file contains XML formatted output for Microsoft Event Viewer logs. We'll want to look for events corresponding to authentication attempts and successful account access. If you start browsing through the XML file, you'll notice the EventID field.
In the above screenshot, an EventID of 4647 corresponds to the security event of "User initiated logoff". For in-depth information on Windows Security Event IDs and their meanings, check out https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-<eventID> (replace <eventID> with the EventID of your choice).
Let's see all the EventIDs and counts:
The sed commands trim off the unnecessary parts of the lines to leave only the EventID numbers. So now we have all the EventIDs in the logs, ordered by how frequently they appeared. Let's start from the top:
The file contains XML formatted output for Microsoft Event Viewer logs. We'll want to look for events corresponding to authentication attempts and successful account access. If you start browsing through the XML file, you'll notice the EventID field.
In the above screenshot, an EventID of 4647 corresponds to the security event of "User initiated logoff". For in-depth information on Windows Security Event IDs and their meanings, check out https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-<eventID> (replace <eventID> with the EventID of your choice).
Let's see all the EventIDs and counts:
grep "EventID" logs.xml | \
sed -e 's/<EventID Qualifiers="">//g' | \
sed -e 's.</EventID>..g' | \
sort | uniq -c | sort -k1nr
![]() |
| EventIDs and their frequencies. |
The sed commands trim off the unnecessary parts of the lines to leave only the EventID numbers. So now we have all the EventIDs in the logs, ordered by how frequently they appeared. Let's start from the top:
- EventID 4624 - "An account was successfully logged on." There are 756 of these, most of which likely pertain to legitimate logins. But somewhere in this haystack lies the login event for the password spray victim, so we'll come back to these later.
- EventID 4625 - "An account failed to log on." 212 of these make sense, given the password spray attempt.
- EventID 4769 - "A Kerberos service ticket was requested."
- EventID 4776 - "The computer attempted to validate the credentials for an account."
- EventID 4768 - "A Kerberos authentication ticket (TGT) was requested."
- EventID 4799 - "A security-enabled local group membership was enumerated."
- EventID 4688 - "A new process has been created."
- EventID 4724 - "An attempt was made to reset an account's password."
- EventID 4738 - "A user account was changed."
- EventID 4904 - "An attempt was made to register a security event source."
- EventID 5059 - "Key migration operation."
- EventID 4608 - "Windows is starting up."
- EventID 4647 - "User initiated logoff."
- EventID 4826 - "Boot Configuration Data loaded."
- EventID 4902 - "The Per-user audit policy table was created."
- EventID 5024 - "The Windows Firewall Service has started successfully."
- EventID 5033 - "The Windows Firewall Driver has started successfully."
For this challenge, the events that we're most interested in are the failed and successful logins - EventIDs 4625 and 4624, respectively.
Looking at which users had successful logons:
grep '<EventID Qualifiers="">4624</EventID>' \
-A 20 logs.xml | \
grep '<Data Name="TargetUserName">' | \
sed -e 's/<Data Name="TargetUserName">//g' | \
sed -e 's.</Data>..g' | \
sort | uniq -c | sort -k1nr
![]() |
| Looking at users with successful logins. |
The -A option with grep will print out the specified number of lines after a match - in this case, 20 lines after a match on "<EventID Qualifiers="">4624</EventID>"
The -B option will print out a specified number of lines before the match.
We have a small enough list of users to test through runtoanswer, but let's see if we can narrow things down first. The victim is likely to be the account that logged in during the same timeframe as the password spray attempt. Let's look at the times for all those failed logins.
grep '<EventID Qualifiers="">4625</EventID>' \
-A 10 logs.xml | \
grep '<TimeCreated SystemTime="' | \
sed -e \
's.\(<TimeCreated SystemTime="\)\|\("></TimeCreated>\)..g' \
| sort > failed_login_times
![]() |
| Analyzing the timeframe for the password spray attack. |
It looks like the password spray attempt went from 13:03:33 to 13:05:39. Now we just need to find successful logins during that timeframe.
grep '<EventID Qualifiers="">4624</EventID>' \
-A 25 logs.xml | egrep \
'<TimeCreated SystemTime="2018-09-10 13:0(3|4|5)' \
-A 20 | grep '<Data Name="TargetUserName">' | \
sed -e 's/<Data Name="TargetUserName">//g' \
| sed -e 's.</Data>..g' \
| sort | uniq -c
![]() |
| Successful logins during password spray attack. |
Looks like Minty's account was logged into during the password spray time. The other two accounts don't look like regular user accounts, so it's safe to assume that Minty's account was the victim - let's go ahead and run runtoanswer and submit her account name "minty.candycane".
Success! Talk to Pepper to get hints on Question 6:
Well, that explains the odd activity in Minty's account. Thanks for your help!
All of the Kringle Castle employees have these cool cards with QR codes on them that give us access to restricted areas.
Unfortunately, the badge-scan-o-matic said my account was disabled when I tried scanning my badge.
I really needed access so I tried scanning several QR codes I made from my phone but the scanner kept saying "User Not Found".
I researched a SQL database error from scanning a QR code with special characters in it and found it may contain an injection vulnerability.
I was going to try some variations I found on OWASP but decided to stop so I don't tick-off Alabaster.
Let's get started on objective 6.
Download the sample badge (which looks like Alabaster's badge). Note the QR code at the bottom.
Head over to the authentication panel. The green square on the right looks like a fingerprint scanner (we probably can't bypass that), and the USB port on the bottom right looks like a badge scanner. Click on it to upload a file of your choice - in this case, we'll try Alabaster's badge. Note that the scanner only accepts PNG files, so convert Alabaster's badge to PNG format before uploading it. A successful upload should give you the error message that Alabaster's account has been disabled. Understandable, considering everyone knows that Alabaster lost his badge.
![]() |
| Unable to use Alabaster's badge |
But we could probably use the QR codes to our advantage. The QR code has some encoded information in it, most likely authentication credentials or some unique token/identifier for the specified owner. If the backend authentication system is using SQL to authenticate, then we could try encoding SQL injection attempts with our QR codes. If you completed Pepper's terminal challenge, then her hints point us in this direction.
Let's first test if SQL injection even works on this machine. Head over to a QR code generator (I'm using https://www.qr-code-generator.com/) and make a QR code with a single quote ' for the QR code. Make sure to save it as PNG.
Submit the PNG through the USB port and take note of the error message that comes up:
EXCEPTION AT (LINE 96 "USER_INFO = QUERY("SELECT FIRST_NAME,LAST_NAME,ENABLED FROM EMPLOYEES WHERE AUTHORIZED = 1 AND UID ='{}' LIMIT 1".FORMAT(UID))"): (1064, U"YOU HAVE AN ERROR IN YOUR SQL SYNTAX; CHECK THE MANUAL THAT CORRESPONDS TO YOUR MARIADB SERVER VERSION FOR THE RIGHT SYNTAX TO USE NEAR '''' LIMIT 1' AT LINE 1")
![]() |
| Snippet of error message. |
This error message gives us most of the information we need - the table name and fields to query. It looks like our QR-encoded information is passed in as the UID. If you try injecting:
' OR '1' = '1
then the system will give you the error message:
AUTHORIZED USER ACCOUNT HAS BEEN DISABLED!
This is probably because the system will first pick Alabaster's account, which was disabled. So we'll need to pick an enabled account. I'm going to assume that "1" will represent enabled, just as "1" represents an authorized account. So let's inject the following string:
' OR enabled = 1 and authorized = 1; --
The the final query in the backend will look like:
SELECT FIRST_NAME,LAST_NAME,ENABLED FROM EMPLOYEES WHERE AUTHORIZED = 1 AND UID ='' OR enabled = 1 and authorized = 1; -- ' LIMIT 1
"OR" will execute after "AND", and we want to make sure our account is both authorized and enabled. Make the QR code with our payload and upload it. You should get successful access with control number 19880715!
![]() |
| Control number revealed after successful entry. |
Enter the control number as the answer to question 6.
That's all for this post. I will upload part 3 later for the next set of objectives for the 2018 Holiday Hack. Thank you for joining me on this adventure, and I hope you learned something new!























No comments:
Post a Comment