Featured image of post Monitoring with PowerShell: Monitoring psexec execution

Monitoring with PowerShell: Monitoring psexec execution

A bunch of bad actors these days uses the great psexec tool by Sysinternals/Microsoft to try to move through the network latterly. PSExec allows you to remotely execute commands on different computers through a very simple command line interface. PSexec also allows you to execute commands or scripts as the SYSTEM account.

We use PSExec professionally to run specific tooling that requires the highest privileges, this means that just flat out blocking PSExec execution on our networks is not possible. We do want to know whenever people do execute this, so we can use it as an early warning system. Please note that this does not capture PSexec clones such as CDEXec and PAexec.

Grabbing PSExec usage actually did not look that hard – you either look for the service it creates, or for the currently running file, so the following simple script would solve it I thought.

The Scripts

1
2
3
4
5
6
7
8
#FindPsexec service
$PSExecmon = get-service PSEXESVC
if (!$PSExecmon) {
    $PSExecHealth = "Healthy - no PSExec service found."
}
else {
    $PSExecHealth = "Unhealthy - PSExec service found"
}

But after checking some of my older scripts I’ve actually found the -r option for PSExec. The -R parameter allows you to change both the servicename and the executable name, making it a little harder to find now. To solve this, we can look for the specific executable where the description is set to PSExec.

1
2
3
4
5
6
7
8
#FindPsexec service
$PSExecmon =  get-process | Where-Object { $_.description -like "*psexec*" }
if (!$PSExecmon) {
    $PSExecHealth = "Healthy - no PSExec service found."
}
else {
    $PSExecHealth = "Unhealthy - PSExec service found"
}

But now you’re saying “But Kelvin, what is someone removes the personal identifying properties?! You won’t find it but it will still run.” And I’d say you’re absolutely right about that. So let’s try a third option;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$Procs = Get-Process | Where-Object { $_.Path -ne $null }
$PSExecmon = foreach ($Proc in $procs) {
    $Sig = Get-AuthenticodeSignature $proc.path
    if ($Sig.SignerCertificate.Thumbprint -eq "3BDA323E552DB1FDE5F4FBEE75D6D5B2B187EEDC") { $proc }
}
if (!$PSExecmon) {
    $PSExecHealth = "Healthy - no PSExec service found."
}
else {
    $PSExecHealth = "Unhealthy - PSExec service found"
}

This last option does have a downside too; Microsoft used the same signing certificate for the PSTools as they did for a .NET installer. This might generate one or two false positives, but it does seem the best way to detect PsExec usage right now. We’ve loaded this up in our RMM and are running this job to make sure we can see whenever PSExec is executed. With this option you could also stop the process automatically.

And that’s it! Hopefully it helps prevent lateral movement in your networks too. As always, Happy PowerShelling!

All blogs are posted under AGPL3.0 unless stated otherwise
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy