Most modern day EDRs have some sort of feature which allows blue teamers to remotely connect to hosts with an EDR agent/sensor installed, to aid in their investigation of incidents. In CrowdStrike, this is called Real Time Response, and it provides a wide range of capabilities, from executing built-in commands like ipconfig and netstat to running your own PowerShell scripts.
In this blog post, I’ll showcase how CrowdStrike’s PSFalcon PowerShell module can be used to execute RTR commands on multiple hosts at once for the purpose of threat hunting. I’ll also be providing the code for the threat hunting script, and by the end of this blog you will be able to use the script to pull registry run keys, scheduled tasks, WMI subscriptions, startup folder files, and services from multiple machines, to uncover hidden persistence mechanisms. Attackers may establish persistence in your environment without being detected, as such hunting for some of the techniques they use could uncover a potential breach. You can find the Persistence-Hunter script here: https://github.com/NVISOsecurity/blogposts/blob/master/Persistence%20Hunter/Persistence-Hunter.ps1
Before interacting with CrowdStrike’s Oauth2 API via PSFalcon, you will need PowerShell installed and a valid API client (which consists of a ClientID and a secret), that you can create via this link https://falcon.crowdstrike.com/api-clients-and-keys/clients. You can get an API client yourself if you have the Falcon administrator role, otherwise an administrator has to provide you with one. Make sure that your client has the Real time response (admin): Write
permission enabled. After your API client is created, you have to install the PSFalcon module. You can find instructions on that through this link https://github.com/CrowdStrike/psfalcon/wiki/Installation,-Upgrade-and-Removal#use-the-powershell-gallery. Once that is done, run Show-FalconModule
in a PowerShell prompt to verify that everything is correctly installed.
Since API keys could provide someone with a great deal of access, here are some best practices to keep in mind when handling them:
Persistence-Hunter.ps1 utilizes the PSFalcon module in order to query multiple hosts at once. It initiates Real Time Response sessions to each host in a specific group simultaneously and checks for persistence mechanisms that indicate if a host might be compromised or not.
Invoke-FalconRtr
is used to initiates RTR sessions. Depending on the parameter provided, it will start a Real-time Response session with:
-GroupId
: Members of the specified host group identifier-HostId
: A single host identifier-HostIds
: An array containing one or more host identifiersExample command:
Invoke-FalconRtr -Command 'runscript' -Argument $Arguments -Timeout 60 -GroupId $group_ID
In this case, Invoke-FalconRtr
was supplied with the with the following parameters:
runscript
: To run a PowerShell scriptArguments
: the Base64 commands about to be executedTimeout
: timeout limitGroup_ID
: The ID of the host groupSadly, PSFalcon does not understand host group names, so you need to convert the host group name to the corresponding host group identifier (GroupId).
How do I go from group name to GroupId?
You can do it manually via PSFalcon. Let’s say you want to find the GroupId of the following group:
Domain - Workstations
First, you need to turn all of the characters into lowercase:
$GroupName = 'Domain - Workstations'.ToLower()
You can get the value of GroupName in a PowerShell prompt to see if it worked by typing $GroupName:
domain - workstations
Then you need to use the following PSFalcon cmdlet:
$Id = Get-FalconHostGroup -Filter "name:'$GroupName'"
Once again you can get the value of id in a PowerShell prompt by typing $Id :
k43b…………………..d9120
The value of id is your GroupId, which is a 32-character long string. The GroupId parameter can then be supplied to the Persistence-Hunter script.
gi -path 'Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run\' -ea silentlycontinue | out-string ;
gi -path 'Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce\' -ea SilentlyContinue | out-string;
gi -path 'Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run\' -ea silentlycontinue | out-string;
schtasks /query /fo csv /v | convertfrom-csv | select TaskName, 'Task To Run', Author | fl | out-string;
gci -path 'C:\Users\*\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\*' -ea silentlycontinue | select fullname,Length,CreationTime,LastWriteTime,LastAccessTime,Mode | fl | out-string;
gci -path 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\*' -ea silentlycontinue | select fullname,Length,CreationTime,LastWriteTime,LastAccessTime,Mode | fl | out-string;
Get-WmiObject -namespace 'root\subscription' -class __EventConsumer | fl | out-string
Get-WmiObject -namespace 'root\subscription' -class __EventFilter | fl | out-string
Get-WmiObject -namespace 'root\subscription' -class __FilterToConsumerBinding | fl | out-string
gwmi win32_service |select name,pathname,state,status,startmode| fl | out-string;
The commands need to be Base64 encoded since they are custom scripts to be executed. If you want to run your own PowerShell commands, you can use the following snippet to Base64 encode them:
$EncodedScript = [Convert]::ToBase64String( [System.Text.Encoding]::Unicode.GetBytes((Get-Content -Path $Path -Raw)))
Before running the script, you’ll need to edit line 39 to include your group ID, and change the group name in line 42 as well. With that done, you are ready to run it via the command line. The script will produce 5 different csv files, one for each technique mentioned above. Happy hunting!
In this blog post, we looked into how the PSFalcon module can be leveraged in order to execute multiple commands in a group of hosts in CrowdStrike for threat hunting purposes.
This script has assisted me in the following use cases:
All in all, this code and the methodology presented could be modified to execute any PowerShell command in a group of hosts, so feel free to experiment with your own commands, whether it is threat hunting, system hardening or whatever else you want to do.
Dimitris is a senior cybersecurity consultant at NVISO working as a Cyber Emergency Response Team (CERT) member. In his free time, he enjoys tinkering with code and skateboarding.