Compare commits

..

1 Commits

10 changed files with 174 additions and 415 deletions

View File

@@ -212,14 +212,15 @@ jobs:
steps:
# Download repo
- uses: actions/checkout@v5
- uses: actions/checkout@v2
with:
ref: ${{ github.head_ref }}
# Setup go
- uses: actions/setup-go@v6
- uses: actions/setup-go@v2
with:
go-version: '1.23'
go-version: 1.17.0-rc1
stable: false
- run: go version
# Build linpeas

View File

@@ -1,72 +0,0 @@
# Title: Software Information - PostgreSQL Event Triggers
# ID: SI_Postgresql_Event_Triggers
# Author: HT Bot
# Last Update: 19-11-2025
# Description: Detect unsafe PostgreSQL event triggers and postgres_fdw custom scripts that grant temporary SUPERUSER
# License: GNU GPL
# Version: 1.0
# Functions Used: echo_not_found, print_2title, print_info
# Global Variables: $DEBUG, $E, $SED_GREEN, $SED_RED, $SED_YELLOW, $TIMEOUT
# Initial Functions:
# Generated Global Variables: $psql_bin, $psql_evt_output, $psql_evt_status, $psql_evt_err_line, $postgres_fdw_dirs, $postgres_fdw_hits, $old_ifs, $evtname, $enabled, $owner, $owner_is_super, $func, $func_owner, $func_owner_is_super, $IFS
# Fat linpeas: 0
# Small linpeas: 1
if [ "$DEBUG" ] || { [ "$TIMEOUT" ] && [ "$(command -v psql 2>/dev/null || echo -n '')" ]; }; then
print_2title "PostgreSQL event trigger ownership & postgres_fdw hooks"
print_info "https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#postgresql-event-triggers"
psql_bin="$(command -v psql 2>/dev/null || echo -n '')"
if [ "$TIMEOUT" ] && [ "$psql_bin" ]; then
psql_evt_output="$($TIMEOUT 5 "$psql_bin" -w -X -q -A -t -d postgres -c "WITH evt AS ( SELECT e.evtname, e.evtenabled, pg_get_userbyid(e.evtowner) AS trig_owner, tr.rolsuper AS trig_owner_super, n.nspname || '.' || p.proname AS function_name, pg_get_userbyid(p.proowner) AS func_owner, fr.rolsuper AS func_owner_super FROM pg_event_trigger e JOIN pg_proc p ON e.evtfoid = p.oid JOIN pg_namespace n ON p.pronamespace = n.oid LEFT JOIN pg_roles tr ON tr.oid = e.evtowner LEFT JOIN pg_roles fr ON fr.oid = p.proowner ) SELECT evtname || '|' || evtenabled || '|' || COALESCE(trig_owner,'?') || '|' || COALESCE(CASE WHEN trig_owner_super THEN 'yes' ELSE 'no' END,'unknown') || '|' || function_name || '|' || COALESCE(func_owner,'?') || '|' || COALESCE(CASE WHEN func_owner_super THEN 'yes' ELSE 'no' END,'unknown') FROM evt WHERE COALESCE(trig_owner_super,false) = false OR COALESCE(func_owner_super,false) = false;" 2>&1)"
psql_evt_status=$?
if [ $psql_evt_status -eq 0 ]; then
if [ "$psql_evt_output" ]; then
echo "Non-superuser-owned event triggers were found (trigger|enabled?|owner|owner_is_super|function|function_owner|fn_owner_is_super):" | sed -${E} "s,.*,${SED_RED},"
printf "%s\n" "$psql_evt_output" | while IFS='|' read evtname enabled owner owner_is_super func func_owner func_owner_is_super; do
case "$enabled" in
O) enabled="enabled" ;;
D) enabled="disabled" ;;
*) enabled="status_$enabled" ;;
esac
echo " - $evtname ($enabled) uses $func owned by $func_owner (superuser:$func_owner_is_super); trigger owner: $owner (superuser:$owner_is_super)" | sed -${E} "s,superuser:no,${SED_RED},g"
done
else
echo "No event triggers owned by non-superusers were returned." | sed -${E} "s,.*,${SED_GREEN},"
fi
else
psql_evt_err_line=$(printf '%s\n' "$psql_evt_output" | head -n1)
echo "Could not query pg_event_trigger (psql exit $psql_evt_status): $psql_evt_err_line" | sed -${E} "s,.*,${SED_YELLOW},"
fi
else
if ! [ "$TIMEOUT" ]; then
echo_not_found "timeout"
fi
if ! [ "$psql_bin" ]; then
echo_not_found "psql"
fi
fi
postgres_fdw_dirs="/etc/postgresql /var/lib/postgresql /var/lib/postgres /usr/lib/postgresql /usr/local/lib/postgresql /opt/supabase /opt/postgres /srv/postgres"
postgres_fdw_hits=""
for d in $postgres_fdw_dirs; do
if [ -d "$d" ]; then
old_ifs="$IFS"
IFS="\n"
for f in $(find "$d" -maxdepth 5 -type f \( -name '*postgres_fdw*.sql' -o -name '*postgres_fdw*.psql' -o -name 'after-create.sql' \) 2>/dev/null); do
if [ -f "$f" ] && grep -qiE "alter[[:space:]]+role[[:space:]]+postgres[[:space:]]+superuser" "$f" 2>/dev/null; then
postgres_fdw_hits="$postgres_fdw_hits\n$f"
fi
done
IFS="$old_ifs"
fi
done
if [ "$postgres_fdw_hits" ]; then
echo "Detected postgres_fdw custom scripts granting postgres SUPERUSER (check for SupaPwn-style window):" | sed -${E} "s,.*,${SED_RED},"
printf "%s\n" "$postgres_fdw_hits" | sed "s,^, - ,"
fi
fi
echo ""

