9 minutes
HuntressCTF: Nightmare on Hunt Street
Another writeup for the HuntressCTF: “Nightmare on Hunt Street”. This is a five-part challenge that dives into Windows Forensics. I managed to questions 1,2,3 and 5 during the event, with the 4th question being solved by my teammate K-Scorpio (shoutout!) on Discord.
Challenge Description
We’re presented with a single ZIP file and the following questions where each question has a flag associated with it.
- What is the IP address of the host that the attacker used?
- How many times was the compromised account brute-forced?
- What is the name of the offensive security tool that was used to gain initial access?
- How many unique enumeration commands were run with net.exe?
- What password was successfully given to the user created?
Solve #1
What is the IP address of the host that the attacker used?
I started out by unzipping the provided file, which produced three Windows event log files:
┌──(kali㉿kali)-[~/huntress]
└─$ unzip logs-parts1-5.zip
Archive: logs-parts1-5.zip
inflating: Application.evtx
inflating: __MACOSX/._Application.evtx
inflating: Security.evtx
inflating: __MACOSX/._Security.evtx
inflating: System.evtx
inflating: __MACOSX/._System.evtx
To solve this challenge, I wanted to use the chainsaw
tool that was shown to me throughout the HackTheBox CDSA learning path. Solving the first question turned out to be quite simple once I got the proper grep
string:
┌──(kali㉿kali)-[~/huntress]
└─$ chainsaw dump Security.evtx | grep 'IpAddress' | sort -u
██████╗██╗ ██╗ █████╗ ██╗███╗ ██╗███████╗ █████╗ ██╗ ██╗
██╔════╝██║ ██║██╔══██╗██║████╗ ██║██╔════╝██╔══██╗██║ ██║
██║ ███████║███████║██║██╔██╗ ██║███████╗███████║██║ █╗ ██║
██║ ██╔══██║██╔══██║██║██║╚██╗██║╚════██║██╔══██║██║███╗██║
╚██████╗██║ ██║██║ ██║██║██║ ╚████║███████║██║ ██║╚███╔███╔╝
╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝
By WithSecure Countercept (@FranticTyping, @AlexKornitzer)
[+] Dumping the contents of forensic artefacts from: Security.evtx (extensions: *)
[+] Loaded 1 forensic artefacts (1.1 MB)
[+] Done
IpAddress: '-'
IpAddress: 10.1.1.42
Seeing as we get one IP address back, 10.1.1.42
, the answer is flag{10.1.1.42}
!
Solve #2
How many times was the compromised account brute-forced?
In order to find how many times the compromised account was brute-forced, we need to know which account was compromised. That’s probably the most redundant sentence you’ve read today. I begin by searching the events for the successful logon and printing the unique associated target usernames. The event ID found for a successful logon event was found through a google search: 4624.
┌──(venv)─(kali㉿kali)-[~/huntress]
└─$ chainsaw dump Security.evtx -j | jq '.[].Event | select(.System.EventID==4624) | .EventData.TargetUserName' | sort -u
██████╗██╗ ██╗ █████╗ ██╗███╗ ██╗███████╗ █████╗ ██╗ ██╗
██╔════╝██║ ██║██╔══██╗██║████╗ ██║██╔════╝██╔══██╗██║ ██║
██║ ███████║███████║██║██╔██╗ ██║███████╗███████║██║ █╗ ██║
██║ ██╔══██║██╔══██║██║██║╚██╗██║╚════██║██╔══██║██║███╗██║
╚██████╗██║ ██║██║ ██║██║██║ ╚████║███████║██║ ██║╚███╔███╔╝
╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝
By WithSecure Countercept (@FranticTyping, @AlexKornitzer)
[+] Dumping the contents of forensic artefacts from: Security.evtx (extensions: *)
[+] Loaded 1 forensic artefacts (1.1 MB)
[+] Done
"Jsmith"
"SYSTEM"
So from the output we know that the Jsmith
account was the only user account to have a successful logon. But the question is how many times was a logon attempted? For that we need to find the event ID associated with a logon attempt, which ends out being 4625.
┌──(venv)─(kali㉿kali)-[~/huntress]
└─$ chainsaw dump Security.evtx -j | jq '.[].Event | select((.System.EventID==4625) and (.EventData.TargetUserName=="Jsmith")) | "found!"' | wc -l
██████╗██╗ ██╗ █████╗ ██╗███╗ ██╗███████╗ █████╗ ██╗ ██╗
██╔════╝██║ ██║██╔══██╗██║████╗ ██║██╔════╝██╔══██╗██║ ██║
██║ ███████║███████║██║██╔██╗ ██║███████╗███████║██║ █╗ ██║
██║ ██╔══██║██╔══██║██║██║╚██╗██║╚════██║██╔══██║██║███╗██║
╚██████╗██║ ██║██║ ██║██║██║ ╚████║███████║██║ ██║╚███╔███╔╝
╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝
By WithSecure Countercept (@FranticTyping, @AlexKornitzer)
[+] Dumping the contents of forensic artefacts from: Security.evtx (extensions: *)
[+] Loaded 1 forensic artefacts (1.1 MB)
[+] Done
32
There’s a lot going on in this command so I’ll break it down:
- chainsaw dump Security.evtx -j
- Output all events in the EVTX file as JSON
| jq '.[].Event | select((.System.EventID==4625) and (.EventData.TargetUserName=="Jsmith")) | "found!"'
- Output all events in the EVTX file as JSON
- Run the JSON parser command in stages:
.[].Event
=> Filter the JSON objects to only include the Event key and valueselect((.System.EventID==4625) and (.EventData.TargetUserName=="Jsmith"))
=> With this filtered JSON we want to filter out any event objects that don’t have failed logon attempts for Jsmith.`| "found!"
=> Instead of outputting any event data for the remaining (matched) events, just output a string, making it easy to count how many events there are with the wc command.`| wc -l
=> Count how many lines were outputted. We know from the jq command that for each matched event we will get a single line of found! being produced.
We see the answer of 32, meaning there were 32 failed logon attempts for Jsmith
in these log files: flag{32}
.
Solve – #3
What is the name of the offensive security tool that was used to gain initial access?
This one was a bit tricky, and at the time of writing is the one with the least amount of solves out of the 5. This is because the answer isn’t actually found in the file itself. The clues are in the file, but it takes some prior experience and pattern recognition to solve.
This was the last one I solved for the whole challenge, so I slightly edited a command that will be shown below in the solution for #5.
┌──(venv)─(kali㉿kali)-[~/huntress]
└─$ chainsaw dump Security.evtx -j | jq '.[].Event | "\(.System.EventID) \(.EventData.CommandLine)"' | grep 4624 -A2
██████╗██╗ ██╗ █████╗ ██╗███╗ ██╗███████╗ █████╗ ██╗ ██╗
██╔════╝██║ ██║██╔══██╗██║████╗ ██║██╔════╝██╔══██╗██║ ██║
██║ ███████║███████║██║██╔██╗ ██║███████╗███████║██║ █╗ ██║
██║ ██╔══██║██╔══██║██║██║╚██╗██║╚════██║██╔══██║██║███╗██║
╚██████╗██║ ██║██║ ██║██║██║ ╚████║███████║██║ ██║╚███╔███╔╝
╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝
By WithSecure Countercept (@FranticTyping, @AlexKornitzer)
[+] Dumping the contents of forensic artefacts from: Security.evtx (extensions: *)
[+] Loaded 1 forensic artefacts (1.1 MB)
[+] Done
"4624 null"
"4627 null"
"4776 null"
--
"4624 null"
"4627 null"
"4688 C:\\Windows\\wgWMRHln.exe"
--
"4624 null"
"4627 null"
"4776 null"
--
"4624 null"
"4627 null"
"4776 null"
--
"4624 null"
"4627 null"
"4688 cmd.exe"
--
"4624 null"
"4627 null"
"4672 null"
--
"4624 null"
"4627 null"
"4688 C:\\Windows\\MrEQbpfX.exe"
--
"4624 null"
"4627 null"
"4776 null"
--
"4624 null"
"4627 null"
"4776 null"
--
"4624 null"
"4627 null"
"4688 powershell.exe"
What I did here was look for the CommandLine
fields that occurred in events immediately following a successful logon (4624). It took some adjusting to see some useful information, but after including 2 events after successful logon we some some strange executables being run.
This is where the previous experience comes into play. A very common way to get a shell on a windows system you have local administrative access to is by using PsExec.
PsExec uses the Microsoft Windows Service Control Manager (SCM) to start an instance of the service on the remote system, which allows the tool to run the specified command or application with the account’s privileges of the service account on the remote system.
PsExec uploads an executable with a random name (to avoid collisions) to the C:\Windows\
directory and starts a Windows service that executes it. Using the SCM to execute it means the executable runs as SYSTEM
, which also explained why there was a logon for SYSTEM
in question #2.
For further evidence we can look for the children processes created by services.exe
and look for these randomly named executables.
┌──(venv)─(kali㉿kali)-[~/huntress]
└─$ chainsaw dump Security.evtx -j | jq '.[].Event | "Parent Proccess: \(.EventData.ParentProcessName) Child Process: \(.EventData.CommandLine)"' | grep -i 'services.exe'
██████╗██╗ ██╗ █████╗ ██╗███╗ ██╗███████╗ █████╗ ██╗ ██╗
██╔════╝██║ ██║██╔══██╗██║████╗ ██║██╔════╝██╔══██╗██║ ██║
██║ ███████║███████║██║██╔██╗ ██║███████╗███████║██║ █╗ ██║
██║ ██╔══██║██╔══██║██║██║╚██╗██║╚════██║██╔══██║██║███╗██║
╚██████╗██║ ██║██║ ██║██║██║ ╚████║███████║██║ ██║╚███╔███╔╝
╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝
By WithSecure Countercept (@FranticTyping, @AlexKornitzer)
[+] Dumping the contents of forensic artefacts from: Security.evtx (extensions: *)
[+] Loaded 1 forensic artefacts (1.1 MB)
[+] Done
"Parent Proccess: C:\\Windows\\System32\\services.exe Child Process: C:\\Windows\\wgWMRHln.exe"
"Parent Proccess: C:\\Windows\\System32\\services.exe Child Process: C:\\Windows\\servicing\\TrustedInstaller.exe"
"Parent Proccess: C:\\Windows\\System32\\services.exe Child Process: C:\\Windows\\MrEQbpfX.exe"
The challenge accepts flag{psexec}
, which took way longer for me to solve than I’d like to admit, since I didn’t notice the challenge asking for the answer in all lowercase…
Solve – #4
How many unique enumeration commands were run with net.exe
?
This question was the one I personally didn’t solve, but I got the answer after the fact. Following the trend of questions #1 and #2, I formed a jq
+ grep
command that looks for CommandLine
fields including the net command.
┌──(venv)─(kali㉿kali)-[~/huntress]
└─$ chainsaw dump Security.evtx -j | jq '.[].Event.EventData.CommandLine' | grep -v null | grep 'net'
██████╗██╗ ██╗ █████╗ ██╗███╗ ██╗███████╗ █████╗ ██╗ ██╗
██╔════╝██║ ██║██╔══██╗██║████╗ ██║██╔════╝██╔══██╗██║ ██║
██║ ███████║███████║██║██╔██╗ ██║███████╗███████║██║ █╗ ██║
██║ ██╔══██║██╔══██║██║██║╚██╗██║╚════██║██╔══██║██║███╗██║
╚██████╗██║ ██║██║ ██║██║██║ ╚████║███████║██║ ██║╚███╔███╔╝
╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝
By WithSecure Countercept (@FranticTyping, @AlexKornitzer)
[+] Dumping the contents of forensic artefacts from: Security.evtx (extensions: *)
[+] Loaded 1 forensic artefacts (1.1 MB)
[+] Done
"net user"
"C:\\Windows\\system32\\net1 user"
"net localgroup"
"C:\\Windows\\system32\\net1 localgroup"
"net share"
"C:\\Windows\\system32\\net1 share"
"netstat -ano"
"net user susan_admin \"SusanIsStrong123\" /ADD"
"C:\\Windows\\system32\\net1 user susan_admin \"SusanIsStrong123\" /ADD"
"\"C:\\Windows\\system32\\net.exe\" user susan_admin SusanIsStrong123 /ADD"
"C:\\Windows\\system32\\net1 user susan_admin SusanIsStrong123 /ADD"
"\"C:\\Windows\\system32\\net.exe\" user"
"C:\\Windows\\system32\\net1 user"
"\"C:\\Windows\\system32\\net.exe\" user susan_admin Susan123! /ADD"
"C:\\Windows\\system32\\net1 user susan_admin Susan123! /ADD"
"\"C:\\Windows\\system32\\net.exe\" localgroup administrators susan_admin /ADD"
"C:\\Windows\\system32\\net1 localgroup administrators susan_admin /ADD"
"\"C:\\Windows\\system32\\net.exe\" users"
"C:\\Windows\\system32\\net1 users"
The question specifically asks for “unique enumeration commands were run with net.exe
”, so we can remove all the commands that aren’t for enumeration, such as the /ADD
commands. Since they’re looking for “unique” commands, we know that net
, net.exe
and net1
are all using the same net.exe
executable, so we will only count the unique invocations: user, users and share.
Therefore the answer is flag{3}
.
Solve – #5
What password was successfully given to the user created?
Question five was actually the easiest of the bunch, and once I realized they didn’t need to be solved in order, I immediately went to solve this one. After a quick google search for the event ID associated with a user being successfully added. I cleaned up the jq
command to be shown cleaner in this post, but I solved the challenge in the same way during the event.
┌──(venv)─(kali㉿kali)-[~/huntress]
└─$ chainsaw dump Security.evtx -j | jq '.[].Event | "\(.System.EventID) \(.EventData.CommandLine)"' | grep -i -B1 -A2 '/ADD'
██████╗██╗ ██╗ █████╗ ██╗███╗ ██╗███████╗ █████╗ ██╗ ██╗
██╔════╝██║ ██║██╔══██╗██║████╗ ██║██╔════╝██╔══██╗██║ ██║
██║ ███████║███████║██║██╔██╗ ██║███████╗███████║██║ █╗ ██║
██║ ██╔══██║██╔══██║██║██║╚██╗██║╚════██║██╔══██║██║███╗██║
╚██████╗██║ ██║██║ ██║██║██║ ╚████║███████║██║ ██║╚███╔███╔╝
╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝
By WithSecure Countercept (@FranticTyping, @AlexKornitzer)
[+] Dumping the contents of forensic artefacts from: Security.evtx (extensions: *)
[+] Loaded 1 forensic artefacts (1.1 MB)
[+] Done
"4689 null"
"4688 net user susan_admin \"SusanIsStrong123\" /ADD"
"4688 C:\\Windows\\system32\\net1 user susan_admin \"SusanIsStrong123\" /ADD"
"4689 null"
"4689 null"
"4688 powershell.exe"
"4688 \"C:\\Windows\\system32\\net.exe\" user susan_admin SusanIsStrong123 /ADD"
"4688 C:\\Windows\\system32\\net1 user susan_admin SusanIsStrong123 /ADD"
"4689 null"
"4689 null"
--
"4689 null"
"4688 \"C:\\Windows\\system32\\net.exe\" user susan_admin Susan123! /ADD"
"4688 C:\\Windows\\system32\\net1 user susan_admin Susan123! /ADD"
"4728 null"
"4720 null"
--
"4689 null"
"4688 \"C:\\Windows\\system32\\net.exe\" localgroup administrators susan_admin /ADD"
"4688 C:\\Windows\\system32\\net1 localgroup administrators susan_admin /ADD"
"4732 null"
"4689 null"
What I did here was put every event’s EventID
and CommandLine
on a single line then grep
for the invocation of net.exe
with the /ADD
flag. The output lets us see groups of events that immediately followed the attempt to add a user. After a quick google search, we find the event ID associated with correctly adding a user is 4720. This tells us that the middle grouping shown above was the successful command, as opposed to the first group. When I first tried this, I only looked for the event ID immediately following the attempt to add a user, which led me to find out event ID 4728 was for a user being successfully added to a group, so I adjusted the grep
command to look for two events following the matched event and saw the expected 4720.
flag{Susan123!}