Fork me on Github

You can find a complete version of the project that is described in this paper on my Github account.

https://github.com/DarkCoderSc/PowerRunAsAttached

PowerRunAsAttached is a ported version of RunAsAttachedLocal in Powershell with inline CSharp.

This script allows to spawn a new interactive console as another user account in the same calling console (console instance/window).

One possible example is that this tool gives you with ease the possibility to do vertical / horizontal privilege escalation through your already established Netcat / WinRM session.

Usage

You can use this script both as a PowerShell Module or Raw Script (Pasted, from Encoded Base64 String, DownloadString(...) etc...).

As a Module

Choose a registered PowerShell Module location (see echo $env:PSModulePath)

Create a folder called PowerRunAsAttached and place the PowerRunAsAttached.psm1 file inside the new folder.

Open a new PowerShell Window and enter Import-Module PowerRunAsAttached

The module should be imported with available functions:

  • Invoke-RunAsAttached

As a Raw Script

You can import this script alternatively by:

  • Pasting the whole code to a new PowerShell window
  • Importing a Base64 encoded version of the code through IEX/Invoke-Expression
  • Remote Location through DownloadString(...) then IEX/Invoke-Expression
  • Your imagination

Available Commands

Invoke-RunAsAttached

Run a new cmd.exe as another user.

Notice, it starts cmd.exe by default, but you can replace it with powershell.exe or even add an extra argument to the function to support another shell. You can anyway run powershell.exe from cmd.exe. What I like to call shell inception is perfectly supported.

Parameters

  • Username (MANDATORY): A Valid Microsoft Windows User Account
  • Password (MANDATORY): Associated account password
Example

Invoke-RunAsAttached -Username "darkcodersc" -Password "testmepliz"

Demo Video

https://www.youtube.com/watch?v=n71apwuPZYw

PowerRunAsAttached Code

<#-------------------------------------------------------------------------------
    .Developer
        Jean-Pierre LESUEUR (@DarkCoderSc)
        https://www.twitter.com/darkcodersc
        https://github.com/DarkCoderSc
        www.phrozen.io
        jplesueur@phrozen.io
        PHROZEN
    .License
        Apache License
        Version 2.0, January 2004
        http://www.apache.org/licenses/
-------------------------------------------------------------------------------#>   

Add-Type -Language CSharp -TypeDefinition @'
    using System;
    using System.IO;
    using System.Net;
    using System.Diagnostics;    
    using System.Threading;
    using System.Security;
    public class RunAsAttached
    {
        private string Username = "";
        private SecureString SecurePassword = null;
        private string Domain = "";
        private Process Proc = null;
        private readonly object CriticalSection = new object();
        public void ReadStdThread(Process proc, bool stdErr = false) 
        {        
            StreamReader reader = null;
            if (stdErr)
            {
                reader = proc.StandardError;
            } 
            else 
            {
                reader = proc.StandardOutput;
            }
            char[] buffer = new char[1024];
            while (!proc.HasExited) 
            {
                int read = reader.ReadAsync(buffer, 0, buffer.Length).Result;
                lock (this.CriticalSection) 
                {
                    if (stdErr) {Console.ForegroundColor = ConsoleColor.Red;}
                    Console.Write(buffer, 0, read);
                    if (stdErr) {Console.ResetColor();}
                }
            }            
        }
        public RunAsAttached(string username, string password, string domain = "") 
        {
            this.Username = username;            
            this.Domain = domain;
            this.SecurePassword = new NetworkCredential("", password).SecurePassword;
        }
        public void Spawn() 
        {
            ProcessStartInfo processInformation = new ProcessStartInfo();                    

            processInformation.FileName = "cmd.exe";
            processInformation.WorkingDirectory = Environment.GetEnvironmentVariable("SystemRoot");
            processInformation.UseShellExecute = false;
            processInformation.RedirectStandardError = true;
            processInformation.RedirectStandardOutput = true;
            processInformation.RedirectStandardInput = true;
            processInformation.Domain = this.Domain;
            processInformation.UserName = this.Username;
            processInformation.Password = this.SecurePassword;
            processInformation.Arguments = "";
            processInformation.CreateNoWindow = true;
            Console.WriteLine(processInformation.FileName);
            this.Proc = new Process();
            this.Proc.StartInfo = processInformation;

            this.Proc.Start();
            Thread stdOutReader = new Thread(() => this.ReadStdThread(this.Proc));
            Thread stdErrReader = new Thread(() => this.ReadStdThread(this.Proc, true));

            stdOutReader.Start();
            stdErrReader.Start();
            while (!this.Proc.HasExited) 
            {
                this.Proc.StandardInput.WriteLine(Console.ReadLine());
            }
            Console.WriteLine("...");
        }
    }