View File

@@ -29,7 +29,7 @@ fi
peass{SSH}
grep "PermitRootLogin \|ChallengeResponseAuthentication \|PasswordAuthentication \|UsePAM \|Port\|PermitEmptyPasswords\|PubkeyAuthentication\|ListenAddress\|ForwardAgent\|AllowAgentForwarding\|AuthorizedKeysFile" /etc/ssh/sshd_config 2>/dev/null | grep -v "#" | sed -${E} "s,PermitRootLogin.*es|PermitEmptyPasswords.*es|ChallengeResponseAuthentication.*es|FordwardAgent.*es,${SED_RED},"
grep "PermitRootLogin \|ChallengeResponseAuthentication \|PasswordAuthentication \|UsePAM \|Port\|PermitEmptyPasswords\|PubkeyAuthentication\|ListenAddress\|ForwardAgent\|AllowAgentForwarding\|AuthorizedKeysFiles" /etc/ssh/sshd_config 2>/dev/null | grep -v "#" | sed -${E} "s,PermitRootLogin.*es|PermitEmptyPasswords.*es|ChallengeResponseAuthentication.*es|FordwardAgent.*es,${SED_RED},"
if ! [ "$SEARCH_IN_FOLDER" ]; then
if [ "$TIMEOUT" ]; then

View File

@@ -0,0 +1,64 @@
# Title: Interesting Files - Suspicious sed persistence commands in history
# ID: IF_Suspicious_sed_history
# Author: HT Bot
# Last Update: 26-11-2025
# Description: Flags sed history entries that write/read sensitive startup files, indicating possible prompt-injection persistence (e.g., CVE-2025-64755 style attacks).
# License: GNU GPL
# Version: 1.0
# Functions Used: print_2title
# Global Variables: $DEBUG, $HOME, $PSTORAGE_HISTORY
# Initial Functions:
# Generated Global Variables: $sed_history_sensitive, $sed_history_pattern, $history_candidates, $matches
# Fat linpeas: 0
# Small linpeas: 1
sed_history_sensitive='\\.zsh(env|rc|profile|login|logout)|\\.zprofile|\\.zlogin|\\.zlogout|\\.bash(rc|_profile|_login|_logout)?|\\.profile|\\.kshrc|\\.cshrc|\\.login|\\.aws/credentials|\\.ssh/(authorized_keys|config)|\\.kube/config'
sed_history_pattern="sed[^|;&]*[wWrR][[:space:]]*(~|/|\\.)[^|;&]*(${sed_history_sensitive})"
history_candidates=""
if [ "$PSTORAGE_HISTORY" ]; then
history_candidates="$PSTORAGE_HISTORY"
fi
if [ -z "$history_candidates" ]; then
if [ "$HOME" ]; then
for hf in "$HOME/.bash_history" "$HOME/.zsh_history" "$HOME/.zhistory" "$HOME/.history" "$HOME/.sh_history" "$HOME/.ksh_history" "$HOME/.config/fish/fish_history"; do
if [ -r "$hf" ]; then
if [ "$history_candidates" ]; then
history_candidates="$history_candidates"$'\n'"$hf"
else
history_candidates="$hf"
fi
fi
done
fi
for hf in "/root/.bash_history" "/root/.zsh_history" "/var/root/.zsh_history" "/var/root/.bash_history"; do
if [ -r "$hf" ]; then
if [ "$history_candidates" ]; then
history_candidates="$history_candidates"$'\n'"$hf"
else
history_candidates="$hf"
fi
fi
done
fi
if [ -z "$history_candidates" ] && [ -d "$HOME" ]; then
history_candidates=$(find "$HOME" -maxdepth 2 -type f \( -name "*_history" -o -name ".*history" -o -name "history" \) 2>/dev/null | head -n 40)
fi
history_candidates=$(printf "%s\n" "$history_candidates" | awk 'NF && !seen[$0]++')
if [ "$history_candidates" ] || [ "$DEBUG" ]; then
print_2title "Suspicious sed commands writing sensitive files (history)"
printf "%s\n" "$history_candidates" | while IFS= read -r f; do
[ -n "$f" ] || continue
[ -r "$f" ] || continue
matches=$(grep -Ein --color=never -E "$sed_history_pattern" "$f" 2>/dev/null | head -n 20)
if [ "$matches" ]; then
printf "%s\n" "$matches" | sed -${E} "s,${sed_history_sensitive},${SED_RED},g"
fi
done
echo ""
fi

View File

@@ -0,0 +1,58 @@
# Title: Interesting Files - Suspicious payloads in shell startup files
# ID: IF_Suspicious_startup_payloads
# Author: HT Bot
# Last Update: 26-11-2025
# Description: Scans shell startup files for reverse-shell style commands likely dropped via sed-based persistence.
# License: GNU GPL
# Version: 1.0
# Functions Used: print_2title
# Global Variables: $DEBUG, $HOME
# Initial Functions:
# Generated Global Variables: $startup_indicator_pattern, $startup_files, $matches
# Fat linpeas: 0
# Small linpeas: 1
startup_indicator_pattern='curl[[:space:]].*\|[[:space:]]*(bash|sh)|wget[[:space:]].*\|[[:space:]]*(bash|sh)|bash[[:space:]]+-i[[:space:]]+>&|/dev/tcp|nc[[:space:]].*(-e|/bin/sh)|ncat[[:space:]].*(-e|/bin/sh)|socat[[:space:]]+TCP|python[[:space:]]+-c[[:space:]].*[Ss]ocket|perl[[:space:]]+-e[[:space:]].*[Ss]ocket|ruby[[:space:]]+-rsocket|php[[:space:]]+-r[[:space:]].*fsockopen'
startup_files=""
if [ "$HOME" ]; then
for f in "$HOME/.zshenv" "$HOME/.zprofile" "$HOME/.zlogin" "$HOME/.zlogout" "$HOME/.zshrc" \
"$HOME/.bashrc" "$HOME/.bash_profile" "$HOME/.bash_login" "$HOME/.bash_logout" "$HOME/.profile" \
"$HOME/.kshrc" "$HOME/.cshrc" "$HOME/.shrc" "$HOME/.config/fish/config.fish"; do
if [ -r "$f" ]; then
if [ "$startup_files" ]; then
startup_files="$startup_files"$'\n'"$f"
else
startup_files="$f"
fi
fi
done
fi
for f in "/etc/zshenv" "/etc/zprofile" "/etc/zlogin" "/etc/zlogout" "/etc/zsh/zshrc" "/etc/zshrc" \
"/etc/profile" "/etc/bash.bashrc" "/etc/bashrc" "/usr/local/etc/zshenv" "/usr/local/etc/zprofile" \
"/usr/local/etc/zlogin" "/usr/local/etc/zlogout" "/usr/local/etc/zshrc"; do
if [ -r "$f" ]; then
if [ "$startup_files" ]; then
startup_files="$startup_files"$'\n'"$f"
else
startup_files="$f"
fi
fi
done
startup_files=$(printf "%s\n" "$startup_files" | awk 'NF && !seen[$0]++')
if [ "$startup_files" ] || [ "$DEBUG" ]; then
print_2title "Suspicious commands sourced by shell startup files"
printf "%s\n" "$startup_files" | while IFS= read -r f; do
[ -n "$f" ] || continue
[ -r "$f" ] || continue
matches=$(grep -Ein --color=never -E "$startup_indicator_pattern" "$f" 2>/dev/null | head -n 20)
if [ "$matches" ]; then
printf "%s\n" "$matches" | sed -${E} "s,${startup_indicator_pattern},${SED_RED},g"
fi
done
echo ""
fi

