This is a short reverse engineering review of one useful remote administration utility, originally authored by Mark Russinovich (you can download it from Microsoft web-site here). The original version of this review was published on this site in 2004, but since the utility is still very popular and users are interested about its internal design, I decided to slightly update and republish it. The short description from utility homepage: “Utilities like Telnet and remote control programs like Symantec’s PC Anywhere let you execute programs on remote systems, but they can be a pain to set up and require that you install client software on the remote systems that you wish to access. PsExec is a light-weight Telnet-replacement that lets you execute processes on other systems, complete with full interactivity for console applications, without having to manually install client software. PsExec’s most powerful uses include launching interactive command-prompts on remote systems and remote-enabling tools like IpConfig that otherwise do not have the ability to show information about remote systems.” Actually, I was questioned before by several System Administrators regarding possibility to start programs on remote system without installing any additional software on it. That’s why this tool appeared to be very interesting for me. Regretfully, Mark did not give any tips on how this utility works, so one pretty Sunday (the weather was pretty awful outside) I’ve fired up IDA and looked inside this tool.
Smart and simple
First I’ve found out that psexec.exe
contains embedded binary resource PSEXESVC
, which is actually a PE-executable, more exactly it’s a Win32 service binary. Some initial reversing of PSEXESVC
discovered that this is a server part of the utility, responsible for starting processes and redirecting I/O to/from the client system. However, let’s start from the very beginning and describe what psexec.exe
do in sequence.
As it could be expected first what utility does is checking host operating system and parameters validity, an example, it checks if the application to “copy and execute” exists on the host system. I think here is no need to describe this part in details, any programmer working over console application does the same things (again and again in an endless loop…).
After parameters are validated, psexec.exe
obtains a pointer and size of PSEXESVC
resource:
HRSRC hSvc = FindResource (NULL, "PSEXESVC", "BINRES" );
if ( !hSvc ) return 0;
HGLOBAL hGbDesc = LoadResource (NULL, hSvc);
DWORD dwSvcSize = SizeofResource (NULL, hSvc);
PBYTE pPsExeSvc = LockResource (hGbDesc);
Then it creates a file in \\RemoteSystemName\ADMIN$\System32
named PSEXESVC.EXE
and saves the binary extracted from the resource into it. If there is no existing session with permissions to access RemoteAdmin (ADMIN$
) share, then it tries to establish a new session using the username and password specified in the command line through the call to WNetAddConnection2
as the following:
DWORD
PsExecRemoteLogon (
LPCSTR lpComputerName,
LPCSTR lpUserName,
LPCSTR lpPassword
)
{
char szFullPath [_MAX_PATH];
NETRESOURCE NetResource;
sprintf (szFullPath, "\\\\%s\\IPC$");
// Initialize NetResource structure, omitted here
...
return (NO_ERROR ==
WNetAddConnection2 (
&NetResource,
lpPassword,
lpUserName,
0)
);
}
If no error occurs, then we get PSEXESVC.EXE
service binary in \\SystemRoot\System32
on the remote system. Note, if there is an executable to start remotely which must be copied to the remote system, then it is also placed into that folder. After this, psexec.exe install and start PSEXESVC
service using SCM API (OpenSCManager
, CreateService
, StartService
). Full description of these calls is quite ordinary and along with the source would take pretty much the place, so I don’t see real need to do this.
After start, PSEXESVC
creates named pipe psexecsvc
, and starts reading messages from it. By this moment, we have the server part installed and started on the remote system, which is ready to accept command messages. Everything else is typical for client/server applications (for better understanding of writing server applications I strongly recommend Jeffrey Richter, Jason D. Clark “Programming Server-Side Applications for MS Windows 2000”). So, once again in two words, psexec.exe
copies executable to start to the remote system if necessary, opens a psexecsvc
pipe on a remote host (CreateFile
), fill in the message structure with necessary parameters (command line arguments, username & password if specified etc…) and sends it into \\RemoteSytem\pipe\psexecsvc
(TransactNamedPipe
API call).
On receiving this message, PSEXESVC
creates three named pipe instances psexecsvc-app_name-app_instance-stdin
, psexecsvc-app_name-app_instance-stdout
, psexecsvc-app_name-app_instance-stderr
. As you may suspect, psexec.exe
connects to each of these pipes and creates separate threads to work with each one. Using console functions (GetStdHandle
, ReadConsole
, WriteConsole
etc…) standard I/O streams (input, output, error) are redirected to/from remote systems through these named pipes.
On exiting application, psexec.exe
stops and uninstall PSEXESVC
service, removes its binary from remote host and removes console executable if it was also copied.
As a result, we have a Telnet like application with extensive use of Windows NT/2000 features, it can be effectively used by system administrators for common administration tasks. The only hole (mentioned on utility homepage) is security: “If you omit a username the remote process runs in the same account from which you execute PsExec
, but because the remote process is impersonating it will not have access to network resources on the remote system. When you specify a username, the remote process executes in the account specified, and will have access to any network resources the account has access to. Note that the password is transmitted in clear text to the remote system”. As you can see, this tool is dangerous to use for remote administration over non-trusted networks and Internet and possibly sometimes even in corporate network (as dangerous as telnet, an example). One of the possible extension of this tool would be securing communication of psexec
and PSEXESVC
with some kind of encryption.
which are the GPO policies which can stop psexec from executing on target machine?
I think you could just disable administrative shares to prevent psexec to be uploaded on the target system. Please check this article from Microsoft “How to remove administrative shares in Windows Server 2008“
year 2018 and this article is still informative. Now I know why sometimes PSExec fails when called second time in a row.
To disable psexec you can:
– use AppLocker (if you have Enterprise or Ultimate versions of Windows)
– use UAC LocalAccountTokenFilterPolicy
I would prefer second method. Typically IT require using of administrative shares for administrative task so you should take a look at Powershell WinRM and JEA instead…