'@ 

function Invoke-RunAsAttached
{
    param (
        [Parameter(Mandatory=$true)]
        [string] $Username,
        [Parameter(Mandatory=$true)]
        [string] $Password,
        [string] $Domain = ""
    )


    $runAsAttached = New-Object -TypeName RunAsAttached -ArgumentList $Username, $Password, $Domain    

    $runAsAttached.Spawn()
}

try {  
    Export-ModuleMember -Function Invoke-RunAsAttached
} catch {}

CSharp Version: SharpRunAsAttached

You will find a version of this project in pure C#

/*-------------------------------------------------------------------------------
    .Developer
        Jean - Pierre LESUEUR(@DarkCoderSc)
        https://www.twitter.com/darkcodersc
        https://github.com/DarkCoderSc
        www.phrozen.io
        jplesueur@phrozen.io
        PHROZEN
    .License
        Apache License
        Version 2.0, January 2004
        http://www.apache.org/licenses/
    .Todo
        - Better command line argument handling
    Usage: SharpRunAsAttached <username> <password> <domain>
-------------------------------------------------------------------------------*/

using System;
using System.IO;
using System.Net;
using System.Diagnostics;
using System.Threading;
using System.Security;

namespace SharpRunAsAttached
{
    public class RunAsAttached
    {
        private string Username = "";
        private SecureString SecurePassword = null;
        private string Domain = "";
        private Process Proc = null;
        private readonly object CriticalSection = new object();
        public void ReadStdThread(Process proc, bool stdErr = false)
        {
            StreamReader reader = null;
            if (stdErr)
            {
                reader = proc.StandardError;
            } 
            else 
            {
                reader = proc.StandardOutput;
            }

            char[] buffer = new char[1024];
            while (!proc.HasExited)
            {
                int read = reader.ReadAsync(buffer, 0, buffer.Length).Result;
                lock (this.CriticalSection)
                {
                    if (stdErr) { Console.ForegroundColor = ConsoleColor.Red; }
                    Console.Write(buffer, 0, read);
                    if (stdErr) { Console.ResetColor(); }
                }
            }
        }
        public RunAsAttached(string username, string password, string domain = "")
        {
            this.Username = username;
            this.Domain = domain;
            this.SecurePassword = new NetworkCredential("", password).SecurePassword;
        }
        public void Spawn()
        {
            ProcessStartInfo processInformation = new ProcessStartInfo();

            processInformation.FileName = "cmd.exe";
            processInformation.WorkingDirectory = Environment.GetEnvironmentVariable("SystemRoot");
            processInformation.UseShellExecute = false;
            processInformation.RedirectStandardError = true;
            processInformation.RedirectStandardOutput = true;
            processInformation.RedirectStandardInput = true;
            processInformation.Domain = this.Domain;
            processInformation.UserName = this.Username;
            processInformation.Password = this.SecurePassword;
            processInformation.Arguments = "";
            processInformation.CreateNoWindow = true;
            Console.WriteLine(processInformation.FileName);
            this.Proc = new Process();
            this.Proc.StartInfo = processInformation;

            this.Proc.Start();
            Thread stdOutReader = new Thread(() => this.ReadStdThread(this.Proc));
            Thread stdErrReader = new Thread(() => this.ReadStdThread(this.Proc, true));

            stdOutReader.Start();
            stdErrReader.Start();
            while (!this.Proc.HasExited)
            {
                this.Proc.StandardInput.WriteLine(Console.ReadLine());
            }

            Console.WriteLine("...");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(args.Length);
            if (args.Length < 2)
            {
                throw new ArgumentException("Missing mandatory arguments. Ex: SharpRunAsAttached <username> <password>");
            }

            string domain = "";            
            if (args.Length == 3)
            {
                domain = args[2];
            }

            RunAsAttached runAsAttached = new RunAsAttached(args[0], args[1], domain);

            runAsAttached.Spawn();
        }
    }
}

Pure PowerShell Version

Bellow an alternative without using inline C# code.

<#-------------------------------------------------------------------------------
    .Developer
        Jean-Pierre LESUEUR (@DarkCoderSc)
        https://www.twitter.com/darkcodersc
        https://github.com/DarkCoderSc
        www.phrozen.io
        jplesueur@phrozen.io
        PHROZEN
    .License
        Apache License
        Version 2.0, January 2004
        http://www.apache.org/licenses/
-------------------------------------------------------------------------------#>   

$global:CriticalSection = [HashTable]::Synchronized(@{
    Host = $host
    StdErrTick = 0
})

function Add-StdHandler
{     
    param (
        [Parameter(Mandatory=$true)]
        [System.IO.StreamReader] $Stream,

        [bool] $StandardErrorFlag = $false
    )

    $stdRunspace = [RunspaceFactory]::CreateRunspace()
    $stdRunspace.ThreadOptions = "ReuseThread"
    $stdRunspace.ApartmentState = "STA"
    $stdRunspace.Open() 

    $syncObjects = [HashTable]::Synchronized(@{})

    $stdRunspace.SessionStateProxy.SetVariable("CriticalSection", $global:CriticalSection)
    $stdRunspace.SessionStateProxy.SetVariable("Stream", $Stream);
    $stdRunspace.SessionStateProxy.SetVariable("StandardErrorFlag", $StandardErrorFlag);

    $psStdInstance = [PowerShell]::Create().AddScript({     
        try
        {           
            while ($true)
            {                            
                if ((-not $StandardErrorFlag) -and (([Environment]::TickCount - $CriticalSection.StdErrTick) -le 100))
                {
                    Start-Sleep -Milliseconds 200
                    continue
                }      

                if ($StandardErrorFlag)
                {
                    $CriticalSection.StdErrTick = [Environment]::TickCount # Update
                }

                $CriticalSection.host.UI.Write([char]$Stream.BaseStream.ReadByte())                          
            }
        } catch { break }            
    })

    $psStdInstance.Runspace = $stdRunspace

    $psStdInstance.BeginInvoke() | Out-Null

    return $stdRunspace  
}

function Invoke-RunAsAttached
{
    param (
        [Parameter(Mandatory=$true)]
        [string] $Username,
        [Parameter(Mandatory=$true)]
        [string] $Password,
        [string] $Domain = ""
    )

    $protectedPassword = ConvertTo-SecureString $Password -AsPlainText -Force

    $processInformation = New-Object System.Diagnostics.ProcessStartInfo
    $processInformation.FileName = "cmd.exe"
    $processInformation.WorkingDirectory = $env:SystemRoot      
    $processInformation.UseShellExecute = $false    
    $processInformation.RedirectStandardError = $true
    $processInformation.RedirectStandardOutput = $true
    $processInformation.RedirectStandardInput = $true
    $processInformation.Domain = $Domain
    $processInformation.Username = $Username
    $processInformation.Password = $protectedPassword
    $processInformation.Arguments = ""
    $processInformation.CreateNoWindow = $true

    $proc = New-Object System.Diagnostics.Process

    $proc.StartInfo = $processInformation

    $procResult = $proc.Start()

    if (-not $procResult)
    {
        return
    }    

    $psInstances = New-Object System.Collections.ArrayList
    try
    {
        $psInstance = (Add-StdHandler -Stream $proc.StandardError -StandardErrorFlag $true)
        if ($psInstance -eq $null)
        {
            throw "Could not create ""StandardError"" handler."
        }

        $psInstances.Add($psInstance) | Out-Null

        $psInstance = (Add-StdHandler -Stream $proc.StandardOutput)
        if ($psInstance -eq $null)
        {
            throw "Could not create ""StandardOutpout"" handler."
        }

        $psInstances.Add($psInstance) | Out-Null

        while (-not $proc.HasExited)
        {                               
            $proc.StandardInput.WriteLine((Read-Host))
        }
    }
    finally
    {
        foreach ($psInstance in $psInstances)
        {
            $psInstance.Close()
            $psInstance.Dispose()
        }
    }
}

try {  
    Export-ModuleMember -Function Invoke-RunAsAttached
} catch {}

Written the Dec. 3, 2021, 11:57 a.m. by Jean-Pierre LESUEUR

Updated: ago.