Use of PsExec That Doesn’t Reveal Password Hashes

November 6, 2018

Cyber Triage is an agentless incident response system and one of the methods that we use to get data from a compromised endpoint is to send our collection tool out via PsExec.

When we tell experienced incident responders this, the typical dialog is:

  • Responder: So, are you pushing Administrator credentials to the endpoint? Are we going to give the attacker an admin password hash they can use for lateral movement?
  • Us: No, we use techniques to avoid this.

And those techniques worked in 90% of environments but generated errors in others. Notably, the not very useful “Error Code: 6”. This blog post outlines what changes we had to make so that we got reliable remote executions using Cyber Triage and PsExec.

The Problem

If you run PsExec and specify the login and password with ‘-u’ and ‘-p’ arguments, then PsExec will authenticate with the remote computer using those credentials. This results in a “Type 2 Interactive Logon”, which causes the password hash to get stored on the endpoint.

If an attacker is active on that endpoint (which could be very likely if you are performing incident response on it), then they can get a copy of the password hash and use it to log into other systems.

So, if you are not careful, then you may end up giving the attackers more keys to your kingdom as part of your response.

Some responders don’t consider this a huge threat because many of their endpoints already have an administrator password hash on them. But, others want to make sure that the risk of this is limited.

The Old Way: net use

The initial versions of Cyber Triage used a documented approach that does not send hashes. The general idea is to force a “Type 3 Network Logon” before running PsExec and then PsExec will leverage that previous logon. A network logon (versus an interactive one) uses a challenge-response method of authentication (such as NTLM or Kerberos).

More specifically, Cyber Triage would:

  1. Use ‘net use’ to SMB mount the admin share (admin$) on the remote computer using the credentials specified by the user. This process authenticates using a network logon with the remote system.
  2. Run PsExec and not specify a username or password. Because PsExec needs to copy a file over to the remote system, it would use the previously established SMB session created from ‘net use’ and (often) start the remote PsExeSvc service as the account that the SMB mount was created with.

For more details on how PsExec works, refer to this post.

The ‘net use’ approach worked most of the time, except:

  • If there were stored credentials for the remote endpoint, then those would be used instead of the specified user and the stored credentials may not have admin rights.
  • PsExec sometimes did not obtain sufficient permissions from the SMB mount to start the service on the remote system. Because this most often occurred on our customer’s systems that we did not have access to, we were not able to extensively debug this, but we believe it had to do with different security settings, including UAC and LocalAccountTokenFilterPolicy.

We needed a more reliable way to get the PsExeSvc service to start.

The New Way: Run As

The solution to our problem is to execute PsExec using CreateProcessWithLogon() and specify LOGON_NETCREDENTIALS_ONLY,  which will use the specified credentials for any network resources. It’s the programmatic-equivalent of right-clicking on the file and choosing “Run As”, but with the additional qualification to only use the specified account for network-related things.

Therefore, what happens now is:

  • We call ‘net use’ to mount the admin$ share, but our main motivation now is because it allows us to quickly resolve password and hostname errors.
  • PsExec is executed using CreateProcessWithLogon() with the specified admin credentials.
  • PsExec mounts the admin$ mount using the specified credentials.
  • PsExec remotely starts the remote PsExeSvc service using the specified credentials.

This method is more reliable because we do not send a password hash and we are forcing PsExec to use specific admin credentials to start the remote service.


It is important that as part of your response, that you do not reveal more information to the attacker. And, it’s important that you can reliably get data from your suspicious endpoints. Our recent changes to Cyber Triage and PsExec ensure both of these.

If you found this blog because you were trying to get PsExec to reliably work in these kinds of situations, we hope it was useful. If you found this blog because you want to learn all about Cyber Triage, then you can get a free eval copy using our form and we’ll send you a download link.