View File

@@ -371,7 +371,7 @@ echo ""
printf ${BLUE}"Linux Privesc Checklist: ${YELLOW}https://book.hacktricks.wiki/en/linux-hardening/linux-privilege-escalation-checklist.html\n"$NC
echo " LEGEND:" | sed "s,LEGEND,${C}[1;4m&${C}[0m,"
echo " RED/YELLOW: 95% a PE vector" | sed "s,RED/YELLOW,${SED_RED_YELLOW},"
echo " RED: You should take a look into it" | sed "s,RED,${SED_RED},"
echo " RED: You should take a look to it" | sed "s,RED,${SED_RED},"
echo " LightCyan: Users with console" | sed "s,LightCyan,${SED_LIGHT_CYAN},"
echo " Blue: Users without console & mounted devs" | sed "s,Blue,${SED_BLUE},"
echo " Green: Common things (users, groups, SUID/SGID, mounts, .sh scripts, cronjobs) " | sed "s,Green,${SED_GREEN},"
@@ -514,4 +514,4 @@ else
HOMESEARCH="$HOME $HOMESEARCH"
fi
fi
GREPHOMESEARCH=$(echo "$HOMESEARCH" | sed 's/ *$//g' | tr " " "|") #Remove ending spaces before putting "|"
GREPHOMESEARCH=$(echo "$HOMESEARCH" | sed 's/ *$//g' | tr " " "|") #Remove ending spaces before putting "|"

View File

