Skip to content

jfjallid/go-psexec

Repository files navigation

go-psexec

A native Go implementation of the PsExec protocol for executing commands on remote Windows systems over SMB. This tool connects to a target via SMB, uploads and installs the signed PsExecSvc service binary, then communicates with it over named pipes to run commands interactively or detached.

The tool is built on top of the library go-smb and use it to create the PsExec service, upload the service binary, and to communicate over the named pipes.

Supports NTLM, Kerberos, and NTLM relay authentication. Supports multiple PsExecSvc protocol versions (2.0 through 2.43) and encrypted command channels.

Currently, only a single version of the service binary is included for upload and execution. Using the "auto" mode, the client will attempt to detect an existing PsExec service on the system and reuse it if the version is supported and otherwise fallback to uploading the included version.

I built this tool to facilitate interaction with Windows from Linux and as way to stay a bit more undetected during assessments.

License

MIT License - see source files for details.

Build

make

Produces a statically linked go-psexec binary for linux/amd64.

Usage

Usage: ./go-psexec [options]

options:
      --host                Hostname or ip address of remote server. Must be hostname when using Kerberos
  -P, --port                SMB Port (default 445)
  -d, --domain              Domain name to use for login
  -u, --user                Username
  -p, --pass                Password
  -n, --no-pass             Disable password prompt and send no credentials
      --hash                Hex encoded NT Hash for user password
      --local               Authenticate as a local user instead of domain user
      --null                Attempt null session authentication
  -k, --kerberos            Use Kerberos authentication. (KRB5CCNAME will be checked on Linux)
      --dc-ip               Optionally specify ip of KDC when using Kerberos authentication
      --target-ip           Optionally specify ip of target when using Kerberos authentication
      --aes-key             Use a hex encoded AES128/256 key for Kerberos authentication
  -c, --command             Executable to run (default cmd.exe)
      --args                Arguments to pass to the executable
  -s, --system              Run command as NT AUTHORITY\\SYSTEM
  -w, --workdir             Working directory for remote process (default c:\Windows)
      --alt-user            Username for spawning process with LogonUserW instead of CreateProcessAsUserW.
                            Requires correct logon rights.
      --alt-pass            Password for spawning process with LogonUserW
      --no-interactive      Run command detached and don't wait for it to finish
      --desktop             Spawn command window on remote console instead of locally. When used
                            with --alt-user, LOGON_INTERACTIVE, otherwise LOGON_SERVICE
      --num <n>             Specify which desktop to spawn window on (default Console 0xFFFFFFFF)
  -l, --restricted          Spawn process with a restriced token, low integrity process
  -e, --elevated            Spawn process with an elevated token, high integrity process
      --no-profile          Do not load user profile. Only relevant when using --alt-user
  -a, --affinity            Specify comma separated list of CPUs where the program can run (default all CPUs)
      --priority            Specify process priority: background,low,belownormal,normal,abovenormal,high,realtime (default normal)
      --service             Name of service to create (default PSEXESVC)
      --display             Display name of service to create (default same as --service name)
      --pipe                Name of pipe to create (also name of binary created in --service-dir and --share) (default PSEXESVC)
      --client-name         Client computer name to send (default random name)
      --share               SMB share to upload service binary to (default ADMIN$)
      --share-root          Absolute path the share maps to on the remote system (default C:\Windows\)
      --service-dir         Directory relative to share root for service binary (default "", i.e., share root)
      --svc-version <ver>   PsExecSvc protocol version: auto, 2.43 (default auto)
      --force-pubkey        Use RSA pubkey exchange for v2.43 instead of session-key derived AES
      --clean               Only perform cleanup of service and service binary
      --noclean             Skip cleanup e.g., service will be left running
      --relay               Start an SMB listener that will relay incoming
                            NTLM authentications to the remote server and
                            use that connection. NOTE that this forces SMB 2.1
                            without encryption.
      --relay-port <port>   Listening port for relay (default 445)
      --socks-host <target> Establish connection via a SOCKS5 proxy server
      --socks-port <port>   SOCKS5 proxy port (default 1080)
  -t, --timeout <duration>  Dial timeout specified in 5s, 1m, 10m format (default 5s)
      --dns-host <ip:port>  Override system's default DNS resolver
      --dns-tcp             Force DNS lookups over TCP. Default true when using --socks-host
      --noenc               Disable smb encryption
      --smb2                Force smb 2.1
      --verbose             Enable verbose logging
      --debug               Enable debug logging
  -v, --version             Show version

Examples

Basic interactive shell

Connect with domain credentials and get a cmd.exe shell:

./go-psexec --host 192.168.1.10 -d corp -u admin -p 'P@ssw0rd'

System interactive shell

