Security Bulletin: SPLUNK it to detect MOVEit

By Bryan Bollou, Team Lead, Cybersecurity Engineering

Background

On May 31st, 2023, it was announced that there was an expanding occurrence of the MOVEit vulnerability – an application used on over 2.5k servers on the internet. This was a critical vulnerability that could be exploited using SQL injection to do the following: 

  • Obtain a list of all folders, files, and users within MOVEit 
  • Download any file within MOVEit 
  • Insert an administrative backdoor user into MOVEit and give attackers an active session to allow credential bypass 

Since then, a patch has been released that will prevent this exploitation of systems. So, the issue is resolved, right? Absolutely not! We know change management processes can take a while, even in serious situations like this. It may take many cycles before the proper patching is done to your machines to stop this attack. You may have already put in some workarounds to prevent the attack such as disabling ports 80 and 443 on the web servers or some detections to see the exploit. So far, we have seen many good options and would like to present a few specific cases using everyone’s favorite SIEM: Splunk.

Objective

The purpose of this security bulletin is not to fully explain or give recommendations on remediating the vulnerability, as has been discussed at length by various resources such as Progress Community.

Our goal here is to aggregate the detections to maximize your chances of detecting this critical attack. A part of that is gathering the list of IOCs scattered in multiple locations on the internet and looking at activity that could point to the MOVEit vulnerability being exploited. Here at TekStream, we have several security engineers that are intimate with cybersecurity knowledge and especially the logs of our clients.

We will walk you through the various steps in the MOVEit vulnerability exploitation and detection. With this format, we are providing a more generic data model “tstats” command. This is taking advantage of the data model to quickly find data that may match our IOC list. We then provide examples of a more specific search that will add context to the first find. There will be a wide variety of specific searches as each client has their own specific technologies. To get help building detection for your specific client, fill in the form below and get access to our Splunk/security expertise.

The following detection steps mirror the stages and TTP-related indicators used in the attack:

  1. Detect initial malicious file spawning SQL Injections
  2. Search for potential beaconing web traffic containing specific parameters
  3. Detect existence of downloaded malicious script
  4. Detect ancillary signs of malicious script activity
  5. Persistent malicious file install
  6. Detect data exfiltration
  7. Scan for related known malicious IPs
  8. Scan for related known malicious web domain

Detections

Step 1

As part of the exploitation, a backdoor named “human2.aspx” was uploaded to multiple sites, this was a main file responsible for performing the SQL injection and exfiltrate sensitive data. Other executable files leveraged in the attack include:

moveitisapi.dll to perform SQL injection directed by specific headers seen below.

guestaccess.aspx to create a session and grab CSRF tokens and other parameters for more actions.

Actions to Detect
GET /human2.aspx – 443 
POST /moveitisapi/moveitisapi.dll
POST /guestaccess.aspx
GET /human2.aspx

SPL

| tstats `summariesonly` sum("Web.bytes") as bytes,values("Web.http_content_type") as http_content_type,values("Web.http_method") as http_method,values("Web.http_user_agent") as http_user_agent,values("Web.status") as status from datamodel="Web"."Web" where (http_method = GET AND Web.url = "*human2.aspx*") OR (http_method = POST AND Web.url = "*/moveitisapi/moveitisapi.dll*") OR (http_method = POST AND Web.url = "*/guestaccess.aspx*") OR (http_method = GET AND Web.url = "*/human2.aspx") by "Web.src", "Web.dest", "Web.user", "Web.url", _time | fields _time src, dest, user, url, http_content_type, http_method, http_user_agent, status, bytes | fieldformat Time = strftime(_time,"%m/%d/%Y %T")

Step 2

In the backdoor code, there is a check for specific parameters that will tell the malicious script what action to perform. Looking for the specific string of this request could be used to detect attempts to exploit the MOVEit Vulnerability. Search for web requests that contain any of the request or response headers listed below:

Parameters to Detect
X-siLock-Step1
X-siLock-Comment
X-siLock-Step2
X-siLock-Step3

SPL

