In this post we will try to emphasize the importance of not only looking for MITRE ATT&CK TTPs in an attempt to flesh out adversaries, but also consider the role corporate employees play as the human element in the cyber-breach equation.
Yes - the employees which were given permissions to, and who we trust with virtually every piece of information within our organization. Those employees can easily be used against the organization, knowingly or inadvertently. Below, we outline popular insider use cases with their matching Cortex XDR XQL queries, which you can implement in your day-to-day hunting routine.
Here’s a fairly popular use case: an admin needs to access a certain file or service legitimately ,however, their non-admin user has no access to it.
What would the admin do?
We can already envision most of the admins reading this post trying to hide a sly smile on their face while reading option 3.
The real problem with option 3 is that you are now logged in with your admin account on a machine that is more exposed to threats than your Domain Controller for example. Your admin account kerberos ticket now resides within memory and is vulnerable to multiple techniques that can be exploited by threat actors for elevation/lateral movement.
This is why the Cortex Managed Threat Hunting team has created the following query to assist you in locating workstations that are logged in with both admin/non-admin accounts in your organization.
config case_sensitive = false |//Setting the query to be case-insensitive.
dataset = xdr_data // Using the xdr dataset |filter event_type = PROCESS and event_sub_type = PROCESS_START and actor_effective_username not contains"system" and actor_effective_username not contains "network service" and actor_effective_username not contains "local service" and actor_effective_username not contains "DWM" and actor_effective_username not contains "_tmp" | fields agent_hostname as Hostname, actor_effective_username as Username | join (dataset = xdr_data |filter event_type = PROCESS and causality_actor_process_image_name ="explorer.exe" and actor_effective_username contains "adm") as AdminHosts Hostname = AdminHosts.agent_hostname | dedup Hostname ,Username | sort asc Hostname, asc Username |
A few notes regarding the query:
Tips for query enhancement:
This query will assist you in targeting those admin users who are possibly abusing their admin accounts on their corporate machines rather than using them to perform administrative tasks only.
Our recommendations in this case are as follows:
Cloud storage is becoming more affordable these days, and most organizations prefer using corporate cloud storage over traditional on-prem ones.
With that said, have you ever thought about a user that is logging into their own cloud account and syncing corporate files to it?
Part of the Cortex Managed Threat Hunting team tasks is to watch for anomalies in terms of uploads that are going into the cloud, essentially leaving the organization with no control of them.
(Unlike other queries mentioned above, this query would have to include a few manipulations to match your organization)
config case_sensitive = false |
dataset = xdr_data // Using the xdr dataset | filter event_type = NETWORK and (actor_process_image_name contains "googledrive" or actor_process_image_name contains "onedrive" or actor_process_image_name contains "dropbox" or actor_process_image_name contains "baidu") and (action_external_hostname != "") | fields action_upload, action_remote_ip as remote_ip, action_external_hostname as remote_hostname, actor_process_image_name as process_name, actor_causality_id, actor_process_image_sha256 as sha_256, agent_hostname as Hostname, actor_effective_username as Username // Selecting the relevant fields | join (dataset = xdr_data // Using the xdr dataset | filter event_type = NETWORK and (actor_process_image_name contains "googledrive" or actor_process_image_name contains "onedrive" or actor_process_image_name contains "dropbox" or actor_process_image_name contains "baidu") and (action_external_hostname != "") | fields action_upload, action_remote_ip as remote_ip, action_external_hostname as remote_hostname, actor_process_image_name as process_name, actor_causality_id, actor_process_image_sha256 as sha_256, agent_hostname as Hostname, actor_effective_username as Username // Selecting the relevant fields | join (dataset = xdr_data | filter event_type = NETWORK and (actor_process_image_name contains "googledrive" or actor_process_image_name contains "onedrive" or actor_process_image_name contains "dropbox" or actor_process_image_name contains "baidu") and (action_external_hostname != "") | fields action_upload, action_remote_ip as remote_ip, action_external_hostname as remote_hostname, actor_process_image_name as process_name, actor_causality_id, actor_process_image_sha256 as sha_256, agent_hostname as Hostname, actor_effective_username as Username // Selecting the relevant fields | comp sum(action_upload) as total_upload by process_name, remote_hostname, Hostname , Username // Summing the total upload by process + ip + host |filter total_upload > 104857600) as Uploading_Agents Hostname = Uploading_Agents.Hostname | comp count(Username) as counter by process_name, remote_hostname, Hostname // Summing the total upload by process + ip + host | sort asc counter) as Upload_agent Hostname = Upload_agent.Hostname | comp sum(action_upload) as total_upload by process_name, remote_hostname, Hostname , Username // Summing the total upload by process + ip + host | sort desc total_upload // Sorting by total upload |
A few notes regarding the query:
Tips for query enhancement:
Our recommendations in this case are as follows:
Let’s face it. When it comes to password management, collectively we have a problem. Not only do we have too many passwords to remember, but those passwords are getting more complex, and more restrictive. It’s pretty clear to all of us in the industry that these policies are needed, however, not so much for our users with all the cumbersome requirements around password policies.
Hence in an attempt to keep track of all of them, a user will go on and create an innocent file called “passwords.txt” or “passwords.docx” to store all of their passwords in a single place for future reference. The more sophisticated users will even make password protected files.
The fundamental problem here actually relies on us, the security professionals who failed in educating the user on WHY is it so dangerous to store those credentials in plain text. But I guess properly educating users to Security Awareness is a topic for another post so I’ll just say it once:
“Saying ‘Don’t’ to a user is great, Saying ‘Don’t’ to a user and explaining why is far better!”
So the user has created this file, yet why is it so risky? It’s because this is considered to be low hanging fruit from a threat actor's point of view on their initial access to a machine. A plaintext password can save a whole lot of time for an attacker who attempts to elevate his session or lateral move within the organization.
This is the reason the Cortex Managed Threat Hunting team has created the following query that will assist you with hunting for cleartext passwords containing files within your organization.
config case_sensitive = false | //Setting the query to be case-insensitive.
dataset = xdr_data // Using the xdr dataset | filter action_file_name contains "password" and (action_file_name contains ".doc" or action_file_name contains ".xls" or action_file_name contains ".txt" or action_file_name contains ".csv") and action_file_path not contains "chrome" and action_file_path not contains "firefox" and action_file_name not contains "~$" and action_file_name not contains ".lnk" and action_file_name not contains ":Zone.Identifier" and actor_effective_username not contains "system" and actor_process_image_name not contains "chrome.exe" and actor_process_image_name not contains "cmd.exe" and actor_process_image_name not contains "java.exe" and actor_process_image_name not contains "searchprotocolhost.exe" and action_file_path contains "users" |fields action_file_name as FileName, action_file_path as File_Path, actor_effective_username as User, agent_hostname as Hostname, actor_process_image_name as Acting_Process | dedup FileName , Hostname | sort asc User, asc Hostname |
A few notes regarding the query:
Tips for query enhancement:
e.g. (action_file_name contains "Passwort" or action_file_name contains “Passwörter”)
Screenshot of expected results:
While this is far from being a sophisticated hunting technique, you would be surprised by the sheer amount of users (including privileged ones!) and files we were able to locate by utilizing this method.
Our recommendations in this case are as follows:
In conclusion, the Threat Hunters’ job is far from being routine and repetitive.
A good threat hunter will always strive to look for anomalies and events that aren’t necessarily caught by security products due to their non-malicious nature.
There’s nothing wrong with logging into a machine with a Domain Admin account - unless it’s a regular workstation furthermore it is recommended that you use a dedicated software to manage privileged accounts of any type.
There’s nothing wrong with uploading a file to the cloud - unless it’s a private account and not private company information.
There’s also nothing wrong with storing passwords on a plain text file (OK, we couldn’t find an “Unless” here.) It’s totally wrong to store passwords in a plain text file no matter what the situation is.
And all of those things are probably unintentionally performed by users in your organization.
We hope the provided XQL queries will assist you in locating and remediating them.
Happy hunting!
Download our Cortex XDR Managed Threat Hunting Solution Brief
Download our Cortex XDR Whitepaper
By submitting this form, you agree to our Terms of Use and acknowledge our Privacy Statement. Please look for a confirmation email from us. If you don't receive it in the next 10 minutes, please check your spam folder.