This post is a write-up or clues on how to resolve the KC7 investigation case of SANS Holiday Hack Challenge 2024 The Great Elf Conflict . You can use it as a helpful guide when encountering an obstacle or trying to understand a question. Different ways to answer questions might exist, so feel free to explore your path.
Section 1: KQL 101
You got it š¾
Section 2: Section 2: Operation Surrender Alabaster’s Espionage
Question 1:
surrender
Question 2: Who was the sender of the phishing email that set this plan into motion?
The question had the hind, which is surrender. Using that keyword in our search, we can identify the sender’s email address in the phishing attack.
Email
| where subject contains "surrender"
| distinct sender
Question 3: What was the filename of the document that Team Alabaster distributed in their phishing email?
Email
| where subject contains "surrender"
| distinct recipient
| count
Question 4: What was the filename of the document that Team Alabaster distributed in their phishing email?
Email
| where subject contains "surrender"
| extend FilePath = (parse_url(link).Path)
| extend FileName = tostring(split(FilePath, "/")[-1])
| distinct link, FileName
Line 3: | extend FilePath = (parse_url(link).Path)
This line creates a new column called FilePath
. The parse_url(link)
function is used to break down the link field into its components. The .Path
property retrieves the path part of the URL. The result is stored in the FilePath column.
Line 4: | extend FileName = tostring(split(FilePath, "/")[-1])
This line creates another new column called FileName. Here’s what happens in this line:
split(FilePath, "/")
splits theFilePath
string into an array of substrings using the / character as the delimiter. For example, ifFilePath
is/public/share/images/Team_Wombley_Surrender.doc
, the result of the split would be an array like["", "public", "share", "images", "Team_Wombley_Surrender.doc"]
.[-1]
accesses the last element of that array, which is the file name (Team_Wombley_Surrender.doc
in this case).tostring(...)
ensures that the result is explicitly cast to a string type, which is important for further operations like distinct.
Question 5: Who was the first person from Team Wombley to click the URL in the phishing email?
You got it š¾
Question 6: What was the filename that was created after the .doc was downloaded and executed?
First, find the timestamp
when the .doc file was downloaded to Joyelle Tinseltoe’s host.
ProcessEvents
| where process_commandline contains "Team_Wombley_Surrender.doc"
| where hostname == "Elf-Lap-W-Tinseltoe"
Then, find all events after the timestamp
.
ProcessEvents
| where timestamp >= datetime(2024-11-27T14:12:44Z)
| where hostname == "Elf-Lap-W-Tinseltoe"
| project process_commandline
Question 7: Enter your flag to continue
You got it š¾
Section 3: Operation Snowfall: Team Wombley’s Ransomware Raid
Question 1:
snowfall
Question 2: What was the IP address associated with the password spray?
You got it š¾
Hit: IP address with the top failed login attempts.
Question 3: How many unique accounts were impacted where there was a successful login from 59.171.58.12?
The question provided us with the activities of interest, and we can confirm which strings to filter in the result
column by getting a distinct
list of the logged activities. Ā
AuthenticationEvents
| distinct result
Let’s put the a missing pieces together.
AuthenticationEvents
| where src_ip == "59.171.58.12"
| where result == "Successful Login"
| distinct username
| count
Question 4: What service was used to access these accounts/devices?
You got it š¾
Hint: Did you look at the image? Did you check the description?
AuthenticationEvents
| where src_ip == "59.171.58.12"
| where result == "Successful Login"
Question 5: What file was exfiltrated from Alabasterās laptop?
The question gave us a hint about checking the ProcessEvents
table. Let’s take a look at the information in the table.
ProcessEvents
| take 10
Okay! We will need the hostname
and the username
by analyzing the logs.
First, let’s find Alabasterās information from the Employees
table.
Employees
| where name contains "Alabaster"
hostname
:Elf-Lap-A-Snowball
username
:alsnowball
Then, let’s check what logs we recorded for the hostname
.
ProcessEvents
| where hostname has "Elf-Lap-A-Snowball"
The results show 25 activities which could be investigated easily. However, the instructions recommend using a timestamp
to filter the results.
The IP address associated with the password spray is 59.171.58.12
, and the victim username is identified as snowball.
AuthenticationEvents
| where src_ip == "59.171.58.12"
| where result == "Successful Login"
| where username == "alsnowball"
Perfect! We have our time stamp and it is time to analyze the log activities in the process_commandline
.
ProcessEvents
| where hostname has "Elf-Lap-A-Snowball"
| where timestamp > datetime(2024-12-11T01:39:50Z)
Question 6: What is the name of the malicious file that was run on Alabaster’s laptop?
Using the query we built from question 5 and investigating the activities in the process_commandline
, we can locate the command line executing the ransomware.
ProcessEvents
| where hostname has "Elf-Lap-A-Snowball"
| where timestamp > datetime(2024-12-11T01:39:50Z)
Question 7: Enter your flag to continue
You got it š¾
Section 4: Echoes in the Frost: Tracking the Unknown Threat
Question 1:
stay frosty
Question 2: What was the timestamp of first phishing email about the breached credentials received by Noel Boetie?
Let’s find Noel Boetie from the Employees
table.
Employees
| where name contains "Noel Boetie"
Let’s find the email.
Email
| where recipient == "noel_boetie@santaworkshopgeeseislands.org"
| where subject contains "credentials"
| top 1 by timestamp asc
Question 3: When did Noel Boetie click the link to the first file?
This activity should be logged in the OutboundNetworkEvents
table. By doing take 10
, we will identify the columns we can filter on to locate the timestmap
of the activity.
OutboundNetworkEvents
| take 10
Okay, we can use the url
and filter our results.
OutboundNetworkEvents
| where url contains "https://holidaybargainhunt.io/published/files/files/echo.exe"
Question 4: What was the IP for the domain where the file was hosted?
The list of the available tables shows a table named PassiveDns
.
PassiveDns
| where domain contains "holidaybargainhunt.io"
Question 5: Letās take a closer look at the authentication events. I wonder if any connection events from 182.56.23.122. If so what hostname was accessed?
The AuthenticationEvents
table will log this activity. By running this query, we can identify the hostname
.
AuthenticationEvents
| where src_ip == "182.56.23.122"
Question 6: What was the script that was run to obtain credentials?
ProcessEvents
| where hostname contains "WebApp-ElvesWorkshop"
Hint: Invoke-********.ps1
Question 7: What is the timestamp where Noel executed the file?
In question 3, we found out when Noel clicked the link to download the file. Let’s get the ‘ProcessEvents’ activities after that time.
ProcessEvents
| where hostname contains "Elf-Lap-A-Boetie"
| where timestamp > datetime(2024-12-12T15:13:55Z)
Question 8: What domain was the holidaycandy.hta
file downloaded from?
OutboundNetworkEvents
| where url contains "holidaycandy.hta"
Question 9: what was the first file that was created after extraction?
Starting from our query in question 7 start analyzing process_commandline
to identify the file.
ProcessEvents
| where hostname contains "Elf-Lap-A-Boetie"
| where timestamp > datetime(2024-12-12T15:13:55Z)
Question 10: What is the name of the property assigned to the new registry key?
Continue analyzing the results from question 9.
Question 11: To obtain your FINAL flag use the KQL below with your last answer!
You got it š¾