@@ -0,0 +1,43 @@
# Title: Variables - History files inventory
# ID: PSTORAGE_HISTORY
# Author: HT Bot
# Last Update: 26-11-2025
# Description: Collects readable shell history files to be reused by other modules.
# License: GNU GPL
# Version: 1.0
# Functions Used:
# Global Variables: $HOME
# Initial Functions:
# Generated Global Variables: $PSTORAGE_HISTORY, $history_inventory_candidates
# Fat linpeas: 0
# Small linpeas: 1
history_inventory_candidates=""
add_history_path() {
[ -n "$1" ] || return 0
[ -r "$1" ] || return 0
if [ "$history_inventory_candidates" ]; then
history_inventory_candidates="${history_inventory_candidates}"$'
'"$1"
else
history_inventory_candidates="$1"
fi
}
if [ "$HOME" ]; then
for hf in "$HOME/.bash_history" "$HOME/.bash_logout" "$HOME/.bash_login" "$HOME/.bash_profile" "$HOME/.profile" "$HOME/.zsh_history" "$HOME/.zhistory" "$HOME/.zshrc" "$HOME/.zlogin" "$HOME/.zlogout" "$HOME/.zshenv" "$HOME/.ksh_history" "$HOME/.kshrc" "$HOME/.cshrc" "$HOME/.history" "$HOME/.sh_history" "$HOME/.config/fish/fish_history"; do
add_history_path "$hf"
done
fi
for hf in "/root/.bash_history" "/root/.zsh_history" "/var/root/.bash_history" "/var/root/.zsh_history" "/etc/profile" "/etc/zprofile" "/etc/zlogin" "/etc/zlogout" "/etc/zsh/zshrc" "/etc/zshenv" "/etc/zshrc" "/etc/bash.bashrc" "/etc/bashrc"; do
add_history_path "$hf"
done
if [ -z "$history_inventory_candidates" ] && [ -n "$HOME" ] && [ -d "$HOME" ]; then
history_inventory_candidates=$(find "$HOME" -maxdepth 2 -type f \( -name "*_history" -o -name ".*history" -o -name "history" \) 2>/dev/null | head -n 60)
fi
PSTORAGE_HISTORY=$(printf "%s
" "$history_inventory_candidates" | awk 'NF && !seen[$0]++')

View File

@@ -405,7 +405,7 @@ CALL :T_Progress 1
:BasicUserInfo
CALL :ColorLine "%E%32m[*]%E%97m BASIC USER INFO
ECHO. [i] Check if you are inside the Administrators group or if you have enabled any token that can be use to escalate privileges like SeImpersonatePrivilege, SeAssignPrimaryPrivilege, SeTcbPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeCreateTokenPrivilege, SeLoadDriverPrivilege, SeTakeOwnershipPrivilege, SeDebugPrivilege
ECHO. [i] Check if you are inside the Administrators group or if you have enabled any token that can be use to escalate privileges like SeImpersonatePrivilege, SeAssignPrimaryPrivilege, SeTcbPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeCreateTokenPrivilege, SeLoadDriverPrivilege, SeTakeOwnershipPrivilege, SeDebbugPrivilege
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#users--groups
ECHO.
CALL :ColorLine " %E%33m[+]%E%97m CURRENT USER"

View File

@@ -19,14 +19,6 @@ Download the **[latest releas from here](https://github.com/peass-ng/PEASS-ng/re
powershell "IEX(New-Object Net.WebClient).downloadString('https://raw.githubusercontent.com/peass-ng/PEASS-ng/master/winPEAS/winPEASps1/winPEAS.ps1')"
```
## Recent Updates
- Added Active Directory awareness checks to highlight Kerberos-only environments (NTLM restrictions) and time skew issues before attempting ticket-based attacks.
- winPEAS.ps1 now reviews AD-integrated DNS ACLs to flag zones where low-privileged users can register/modify records (dynamic DNS hijack risk).
- Enumerates high-value SPN accounts and weak gMSA password readers so you can immediately target Kerberoastable admins or abused service accounts.
- Surfaces Schannel certificate mapping settings to warn about ESC10-style certificate abuse opportunities when UPN mapping is enabled.
## Advisory
All the scripts/binaries of the PEAS Suite should be used for authorized penetration testing and/or educational purposes only. Any misuse of this software will not be the responsibility of the author or of any other collaborator. Use it at your own networks and/or with the network owner's permission.

View File

@@ -148,244 +148,6 @@ function Get-ClipBoardText {
}
}
function Get-DomainContext {
try {
return [System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain()
}
catch {
return $null
}
}
function Convert-SidToName {
param(
$SidInput
)
if ($null -eq $SidInput) { return $null }
try {
if ($SidInput -is [System.Security.Principal.SecurityIdentifier]) {
$sidObject = $SidInput
}
else {
$sidObject = New-Object System.Security.Principal.SecurityIdentifier($SidInput)
}
return $sidObject.Translate([System.Security.Principal.NTAccount]).Value
}
catch {
try { return $sidObject.Value }
catch { return [string]$SidInput }
}
}
function Get-WeakDnsUpdateFindings {
param(
[System.DirectoryServices.ActiveDirectory.Domain]$DomainContext
)
if (-not $DomainContext) { return @() }
$domainDN = $DomainContext.GetDirectoryEntry().distinguishedName
$forestDN = $DomainContext.Forest.RootDomain.GetDirectoryEntry().distinguishedName
$paths = @(
"LDAP://CN=MicrosoftDNS,DC=DomainDnsZones,$domainDN",
"LDAP://CN=MicrosoftDNS,DC=ForestDnsZones,$forestDN",
"LDAP://CN=MicrosoftDNS,$domainDN"
)
$weakPatterns = @(
"authenticated users",
"everyone",
"domain users"
)
$dangerousRights = @("GenericAll", "GenericWrite", "CreateChild", "WriteProperty", "WriteDacl", "WriteOwner")
$findings = @()
foreach ($path in $paths) {
try {
$container = New-Object System.DirectoryServices.DirectoryEntry($path)
$null = $container.NativeGuid
}
catch { continue }
$searcher = New-Object System.DirectoryServices.DirectorySearcher($container)
$searcher.Filter = "(objectClass=dnsZone)"
$searcher.PageSize = 500
$results = $searcher.FindAll()
foreach ($result in $results) {
try {
$zoneEntry = $result.GetDirectoryEntry()
$zoneEntry.Options.SecurityMasks = [System.DirectoryServices.SecurityMasks]::Dacl
$sd = $zoneEntry.ObjectSecurity
foreach ($ace in $sd.Access) {
if ($ace.AccessControlType -ne 'Allow') { continue }
$principal = Convert-SidToName $ace.IdentityReference
if (-not $principal) { continue }
$principalLower = $principal.ToLower()
if (-not ($weakPatterns | Where-Object { $principalLower -like "*${_}*" })) { continue }
$rights = $ace.ActiveDirectoryRights.ToString()
if (-not ($dangerousRights | Where-Object { $rights -like "*${_}*" })) { continue }
$findings += [pscustomobject]@{
Zone = $zoneEntry.Properties["name"].Value
Partition = $path.Split(',')[1]
Principal = $principal
Rights = $rights
}
}
}
catch { continue }
}
}
return ($findings | Sort-Object Zone, Principal -Unique)
}
function Get-GmsaReadersReport {
param(
[System.DirectoryServices.ActiveDirectory.Domain]$DomainContext
)
if (-not $DomainContext) { return @() }
$domainDN = $DomainContext.GetDirectoryEntry().distinguishedName
try {
$searcher = New-Object System.DirectoryServices.DirectorySearcher
$searcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$domainDN")
$searcher.Filter = "(&(objectClass=msDS-GroupManagedServiceAccount))"
$searcher.PageSize = 500
[void]$searcher.PropertiesToLoad.Add("sAMAccountName")
[void]$searcher.PropertiesToLoad.Add("msDS-GroupMSAMembership")
$results = $searcher.FindAll()
}
catch { return @() }
$report = @()
foreach ($result in $results) {
$name = $result.Properties["samaccountname"]
$blobs = $result.Properties["msds-groupmsamembership"]
if (-not $blobs) { continue }
$principals = @()
foreach ($blob in $blobs) {
try {
$raw = New-Object System.Security.AccessControl.RawSecurityDescriptor (, $blob)
foreach ($ace in $raw.DiscretionaryAcl) {
$sid = Convert-SidToName $ace.SecurityIdentifier
if ($sid) { $principals += $sid }
}
}
catch { continue }
}
if ($principals.Count -eq 0) { continue }
$principals = $principals | Sort-Object -Unique
$weak = $principals | Where-Object { $_ -match 'Domain Users|Authenticated Users|Everyone' }
$report += [pscustomobject]@{
Account = ($name | Select-Object -First 1)
Allowed = ($principals -join ", ")
WeakPrincipals = if ($weak) { $weak -join ", " } else { "" }
}
}
return $report
}
function Get-PrivilegedSpnTargets {
param(
[System.DirectoryServices.ActiveDirectory.Domain]$DomainContext
)
if (-not $DomainContext) { return @() }
$domainDN = $DomainContext.GetDirectoryEntry().distinguishedName
$keywords = @(
"Domain Admin",
"Enterprise Admin",
"Administrators",
"Exchange",
"IT_",
"Schema Admin",
"Account Operator",
"Server Operator",
"Backup Operator",
"DnsAdmin"
)
try {
$searcher = New-Object System.DirectoryServices.DirectorySearcher
$searcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$domainDN")
$searcher.Filter = "(&(objectClass=user)(servicePrincipalName=*))"
$searcher.PageSize = 500
[void]$searcher.PropertiesToLoad.Add("sAMAccountName")
[void]$searcher.PropertiesToLoad.Add("memberOf")
$results = $searcher.FindAll()
}
catch { return @() }
$findings = @()
foreach ($res in $results) {
$groups = $res.Properties["memberof"]
if (-not $groups) { continue }
$matchedGroups = @()
foreach ($group in $groups) {
$cn = ($group -split ',')[0] -replace '^CN=',''
if ($keywords | Where-Object { $cn -like "*${_}*" }) {
$matchedGroups += $cn
}
}
if ($matchedGroups.Count -gt 0) {
$findings += [pscustomobject]@{
User = ($res.Properties["samaccountname"] | Select-Object -First 1)
Groups = ($matchedGroups | Sort-Object -Unique) -join ', '
}
}
}
return ($findings | Sort-Object User | Select-Object -First 12)
}
function Get-NtlmPolicySummary {
try {
$msv = Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0' -ErrorAction Stop
}
catch { return $null }
$lsa = Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa' -ErrorAction SilentlyContinue
return [pscustomobject]@{
RestrictReceiving = $msv.RestrictReceivingNTLMTraffic
RestrictSending = $msv.RestrictSendingNTLMTraffic
LmCompatibility = if ($lsa) { $lsa.LmCompatibilityLevel } else { $null }
}
}
function Get-TimeSkewInfo {
param(
[System.DirectoryServices.ActiveDirectory.Domain]$DomainContext
)
if (-not $DomainContext) { return $null }
try {
$pdc = $DomainContext.PdcRoleOwner.Name
}
catch { return $null }
try {
$stripchart = w32tm /stripchart /computer:$pdc /dataonly /samples:3 2>$null
$sample = $stripchart | Where-Object { $_ -match ',' } | Select-Object -Last 1
if (-not $sample) { return $null }
$parts = $sample.Split(',')
if ($parts.Count -lt 2) { return $null }
$offsetString = $parts[1].Trim().TrimEnd('s')
[double]$offsetSeconds = 0
if (-not [double]::TryParse($offsetString, [ref]$offsetSeconds)) { return $null }
return [pscustomobject]@{
Source = $pdc
OffsetSeconds = $offsetSeconds
RawSample = $sample
}
}
catch {
return $null
}
}
function Get-AdcsSchannelInfo {
$info = [ordered]@{
MappingValue = $null
UpnMapping = $false
ServiceState = $null
}
try {
$schannel = Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL' -Name 'CertificateMappingMethods' -ErrorAction Stop
$info.MappingValue = $schannel.CertificateMappingMethods
if (($schannel.CertificateMappingMethods -band 0x4) -eq 0x4) { $info.UpnMapping = $true }
}
catch { }
$svc = Get-Service -Name certsrv -ErrorAction SilentlyContinue
if ($svc) { $info.ServiceState = $svc.Status }
return [pscustomobject]$info
}
function Search-Excel {
[cmdletbinding()]
Param (
@@ -1464,95 +1226,6 @@ Write-Host -ForegroundColor Blue "=========|| LISTENING PORTS"
Start-Process NETSTAT.EXE -ArgumentList "-ano" -Wait -NoNewWindow
######################## ACTIVE DIRECTORY / IDENTITY MISCONFIG CHECKS ########################
Write-Host ""
if ($TimeStamp) { TimeElapsed }
Write-Host -ForegroundColor Blue "=========|| ACTIVE DIRECTORY / IDENTITY MISCONFIG CHECKS"
$domainContext = Get-DomainContext
if (-not $domainContext) {
Write-Host "Host appears to be in a workgroup or the AD context could not be resolved. Skipping domain-specific checks." -ForegroundColor DarkGray
}
else {
$ntlmStatus = Get-NtlmPolicySummary
if ($ntlmStatus) {
$recvValue = if ($ntlmStatus.RestrictReceiving -ne $null) { [int]$ntlmStatus.RestrictReceiving } else { -1 }
$sendValue = if ($ntlmStatus.RestrictSending -ne $null) { [int]$ntlmStatus.RestrictSending } else { -1 }
$lmValue = if ($ntlmStatus.LmCompatibility -ne $null) { [int]$ntlmStatus.LmCompatibility } else { -1 }
$ntlmMsg = "Receiving:{0} Sending:{1} LMCompat:{2}" -f $recvValue, $sendValue, $lmValue
if ($recvValue -ge 1 -or $sendValue -ge 1 -or $lmValue -ge 5) {
Write-Host "[!] NTLM is restricted/disabled ($ntlmMsg). Expect Kerberos-only auth paths (sync time before Kerberoasting)." -ForegroundColor Yellow
}
else {
Write-Host "[i] NTLM restrictions appear relaxed ($ntlmMsg)."
}
}
$timeSkew = Get-TimeSkewInfo -DomainContext $domainContext
if ($timeSkew) {
$offsetAbs = [math]::Abs($timeSkew.OffsetSeconds)
$timeMsg = "Offset vs {0}: {1:N3}s (sample: {2})" -f $timeSkew.Source, $timeSkew.OffsetSeconds, $timeSkew.RawSample.Trim()
if ($offsetAbs -gt 5) {
Write-Host "[!] Significant Kerberos time skew detected - $timeMsg" -ForegroundColor Yellow
}
else {
Write-Host "[i] Kerberos time offset looks OK - $timeMsg"
}
}
$dnsFindings = @(Get-WeakDnsUpdateFindings -DomainContext $domainContext)
if ($dnsFindings.Count -gt 0) {
Write-Host "[!] AD-integrated DNS zones allow low-priv principals to write records (dynamic DNS hijack / service MITM risk)." -ForegroundColor Yellow
$dnsFindings | Format-Table Zone,Partition,Principal,Rights -AutoSize | Out-String | Write-Host
}
else {
Write-Host "[i] No obvious insecure dynamic DNS ACLs found with current privileges."
}
$spnFindings = @(Get-PrivilegedSpnTargets -DomainContext $domainContext)
if ($spnFindings.Count -gt 0) {
Write-Host "[!] High-value SPN accounts identified (prime Kerberoast targets):" -ForegroundColor Yellow
$spnFindings | Format-Table User,Groups -AutoSize | Out-String | Write-Host
}
else {
Write-Host "[i] No privileged SPN users detected via quick LDAP search."
}
$gmsaReport = @(Get-GmsaReadersReport -DomainContext $domainContext)
if ($gmsaReport.Count -gt 0) {
$weakGmsa = $gmsaReport | Where-Object { $_.WeakPrincipals -ne "" }
if ($weakGmsa) {
Write-Host "[!] gMSA passwords readable by low-priv groups/principals: " -ForegroundColor Yellow
$weakGmsa | Select-Object Account, WeakPrincipals | Format-Table -AutoSize | Out-String | Write-Host
}
else {
Write-Host "[i] gMSA accounts discovered (review allowed readers below)."
$gmsaReport | Select-Object Account, Allowed | Sort-Object Account | Select-Object -First 5 | Format-Table -Wrap | Out-String | Write-Host
}
}
else {
Write-Host "[i] No gMSA objects found via LDAP."
}
$adcsInfo = Get-AdcsSchannelInfo
if ($adcsInfo.MappingValue -ne $null) {
$hex = ('0x{0:X}' -f [int]$adcsInfo.MappingValue)
if ($adcsInfo.UpnMapping) {
Write-Host ("[!] Schannel CertificateMappingMethods={0} (UPN mapping allowed) - ESC10 certificate abuse possible if you can edit another user's UPN." -f $hex) -ForegroundColor Yellow
}
else {
Write-Host ("[i] Schannel CertificateMappingMethods={0} (UPN mapping flag not set)." -f $hex)
}
if ($adcsInfo.ServiceState) {
Write-Host ("[i] AD CS service state: {0}" -f $adcsInfo.ServiceState)
}
}
else {
Write-Host "[i] Could not read Schannel certificate mapping configuration." -ForegroundColor DarkGray
}
}
Write-Host ""
if ($TimeStamp) { TimeElapsed }
Write-Host -ForegroundColor Blue "=========|| ARP Table"
@@ -1650,7 +1323,7 @@ Write-Host -ForegroundColor Blue "=========|| WHOAMI INFO"
Write-Host ""
if ($TimeStamp) { TimeElapsed }
Write-Host -ForegroundColor Blue "=========|| Check Token access here: https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/privilege-escalation-abusing-tokens.html#abusing-tokens" -ForegroundColor yellow
Write-Host -ForegroundColor Blue "=========|| Check if you are inside the Administrators group or if you have enabled any token that can be use to escalate privileges like SeImpersonatePrivilege, SeAssignPrimaryPrivilege, SeTcbPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeCreateTokenPrivilege, SeLoadDriverPrivilege, SeTakeOwnershipPrivilege, SeDebugPrivilege"
Write-Host -ForegroundColor Blue "=========|| Check if you are inside the Administrators group or if you have enabled any token that can be use to escalate privileges like SeImpersonatePrivilege, SeAssignPrimaryPrivilege, SeTcbPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeCreateTokenPrivilege, SeLoadDriverPrivilege, SeTakeOwnershipPrivilege, SeDebbugPrivilege"
Write-Host "https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#users--groups" -ForegroundColor Yellow
Start-Process whoami.exe -ArgumentList "/all" -Wait -NoNewWindow