| tstats `summariesonly` sum("Web.bytes") as bytes,values("Web.http_content_type") as http_content_type,values("Web.http_method") as http_method,values("Web.http_user_agent") as http_user_agent,values("Web.status") as status from datamodel="Web"."Web" where Web.url = "*X-siLock-Step1*" OR Web.url = "*X-siLock-Comment*" OR Web.url = "*X-siLock-Step2*" OR Web.url = "*X-siLock-Step3*" by "Web.src", "Web.dest", "Web.user", "Web.url", _time | fields _time src, dest, user, url, http_content_type, http_method, http_user_agent, status, bytes | fieldformat Time = strftime(_time,"%m/%d/%Y %T")

Step 3

As mentioned above, depending on the parameters supplied, the malicious script can do multiple actions. Some include creating a backdoor user or deleting it. The account is called “Health Check Service” and doing searches for the existence of the user in a MOVEit database, or any account activity would help in detecting the exploit.

Activity to Detect
IF X-siLockStep1 = -2
A backdoor user called Health Check Service is removed from the users table, potentially as a method to cover tracks.

IF X-siLockStep1 = null AND X-siLock-Step2 = null AND X-siLock-Step3 = null
The malicious script creates an administrative user named Health Check Service in the users table. It also creates and inserts a new active session for this user into the application.

SPL

| tstats `summariesonly` latest(_time) as _time from datamodel="Change"."All_Changes" where nodename="All_Changes.Account_Management" (All_Changes.user="Health Check Service" OR All_Changes.src_user="Health Check Service") by "All_Changes.action", "All_Changes.src", "All_Changes.Account_Management.src_user", "All_Changes.dest", "All_Changes.user"  | fields _time, action, src, src_user, dest, user
| fieldformat Time = strftime(_time,"%m/%d/%Y %T")

Step 4

Like the above, with different parameters, the malicious script looks to enumerate information about the targeted MOVEit instances. It uses a malformed Azure account that can be detected.

Activity to Detect

IF X-siLockStep1 = -1
The script will attempt to leak Azure information via the response header and return a GZIP stream of all files, file owners and file sizes, and institution data present in MOVEit instance. Account to Detect- azureAccout

SPL

index=azure (sourcetype="azure:aad:audit" "initiatedBy.user"=" azureAccout") OR (sourcetype="azure:aad:signin" userPrincipalName=" azureAccout ")

Step 5

The posting of the malicious file “human2.aspx” will add the file to the C:\MOVEitTransfer\wwwroot\ directory on the MOVEit instance. This filesystem path is based on install locations and can vary (for example it can be E drive). The detections here are to detect any files that are created in these vulnerable locations.

File and File Location to Monitor

:\MOVEitTransfer\wwwroot\
 human2.aspx
 App_Web_*.dll

SPL

| tstats `summariesonly` latest(_time) as _time, latest(Filesystem.file_create_time) as file_create_time, latest(Filesystem.file_modify_time) as file_modify_time, latest(Filesystem.file_access_time) as file_access_time from datamodel="Endpoint"."Filesystem", values(Filesystem.dest) as dest, values(Filesystem.action) as action, values(Filesystem.file_name) as file_name, values(Filesystem.file_hash) as file_hash, values(Filesystem.file_path) as file_path, values(Filesystem.file_size) as file_size where (Filesystem.file_name = "*human2.aspx" OR Filesystem.file_name = "*App_Web_*.dll" OR Filesystem.file_path = "*:\MOVEitTransfer\wwwroot\*") | fields _time, dest, action, file_name, file_hash, file_path, file_size, file_create_time, file_modify_time, file_access_time
| fieldformat Time = strftime(_time,"%m/%d/%Y %T")

Step 6

Detecting the exfiltration of data is another way to find out if a bad actor is exploiting the MOVEit vulnerability. Examine firewall logs for large outbound network transfers from the MOVEit environment. 

IPs and Volume to Detect