Connect with administrator credentials and get a cmd.exe shell running as SYSTEM:

./go-psexec --host 192.168.1.10 -d corp -s -u admin -p 'P@ssw0rd'

Run a specific command

Execute ipconfig /all:

./go-psexec --host 192.168.1.10 -d corp -u admin -p 'P@ssw0rd' \
  -c ipconfig --args "/all"

Run PowerShell with arguments

./go-psexec --host 192.168.1.10 -d corp -u admin -p 'P@ssw0rd' \
  -c powershell.exe --args "-NoProfile -Command Get-Process"

Pass-the-hash

Authenticate using an NT hash instead of a password:

./go-psexec --host 192.168.1.10 -d corp -u admin \
  --hash <NT Hash> 

Kerberos authentication

Using a Kerberos ticket from a ccache file (make sure to use FQDN for domain):

KRB5CCNAME=/tmp/krb5cc_admin ./go-psexec --host dc01.corp.local \
  -k -n -d corp.local -u admin --dc-ip <ip of domain controller>

With an AES256 key directly:

./go-psexec --host dc01.corp.local -k -d corp.local -u admin \
  --aes-key 4a3c...hex... --dc-ip <ip of domain controller>

Run as a different user on the target

Use --alt-user to spawn the process via LogonUserW as a specific user. This requires the user to have the appropriate logon rights on the target:

./go-psexec --host 192.168.1.10 -d corp -u admin -p 'P@ssw0rd' \
  --alt-user serviceaccount --alt-pass 'SvcP@ss' \
  -c whoami

Detached (non-interactive) execution

Run a command without waiting for output:

./go-psexec --host 192.168.1.10 -d corp -u admin -p 'P@ssw0rd' \
  --no-interactive -c notepad.exe

Spawn on remote desktop session

Launch a visible window on the remote console:

./go-psexec --host 192.168.1.10 -d corp -u admin -p 'P@ssw0rd' \
  --desktop -c calc.exe

Custom service and pipe names

Use non-default names to avoid conflicts or for stealth:

./go-psexec --host 192.168.1.10 -d corp -u admin -p 'P@ssw0rd' \
  --service MYSERVICE --pipe MYSERVICE --display "My Service"

Upload binary to a different share

Place the service binary on C$ instead of ADMIN$ but keep in mind that all versions of PsExec from 2.30 use a key file that is always located in ADMIN$:

./go-psexec --host 192.168.1.10 -d corp -u admin -p 'P@ssw0rd' \
  --share 'C$' --share-root 'C:\' --service-dir 'ProgramData\'

Cleanup only

Remove a previously installed service and binary without running anything:

./go-psexec --host 192.168.1.10 -d corp -u admin -p 'P@ssw0rd' --clean

Skip cleanup

Leave the service running after execution for repeated use:

./go-psexec --host 192.168.1.10 -d corp -u admin -p 'P@ssw0rd' --noclean

On subsequent runs the tool will detect the running service and reuse it without re-uploading.

Adding Service Binaries

The tool ships with the PsExecSvc v2.43 binary embedded as a hex string in servicebinary.go. The protocol supports versions 2.0 through 2.43, and the tool can communicate with any supported version it finds already installed on a target. However, to upload a specific version that is supported by the project, the binary must be embedded in the build.

To add support for uploading an additional version:

1. Create the hex-encoded binary

Convert your PSEXESVC.EXE binary to a Go hex string constant:

xxd -p PSEXESVC.EXE | tr -d '\n' > svc_hex.txt

2. Add it to servicebinary.go

Add a new hex constant and decode it in the init() function, following the existing pattern:

const psexecsvc2_20_hex = "4d5a9000..." // paste from svc_hex.txt

func init() {
    // existing v2.43 decode ...

    psexecbytes2_20, _ = hex.DecodeString(psexecsvc2_20_hex)
}

3. Declare the byte slice in main.go

Add a global variable alongside the existing one:

var psexecbytes2_20 []byte

4. Wire up the upload and version validation

In main.go, update two switch statements:

The --svc-version validation (search for Add to this list):

switch svcVersionStr {
case "auto", "2.43", "2.20": // add new version string here

The upload version selection (search for Determine which binary to upload):

switch svcVersion {
case Version_2_43, 0xFFFFFFFF:
    uploadVersion = Version_2_43
case Version_2_20:
    uploadVersion = Version_2_20

And in service.go, add a case in uploadServiceBinary to write the correct bytes:

case Version_2_20:
    err = session.PutFile(shareName, filename, 0, bytes.NewReader(psexecbytes2_20).Read)
    detectedVersion = Version_2_20

6. Build and test

make
./go-psexec --host TARGET -u admin -p pass --svc-version 2.20

About

One PsExec client to rule them all

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages