-
Notifications
You must be signed in to change notification settings - Fork 189
2 ‐ Usage
Once the module has been imported, there is only one function you need to learn to use: Find-AllPersistence
. First things first, this function supports PowerShell's Get-Help
cmdlet. Using it will show a number of examples, most of which are detailed in this Wiki.
Get-Help -Name Find-AllPersistence -Full
The behavior of Find-AllPersistence
can be modified using the following parameters:
-
-ComputerName
: string or array of strings containing the Fully Qualified Domain Name (FQDN) of PowerShell Remoting-enabled hosts on which to run PersistenceSniper, not mandatory and defaults to localhost. Check the Running PersistenceSniper on Remote Hosts paragraph of this section; -
-DiffCSV
: the path to a CSV file containing a table of persistence techniques to exclude from the current run of PersistenceSniper. Check the Filtering Out False Positives paragraph of this section. Not mandatory; -
-IncludeHighFalsePositivesChecks
: this switch enables a number of checks which usually yield a high number of false positives (e.g. Service detection) and are disabled by default. Not mandatory; -
-PersistenceMethod
: string used to specify a single persistence technique to check for. Not mandatory and defaults to "All"; -
-OutputCSV
: the path to a file that will be overwritten withFind-AllPersistence
output in CSV format. Not mandatory; -
-VTApiKey
: the value of a Virustotal API key thatFind-AllPersistence
can use to submit findings to Virustotal. Not mandatory; -
-LogFindings
: this switch instructsFind-AllPersistence
to save its output to the Windows Event Log, underWindows Logs\Application
with sourcePersistenceSniper
. Not mandatory.
The Find-AllPersistence
cmdlet calls a number of PowerShell routines which are not exported from the module and outputs an array of PSCustomObject structured as follows:
$PersistenceObject = [PSCustomObject]@{
'ComputerName' = $ComputerName
'Technique' = $Technique
'Classification' = $Classification
'Path' = $Path
'Value' = $Value
'Access Gained' = $AccessGained
'Note' = $Note
'Reference' = $Reference
'Signature' = Find-CertificateInfo (Get-ExecutableFromCommandLine $Value)
'IsBuiltinBinary' = Get-IfBuiltinBinary (Get-ExecutableFromCommandLine $Value)
'IsLolbin' = Get-IfLolBin (Get-ExecutableFromCommandLine $Value)
'VTEntries' = CheckHashAgainstVT(Get-ExecutableFromCommandLine $Value)
}
Here is an explanation of the properties that constitute this instance of PSCustomObject:
- ComputerName: this is the hostname of the host on which
Find-AllPersistence
is run; - Technique: this is the name of the technique itself, as it's commonly known in the infosec community;
- Classification: this property can be used to quickly identify techniques based on their MITRE ATT&CK technique and subtechnique number. For those techniques which don't have a MITRE ATT&CK classification, other classifications are used, the most common being Hexacorn's one since a lot of techniques were discovered by him. When a technique's source cannot be reliably identified or no classification applies, the "Uncatalogued Technique N.#" classification is used;
- Path: this is the path, on the filesystem or in the registry, at which the technique has been implanted. For those detections that don't have a path either in the registry or in the FS, an explanation is given;
- Value: this is the value of the registry property the techniques uses, or the name of the executable/library used, in case it's a technique which relies on planting something on the filesystem. For those detections that don't conform to this rule, an explanation is given;
- Access Gained: this is the kind of access the technique grants the attacker. If it's a Run key under HKCU for example, the access gained will be at a user level, while if it's under HKLM it will be at system level;
- Note: this is a quick explanation of the technique, so that its workings can be easily grasped. The same explanation can be found in the Detection section of this document;
- Reference: this is a link to a more in-depth explanation of the technique, should the analyst need to study it more;
- Signature: this property reports information on the signature of the binary associated with the persistence technique found;
- IsBuiltinBinary: this boolean property reports if the binary associated with the persistence technique found is normally found on the Operating System and is considered builtin. Ignore this property for detections of techniques which don't rely on a binary;
- IsLolbin: this boolean property is set to True if the the binary associated with the persistence technique found is a LOLBin. Ignore this property for detections of techniques which don't rely on a binary;
- VTEntries: a value different from "N/A" will indicate that the identified file is known to VirusTotal and has zero or more detections. This property will be populated if the parameter
-VTApiKey
is present.
Using PersistenceSniper on localhost is as simple as importing the module and running Find-AllPersistence
without any parameter. This will cause PersistenceSniper to run on localhost, exclude high false positive checks and output the result to the console. Using PowerShell's -Verbose
parameter will print out all the checks PersistenceSniper performs under the hood.
Find-AllPersistence -Verbose
If you only want to check for a single persistence technique, you can rely on Find-AllPersistence
's PersistenceMethod
parameter. Say, for example, you only want to check for persistences implanted through the Run and RunOnce registry keys:
Find-AllPersistence -PersistenceMethod RunAndRunOnce
The PersistenceMethod
parameter uses Powershell's ValidateSet
directive, so you can tab through it instead of writing down the persistence method of choice.
Since PersistenceSniper's output is an array of PSCustomObjects, it is easy to format and filter the output using all the facilities PowerShell provides. Let's say you only want to see the persistences that will allow the attacker to regain high privilege access (i.e. System):
Find-AllPersistence | Where-Object "Access Gained" -EQ "System"
Of course, being PersistenceSniper a Powershell-based tool, some cool tricks can be performed, like passing its output to Out-GridView
in order to have a GUI-based table to interact with.
What makes PersistenceSniper really shine in my definitely unbiased opinion is the capability of running it remotely on other hosts without uploading it to said hosts and without leaving credentials cached anywhere. This is possible thanks to PersistenceSniper's support of a feature called PowerShell Remoting. In a nutshell, PowerShell Remoting is a Windows functionality, Opt-In on Workstation versions of the OS and Opt-Out on Server versions, which allows for remote management of machines using the WSMan protocol on port 5985 (not encrypted) and port 5986 (TLS encrypted). This is very useful, especially in an Active Directory environment, because it allows for safe, remote management of workstations and servers, without using cleartext credentials on remote hosts and/or leaving NT hashes cached in the remote hosts' LSASS, because PS Remoting uses Kerberos TGS tickets for authentication.
In order to run PersistenceSniper remotely, three requirements must be satisfied:
- PowerShell Remoting is enabled on the remote host (default for servers, not default for workstations);
- The user under whose context PersistenceSniper is running must be in the BUILTIN/Administrators group of the remote machines (default if PersistenceSniper is being run by a Domain Admin);
- The remote machine must be a Trusted Host (default if using the FQDN of a machine in the same domain);
Once these requirements are satisfied, running PersistenceSniper remotely through PowerShell Remoting is as easy as specifying the FQDN of the remote host(s) on which to run Find-AllPersistence
:
Find-AllPersistence -ComputerName server1.macrohard.lol
All the PS Remoting session setting up and code execution is handled by PersistenceSniper and PowerShell under the hood without the user having to worry about it 😊. Of course, anything you can do locally with PersistenceSniper can be done remotely through PS Remoting, no caveats apply.
One of the great problems of hunting for persistence techniques is having to deal with a lot of false positives. This happens because, while some techniques are almost never legimately used, many indeed are by legit software which needs to autorun when the system boots or at user login.
This poses a challenge, which in many environments can be tackled by creating a CSV file containing known false positives. If your organization deploys systems using something like a golden image, you can run PersistenceSniper on a system you just created, get a CSV of the results and use it to filter out results on other machines. This approach comes with the following benefits:
- Not having to manage a whitelist of persistences which can be tedious and error-prone;
- Tailoring the false positives to the organizations, and their organizational units, which use the tool;
- Making it harder for attackers who want to blend in false positives by not publicly disclosing them in the tool's code.
Find-AllPersistence
comes with parameters allowing direct output of the findings to a CSV file, while also being able to take a CSV file as input and diffing the results. The idea is to run Find-AllPersistence
with the -IncludeHighFalsePositivesChecks
enabled on a machine that has just been deployed and is highly likely to be clean, output the result to a false_positives.csv
file and use said file later with the -DiffCSV
parameter in order to filter out the results already contained in the false_positives.csv
. To recap:
Clean Machine
Find-AllPersistence -IncludeHighFalsePositivesChecks -OutputCSV .\false_positives.csv
Potentially Compromised Machine
Find-AllPersistence -ComputerName server1.macrohard.lol -IncludeHighFalsePositivesChecks -DiffCSV .\false_positives.csv
MAKE SURE TO INCLUDE THE -IncludeHighFalsePositivesChecks WHEN CREATING YOUR FALSE POSITIVES FILE SO THAT YOU CAN FILTER OUT EVEN HIGH FALSE POSITIVE TECHNIQUES
With the basics in mind, we can now go through a couple of more complex usage examples.
In this example we will run PersistenceSniper locally, looking for the RunAndRunOnce persistence techniques, filtering out the false positives stored in false_positives.csv
, and outputting the results to results.csv
:
Find-AllPersistence -PersistenceMethod RunAndRunOnce -DiffCSV .\false_positives.csv -OutputCSV .\results.csv
In this other example we will run PersistenceSniper remotely on two hosts, looking for all the possible persistence techniques (high false positives checks included), filtering out the false positives stored in false_positives.csv
, and finally outputting the results to results.csv
:
Find-AllPersistence -ComputerName @('server1.macrohard.lol','workstation2.macrohard.lol') -DiffCSV .\false_positives.csv -OutputCSV .\results.csv -IncludeHighFalsePositivesChecks
This example is the same as example 2, but the hosts on which to run PersistenceSniper are saved in a file called computers.txt
, with every line of the file containing a single FQDN:
computers.txt
server1.macrohard.lol
dc1.macrohard.lol
workstation2.macrohard.lol
We will use PowerShell's Get-Content
cmdlet to output the content of computer.txt
directly as a string array into Find-AllPersistence
's -ComputerName
parameter.
Find-AllPersistence -ComputerName (Get-Content .\computers.txt) -DiffCSV .\false_positives.csv -OutputCSV .\results.csv -IncludeHighFalsePositivesChecks
Now that you know how to use PersistenceSniper, you can check which persistence techniques it is able to find by heading to the Detections section of this document.