IPs – these will be your MOVEit Instance IPs
Volume in bytes – this will depend on time (defaulted to 1 hour in this detection) and what is considered abnormally high volume in your environment (default to 1MB in this detection).

SPL

| tstats `summariesonly` values(_time) as _time, sum("All_Traffic.bytes") as bytes, values("All_Traffic.src_port") as src_port, values("All_Traffic.transport") as transport, values("All_Traffic.dest_port") as dest_port from datamodel="Network_Traffic"."All_Traffic", values("All_Traffic.action") as action where All_Traffic.src="[INSERT MOVEit INSTANCES IPS]” AND All_Traffic.action !=blocked AND All_Traffic.dest_category !=internal AND All_Traffic.bytes > 1000
 by  "All_Traffic.dest" , "All_Traffic.user", "All_Traffic.src", _time span=1h
| rename "All_Traffic.dest" as dest, "All_Traffic.user" as user, "All_Traffic.src" as src
| table_time, action, src, src_port, dest, transport, dest_port, user, bytes
| fieldformat Time = strftime(_time,"%m/%d/%Y %T") 

Step 7

There are several IP addresses that have been associated with the exploitation of the MOVEit vulnerability. TekStream has consolidated a list of these IOCs from numerous sources on the internet. These IOCs can be added to a lookup table and used in the detection below.

TekStream MOVEit IOC List

This CSV has the list of the IOCs at the time of this blog post being written – for a more updated version and/or information on how to build the lookup in the detection, please contact a TekStream consultant below.

Search firewall and MOVEit IIS logs for requests from any of the IP addresses specified within the IOCs below.

IPs To Detect

In this case, you will look for any and all of the IP’s on the TekStream MOVEit IOC List

SPL

| tstats `summariesonly` values(_time) as _time, sum("All_Traffic.bytes") as bytes, values("All_Traffic.src_port") as src_port, values("All_Traffic.transport") as transport, values("All_Traffic.dest_port") as dest_port from datamodel="Network_Traffic"."All_Traffic", values("All_Traffic.action") as action
 by  "All_Traffic.dest" , "All_Traffic.user", "All_Traffic.src"
| rename "All_Traffic.dest" as dest, "All_Traffic.user" as user, "All_Traffic.src" as src
| eval allips = mvappend(src, dest)
| inputlookup TS_MOVEit_IPs_List.csv | fields ip | rename ip as allips
| table_time, action, src, src_port, dest, transport, dest_port, user, bytes
| fieldformat Time = strftime(_time,"%m/%d/%Y %T")

Step 8

There is a domain associated with the MOVEit vulnerability and it is detectable with the logic below.

Domain to Detect

dojustit[.]mooo[.]com

SPL

| tstats `summariesonly` latest(_time) as _time  values("DNS.dest") as dest, values("DNS.query") as query, values("DNS.query_count") as query_count, values("DNS.message_type") as message_type, values("DNS.answer") as answer, values("DNS.reply_code") as reply_code from datamodel="Network_Resolution"."DNS" where DNS.query="dojustit[.]mooo[.]com" | table _time, dest, query, query_count, message_type, answer, reply_code | fieldformat Time = strftime(_time,"%m/%d/%Y %T")

IOC List

Below is an aggregate of IOCs found related to the MOVEit vulnerability. It has been presented here for you to have it consolidated in one spot and made easier to export to a lookup for notable detections.

TekStream MOVEit IOC List

Conclusion

Ideally, you could make scheduled searches like what is shown above with lookup tables for matching more specific and new detections. These can be set to run on a continuous schedule to ensure the monitoring of your assets from new vulnerabilities. Old vulnerabilities that have been patched (and applied) can also be aged out of this lookup table to ensure it is timely and efficient. For questions on how to build such a process that is dynamic and customizable for your environment, ask one of our consultants by filling in the form below.

References

Articles referenced and used for this post: Trusted SEC, Huntress, Progress Community

Disclaimer: The approaches recommended herein have not been tested broadly across the TekStream customer base. They are preliminary in nature and come without any certification of efficacy.

We are available to assist if you have any questions, just contact us here: