This post is also available in: 日本語 (Japanese)
SolarStorm Response With Cortex XDR
Customers running Cortex XDR Pro can leverage the product's existing alert sets and hunt for related activity.
Please note that the Cortex XDR Managed Threat Hunting Service scanned all data available for all XDR Pro customers – even those who are not currently subscribed to the service – and sent an impact report based on the findings to all XDR Pro customers.
Firstly, to understand if the organization is breached, we can search for SolarWinds installations based either on endpoint or network data using the following query, leveraging AppID and known SolarWinds domains (For updated and copy/paste-friendly versions, all queries described in this section are available on GitHub.):
1 2 3 4 |
dataset = xdr_data|filter arraystring(action_app_id_transitions, ",") contains "solarwinds" or dst_action_external_hostname = "api.solarwinds.com" or action_external_hostname = "api.solarwinds.com"| fields agent_hostname, action_local_ip|dedup agent_hostname, action_local_ip |
To verify if you have been a victim of the attack, assuming there is a Palo Alto Networks NGFW or an agent installed on a SolarWinds server, you can run a query to check for known IOCs.
It’s possible to load known IOCs, such as IPs, domains, hashes and filenames, into XDR and it will automatically run a backwards scan, resulting in alerts on historic data.
To do this, create one file with all the IOCs:
Go to the Rules → IOC page and click on “+ Add IOC” and then select “Upload File” in the popup view.
Add your file, assign a severity, reputation, reliability and expiration date, then click “Upload.”
After loading, you’ll see the “Backwards Scan Status” as pending and “# Of Hits” as 0. A few minutes later, you’ll see the status change to “Done” with a timestamp.
If any matches were found, you’ll see the “# Of Hits” change from 0 to the amount of hits the system found per IOC.
You can right-click on the IOC and select “View Associated Alerts” to pivot to the alert page.
Whenever you see this icon next to a rule name in XDR, it means that this is a historic match based on backwards scanning on an IOC or Behavioral IOC.
You can right-click on the alert to analyze it and drill down into it.
Vice versa, you can run an XQL query with the known IOCs. This will look across file writes, module loads, process executions, network traffic and DNS queries coming either through NGFW, Cortex Agent or any third party network traffic that is ingested into the Cortex XDR Data Lake:
1 2 3 4 5 6 |
dataset = xdr_data|filter action_file_sha256 in ("32519b85c0b422e4656de6e6c41878e95fd95026267daab4215ee59c107d6c77", "dab758bf98d9b36fa057a66cd0284737abf89857b73ca89280267ee7caf62f3b", "eb6fab5a2964c5817fb239a7a5079cabca0a00464fb3e07155f28b0a57a2c0ed", "c09040d35630d75dfef0f804f320f8b3d16a481071076918e9b236a321c1ea77", "ac1b2b89e60707a20e9eb1ca480bc3410ead40643b386d624c5d21b47c02917c", "019085a76ba7126fff22770d71bd901c325fc68ac55aa743327984e89f4b0134", "ce77d116a074dab7a22a0fd4f2c1ab475f16eec42e1ded3c0b0aa8211fe858d6", "a25cadd48d70f6ea0c4a241d99c5241269e6faccb4054e62d16784640f8e53bc", "d3c6785e18fba3749fb785bc313cf8346182f532c59172b69adfb31b96a5d0af", “118189f90da3788362fe85eafa555298423e21ec37f147f3bf88c61d4cd46c51”) or action_module_sha256 in ("32519b85c0b422e4656de6e6c41878e95fd95026267daab4215ee59c107d6c77", "dab758bf98d9b36fa057a66cd0284737abf89857b73ca89280267ee7caf62f3b", "eb6fab5a2964c5817fb239a7a5079cabca0a00464fb3e07155f28b0a57a2c0ed", "c09040d35630d75dfef0f804f320f8b3d16a481071076918e9b236a321c1ea77", "ac1b2b89e60707a20e9eb1ca480bc3410ead40643b386d624c5d21b47c02917c", "019085a76ba7126fff22770d71bd901c325fc68ac55aa743327984e89f4b0134", "ce77d116a074dab7a22a0fd4f2c1ab475f16eec42e1ded3c0b0aa8211fe858d6", "a25cadd48d70f6ea0c4a241d99c5241269e6faccb4054e62d16784640f8e53bc", "d3c6785e18fba3749fb785bc313cf8346182f532c59172b69adfb31b96a5d0af", “118189f90da3788362fe85eafa555298423e21ec37f147f3bf88c61d4cd46c51”) or action_process_image_sha256 in ("32519b85c0b422e4656de6e6c41878e95fd95026267daab4215ee59c107d6c77", "dab758bf98d9b36fa057a66cd0284737abf89857b73ca89280267ee7caf62f3b", "eb6fab5a2964c5817fb239a7a5079cabca0a00464fb3e07155f28b0a57a2c0ed", "c09040d35630d75dfef0f804f320f8b3d16a481071076918e9b236a321c1ea77", "ac1b2b89e60707a20e9eb1ca480bc3410ead40643b386d624c5d21b47c02917c", "019085a76ba7126fff22770d71bd901c325fc68ac55aa743327984e89f4b0134", "ce77d116a074dab7a22a0fd4f2c1ab475f16eec42e1ded3c0b0aa8211fe858d6", "a25cadd48d70f6ea0c4a241d99c5241269e6faccb4054e62d16784640f8e53bc", "d3c6785e18fba3749fb785bc313cf8346182f532c59172b69adfb31b96a5d0af", “118189f90da3788362fe85eafa555298423e21ec37f147f3bf88c61d4cd46c51”) or dst_action_external_hostname ~= ".*freescanonline.com|.*deftsecurity.com|.*thedoccloud.com|.*websitetheme.com|.*highdatabase.com|.*incomeupdate.com|.*databasegalore.com|.*panhardware.com|.*zupertech.com|.*virtualdataserver.com|.*digitalcollege.org|.*avsvmcloud.com|.*solartrackingsystem.net|.*webcodez.com|.*seobundlekit.com|.*virtualwebdata.com|.*lcomputers.com|.*mobilnweb.com|.*kubecloud.com" or action_external_hostname ~= ".*freescanonline.com|.*deftsecurity.com|.*thedoccloud.com|.*websitetheme.com|.*highdatabase.com|.*incomeupdate.com|.*databasegalore.com|.*panhardware.com|.*zupertech.com|.*virtualdataserver.com|.*digitalcollege.org|.*avsvmcloud.com|.*solartrackingsystem.net|.*webcodez.com|.*seobundlekit.com|.*virtualwebdata.com|.*lcomputers.com|.*mobilnweb.com|.*kubecloud.com" or dns_query_name ~= ".*freescanonline.com|.*deftsecurity.com|.*thedoccloud.com|.*websitetheme.com|.*highdatabase.com|.*incomeupdate.com|.*databasegalore.com|.*panhardware.com|.*zupertech.com|.*virtualdataserver.com|.*digitalcollege.org|.*avsvmcloud.com|.*solartrackingsystem.net|.*webcodez.com|.*seobundlekit.com|.*virtualwebdata.com|.*lcomputers.com|.*mobilnweb.com|.*kubecloud.com" | fields agent_hostname, causality_actor_process_image_path, actor_process_image_path,action_external_hostname, action_file_path, action_module_path, dst_action_external_hostname, dns_query_name |dedup agent_hostname, causality_actor_process_image_path, actor_process_image_path,action_external_hostname, action_file_path, action_module_path, dst_action_external_hostname, dns_query_name |
As attackers might have used different domains and hashes, we suggest hunting for behavior from the infected SolarWinds executable in addition to searching for known IOCs.
We suggest using the following queries to verify that no suspicious activity took place:
1. Look at alerts and incidents that have any SolarWinds binary attached to them or any alerts related to Cobalt Strike, as these attackers have been seen using the framework:
2. Look for binary and scripting files dropped from the infected SolarWinds process:
1 2 3 4 5 6 7 |
dataset = xdr_data|filter event_type = FILE and event_sub_type = FILE_WRITE and lowercase(actor_process_image_name) = “solarwinds.businesslayerhost*.exe” and action_file_extension in (“dll”, “exe”, “sys”, “msi”, “scr”, “ocx”, “cmd”, “bat”, “ps1”, “vba”, “vbs”, “com”, “cpl”, “bin”, “vbe”)| fields causality_actor_process_image_path, actor_process_image_path, agent_hostname, action_file_path, action_file_name|dedup causality_actor_process_image_path, actor_process_image_path, agent_hostname, action_file_name |
3. Look for signs of the infected SolarWinds process accessing non-SolarWinds domains:
1 2 3 4 5 6 |
dataset = xdr_data|filter event_type = NETWORK and lowercase(actor_process_image_name) = "solarwinds.businesslayerhost*.exe" and action_external_hostname not contains "solarwinds.com" and action_external_hostname != "*.local" | fields causality_actor_process_image_path, actor_process_image_path, agent_hostname, action_remote_ip, action_external_hostname|dedup causality_actor_process_image_path, actor_process_image_path, agent_hostname, action_remote_ip, action_external_hostname |
4. Look for the infected SolarWinds process running Windows Management Instrumentation queries:
1 2 3 4 |
dataset = xdr_data|filter event_type = RPC_CALL and lowercase(actor_process_image_name) = "solarwinds.businesslayerhost*.exe" and action_rpc_interface_name = "IWbemServices"|fields agent_hostname, action_rpc_func_str_call_fields |
5. Look for the infected SolarWinds process modifying or creating a service:
1 2 3 4 5 6 7 |
dataset = xdr_data|filter event_type = REGISTRY and lowercase(actor_process_image_name) = "solarwinds.businesslayerhost*.exe" and action_registry_key_name = "HKEY_LOCAL_MACHINE\SYSTEM\*\Services\*" | fields causality_actor_process_image_path, actor_process_image_path, agent_hostname, action_registry_key_name, action_registry_value_name, action_registry_data |dedup causality_actor_process_image_path, actor_process_image_path, agent_hostname, action_registry_key_name, action_registry_value_name, action_registry_data |
6. We can hunt down backdoored DLLs which initiated network connections and look for any suspicious connection that involves DGA domains:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
dataset = xdr_data | filter (event_type = NETWORK or event_type = STORY) and lowercase(actor_process_image_name) contains "solarwinds.businesslayerhost" | filter action_external_hostname not contains "solarwinds" and action_external_hostname not contains ".local" | fields agent_hostname, agent_id, actor_process_instance_id, actor_process_image_name, action_external_hostname, dst_action_external_hostname, dns_query_name | join (dataset = xdr_data | filter event_sub_type = LOAD_IMAGE_MODULE and action_module_sha256 in ("019085a76ba7126fff22770d71bd901c325fc68ac55aa743327984e89f4b0134", "32519b85c0b422e4656de6e6c41878e95fd95026267daab4215ee59c107d6c77", "ce77d116a074dab7a22a0fd4f2c1ab475f16eec42e1ded3c0b0aa8211fe858d6") and lowercase(actor_process_image_name) contains "solarwinds.businesslayerhost" | fields agent_hostname, agent_id, actor_process_instance_id, actor_process_image_name, action_module_sha256, action_module_path) as modules modules.actor_process_instance_id = actor_process_instance_id and modules.agent_id = agent_id | fields agent_hostname, agent_id, actor_process_instance_id, actor_process_image_name, action_module_sha256, action_module_path, action_external_hostname, dst_action_external_hostname, dns_query_name | dedup agent_hostname, agent_id, actor_process_instance_id, actor_process_image_name, action_module_path, action_external_hostname, dst_action_external_hostname, dns_query_name |
7. Hunt based on the known backdoor named pipe:
1 2 3 4 5 6 7 |
dataset = xdr_data | filter action_file_device_type = 1 and action_file_name != null and lowercase(actor_process_image_name) contains "solarwinds.businesslayerhost" | filter action_file_name = "583da945-62af-10e8-4902-a8f205c72b2e" | fields agent_hostname, actor_process_instance_id, actor_process_image_name, action_file_name | dedup actor_process_instance_id, actor_process_image_name, action_file_name |
XDR 2.6.5, the latest release, now opens up new abilities to query Azure Active Directory (AD) audit logs to hunt for activities that the threat actor has done after gaining access and leveraging the backdoor to get credentials. You can use the following queries to hunt for such activity assuming you have configured your XDR using our admin guide:
1. Hunt for Azure AD service account created or modified:
1 2 3 |
preset = msft_azure_ad_audit // go over azure ad audit logs | filter activityDisplayName IN ("Add service principal credentials", "Add service principal") AND result = "success" // find cases where someone adds SPNs to an account |
2. Hunt for Azure AD application sharing with additional tenants:
1 2 3 4 5 |
preset = msft_azure_ad_audit // go over azure ad audit logs | filter activityDisplayName = "Update application" AND operationType="Update" and result="success" and modifiedDisplayName = "AvailableToOtherTenants" // find cases where someone grants permission to access an app from another azure ad tenant |
3. Hunt for Azure AD custom unverified domain was added:
1 2 3 |
preset = msft_azure_ad_audit // go over azure ad audit logs | filter activityDisplayName = "Add unverified domain" AND result = "success" // find cases where someone added a custom domain to the azure ad env |
4. Hunt for SSO being disabled for a domain:
1 2 3 |
preset = msft_azure_ad_audit // go over azure ad audit logs | filter activityDisplayName = "Disable Desktop Sso for a specific domain" AND result = "success" // remove need for SSO on desktop devices |
5. Hunt for domain federation settings modified:
1 2 |
preset = msft_azure_ad_audit // go over azure ad audit logs | filter activityDisplayName = "Set federation settings on domain" |
6. Hunt for cases where mail permissions were added to a service principal:
1 2 3 4 5 6 |
preset = msft_azure_ad_audit // go over azure ad audit logs | filter activityDisplayName IN ("Add app role assignment to service principal", "Add delegated permission grant", "Add application" ) and modifiedPropertyNewValue ~= "(Mail.Read|Mail.ReadWrite)" and modifiedPropertyOldValue not contains "Mail.Read" // find cases where mail read was added as a permission to another account |
These queries are also waiting in our query center for easy execution:
(See the Appendix for IOCs, or find them on GitHub.)
SolarStorm Response With Cortex XSOAR
Cortex XSOAR has launched a rapid response playbook to speed up the discovery of SolarWind installations within your network, uncover signs of a potential SolarStorm activity and automate response actions such as the quarantining of compromised endpoints.
Continue reading: Conclusion, Additional Resources and IOCs