FuzzySecurity / PowerShell-Suite

My musings with PowerShell
BSD 3-Clause "New" or "Revised" License
2.6k stars 762 forks source link

Except Invoke-Runas.ps1 to output stdout of command which we excute #10

Open mobilefzb opened 5 years ago

mobilefzb commented 5 years ago

  I try to create a pipe to output the command's stdout.

function Invoke-Runas {

<#
.SYNOPSIS
    Overview:

    Functionally equivalent to Windows "runas.exe", using Advapi32::CreateProcessWithLogonW (also used
    by runas under the hood).

    Parameters:
     -User              Specifiy username.

     -Password          Specify password.

     -Domain            Specify domain. Defaults to localhost if not specified.

     -LogonType         dwLogonFlags:
                          0x00000001 --> LOGON_WITH_PROFILE
                                           Log on, then load the user profile in the HKEY_USERS registry
                                           key. The function returns after the profile is loaded.

                          0x00000002 --> LOGON_NETCREDENTIALS_ONLY (= /netonly)
                                           Log on, but use the specified credentials on the network only.
                                           The new process uses the same token as the caller, but the
                                           system creates a new logon session within LSA, and the process
                                           uses the specified credentials as the default credentials.

     -Binary            Full path of the module to be executed.

     -Args              Arguments to pass to the module, e.g. "/c calc.exe". Defaults
                        to $null if not specified.

.DESCRIPTION
    Author: Ruben Boonen (@FuzzySec)
    License: BSD 3-Clause
    Required Dependencies: None
    Optional Dependencies: None
.EXAMPLE
    Start cmd with a local account
    C:\PS> Invoke-Runas -User SomeAccount -Password SomePass -Binary C:\Windows\System32\cmd.exe -LogonType 0x1

.EXAMPLE
    Start cmd with remote credentials. Equivalent to "/netonly" in runas.
    C:\PS> Invoke-Runas -User SomeAccount -Password SomePass -Domain SomeDomain -Binary C:\Windows\System32\cmd.exe -LogonType 0x2
#>

    param (
        [Parameter(Mandatory = $True)]
        [string]$User,
        [Parameter(Mandatory = $True)]
        [string]$Password,
        [Parameter(Mandatory = $False)]
        [string]$Domain=".",
        [Parameter(Mandatory = $True)]
        [string]$Binary,
        [Parameter(Mandatory = $False)]
        [string]$Args=$null,
        [Parameter(Mandatory = $True)]
        [int][ValidateSet(1,2)]
        [string]$LogonType
    )  

    Add-Type -TypeDefinition @"
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Security.Principal;
    using Microsoft.Win32.SafeHandles;

    [StructLayout(LayoutKind.Sequential)]
    public struct PROCESS_INFORMATION
    {
        public IntPtr hProcess;
        public IntPtr hThread;
        public uint dwProcessId;
        public uint dwThreadId;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct STARTUPINFO
    {
        public uint cb;
        public string lpReserved;
        public string lpDesktop;
        public string lpTitle;
        public uint dwX;
        public uint dwY;
        public uint dwXSize;
        public uint dwYSize;
        public uint dwXCountChars;
        public uint dwYCountChars;
        public uint dwFillAttribute;
        public uint dwFlags;
        public short wShowWindow;
        public short cbReserved2;
        public IntPtr lpReserved2;
        public IntPtr hStdInput;
        public IntPtr hStdOutput;
        public IntPtr hStdError;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES
    {
        public int nLength;
        public IntPtr lpSecurityDescriptor;
        [MarshalAs(UnmanagedType.Bool)]
        public bool bInheritHandle;
    }

    public enum StdHandle { Stdin = -10, Stdout = -11, Stderr = -12 };

    public static class Advapi32
    {
        [DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
        public static extern bool CreateProcessWithLogonW(
            String userName,
            String domain,
            String password,
            int logonFlags,
            String applicationName,
            String commandLine,
            int creationFlags,
            int environment,
            String currentDirectory,
            ref  STARTUPINFO startupInfo,
            out PROCESS_INFORMATION processInformation);
    }

    public static class Kernel32
    {
        [DllImport("kernel32.dll")]
        public static extern uint GetLastError();

        [DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
        public static extern bool CreatePipe(
            ref IntPtr hReadPipe,
            ref IntPtr hWritePipe,
            IntPtr lpPipeAttributes,
            int nSize);

        [DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
        public static extern bool SetHandleInformation(
            IntPtr hObject,
            int dwMask,
            int dwFlags);

        [DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
        public static extern bool CloseHandle(
            IntPtr hObject);

        [DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
        public static extern IntPtr GetStdHandle(
            StdHandle std);

        [DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
        public static extern bool ReadFile(
            IntPtr hFile,
            [Out] byte[] lpBuffer,
            uint nNumberOfBytesToRead,
            out uint lpNumberOfBytesRead,
            IntPtr lpOverlapped);

        [DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
        public static extern bool WriteFile(
            IntPtr hFile,
            [In] byte[] lpBuffer,
            int nNumberOfBytesToRead,
            out uint lpNumberOfBytesRead,
            IntPtr lpOverlapped);
    }
"@
    # prepare pipeline
    $sa = New-Object SECURITY_ATTRIBUTES
    $sa.nLength = [System.Runtime.InteropServices.Marshal]::SizeOf($sa)
    $sa.lpSecurityDescriptor = 0
    $sa.bInheritHandle = $True
    [IntPtr]$attr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal([System.Runtime.InteropServices.Marshal]::SizeOf($sa))
    [System.Runtime.InteropServices.Marshal]::StructureToPtr($sa, $attr, $True)
    [IntPtr]$hWrite = 0
    [IntPtr]$hRead = 0
    $CallResult = [Kernel32]::CreatePipe([ref]$hRead, [ref]$hWrite, $attr, 4096)

    if($CallResult) {
        $CallResult = [Kernel32]::SetHandleInformation($hRead, 0x00000001, 0)
    }

    if($CallResult) {
        # StartupInfo Struct
        $StartupInfo = New-Object STARTUPINFO
        $StartupInfo.dwFlags = 0x00000101
        $StartupInfo.wShowWindow = 0x0001
        $StartupInfo.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($StartupInfo)
        $StartupInfo.hStdOutput = $hWrite
        $StartupInfo.hStdError = $hWrite

        # ProcessInfo Struct
        $ProcessInfo = New-Object PROCESS_INFORMATION

        # CreateProcessWithLogonW --> lpCurrentDirectory
        $GetCurrentPath = (Get-Item -Path ".\" -Verbose).FullName

        echo "`n[>] Calling Advapi32::CreateProcessWithLogonW"
        $CallResult = [Advapi32]::CreateProcessWithLogonW(
            $User, $Domain, $Password, $LogonType, $Binary,
            $Args, 0x04000000, $null, $GetCurrentPath,
            [ref]$StartupInfo, [ref]$ProcessInfo)
    }

    if (!$CallResult) {
        echo "`n[!] Mmm, something went wrong! GetLastError returned:"
        echo "==> $((New-Object System.ComponentModel.Win32Exception([int][Kernel32]::GetLastError())).Message)`n"
    } else {
        echo "`n[+] Success, process details:"
        Get-Process -Id $ProcessInfo.dwProcessId
        [Kernel32]::CloseHandle($ProcessInfo.hProcess)
        [Kernel32]::CloseHandle($ProcessInfo.hThread)
        # Read from pipe
        $chBuf = New-Object Byte[] 4096
        [uint]$dwRead = 0
        [uint]$dwWritten = 0
        [SafeHandles]$hParentStdOut = [Kernel32]::GetStdHandle(-11)
        for(;;) {
            $bSuccess = [Kernel32]::ReadFile($hRead, $chBuf, 4096, [ref]$dwRead, [system.Intptr]::Zero)
            if(!$bSuccess -or ($dwRead -eq 0)) {
                break
            }
            $bSuccess = [Kernel32]::WriteFile($hParentStdOut, $chBuf, $dwRead, [ref]$dwWritten, [system.Intptr]::Zero)
            if(!$bSuccess -or ($dwRead -lt 4096)) {
                break
            }
        }
    }
}