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

#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.

#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;

$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!

1 thought on “Monitoring with PowerShell: Monitoring psexec execution

  1. Jon

    some extra info lime posted on reddit:

    Q.) if i don’t use psexe can i just blacklist it in my AV instead?

    A.) Yes actually! if you are sure none of the applications in your network use PsExec in anyway, you could try blocking it using either your AV or NGAV. You could even take it a set futher;

    If you are not using the ADMIN$ share that is default on each computer (\\computername\ADMIN$\) you could even turn that share off which prevents any remote execution via the method that psexec uses. Just note that more RMM’s also use this share for the remote execution or installation of commands.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.