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

commit 99e629a6f82e4c3390d905253838724891485505
parent 275cf76649623435ac6cb8e3e73b7a33306e4939
Author: DAEMON <zer0sec.xp@icloud.com>
Date:   Wed, 16 Sep 2026 02:59:10 +0100

Replace unrendered mermaid diagrams with native flow charts

Shiki has no mermaid grammar, so every mermaid code fence rendered as a
dead plaintext listing instead of a diagram. Replace all 65 diagrams
across 35 sheets with a native, on-theme flow component: CSS-flow for
linear, branch and merge charts, and inline SVG for cyclic and back-edge
graphs. Both render as dark terminal plates that flip with the site
theme, with no runtime JS and no external requests.

- add src/styles/flow.css and import it in app.css
- add a shared SVG arrowhead marker in Base.astro
- convert every mermaid fence under src/content/sheets to flow markup

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Diffstat:
M.gitignore | 2++
Msrc/content/sheets/active-directory/adcs-attack-methodology.md | 89+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/content/sheets/active-directory/bloodhound-ce-python.md | 24++++++++++++++++--------
Msrc/content/sheets/active-directory/dpersist2-rogue-ca-certificate-ntauth-injection.md | 21++++++++++++++-------
Msrc/content/sheets/active-directory/faketime.md | 22++++++++++++++--------
Msrc/content/sheets/active-directory/persist3-account-persistence-via-certificate-renewal.md | 23++++++++++++++++-------
Msrc/content/sheets/active-directory/shadow-credentials-msds-keycredentiallink-abuse.md | 22++++++++++++++--------
Msrc/content/sheets/active-directory/theft5-ntlm-theft-via-pkinit-unpac-the-hash.md | 23++++++++++++++---------
Msrc/content/sheets/git-workflow/git.md | 150++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Msrc/content/sheets/password-attacks/hashcat.md | 26++++++++++++++++++--------
Msrc/content/sheets/password-attacks/john-the-ripper.md | 52++++++++++++++++++++++++++++++++++++----------------
Msrc/content/sheets/pentest-workflow/acl-and-object-abuse.md | 54+++++++++++++++++++++++++++++++++++++++++-------------
Msrc/content/sheets/pentest-workflow/active-directory-enumeration.md | 43+++++++++++++++++++++++++++++++------------
Msrc/content/sheets/pentest-workflow/attack-flow-dashboard.md | 50++++++++++++++++++++++++++++++++++----------------
Msrc/content/sheets/pentest-workflow/attack-flow-guide.md | 42+++++++++++++++++++++++++++---------------
Msrc/content/sheets/pentest-workflow/attacking-common-applications-guide.md | 508++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/content/sheets/pentest-workflow/attacking-common-applications.md | 34+++++++++++++++++++++-------------
Msrc/content/sheets/pentest-workflow/attacking-common-modules-dashboard.md | 61++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/content/sheets/pentest-workflow/attacking-common-services.md | 30++++++++++++++++++++----------
Msrc/content/sheets/pentest-workflow/attacking-enterprise-networks.md | 40++++++++++++++++++++++++++++------------
Msrc/content/sheets/pentest-workflow/cpts-exam-attack-flow.md | 102++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/content/sheets/pentest-workflow/domain-trusts-and-cross-forest.md | 61++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/content/sheets/pentest-workflow/foothold-shells-payloads-metasploit.md | 35++++++++++++++++++++++-------------
Msrc/content/sheets/pentest-workflow/htb-attack-flow-playbook.md | 79+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/content/sheets/pentest-workflow/kerberos-attacks.md | 32++++++++++++++++++--------------
Msrc/content/sheets/pentest-workflow/lateral-movement-pivoting-and-loot.md | 37++++++++++++++++++++++++++-----------
Msrc/content/sheets/pentest-workflow/linux-privesc-cpts.md | 38+++++++++++++++++++++++---------------
Msrc/content/sheets/pentest-workflow/most-used-commands.md | 59++++++++++++++++++++++++++++++++---------------------------
Msrc/content/sheets/pentest-workflow/network-service-attack-manual.md | 64+++++++++++++++++++++++++++++++++++++++++++---------------------
Msrc/content/sheets/pentest-workflow/potato-attacks-and-ads-guide.md | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/content/sheets/pentest-workflow/tty-upgrades-and-restricted-shells.md | 48+++++++++++++++++++++++++++++++++---------------
Msrc/content/sheets/pentest-workflow/web-enumeration-and-exploitation.md | 53+++++++++++++++++++++++++++++++++++------------------
Msrc/content/sheets/pentest-workflow/web-shells.md | 34+++++++++++++++++++++-------------
Msrc/content/sheets/pentest-workflow/windows-privesc-cpts.md | 33++++++++++++++++++---------------
Msrc/content/sheets/pentest-workflow/worked-chains.md | 36++++++++++++++++++++++--------------
Msrc/content/sheets/web/dalfox.md | 26++++++++++++++++++--------
Msrc/layouts/Base.astro | 12++++++++++++
Msrc/styles/app.css | 1+
Asrc/styles/flow.css | 344+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
39 files changed, 1765 insertions(+), 743 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -11,3 +11,5 @@ candidates.json /public/pagefind/ # Playwright MCP scratch output (page snapshots, extension crx) .playwright-mcp/ +.vercel +.env* diff --git a/src/content/sheets/active-directory/adcs-attack-methodology.md b/src/content/sheets/active-directory/adcs-attack-methodology.md @@ -18,15 +18,25 @@ source: "vault:ActiveDirectory/ACL-ESC-Techniques/_ADCS Attack Methodology Guide Active Directory Certificate Services binds a cryptographic identity (a certificate) to an AD principal. The moment a certificate can carry an *authentication* EKU and an attacker can influence *whose* identity is stamped into it, the certificate becomes a password-equivalent that survives password resets. Four things go wrong: -```mermaid -flowchart TD - A[Template misconfig<br/>ESC1-3, ESC9, ESC15] --> X[Attacker obtains a cert<br/>for a privileged identity] - B[Object/CA ACL abuse<br/>ESC4, ESC5, ESC7] --> X - C[CA/DC config or bug<br/>ESC6, ESC8, ESC10-16, Certifried] --> X - D[Existing cert theft<br/>THEFT1-5] --> X - X --> Y[PKINIT auth<br/>TGT + NT hash] - Y --> Z[Persistence<br/>PERSIST1-3, DPERSIST1-3] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">ADCS attack surface</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"> + <div class="flow-node">Template misconfig<span class="sub">ESC1-3, ESC9, ESC15</span></div> + <div class="flow-node">Object/CA ACL abuse<span class="sub">ESC4, ESC5, ESC7</span></div> + <div class="flow-node">CA/DC config or bug<span class="sub">ESC6, ESC8, ESC10-16, Certifried</span></div> + <div class="flow-node">Existing cert theft<span class="sub">THEFT1-5</span></div> + </div> + <div class="flow-join"></div> + <div class="flow-rank"><div class="flow-node is-goal">Attacker obtains a cert<span class="sub">for a privileged identity</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">PKINIT auth<span class="sub">TGT + NT hash</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-danger">Persistence<span class="sub">PERSIST1-3, DPERSIST1-3</span></div></div> + </div> + </div> +</figure> > **Why certificates are dangerous —** A stolen or forged authentication certificate is valid until it **expires** (often 1–5 years) or is **revoked**. Password changes do not invalidate it. Forged certs (Golden Certificate, rogue CA) are never seen by the CA's issuance pipeline, so they **cannot be revoked**. @@ -151,33 +161,50 @@ Certificates make excellent persistence because they outlive password resets. | DPERSIST2 — Rogue CA / NTAuth | Add an attacker CA to `NTAuthCertificates` and Root store | | DPERSIST3 — malicious misconfiguration | Plant ESC4/5/7-style ACL backdoors on PKI objects | -```mermaid -flowchart LR - DA[Domain Admin /<br/>CA server access] --> G[DPERSIST1<br/>steal CA key] - DA --> R[DPERSIST2<br/>rogue CA in NTAuth] - DA --> M[DPERSIST3<br/>ACL backdoor] - G --> F[forge cert for<br/>any principal, offline] - R --> F - M --> E[re-run ESC4/5/7<br/>at will] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Domain persistence routes</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 685 330" role="img" aria-label="Domain Admin or CA server access branches into DPERSIST1 steal CA key, DPERSIST2 rogue CA in NTAuth, and DPERSIST3 ACL backdoor; the first two forge a cert for any principal offline, the third re-runs ESC4/5/7 at will"> + <path class="fedge" d="M185,180 L265,84" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M185,180 L265,180" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M185,180 L265,276" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M415,84 L495,132" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M415,180 L495,132" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M415,276 L495,276" marker-end="url(#flow-arrow)" /> + <g class="fnode is-entry"><rect class="fnode__box" x="35" y="156" width="150" height="48" /><text class="fnode__label" x="110" y="177" text-anchor="middle">Domain Admin /<tspan class="sub" x="110" dy="15">CA server access</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="265" y="60" width="150" height="48" /><text class="fnode__label" x="340" y="81" text-anchor="middle">DPERSIST1<tspan class="sub" x="340" dy="15">steal CA key</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="265" y="156" width="150" height="48" /><text class="fnode__label" x="340" y="177" text-anchor="middle">DPERSIST2<tspan class="sub" x="340" dy="15">rogue CA in NTAuth</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="265" y="252" width="150" height="48" /><text class="fnode__label" x="340" y="273" text-anchor="middle">DPERSIST3<tspan class="sub" x="340" dy="15">ACL backdoor</tspan></text></g> + <g class="fnode is-goal"><rect class="fnode__box" x="495" y="108" width="150" height="48" /><text class="fnode__label" x="570" y="129" text-anchor="middle">forge cert for<tspan class="sub" x="570" dy="15">any principal, offline</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="495" y="252" width="150" height="48" /><text class="fnode__label" x="570" y="273" text-anchor="middle">re-run ESC4/5/7<tspan class="sub" x="570" dy="15">at will</tspan></text></g> + </svg> + </div> +</figure> ## 7. Attack Chaining Real engagements chain these. Common paths: -```mermaid -flowchart TD - LP[Low-priv creds] --> F[certipy find] - F -->|vuln template| E1[ESC1/ESC9/ESC15] - F -->|ACL edge| E4[ESC4/ESC5 -> make a template vuln -> ESC1] - F -->|CA rights| E7[ESC7 -> approve own request / ESC6] - F -->|relay vector| E8[ESC8/ESC11 -> relay DC$ -> DA] - E1 --> AUTH[certipy auth -> DA TGT + hash] - E4 --> AUTH - E7 --> AUTH - E8 --> AUTH - AUTH --> DP[DPERSIST1/2/3<br/>domain persistence] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Common attack chains</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Low-priv creds</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">certipy find</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">vuln template</span></div><div class="flow-node">ESC1/ESC9/ESC15</div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">ACL edge</span></div><div class="flow-node">ESC4/ESC5 -&gt; make a template vuln -&gt; ESC1</div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">CA rights</span></div><div class="flow-node">ESC7 -&gt; approve own request / ESC6</div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">relay vector</span></div><div class="flow-node">ESC8/ESC11 -&gt; relay DC$ -&gt; DA</div></div> + </div> + <div class="flow-join"></div> + <div class="flow-rank"><div class="flow-node">certipy auth -&gt; DA TGT + hash</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">DPERSIST1/2/3<span class="sub">domain persistence</span></div></div> + </div> + </div> +</figure> Worked chains: diff --git a/src/content/sheets/active-directory/bloodhound-ce-python.md b/src/content/sheets/active-directory/bloodhound-ce-python.md @@ -40,14 +40,22 @@ sudo apt install bloodhound-ce-python ## 1. Quick Start -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A[Creds or ticket] --> B[bloodhound-ce-python<br/>-c All --zip] - B --> C[*.zip output] - C --> D[Upload in BHCE UI<br/>Administration -> File Ingest] - D --> E[Run Cypher / paths] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Collect to ingest pipeline</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="lr"> + <div class="flow-rank"><div class="flow-node is-entry">Creds or ticket</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">bloodhound-ce-python<span class="sub">-c All --zip</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">*.zip output</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Upload in BHCE UI<span class="sub">Administration -&gt; File Ingest</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">Run Cypher / paths</div></div> + </div> + </div> +</figure> ```bash # Password auth, collect everything, zip the result diff --git a/src/content/sheets/active-directory/dpersist2-rogue-ca-certificate-ntauth-injection.md b/src/content/sheets/active-directory/dpersist2-rogue-ca-certificate-ntauth-injection.md @@ -30,13 +30,20 @@ The forest trusts any certificate chaining to a CA published in the **`NTAuthCer This differs from DPERSIST1 (which steals the *existing* CA key). Here you introduce a *new* trusted CA. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#eb6f92','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - K[Generate rogue<br/>CA keypair] --> P[Publish to<br/>NTAuthCertificates + RootCA] - P --> F[certipy forge<br/>cert for any user] - F --> A[PKINIT auth<br/>as that user] -``` +<figure class="flow plate corners"> +<figcaption class="flow__cap"><span class="flow__kind">Rogue CA persistence</span><span class="flow__dir">LR</span></figcaption> +<div class="flow__body"> +<div class="flow__diagram" data-dir="lr"> +<div class="flow-rank"><div class="flow-node is-entry">Generate rogue<span class="sub">CA keypair</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">Publish to<span class="sub">NTAuthCertificates + RootCA</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">certipy forge<span class="sub">cert for any user</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node is-goal">PKINIT auth<span class="sub">as that user</span></div></div> +</div> +</div> +</figure> *** diff --git a/src/content/sheets/active-directory/faketime.md b/src/content/sheets/active-directory/faketime.md @@ -40,14 +40,20 @@ sudo apt install faketime # ships as libfaketime ## 1. Measuring the Skew -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A[nmap clock-skew<br/>or ntpdate -q] --> B{Skew > 5 min?} - B -->|No| C[Run tool normally] - B -->|Yes| D[faketime wrapper] - D --> E[Kerberos auth succeeds] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Clock-skew check</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="lr"> + <div class="flow-rank"><div class="flow-node is-entry">nmap clock-skew<span class="sub">or ntpdate -q</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Skew &gt; 5 min?</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">No</span></div><div class="flow-node">Run tool normally</div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Yes</span></div><div class="flow-node">faketime wrapper</div><div class="flow-edge"></div><div class="flow-node is-goal">Kerberos auth succeeds</div></div> + </div> + </div> + </div> +</figure> **nmap** reports skew directly on many AD services: diff --git a/src/content/sheets/active-directory/persist3-account-persistence-via-certificate-renewal.md b/src/content/sheets/active-directory/persist3-account-persistence-via-certificate-renewal.md @@ -28,13 +28,22 @@ source: "vault:ActiveDirectory/ACL-ESC-Techniques/PERSIST3 — Account Persisten Templates that allow **renewal** let a holder present their current certificate and receive a fresh one with a new validity window, authenticated *by the existing key* rather than by the user's password. An attacker who obtained a cert (via an ESC, THEFT, or PERSIST1) can therefore roll it forward forever, so long as they renew before each expiry. Password resets never break the chain because renewal never uses the password. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#f6c177','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - C1[cert v1<br/>expires in 30d] -->|renew with key| C2[cert v2<br/>fresh 1-2y] - C2 -->|renew again| C3[cert v3 ...] - C3 -->|forever| C1 -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Renewal persistence loop</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 800 190" role="img" aria-label="cert v1 renews into cert v2, then cert v3, which renews back into the chain forever"> + <path class="fedge" d="M185,82 L323,82" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M475,82 L613,82" marker-end="url(#flow-arrow)" /> + <path class="fedge is-back" d="M690,106 L690,158 L110,158 L110,108" marker-end="url(#flow-arrow)" /> + <g class="fnode"><rect class="fnode__box" x="35" y="58" width="150" height="48" /><text class="fnode__label" x="110" y="79" text-anchor="middle">cert v1<tspan class="sub" x="110" dy="15">expires in 30d</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="325" y="58" width="150" height="48" /><text class="fnode__label" x="400" y="79" text-anchor="middle">cert v2<tspan class="sub" x="400" dy="15">fresh 1-2y</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="615" y="58" width="150" height="48" /><text class="fnode__label" x="690" y="86" text-anchor="middle">cert v3 …</text></g> + <g class="felabel"><rect class="felabel__box" x="216" y="74" width="76" height="16" /><text class="felabel__text" x="254" y="85" text-anchor="middle">renew with key</text></g> + <g class="felabel"><rect class="felabel__box" x="510" y="74" width="68" height="16" /><text class="felabel__text" x="544" y="85" text-anchor="middle">renew again</text></g> + <g class="felabel"><rect class="felabel__box" x="370" y="150" width="60" height="16" /><text class="felabel__text" x="400" y="161" text-anchor="middle">forever</text></g> + </svg> + </div> +</figure> *** diff --git a/src/content/sheets/active-directory/shadow-credentials-msds-keycredentiallink-abuse.md b/src/content/sheets/active-directory/shadow-credentials-msds-keycredentiallink-abuse.md @@ -30,14 +30,20 @@ Windows Hello for Business / Key Trust lets an account authenticate with a publi It is the cleanest way to weaponise a write-ACL edge: unlike a password reset it is reversible and quiet, and unlike an ADCS ESC it needs no vulnerable template — only that PKINIT works in the forest. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - ACL[GenericWrite over target] --> W[Write Key Credential<br/>into msDS-KeyCredentialLink] - W --> P[PKINIT with your<br/>private key] - P --> H[TGT + NT hash of target] - W --> R[Restore attribute<br/>clean up] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Shadow Credentials attack</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="lr"> + <div class="flow-rank"><div class="flow-node is-entry">GenericWrite over target</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Write Key Credential<span class="sub">into msDS-KeyCredentialLink</span></div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">PKINIT with your<span class="sub">private key</span></div><div class="flow-edge"></div><div class="flow-node is-goal">TGT + NT hash of target</div></div> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node is-note">Restore attribute<span class="sub">clean up</span></div></div> + </div> + </div> + </div> +</figure> *** diff --git a/src/content/sheets/active-directory/theft5-ntlm-theft-via-pkinit-unpac-the-hash.md b/src/content/sheets/active-directory/theft5-ntlm-theft-via-pkinit-unpac-the-hash.md @@ -28,15 +28,20 @@ source: "vault:ActiveDirectory/ACL-ESC-Techniques/THEFT5 — NTLM Theft via PKIN When you authenticate with a certificate via **PKINIT**, the KDC returns a TGT whose **PAC** contains the account's **NTLM hash** (so the account can later do NTLM auth after a smart-card logon). "UnPAC-the-hash" requests a **User-to-User (U2U)** service ticket to yourself, decrypts the PAC, and reads that hash out. Net effect: a `.pfx` becomes both a TGT **and** the NT hash, with no password ever touched. "Pass-the-Certificate" is the related idea of simply using the cert to authenticate. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - P[.pfx cert] -->|PKINIT AS-REQ| T[TGT with PAC] - T -->|U2U TGS-REQ to self| U[Decrypt PAC] - U --> H[NT hash extracted] - T --> S[Shell via -k] - H --> PtH[Pass-the-Hash] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">UnPAC-the-Hash flow</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="lr"> + <div class="flow-rank"><div class="flow-node is-entry">.pfx cert</div></div> + <div class="flow-edge"><span class="flow-edge__label">PKINIT AS-REQ</span></div> + <div class="flow-rank"><div class="flow-node">TGT with PAC</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">U2U TGS-REQ to self</span></div><div class="flow-node">Decrypt PAC</div><div class="flow-edge"></div><div class="flow-node is-goal">NT hash extracted</div><div class="flow-edge"></div><div class="flow-node">Pass-the-Hash</div></div> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Shell via -k</div></div> + </div> + </div> + </div> +</figure> *** diff --git a/src/content/sheets/git-workflow/git.md b/src/content/sheets/git-workflow/git.md @@ -15,14 +15,31 @@ source: "vault:Git/git-cheatsheet.md" The mental model: Git tracks snapshots across three areas. Every command moves changes between them. -```mermaid -flowchart LR - W[Working tree<br/>your edits] -->|git add| S[Staging area<br/>index] - S -->|git commit| R[Repository<br/>.git history] - R -->|git checkout / restore| W - R -->|git push| Rm[Remote<br/>GitHub] - Rm -->|git pull / fetch| R -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">The git object model</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 900 200" role="img" aria-label="Working tree to staging to repository to remote, with checkout, restore, pull and fetch flowing back"> + <!-- forward chain --> + <path class="fedge" d="M185,82 L263,82" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M415,82 L493,82" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M645,82 L723,82" marker-end="url(#flow-arrow)" /> + <!-- back edges --> + <path class="fedge is-back" d="M540,106 L540,172 L110,172 L110,108" marker-end="url(#flow-arrow)" /> + <path class="fedge is-back" d="M800,106 L800,148 L600,148 L600,108" marker-end="url(#flow-arrow)" /> + <!-- nodes --> + <g class="fnode"><rect class="fnode__box" x="35" y="58" width="150" height="48" /><text class="fnode__label" x="110" y="79" text-anchor="middle">Working tree<tspan class="sub" x="110" dy="15">your edits</tspan></text></g> + <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">Staging area<tspan class="sub" x="340" dy="15">index</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="495" y="58" width="150" height="48" /><text class="fnode__label" x="570" y="79" text-anchor="middle">Repository<tspan class="sub" x="570" dy="15">.git history</tspan></text></g> + <g class="fnode is-goal"><rect class="fnode__box" x="725" y="58" width="150" height="48" /><text class="fnode__label" x="800" y="79" text-anchor="middle">Remote<tspan class="sub" x="800" dy="15">GitHub</tspan></text></g> + <!-- edge labels --> + <g class="felabel"><rect class="felabel__box" x="199" y="74" width="50" height="16" /><text class="felabel__text" x="224" y="85" text-anchor="middle">git add</text></g> + <g class="felabel"><rect class="felabel__box" x="422" y="74" width="64" height="16" /><text class="felabel__text" x="454" y="85" text-anchor="middle">git commit</text></g> + <g class="felabel"><rect class="felabel__box" x="655" y="74" width="58" height="16" /><text class="felabel__text" x="684" y="85" text-anchor="middle">git push</text></g> + <g class="felabel"><rect class="felabel__box" x="248" y="164" width="164" height="16" /><text class="felabel__text" x="330" y="175" text-anchor="middle">git checkout / restore</text></g> + <g class="felabel"><rect class="felabel__box" x="650" y="140" width="100" height="16" /><text class="felabel__text" x="700" y="151" text-anchor="middle">git pull / fetch</text></g> + </svg> + </div> +</figure> ## 1. Intro & Setup @@ -69,13 +86,21 @@ git commit -am "Fix typo" # add (tracked files) + commit in one st git commit # opens editor for a multi-line message ``` -```mermaid -flowchart LR - A[Edit files] --> B[git status] - B --> C[git add] - C --> D[git commit -m] - D --> A -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">The edit-commit loop</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 900 190" role="img" aria-label="Edit files to git status to git add to git commit, then back to edit files"> + <path class="fedge" d="M185,82 L263,82" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M415,82 L493,82" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M645,82 L723,82" marker-end="url(#flow-arrow)" /> + <path class="fedge is-back" d="M800,106 L800,158 L110,158 L110,108" marker-end="url(#flow-arrow)" /> + <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">Edit files</text></g> + <g class="fnode"><rect class="fnode__box" x="265" y="58" width="150" height="48" /><text class="fnode__label" x="340" y="86" text-anchor="middle">git status</text></g> + <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">git add</text></g> + <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">git commit -m</text></g> + </svg> + </div> +</figure> > **Note — A good commit:** Stage related changes together and write a message in the imperative mood ("Add", "Fix", "Refactor") describing *why*, not just *what*. Use `git add -p` to split unrelated edits into separate commits. @@ -158,19 +183,24 @@ git branch -m old new # rename a branch ### Merging branches -```mermaid -gitGraph - commit id: "init" - commit id: "base" - branch feature-login - checkout feature-login - commit id: "form" - commit id: "validate" - checkout main - commit id: "hotfix" - merge feature-login - commit id: "release" -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Feature branch merge</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">init</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">base</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">branch feature-login</span></div><div class="flow-node">form</div><div class="flow-edge"></div><div class="flow-node">validate</div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">checkout main</span></div><div class="flow-node">hotfix</div></div> + </div> + <div class="flow-join"></div> + <div class="flow-rank"><div class="flow-node">merge feature-login</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">release</div></div> + </div> + </div> +</figure> ```bash # 1. Finish work on the feature branch, commit it @@ -255,12 +285,18 @@ git pull --rebase # fetch + replay your commits on top (linear hi Two ways to start a fresh project. Pick based on whether the code already exists on your machine. -```mermaid -flowchart TD - Q{Code already<br/>on disk?} - Q -->|Yes| A[Local-first:<br/>git init here,<br/>then link empty GitHub repo] - Q -->|No| B[GitHub-first:<br/>create repo on site,<br/>git clone it down] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">New repo path choice</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-decision">Code already<span class="sub">on disk?</span></div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Yes</span></div><div class="flow-node">Local-first:<span class="sub">git init here,</span><span class="sub">then link empty GitHub repo</span></div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">No</span></div><div class="flow-node">GitHub-first:<span class="sub">create repo on site,</span><span class="sub">git clone it down</span></div></div> + </div> + </div> + </div> +</figure> **Step 1 — create the repo on the GitHub website** @@ -325,14 +361,24 @@ git remote add origin https://github.com/YOU/NEWREPO.git git push -u origin main ``` -```mermaid -flowchart LR - A[git clone ...] --> B[rm -rf .git<br/>history gone] - B --> C[git init -b main] - C --> D[git add -A<br/>git commit] - D --> E[remote add origin] - E --> F[git push -u origin main] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Wipe history &amp; re-publish</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="lr"> + <div class="flow-rank"><div class="flow-node is-entry">git clone ...</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-danger">rm -rf .git<span class="sub">history gone</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">git init -b main</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">git add -A<span class="sub">git commit</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">remote add origin</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">git push -u origin main</div></div> + </div> + </div> +</figure> > **Warning — This is destructive and one-way:** `rm -rf .git` permanently deletes every commit, branch, and tag locally. Only do this when you deliberately want a clean slate. Make sure `origin` points at *your* new empty repo before pushing, or you'll try to overwrite the original. @@ -426,15 +472,17 @@ git stash clear # delete all stashes Rebasing moves your branch's commits on top of the latest `main`, producing a straight line instead of a merge commit. -```mermaid -flowchart LR - subgraph Before - M1[main: A-B-C] --- F1[feat: B-D-E] - end - subgraph After - M2[main: A-B-C] --> F2[feat: C-D'-E'] - end -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Rebase: before &amp; after</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="lr"> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-node is-note">Before</div><div class="flow-edge"></div><div class="flow-node">main: A-B-C</div><div class="flow-edge"></div><div class="flow-node">feat: B-D-E</div></div> + <div class="flow-lane"><div class="flow-node is-note">After</div><div class="flow-edge"></div><div class="flow-node">main: A-B-C</div><div class="flow-edge"></div><div class="flow-node">feat: C-D'-E'</div></div> + </div> + </div> + </div> +</figure> ```bash git switch feature/x diff --git a/src/content/sheets/password-attacks/hashcat.md b/src/content/sheets/password-attacks/hashcat.md @@ -29,14 +29,24 @@ Hashcat is **GPU-first**: it excels at fast/salted digests (MD5, SHA-x, NTLM, WP ## 1. Command Anatomy -```mermaid -flowchart LR - A["hashcat"] --> B["-m MODE<br/>hash type"] - B --> C["-a ATTACK<br/>0/1/3/6/7"] - C --> D["hashfile"] - D --> E["wordlist / mask"] - E --> F["-r rules<br/>-O -w tuning"] -``` +<figure class="flow plate corners"> +<figcaption class="flow__cap"><span class="flow__kind">Command anatomy</span><span class="flow__dir">LR</span></figcaption> +<div class="flow__body"> +<div class="flow__diagram" data-dir="lr"> +<div class="flow-rank"><div class="flow-node is-entry">hashcat</div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">-m MODE<span class="sub">hash type</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">-a ATTACK<span class="sub">0/1/3/6/7</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">hashfile</div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">wordlist / mask</div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">-r rules<span class="sub">-O -w tuning</span></div></div> +</div> +</div> +</figure> ```bash hashcat -m 1000 -a 0 ntlm.txt rockyou.txt -r best64.rule -O -w 3 diff --git a/src/content/sheets/password-attacks/john-the-ripper.md b/src/content/sheets/password-attacks/john-the-ripper.md @@ -29,14 +29,24 @@ Use **John the Ripper Jumbo** (`john-jumbo`, the community build shipped on Kali ## 1. Quick Workflow -```mermaid -flowchart LR - A[Obtain hash<br/>or artefact] --> B[Convert with<br/>*2john helper] - B --> C[Identify format<br/>hashid / --list=formats] - C --> D[Pick --format=NAME] - D --> E[Crack:<br/>wordlist -> rules -> incremental] - E --> F[john --show<br/>recover plaintext] -``` +<figure class="flow plate corners"> +<figcaption class="flow__cap"><span class="flow__kind">Quick crack workflow</span><span class="flow__dir">LR</span></figcaption> +<div class="flow__body"> +<div class="flow__diagram" data-dir="lr"> +<div class="flow-rank"><div class="flow-node is-entry">Obtain hash<span class="sub">or artefact</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">Convert with<span class="sub">*2john helper</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">Identify format<span class="sub">hashid / --list=formats</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">Pick --format=NAME</div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">Crack:<span class="sub">wordlist -&gt; rules -&gt; incremental</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node is-goal">john --show<span class="sub">recover plaintext</span></div></div> +</div> +</div> +</figure> ```bash # The canonical three-liner @@ -176,14 +186,24 @@ john --wordlist=/usr/share/wordlists/rockyou.txt --format=ssh ssh.hash ## 5. Cracking Mode Flags -```mermaid -flowchart TD - S[--single] -->|fast, uses GECOS/username| W[--wordlist] - W -->|+ mangling| R[--wordlist + --rules] - R -->|exhausted| M[--mask] - M -->|structured| I[--incremental] - I -->|brute-force, last resort| Z[done or give up] -``` +<figure class="flow plate corners"> +<figcaption class="flow__cap"><span class="flow__kind">Cracking mode escalation</span><span class="flow__dir">TD</span></figcaption> +<div class="flow__body"> +<div class="flow__diagram" data-dir="td"> +<div class="flow-rank"><div class="flow-node is-entry">--single</div></div> +<div class="flow-edge"><span class="flow-edge__label">fast, uses GECOS/username</span></div> +<div class="flow-rank"><div class="flow-node">--wordlist</div></div> +<div class="flow-edge"><span class="flow-edge__label">+ mangling</span></div> +<div class="flow-rank"><div class="flow-node">--wordlist + --rules</div></div> +<div class="flow-edge"><span class="flow-edge__label">exhausted</span></div> +<div class="flow-rank"><div class="flow-node">--mask</div></div> +<div class="flow-edge"><span class="flow-edge__label">structured</span></div> +<div class="flow-rank"><div class="flow-node">--incremental</div></div> +<div class="flow-edge"><span class="flow-edge__label">brute-force, last resort</span></div> +<div class="flow-rank"><div class="flow-node">done or give up</div></div> +</div> +</div> +</figure> | Flag | Mode | Use when | | :-- | :-- | :-- | diff --git a/src/content/sheets/pentest-workflow/acl-and-object-abuse.md b/src/content/sheets/pentest-workflow/acl-and-object-abuse.md @@ -651,19 +651,47 @@ dacledit.py -action restore -file dacledit-*.bak -target victim "$DOMAIN"/"$U":" ## 🧭 Decision flow — edge in hand, what's the quietest kill? -```mermaid -flowchart TD - A[Writable edge found] --> B{Target type?} - B -->|User| C{PKINIT / ADCS present?} - C -->|Yes| D[Shadow Credentials<br/>no password touch] - C -->|No| E[Targeted Kerberoast<br/>plant SPN, roast, remove] - B -->|Computer| F{MAQ > 0?} - F -->|Yes| G[RBCD → S4U → local admin] - F -->|No| H[Shadow creds on MACHINE$] - B -->|Group| I[AddMember → inherit rights<br/>re-enumerate] - B -->|Domain root| J[WriteDacl → grant DCSync<br/>secretsdump → remove] - D & E & G & H & I & J --> K[Revert every write<br/>per OPSEC table] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Quietest kill decision</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 1265 616" role="img" aria-label="Decision tree from a writable edge, branching by target type into the quietest takeover, then reverting every write"> + <path class="fedge" d="M630,106 L630,178" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M630,226 L220,298" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M630,226 L640,298" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M630,226 L940,298" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M630,226 L1140,298" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M220,346 L120,418" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M220,346 L320,418" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M640,346 L540,418" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M640,346 L740,418" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M120,466 L555,538" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M320,466 L585,538" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M540,466 L615,538" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M740,466 L645,538" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M940,346 L940,502 L675,502 L675,538" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M1140,346 L1140,518 L705,518 L705,538" marker-end="url(#flow-arrow)" /> + <g class="fnode is-entry"><rect class="fnode__box" x="545" y="58" width="170" height="48" /><text class="fnode__label" x="630" y="86" text-anchor="middle">Writable edge found</text></g> + <g class="fnode is-decision"><rect class="fnode__box" x="545" y="178" width="170" height="48" /><text class="fnode__label" x="630" y="206" text-anchor="middle">Target type?</text></g> + <g class="fnode is-decision"><rect class="fnode__box" x="135" y="298" width="170" height="48" /><text class="fnode__label" x="220" y="326" text-anchor="middle">PKINIT / ADCS present?</text></g> + <g class="fnode is-decision"><rect class="fnode__box" x="555" y="298" width="170" height="48" /><text class="fnode__label" x="640" y="326" text-anchor="middle">MAQ &gt; 0?</text></g> + <g class="fnode"><rect class="fnode__box" x="855" y="298" width="170" height="48" /><text class="fnode__label" x="940" y="319" text-anchor="middle">AddMember → inherit rights<tspan class="sub" x="940" dy="15">re-enumerate</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="1055" y="298" width="170" height="48" /><text class="fnode__label" x="1140" y="319" text-anchor="middle">WriteDacl → grant DCSync<tspan class="sub" x="1140" dy="15">secretsdump → remove</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="35" y="418" width="170" height="48" /><text class="fnode__label" x="120" y="439" text-anchor="middle">Shadow Credentials<tspan class="sub" x="120" dy="15">no password touch</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="235" y="418" width="170" height="48" /><text class="fnode__label" x="320" y="439" text-anchor="middle">Targeted Kerberoast<tspan class="sub" x="320" dy="15">plant SPN, roast, remove</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="455" y="418" width="170" height="48" /><text class="fnode__label" x="540" y="446" text-anchor="middle">RBCD → S4U → local admin</text></g> + <g class="fnode"><rect class="fnode__box" x="655" y="418" width="170" height="48" /><text class="fnode__label" x="740" y="446" text-anchor="middle">Shadow creds on MACHINE$</text></g> + <g class="fnode"><rect class="fnode__box" x="545" y="538" width="170" height="48" /><text class="fnode__label" x="630" y="559" text-anchor="middle">Revert every write<tspan class="sub" x="630" dy="15">per OPSEC table</tspan></text></g> + <g class="felabel"><rect class="felabel__box" x="406" y="254" width="37" height="16" /><text class="felabel__text" x="425" y="265" text-anchor="middle">User</text></g> + <g class="felabel"><rect class="felabel__box" x="604" y="254" width="62" height="16" /><text class="felabel__text" x="635" y="265" text-anchor="middle">Computer</text></g> + <g class="felabel"><rect class="felabel__box" x="763" y="254" width="43" height="16" /><text class="felabel__text" x="785" y="265" text-anchor="middle">Group</text></g> + <g class="felabel"><rect class="felabel__box" x="844" y="254" width="81" height="16" /><text class="felabel__text" x="885" y="265" text-anchor="middle">Domain root</text></g> + <g class="felabel"><rect class="felabel__box" x="154" y="374" width="31" height="16" /><text class="felabel__text" x="170" y="385" text-anchor="middle">Yes</text></g> + <g class="felabel"><rect class="felabel__box" x="257" y="374" width="25" height="16" /><text class="felabel__text" x="270" y="385" text-anchor="middle">No</text></g> + <g class="felabel"><rect class="felabel__box" x="574" y="374" width="31" height="16" /><text class="felabel__text" x="590" y="385" text-anchor="middle">Yes</text></g> + <g class="felabel"><rect class="felabel__box" x="677" y="374" width="25" height="16" /><text class="felabel__text" x="690" y="385" text-anchor="middle">No</text></g> + </svg> + </div> +</figure> ## 🎯 MITRE ATT&CK mapping diff --git a/src/content/sheets/pentest-workflow/active-directory-enumeration.md b/src/content/sheets/pentest-workflow/active-directory-enumeration.md @@ -33,18 +33,37 @@ Two habits keep this stage from collapsing into noise: **(1)** every command out AD enumeration is **state-driven, not tool-driven**. I move down this ladder and loop back up the moment my access level changes: -```mermaid -flowchart TD - A["No creds — null/guest SMB, anon LDAP, RID brute"] --> B["Username list — kerbrute userenum + RID cycle + email patterns"] - B --> C["AS-REP roast (no creds needed) + ONE careful password spray"] - C --> D["Any valid cred — validate on smb/ldap/winrm/winrm everywhere"] - D --> E["Credentialed LDAP vacuum — users, groups, SPNs, policy, descriptions"] - E --> F["BloodHound collection — mark owned, path to DA"] - F --> G{"New cred / new edge?"} - G -->|yes| E - G -->|no| H["Pick an edge: roast / ACL abuse / LAPS / gMSA / CVE one-shot"] - H --> I["Stage 5 Kerberos · Stage 6 ACL · Stage 7 ADCS"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">AD enumeration loop</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 470 1078" role="img" aria-label="No creds to username list to first cred to credentialed LDAP vacuum to BloodHound, looping back to re-enumerate on any new cred or edge, then handing off to the Kerberos, ACL and ADCS stages"> + <!-- forward chain --> + <path class="fedge" d="M250,88 L250,160" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M250,208 L250,280" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M250,328 L250,400" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M250,448 L250,520" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M250,568 L250,640" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M250,688 L250,760" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M250,808 L250,880" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M250,928 L250,1000" marker-end="url(#flow-arrow)" /> + <!-- back edge: any new cred / new edge loops back to credentialed enum --> + <path class="fedge is-back" d="M70,784 L35,784 L35,544 L70,544" marker-end="url(#flow-arrow)" /> + <!-- nodes --> + <g class="fnode is-entry"><rect class="fnode__box" x="70" y="40" width="360" height="48" /><text class="fnode__label" x="250" y="61" text-anchor="middle">No creds<tspan class="sub" x="250" dy="15">null/guest SMB, anon LDAP, RID brute</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="70" y="160" width="360" height="48" /><text class="fnode__label" x="250" y="181" text-anchor="middle">Username list<tspan class="sub" x="250" dy="15">kerbrute userenum + RID cycle + email patterns</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="70" y="280" width="360" height="48" /><text class="fnode__label" x="250" y="301" text-anchor="middle">AS-REP roast (no creds needed)<tspan class="sub" x="250" dy="15">+ ONE careful password spray</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="70" y="400" width="360" height="48" /><text class="fnode__label" x="250" y="421" text-anchor="middle">Any valid cred<tspan class="sub" x="250" dy="15">validate on smb/ldap/winrm/winrm everywhere</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="70" y="520" width="360" height="48" /><text class="fnode__label" x="250" y="541" text-anchor="middle">Credentialed LDAP vacuum<tspan class="sub" x="250" dy="15">users, groups, SPNs, policy, descriptions</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="70" y="640" width="360" height="48" /><text class="fnode__label" x="250" y="661" text-anchor="middle">BloodHound collection<tspan class="sub" x="250" dy="15">mark owned, path to DA</tspan></text></g> + <g class="fnode is-decision"><rect class="fnode__box" x="70" y="760" width="360" height="48" /><text class="fnode__label" x="250" y="788" text-anchor="middle">New cred / new edge?</text></g> + <g class="fnode"><rect class="fnode__box" x="70" y="880" width="360" height="48" /><text class="fnode__label" x="250" y="901" text-anchor="middle">Pick an edge<tspan class="sub" x="250" dy="15">roast / ACL abuse / LAPS / gMSA / CVE one-shot</tspan></text></g> + <g class="fnode is-goal"><rect class="fnode__box" x="70" y="1000" width="360" height="48" /><text class="fnode__label" x="250" y="1028" text-anchor="middle">Stage 5 Kerberos · Stage 6 ACL · Stage 7 ADCS</text></g> + <!-- edge labels --> + <g class="felabel"><rect class="felabel__box" x="19" y="656" width="32" height="16" /><text class="felabel__text" x="35" y="667" text-anchor="middle">yes</text></g> + <g class="felabel"><rect class="felabel__box" x="237" y="836" width="26" height="16" /><text class="felabel__text" x="250" y="847" text-anchor="middle">no</text></g> + </svg> + </div> +</figure> | Step | State | Goal | Primary tools | |---|---|---|---| diff --git a/src/content/sheets/pentest-workflow/attack-flow-dashboard.md b/src/content/sheets/pentest-workflow/attack-flow-dashboard.md @@ -77,22 +77,40 @@ printf '%s\t%s\n' "$DCIP" "$DC" | sudo tee -a /etc/hosts ## Kill Chain -```mermaid -flowchart LR - A[00 Passive Recon] --> B[01 Host Discovery] - B --> C[02 Web Enumeration] - C --> D[Foothold Toolkits] - D --> E[03 Service Enumeration] - E --> F[04 AD Enumeration] - F --> G[05 Kerberos Attacks] - G --> H[06 ACL and Object Abuse] - H --> I[07 ADCS Abuse] - I --> J[08 Credential Attacks] - J --> K[09 Privilege Escalation] - K --> L[10 Lateral Movement and Pivoting] - L --> M[Trusts and Cross-Forest] - M --> N[11 Documentation and Reporting] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">CPTS kill chain</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="lr"> + <div class="flow-rank"><div class="flow-node is-entry">00 Passive Recon</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">01 Host Discovery</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">02 Web Enumeration</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Foothold Toolkits</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">03 Service Enumeration</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">04 AD Enumeration</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">05 Kerberos Attacks</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">06 ACL and Object Abuse</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">07 ADCS Abuse</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">08 Credential Attacks</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">09 Privilege Escalation</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">10 Lateral Movement and Pivoting</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Trusts and Cross-Forest</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">11 Documentation and Reporting</div></div> + </div> + </div> +</figure> ## Stage Index diff --git a/src/content/sheets/pentest-workflow/attack-flow-guide.md b/src/content/sheets/pentest-workflow/attack-flow-guide.md @@ -38,21 +38,33 @@ source: "vault:Pentest Attack Flow/Companion Guides/Attack-Flow-Guide.md" ## // HIGH_LEVEL_FLOW -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A["SETUP + RECON"] --> B["PER-SERVICE ENUM<br/>(this guide)"] - B --> C["FOOTHOLD CREDS"] - C --> D["SHELL / AUTH"] - D --> E["POST-FOOTHOLD ENUM"] - E --> F{"Escalate?"} - F -->|"loop w/ new creds"| B - F -->|"ADCS/deleg/ACL"| G["DOMAIN ADMIN"] - F -->|"local priv"| G - G --> H["ROOT / FLAGS"] - style C fill:#26233a,stroke:#f6c177,color:#f6c177 - style G fill:#26233a,stroke:#eb6f92,color:#eb6f92 -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">High-level attack flow</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <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"> + <path class="fedge" d="M185,82 L265,82" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M415,82 L495,82" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M645,82 L725,82" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M875,82 L955,82" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M1105,82 L1185,82" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M1335,74 L1415,74" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M1335,92 L1415,92" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M1565,82 L1645,82" marker-end="url(#flow-arrow)" /> + <path class="fedge is-back" d="M1260,106 L1260,172 L340,172 L340,108" marker-end="url(#flow-arrow)" /> + <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> + <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> + <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> + <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> + <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> + <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> + <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> + <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> + <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> + <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> + <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> + </svg> + </div> +</figure> --- diff --git a/src/content/sheets/pentest-workflow/attacking-common-applications-guide.md b/src/content/sheets/pentest-workflow/attacking-common-applications-guide.md @@ -22,18 +22,28 @@ Off-the-shelf applications are the softest part of most networks. A company patc Every target in this module answers to the same loop, so learn the loop rather than memorising eleven separate exploits: -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A["Sweep web ports\n80,443,8000,8080,8180,8500,8009,8089,10000"] --> B["Fingerprint app + exact version\n(headers, generator meta, changelog,\ndefault paths, favicon)"] - B --> C["Reach the admin/management console\n(default creds → weak-password spray → OSINT)"] - C --> D{"Turn access into code execution"} - D --> E["Built-in feature:\ntheme/template editor, script console,\nWAR/app/plugin upload, notification exec"] - D --> F["Version-specific CVE\n(traversal, unauth upload, deserialisation)"] - E --> G["Shell as the service account\n(often SYSTEM or root)"] - F --> G - G --> H["Loot creds → pivot →\nlocal privilege escalation"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">App attack loop</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Sweep web ports<span class="sub">80,443,8000,8080,8180,8500,8009,8089,10000</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Fingerprint app + exact version<span class="sub">(headers, generator meta, changelog,</span><span class="sub">default paths, favicon)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Reach the admin/management console<span class="sub">(default creds → weak-password spray → OSINT)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Turn access into code execution</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Built-in feature:<span class="sub">theme/template editor, script console,</span><span class="sub">WAR/app/plugin upload, notification exec</span></div></div> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Version-specific CVE<span class="sub">(traversal, unauth upload, deserialisation)</span></div></div> + </div> + <div class="flow-join"></div> + <div class="flow-rank"><div class="flow-node is-goal">Shell as the service account<span class="sub">(often SYSTEM or root)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Loot creds → pivot →<span class="sub">local privilege escalation</span></div></div> + </div> + </div> +</figure> > [!danger] Authorised testing only > Every technique below is full exploitation — unauth RCE, credential theft, backdoored uploads. Run it only against systems you are explicitly authorised to test (a lab, a signed engagement). Three things to keep honest on a real assessment: @@ -57,15 +67,24 @@ flowchart LR Browsing every `IP:port` by hand does not scale past a handful of hosts. The workable approach is two Nmap passes feeding a screenshotter, so a wall of open ports becomes a ranked list of applications worth opening. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A[Scope list] --> B["Fast web-port sweep\n(-p 80,443,8000,8080,8180,8888,10000)"] - B --> C["Targeted -sV on responders\n(this is what names Splunk/PRTG)"] - C --> D["Screenshot triage\nEyeWitness / Aquatone / gowitness"] - D --> E["Review high-value hits first\n(dev/qa/acc vhosts on top)"] - E --> F[Per-app footprint + exploit] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Discovery at scale</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="lr"> + <div class="flow-rank"><div class="flow-node is-entry">Scope list</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Fast web-port sweep<span class="sub">(-p 80,443,8000,8080,8180,8888,10000)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Targeted -sV on responders<span class="sub">(this is what names Splunk/PRTG)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Screenshot triage<span class="sub">EyeWitness / Aquatone / gowitness</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Review high-value hits first<span class="sub">(dev/qa/acc vhosts on top)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">Per-app footprint + exploit</div></div> + </div> + </div> +</figure> Lab exercises with FQDN vhosts need `/etc/hosts` entries first, since every vhost resolves to the one spawned IP: @@ -123,18 +142,24 @@ cat web_discovery.xml | ./aquatone -nmap WordPress runs roughly a third of the web, so it turns up on almost every external test. The risk lives in its ~50k-plugin ecosystem, not in core — over half of known WordPress CVEs are plugin or theme bugs. Two reliable routes to code execution: brute an admin login and use the built-in Theme Editor, or exploit a vulnerable plugin directly. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["Footprint: robots.txt,\npage source, wp-admin redirect"] --> B[Enumerate plugins/themes/users] - B --> C{WPScan + manual review} - C -->|Weak admin creds| D["XML-RPC / wp-login brute force"] - D --> E["Appearance → Theme Editor →\nedit 404.php of an inactive theme"] - E --> F["system($_GET[...]) web shell"] - C -->|Vulnerable plugin| G["Direct exploit\n(mail-masta LFI, wpDiscuz upload)"] - F --> H[www-data shell] - G --> H -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">WordPress to RCE</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Footprint: robots.txt,<span class="sub">page source, wp-admin redirect</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Enumerate plugins/themes/users</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">WPScan + manual review</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Weak admin creds</span></div><div class="flow-node">XML-RPC / wp-login brute force</div><div class="flow-edge"></div><div class="flow-node">Appearance → Theme Editor →<span class="sub">edit 404.php of an inactive theme</span></div><div class="flow-edge"></div><div class="flow-node">system($_GET[...]) web shell</div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Vulnerable plugin</span></div><div class="flow-node">Direct exploit<span class="sub">(mail-masta LFI, wpDiscuz upload)</span></div></div> + </div> + <div class="flow-join"></div> + <div class="flow-rank"><div class="flow-node is-goal">www-data shell</div></div> + </div> + </div> +</figure> **Footprint.** The `wp-admin`/`wp-content` paths (also in `robots.txt`) are the fastest tell — hitting `/wp-admin` redirects to `wp-login.php`. Grepping the homepage source reveals the active theme, every enqueued plugin, and each version string: @@ -201,16 +226,24 @@ curl -s "http://blog.inlanefreight.local/wp-content/uploads/2021/08/<uploaded>.p Third-most-used CMS. Unlike WordPress, the login returns a generic error for any wrong field, so username enumeration doesn't work — footprinting leans on files, and brute forcing targets the known `admin` account with a password list. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["Footprint: generator meta,\nREADME.txt, robots.txt"] --> B["Version: joomla.xml, cache.xml"] - B --> C[droopescan / JoomlaScan] - C --> D{Admin access?} - D -->|Weak/default admin| E["Templates → Customise → error.php"] - E --> F["system($_GET[...]) web shell"] - D -->|No admin| G["CVE-2019-10945 traversal\n(auth; also deletes files)"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Joomla to RCE</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Footprint: generator meta,<span class="sub">README.txt, robots.txt</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Version: joomla.xml, cache.xml</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">droopescan / JoomlaScan</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Admin access?</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Weak/default admin</span></div><div class="flow-node">Templates → Customise → error.php</div><div class="flow-edge"></div><div class="flow-node is-goal">system($_GET[...]) web shell</div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">No admin</span></div><div class="flow-node is-danger">CVE-2019-10945 traversal<span class="sub">(auth; also deletes files)</span></div></div> + </div> + </div> + </div> +</figure> **Footprint and version.** The `generator` meta tag, `robots.txt` (references `/administrator/`), and `README.txt` are the quick tells. Two XML files leak the exact version when readable: @@ -265,20 +298,35 @@ python2.7 joomla_dir_trav.py --url "http://dev.inlanefreight.local/administrator Smaller share overall but common in government and higher-ed. Its content model — every item is a "node" at `/node/<id>` — is a fingerprint on its own. Admin access alone isn't instant RCE here: you enable the PHP Filter module, upload a backdoored module, or use one of the three Drupalgeddon CVEs. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["Footprint: 'Powered by Drupal',\nCHANGELOG.txt, /node/<id>"] --> B[droopescan: version + modules] - B --> C{Admin access?} - C -->|Drupal 7| D["Enable PHP Filter module\n→ Basic page with PHP code"] - C -->|Drupal 8+| E["Install PHP Filter manually,\nthen as above"] - C -->|Any version| F["Upload backdoored module\n(shell.php + .htaccess)"] - C -->|No admin| G["Drupalgeddon SQLi\n→ rogue admin"] - G --> D - D --> H[www-data shell] - E --> H - F --> H -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Drupal to RCE</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 1050 600" role="img" aria-label="Drupal footprint to droopescan to an admin-access decision branching to PHP Filter, manual install, backdoored module, or Drupalgeddon SQLi; the SQLi path feeds the PHP Filter node, and three RCE paths converge on a www-data shell"> + <path class="fedge" d="M525,88 L525,160" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M525,208 L525,280" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M525,328 L150,400" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M525,328 L400,400" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M525,328 L650,400" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M525,328 L900,400" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M260,424 L290,424" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M400,448 L525,520" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M650,448 L525,520" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M900,448 L525,520" marker-end="url(#flow-arrow)" /> + <g class="fnode is-entry"><rect class="fnode__box" x="405" y="40" width="240" height="48" /><text class="fnode__label" x="525" y="60" text-anchor="middle">Footprint: 'Powered by Drupal',<tspan class="sub" x="525" dy="15">CHANGELOG.txt, /node/&lt;id&gt;</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="415" y="160" width="220" height="48" /><text class="fnode__label" x="525" y="188" text-anchor="middle">droopescan: version + modules</text></g> + <g class="fnode is-decision"><rect class="fnode__box" x="425" y="280" width="200" height="48" /><text class="fnode__label" x="525" y="308" text-anchor="middle">Admin access?</text></g> + <g class="fnode"><rect class="fnode__box" x="40" y="400" width="220" height="48" /><text class="fnode__label" x="150" y="420" text-anchor="middle">Drupalgeddon SQLi<tspan class="sub" x="150" dy="15">→ rogue admin</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="290" y="400" width="220" height="48" /><text class="fnode__label" x="400" y="420" text-anchor="middle">Enable PHP Filter module<tspan class="sub" x="400" dy="15">→ Basic page with PHP code</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="540" y="400" width="220" height="48" /><text class="fnode__label" x="650" y="420" text-anchor="middle">Install PHP Filter manually,<tspan class="sub" x="650" dy="15">then as above</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="790" y="400" width="220" height="48" /><text class="fnode__label" x="900" y="420" text-anchor="middle">Upload backdoored module<tspan class="sub" x="900" dy="15">(shell.php + .htaccess)</tspan></text></g> + <g class="fnode is-goal"><rect class="fnode__box" x="450" y="520" width="150" height="48" /><text class="fnode__label" x="525" y="548" text-anchor="middle">www-data shell</text></g> + <g class="felabel"><rect class="felabel__box" x="306" y="356" width="62" height="16" /><text class="felabel__text" x="337" y="367" text-anchor="middle">No admin</text></g> + <g class="felabel"><rect class="felabel__box" x="431" y="356" width="62" height="16" /><text class="felabel__text" x="462" y="367" text-anchor="middle">Drupal 7</text></g> + <g class="felabel"><rect class="felabel__box" x="553" y="356" width="68" height="16" /><text class="felabel__text" x="587" y="367" text-anchor="middle">Drupal 8+</text></g> + <g class="felabel"><rect class="felabel__box" x="672" y="356" width="80" height="16" /><text class="felabel__text" x="712" y="367" text-anchor="middle">Any version</text></g> + </svg> + </div> +</figure> **Footprint.** `Powered by Drupal`, the Drupal logo, `CHANGELOG.txt`/`README.txt`, and `/node/<id>` URIs. Newer versions block `CHANGELOG.txt`, so a 404 there doesn't rule Drupal out — fall back to droopescan, which has mature Drupal support: @@ -341,16 +389,20 @@ curl "http://drupal-dev.inlanefreight.local/mrb3n.php?fe8edbabc5c5c9b7b764504cd2 Apache Tomcat serves Java servlets/JSP and is more common internally than externally. Weak creds on `/manager` or `/host-manager` let you deploy a WAR (a zipped JSP shell) through the GUI or API — near-instant RCE, usually as a very privileged service account. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["Footprint: Server header, /docs"] --> B["Find /manager, /host-manager"] - B --> C[Brute the manager login] - C -->|Success| D["Deploy JSP-in-WAR\nvia GUI/API"] - D --> E["Shell as Tomcat account\n(often SYSTEM/root)"] - B -->|No manager| F["AJP 8009 → Ghostcat\nCVE-2020-1938 file read"] - F --> G["Read WEB-INF/web.xml, configs"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Tomcat to RCE</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Footprint: Server header, /docs</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Find /manager, /host-manager</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Brute the manager login</div><div class="flow-edge"><span class="flow-edge__label">Success</span></div><div class="flow-node">Deploy JSP-in-WAR<span class="sub">via GUI/API</span></div><div class="flow-edge"></div><div class="flow-node is-goal">Shell as Tomcat account<span class="sub">(often SYSTEM/root)</span></div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">No manager</span></div><div class="flow-node">AJP 8009 → Ghostcat<span class="sub">CVE-2020-1938 file read</span></div><div class="flow-edge"></div><div class="flow-node">Read WEB-INF/web.xml, configs</div></div> + </div> + </div> + </div> +</figure> > [!info] Tomcat layout worth knowing > `conf/tomcat-users.xml` holds manager credentials and roles (`manager-gui`, `manager-script`, `manager-jmx`, `manager-status`). `webapps/<app>/WEB-INF/web.xml` is the deployment descriptor mapping routes to classes — a prime target for any file-read primitive. @@ -415,15 +467,26 @@ ffuf -w /usr/share/dirb/wordlists/common.txt -u http://10.129.204.227:8080/cgi/F Jenkins is a CI server that frequently runs as `SYSTEM` (Windows) or `root` (Linux). Any authenticated access — even anonymous, if misconfigured — reaches the `/script` Groovy console, and Groovy compiles to JVM bytecode running with the full privileges of the Jenkins process. That makes it a fast, privileged foothold straight into an AD environment, skipping local privesc entirely. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A["Fingerprint login on :8080"] --> B{Auth?} - B -->|None / weak creds| C["/script Groovy console"] - B -->|Anon build+job rights| C - C --> D["Runtime.exec() → reverse shell"] - D --> E["Shell as SYSTEM/root"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Jenkins to RCE</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Fingerprint login on :8080</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Auth?</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">None / weak creds</span></div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Anon build+job rights</span></div></div> + </div> + <div class="flow-join"></div> + <div class="flow-rank"><div class="flow-node">/script Groovy console</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Runtime.exec() → reverse shell</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">Shell as SYSTEM/root</div></div> + </div> + </div> +</figure> **Access the console** at `http://jenkins.inlanefreight.local:8000/script`. Run a command: @@ -465,18 +528,28 @@ nc -lvnp 8443 # → uid=0(root) Splunk has few exploitable CVEs; the risk is weak or absent auth plus built-in functionality. A forgotten Enterprise *trial* silently downgrades to the auth-free *Free* edition after 60 days. Once you have admin — via no auth or weak creds — a custom app with a scripted input runs an arbitrary script on a schedule, as the Splunk service account (often `SYSTEM`/`root`). -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["Fingerprint: Splunkd httpd\non 8000/8089"] --> B{Auth?} - B -->|Trial expired → Free| C[Direct admin, no creds] - B -->|Weak default| D["admin:changeme / weak pw"] - C --> E["Custom app: bin/ script +\ndefault/inputs.conf"] - D --> E - E --> F["tar.gz → Install app from file"] - F --> G["Scripted input fires\n→ reverse shell"] - G --> H["Shell as Splunk account\n(often SYSTEM)"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Splunk to RCE</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Fingerprint: Splunkd httpd<span class="sub">on 8000/8089</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Auth?</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Trial expired → Free</span></div><div class="flow-node">Direct admin, no creds</div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Weak default</span></div><div class="flow-node">admin:changeme / weak pw</div></div> + </div> + <div class="flow-join"></div> + <div class="flow-rank"><div class="flow-node">Custom app: bin/ script +<span class="sub">default/inputs.conf</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">tar.gz → Install app from file</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Scripted input fires<span class="sub">→ reverse shell</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">Shell as Splunk account<span class="sub">(often SYSTEM)</span></div></div> + </div> + </div> +</figure> **Fingerprint.** Both 8000 and 8089 reporting `Splunkd httpd` is definitive. Try `admin:changeme` (shown on old login pages) and common weak passwords if the trial scenario doesn't apply. @@ -520,14 +593,22 @@ sudo nc -lnvp 443 PRTG (Paessler, Delphi) is an agentless monitor, rarely internet-facing but common internally (and the HTB box *Netmon*). Default `prtgadmin:prtgadmin` is often pre-filled and unchanged. Once in, CVE-2018-9276 turns a notification's "Execute Program" action into command execution as the PRTG account — frequently local admin. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A["Fingerprint: Indy httpd\n(Paessler PRTG)"] --> B[Login: default/weak creds] - B --> C["Account Settings → Notifications\n→ Add new"] - C --> D["EXECUTE PROGRAM → outfile.ps1\n+ malicious Parameter"] - D --> E[Click Test → command runs] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">PRTG to RCE</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="lr"> + <div class="flow-rank"><div class="flow-node is-entry">Fingerprint: Indy httpd<span class="sub">(Paessler PRTG)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Login: default/weak creds</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Account Settings → Notifications<span class="sub">→ Add new</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">EXECUTE PROGRAM → outfile.ps1<span class="sub">+ malicious Parameter</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">Click Test → command runs</div></div> + </div> + </div> +</figure> **Fingerprint and version.** `Indy httpd ... Paessler PRTG bandwidth monitor` in the banner is definitive; `17.3.33.2830` predates the 18.2.39 fix: @@ -567,16 +648,18 @@ sudo nxc smb 10.129.201.50 -u prtgadm1 -p 'Pwn3d_by_PRTG!' # (Pwn3d!) = loca osTicket is well-maintained with a thin CVE history, so this section is a *pattern* that applies to any helpdesk (Zendesk, Freshdesk, Jira Service Desk): support portals hand out real company email addresses, and the humans running them leak credentials. This is the chain behind HTB's *Delivery*. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["Fingerprint: OSTSESSID cookie,\n'powered by' footer"] --> B["Submit a ticket →\nget a company email address"] - B --> C["Register on other portals\nwith that address"] - A --> D["OSINT breach data (Dehashed)"] - D --> E["Try leaked creds on the portal"] - E --> F["Read closed tickets:\npassword resets, VPN issues"] - F --> G["Reused / new-joiner password\n→ spray other services"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">osTicket method</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Fingerprint: OSTSESSID cookie,<span class="sub">'powered by' footer</span></div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Submit a ticket →<span class="sub">get a company email address</span></div><div class="flow-edge"></div><div class="flow-node">Register on other portals<span class="sub">with that address</span></div></div> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">OSINT breach data (Dehashed)</div><div class="flow-edge"></div><div class="flow-node">Try leaked creds on the portal</div><div class="flow-edge"></div><div class="flow-node">Read closed tickets:<span class="sub">password resets, VPN issues</span></div><div class="flow-edge"></div><div class="flow-node is-goal">Reused / new-joiner password<span class="sub">→ spray other services</span></div></div> + </div> + </div> + </div> +</figure> **Fingerprint.** Nmap only sees the webserver — the `OSTSESSID` cookie and footer branding identify osTicket. @@ -607,17 +690,22 @@ Try both username and email on any login — `kevin@…` succeeded where `kgrime Self-hosted Git with wikis, issues, and CI/CD. Public and internal repos leak hardcoded secrets, SSH keys, and infra clues. GitLab has a long CVE list, but the most reliable finding is usually that self-registration is on, letting you walk in and browse internal projects. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["Fingerprint: login page, logo"] --> B["Browse /explore (public projects)"] - B --> C{Self-registration on?} - C -->|Yes| D["Register → internal projects"] - C -->|No| E["Enumerate users via\n'email already taken'"] - D --> F["Mine repos: secrets, keys, config"] - D --> G["GitLab CE ≤ 13.10.2:\nExifTool metadata RCE"] - G --> H[Shell as git user] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">GitLab method</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Fingerprint: login page, logo</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Browse /explore (public projects)</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Self-registration on?</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Yes</span></div><div class="flow-node">Register → internal projects</div><div class="flow-branches"><div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Mine repos: secrets, keys, config</div></div><div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">GitLab CE ≤ 13.10.2:<span class="sub">ExifTool metadata RCE</span></div><div class="flow-edge"></div><div class="flow-node is-goal">Shell as git user</div></div></div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">No</span></div><div class="flow-node">Enumerate users via<span class="sub">'email already taken'</span></div></div> + </div> + </div> + </div> +</figure> **Fingerprint and enumerate.** The version only shows on `/help` after login, but `/explore` lists public projects unauthenticated — check it first. Username enumeration works via the registration oracle ("Email has already been taken") even when sign-up is disabled, because `/users/sign_up` stays reachable: @@ -655,15 +743,22 @@ nc -lnvp 8443 # → uid=996(git) CGI is legacy middleware that hands requests to scripts in `cgi-bin`. It's mostly gone from modern servers but lingers on embedded/IoT gear. The classic attack is Shellshock (CVE-2014-6271): vulnerable Bash (≤ 4.3) mis-parses a function definition in an environment variable and runs anything appended after it — and CGI copies HTTP headers into environment variables. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A["Discover cgi-bin scripts"] --> B["Test User-Agent header oracle"] - B --> C{Bash bug present?} - C -->|Yes| D["Chain command after\nthe function definition"] - D --> E["Reverse shell as web user"] - C -->|No| F[Patched — move on] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">CGI Shellshock</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Discover cgi-bin scripts</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Test User-Agent header oracle</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Bash bug present?</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Yes</span></div><div class="flow-node">Chain command after<span class="sub">the function definition</span></div><div class="flow-edge"></div><div class="flow-node is-goal">Reverse shell as web user</div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">No</span></div><div class="flow-node">Patched — move on</div></div> + </div> + </div> + </div> +</figure> **Understand the bug** — everything after the closing `};` runs on a vulnerable shell: @@ -697,16 +792,18 @@ sudo nc -lvnp 7777 # → www-data Thick (fat) clients run real logic locally — Java/.NET/C++ CRMs, internal utilities, project tools. They dodge browser bugs (XSS, CSRF) but fall to hardcoded credentials, insecure local storage, DLL hijacking, and — for three-tier apps — the same SQLi/path-traversal you'd find on the web, once you reverse the protocol. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["Info gathering:\narchitecture, language, entry points"] --> B["Static: disassemble/decompile"] - A --> C["Dynamic: ProcMon, debugger,\nmemory dump"] - A --> D["Network: Wireshark/Burp\non client↔server traffic"] - B --> E["Patch client logic:\nports, filters, validation"] - D --> E - E --> F["Exploit server bugs:\nSQLi, path traversal"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Thick client method</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Info gathering:<span class="sub">architecture, language, entry points</span></div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-rank"><div class="flow-node">Static: disassemble/decompile</div><div class="flow-node">Network: Wireshark/Burp<span class="sub">on client↔server traffic</span></div></div><div class="flow-join"></div><div class="flow-node">Patch client logic:<span class="sub">ports, filters, validation</span></div><div class="flow-edge"></div><div class="flow-node is-goal">Exploit server bugs:<span class="sub">SQLi, path traversal</span></div></div> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Dynamic: ProcMon, debugger,<span class="sub">memory dump</span></div></div> + </div> + </div> + </div> +</figure> > [!info] Two-tier vs three-tier > **Two-tier**: client talks straight to the DB — the client binary can potentially reach it directly. **Three-tier**: client → app server → DB. Safer by design, but the middle tier becomes attackable with web-style bugs once you reverse its protocol. @@ -766,15 +863,22 @@ javac -cp fatty-client-new.jar ...\ClientGuiTest.java # swap only the patche ColdFusion (CFML, Adobe) is Java-based with a recognisable footprint: `.cfm`/`.cfc` extensions, port 8500 for SSL, and `/CFIDE/administrator/`. Older versions carry a traversal that leaks the encrypted datasource store and an unauth RCE via the bundled FCKeditor. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["Fingerprint: 8500, .cfm/.cfc,\n/CFIDE/administrator/"] --> B["searchsploit adobe coldfusion"] - B --> C{Version} - C -->|≤ 9.0.1| D["CVE-2010-2861\ntraversal → password.properties"] - C -->|≤ 8.0.1| E["CVE-2009-2265\nFCKeditor unauth RCE"] - E --> F["Upload JSP → shell as CF account"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">ColdFusion to RCE</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Fingerprint: 8500, .cfm/.cfc,<span class="sub">/CFIDE/administrator/</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">searchsploit adobe coldfusion</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Version</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">≤ 9.0.1</span></div><div class="flow-node">CVE-2010-2861<span class="sub">traversal → password.properties</span></div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">≤ 8.0.1</span></div><div class="flow-node">CVE-2009-2265<span class="sub">FCKeditor unauth RCE</span></div><div class="flow-edge"></div><div class="flow-node is-goal">Upload JSP → shell as CF account</div></div> + </div> + </div> + </div> +</figure> **Fingerprint** on port 8500 + `CFIDE`/`cfdocs` in the webroot; the admin login often discloses the major version. Then match exploits: @@ -814,14 +918,22 @@ python3 50057.py # generates + uploads JSP payload, catches the shell as th Windows generates a legacy 8.3 short name for every file (`somefi~1.txt`) for DOS compatibility. Some IIS versions answer tilde-prefixed requests differently depending on whether a prefix matches, so you can rebuild hidden names one character at a time — turning "guess the whole filename" into "guess an 8-char prefix". -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A["Fingerprint IIS, check OPTIONS"] --> B["IIS-ShortName-Scanner"] - B --> C["Partial names, e.g. TRANSF~1.ASP"] - C --> D["Build a targeted wordlist\n(words starting 'transf')"] - D --> E["Fuzz with extensions →\nrecover the full name"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">IIS short-name enum</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="lr"> + <div class="flow-rank"><div class="flow-node is-entry">Fingerprint IIS, check OPTIONS</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">IIS-ShortName-Scanner</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Partial names, e.g. TRANSF~1.ASP</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Build a targeted wordlist<span class="sub">(words starting 'transf')</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">Fuzz with extensions →<span class="sub">recover the full name</span></div></div> + </div> + </div> +</figure> **Fingerprint and scan** (the numeric args tune threads/requests; it reports the working HTTP method and every partial name): @@ -848,14 +960,22 @@ feroxbuster -u http://10.129.204.231/ -w /tmp/list.txt -t 50 -x aspx,asp Two source-driven bug classes. LDAP-backed logins that concatenate input into a filter fall to injection (the LDAP cousin of SQLi). Framework "mass assignment" binds a whole form onto a model, letting you set fields — `admin`, `confirmed` — that were never meant to be user-controllable. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["nmap: ldap/389 beside web/80"] --> B["Login likely LDAP-backed"] - B --> C["Inject * into user/pass"] - C --> D["(&(objectClass=user)(sAMAccountName=*)(userPassword=*))\nmatches any record"] - D --> E[Auth bypass] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">LDAP injection bypass</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">nmap: ldap/389 beside web/80</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Login likely LDAP-backed</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Inject * into user/pass</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">(&amp;(objectClass=user)(sAMAccountName=*)(userPassword=*))<span class="sub">matches any record</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">Auth bypass</div></div> + </div> + </div> +</figure> > [!info] LDAP vs Active Directory > LDAP is a *protocol* for querying directory data; Active Directory is a directory *service* that speaks LDAP (plus Kerberos, DNS, and more). OpenLDAP is the common cross-platform implementation you meet outside pure-Windows shops. Injection metacharacters: `*` (wildcard), `()` (grouping), `&`/`|` (AND/OR) — `(cn=*)` is the `' OR '1'='1` of LDAP. @@ -893,16 +1013,24 @@ The Rails equivalent (`attr_accessible :username, :email`) breaks the same way Apps that talk to a backend commonly embed a connection string with live credentials in the compiled binary, not a greppable config file. Recover it from two formats — an ELF in a debugger, a .NET DLL in a decompiler — and test the creds for reuse elsewhere. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A["Binary connects to a backend"] --> B{Type?} - B -->|ELF native| C["GDB + GEF/PEDA:\nbreakpoint the connect call"] - B -->|.NET assembly| D["dnSpy: decompile to C#"] - C --> E["Connection string sits\nin a register at the breakpoint"] - D --> E - E --> F["Reuse creds / password-spray"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Connection-string recovery</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Binary connects to a backend</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Type?</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">ELF native</span></div><div class="flow-node">GDB + GEF/PEDA:<span class="sub">breakpoint the connect call</span></div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">.NET assembly</span></div><div class="flow-node">dnSpy: decompile to C#</div></div> + </div> + <div class="flow-join"></div> + <div class="flow-rank"><div class="flow-node">Connection string sits<span class="sub">in a register at the breakpoint</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">Reuse creds / password-spray</div></div> + </div> + </div> +</figure> > [!info] Why not just `strings`? > Connection strings are often assembled at runtime from reordered, endianness-reversed fragments, so a flat `strings` pass can miss the finished value. A breakpoint at the actual connect API captures the complete string. @@ -934,18 +1062,32 @@ Get-FileMetaData .\MultimasterAPI.dll # .NETFramework v4.6.1 · api/getColle The specific apps above are practice material for one transferable method. Applied to anything unfamiliar: -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["Unknown app found"] --> B{Default creds?} - B -->|Yes| C[Admin access] - B -->|No| D{Known CVE for this version?} - D -->|Yes| E[Public exploit / PoC] - D -->|No| F["Read the docs → find built-in\nfunctionality to abuse"] - C --> G["RCE via deploy/upload/script feature"] - E --> G - F --> G -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Unknown-app method</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 960 600" role="img" aria-label="Unknown app found to a default-creds decision; yes gives admin access, no leads to a known-CVE decision splitting into a public exploit or reading the docs for abusable functionality; all three paths converge on RCE via a deploy, upload or script feature"> + <path class="fedge" d="M450,88 L450,160" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M450,208 L240,280" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M450,208 L660,280" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M660,328 L520,400" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M660,328 L800,400" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M240,328 L400,520" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M520,448 L470,520" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M800,448 L540,520" marker-end="url(#flow-arrow)" /> + <g class="fnode is-entry"><rect class="fnode__box" x="360" y="40" width="180" height="48" /><text class="fnode__label" x="450" y="68" text-anchor="middle">Unknown app found</text></g> + <g class="fnode is-decision"><rect class="fnode__box" x="350" y="160" width="200" height="48" /><text class="fnode__label" x="450" y="188" text-anchor="middle">Default creds?</text></g> + <g class="fnode"><rect class="fnode__box" x="150" y="280" width="180" height="48" /><text class="fnode__label" x="240" y="308" text-anchor="middle">Admin access</text></g> + <g class="fnode is-decision"><rect class="fnode__box" x="540" y="280" width="240" height="48" /><text class="fnode__label" x="660" y="308" text-anchor="middle">Known CVE for this version?</text></g> + <g class="fnode"><rect class="fnode__box" x="425" y="400" width="190" height="48" /><text class="fnode__label" x="520" y="428" text-anchor="middle">Public exploit / PoC</text></g> + <g class="fnode"><rect class="fnode__box" x="680" y="400" width="240" height="48" /><text class="fnode__label" x="800" y="420" text-anchor="middle">Read the docs → find built-in<tspan class="sub" x="800" dy="15">functionality to abuse</tspan></text></g> + <g class="fnode is-goal"><rect class="fnode__box" x="325" y="520" width="290" height="48" /><text class="fnode__label" x="470" y="548" text-anchor="middle">RCE via deploy/upload/script feature</text></g> + <g class="felabel"><rect class="felabel__box" x="330" y="236" width="30" height="16" /><text class="felabel__text" x="345" y="247" text-anchor="middle">Yes</text></g> + <g class="felabel"><rect class="felabel__box" x="543" y="236" width="24" height="16" /><text class="felabel__text" x="555" y="247" text-anchor="middle">No</text></g> + <g class="felabel"><rect class="felabel__box" x="575" y="356" width="30" height="16" /><text class="felabel__text" x="590" y="367" text-anchor="middle">Yes</text></g> + <g class="felabel"><rect class="felabel__box" x="718" y="356" width="24" height="16" /><text class="felabel__text" x="730" y="367" text-anchor="middle">No</text></g> + </svg> + </div> +</figure> ### Honourable mentions diff --git a/src/content/sheets/pentest-workflow/attacking-common-applications.md b/src/content/sheets/pentest-workflow/attacking-common-applications.md @@ -45,19 +45,27 @@ The off-the-shelf web apps you meet on nearly every internal network — **CMS** > 2. Admin-console RCE (theme/plugin/script editors) **plants a live backdoor** — track every file and remove it. > 3. `--api-token`, breach-data lookups, and OSINT touch third parties — stay in scope. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A["Sweep web ports\n80,443,8000,8080,8180,8500,8888,10000"] --> B["Fingerprint app + version\n(headers, meta generator,\nCHANGELOG, favicon, /docs)"] - B --> C["Reach admin console\n(default creds / brute / OSINT)"] - C --> D{"RCE primitive"} - D --> E["Editor: theme/plugin/template/script"] - D --> F["Upload: WAR / plugin / custom app"] - D --> G["Version CVE"] - E --> H["Web/reverse shell"] - F --> H - G --> H -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Common-app attack flow</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Sweep web ports<span class="sub">80,443,8000,8080,8180,8500,8888,10000</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Fingerprint app + version<span class="sub">(headers, meta generator,</span><span class="sub">CHANGELOG, favicon, /docs)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Reach admin console<span class="sub">(default creds / brute / OSINT)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">RCE primitive</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Editor: theme/plugin/template/script</div></div> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Upload: WAR / plugin / custom app</div></div> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Version CVE</div></div> + </div> + <div class="flow-join"></div> + <div class="flow-rank"><div class="flow-node is-goal">Web/reverse shell</div></div> + </div> + </div> +</figure> --- diff --git a/src/content/sheets/pentest-workflow/attacking-common-modules-dashboard.md b/src/content/sheets/pentest-workflow/attacking-common-modules-dashboard.md @@ -39,25 +39,48 @@ printf '%s\t%s\n' "$IP" "$TARGET" | sudo tee -a /etc/hosts ## Where these fit in the kill chain -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A["Recon / Host Discovery"] --> B{"What answered?"} - B -->|"web app on a port\n(WP, Tomcat, Jenkins…)"| C["Attacking Common\nApplications"] - B -->|"network service\n(FTP, SMB, SQL, RDP, DNS, SMTP)"| D["Attacking Common\nServices"] - C --> W["Web shell\nwhen the stack supports it"] - W --> E["Raw foothold"] - C --> E - D --> E - E --> T["TTY / interactive\nshell upgrade"] - T --> F{"Target OS?"} - F -->|Linux| G["Linux PrivEsc"] - F -->|Windows| H["Windows PrivEsc"] - G --> I["root"] - H --> J["SYSTEM / admin"] - I --> K["Loot · Pivot · Report"] - J --> K -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Where these cards fit</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 2430 320" role="img" aria-label="Recon leads to an application-or-service decision, then via web shell or raw foothold and a TTY upgrade to an OS decision, Linux or Windows privilege escalation to root or SYSTEM, and finally loot, pivot and report"> + <!-- edges --> + <path class="fedge" d="M185,160 L265,160" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M415,160 L520,160 L520,60 L625,60" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M415,160 L520,160 L520,260 L625,260" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M775,60 L855,60" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M1005,60 L1085,150" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M700,84 L700,112 L1160,112 L1160,136" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M700,236 L700,212 L1160,212 L1160,184" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M1235,160 L1315,160" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M1465,160 L1545,160" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M1695,160 L1735,160 L1735,60 L1775,60" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M1695,160 L1735,160 L1735,260 L1775,260" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M1925,60 L2005,60" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M1925,260 L2005,260" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M2155,60 L2195,60 L2195,160 L2235,160" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M2155,260 L2195,260 L2195,160 L2235,160" marker-end="url(#flow-arrow)" /> + <!-- nodes --> + <g class="fnode is-entry"><rect class="fnode__box" x="35" y="136" width="150" height="48" /><text class="fnode__label" x="110" y="164" text-anchor="middle">Recon / Host Discovery</text></g> + <g class="fnode is-decision"><rect class="fnode__box" x="265" y="136" width="150" height="48" /><text class="fnode__label" x="340" y="164" text-anchor="middle">What answered?</text></g> + <g class="fnode"><rect class="fnode__box" x="625" y="36" width="150" height="48" /><text class="fnode__label" x="700" y="57" text-anchor="middle">Attacking Common<tspan class="sub" x="700" dy="15">Applications</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="625" y="236" width="150" height="48" /><text class="fnode__label" x="700" y="257" text-anchor="middle">Attacking Common<tspan class="sub" x="700" dy="15">Services</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="855" y="36" width="150" height="48" /><text class="fnode__label" x="930" y="57" text-anchor="middle">Web shell<tspan class="sub" x="930" dy="15">when the stack supports it</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="1085" y="136" width="150" height="48" /><text class="fnode__label" x="1160" y="164" text-anchor="middle">Raw foothold</text></g> + <g class="fnode"><rect class="fnode__box" x="1315" y="136" width="150" height="48" /><text class="fnode__label" x="1390" y="157" text-anchor="middle">TTY / interactive<tspan class="sub" x="1390" dy="15">shell upgrade</tspan></text></g> + <g class="fnode is-decision"><rect class="fnode__box" x="1545" y="136" width="150" height="48" /><text class="fnode__label" x="1620" y="164" text-anchor="middle">Target OS?</text></g> + <g class="fnode"><rect class="fnode__box" x="1775" y="36" width="150" height="48" /><text class="fnode__label" x="1850" y="64" text-anchor="middle">Linux PrivEsc</text></g> + <g class="fnode"><rect class="fnode__box" x="1775" y="236" width="150" height="48" /><text class="fnode__label" x="1850" y="264" text-anchor="middle">Windows PrivEsc</text></g> + <g class="fnode is-goal"><rect class="fnode__box" x="2005" y="36" width="150" height="48" /><text class="fnode__label" x="2080" y="64" text-anchor="middle">root</text></g> + <g class="fnode is-goal"><rect class="fnode__box" x="2005" y="236" width="150" height="48" /><text class="fnode__label" x="2080" y="264" text-anchor="middle">SYSTEM / admin</text></g> + <g class="fnode"><rect class="fnode__box" x="2235" y="136" width="150" height="48" /><text class="fnode__label" x="2310" y="164" text-anchor="middle">Loot · Pivot · Report</text></g> + <!-- edge labels --> + <g class="felabel"><rect class="felabel__box" x="445" y="96" width="150" height="28" /><text class="felabel__text" x="520" y="107" text-anchor="middle">web app on a port<tspan class="sub" x="520" dy="13">(WP, Tomcat, Jenkins…)</tspan></text></g> + <g class="felabel"><rect class="felabel__box" x="417" y="196" width="206" height="28" /><text class="felabel__text" x="520" y="207" text-anchor="middle">network service<tspan class="sub" x="520" dy="13">(FTP, SMB, SQL, RDP, DNS, SMTP)</tspan></text></g> + <g class="felabel"><rect class="felabel__box" x="1713" y="102" width="44" height="16" /><text class="felabel__text" x="1735" y="113" text-anchor="middle">Linux</text></g> + <g class="felabel"><rect class="felabel__box" x="1707" y="202" width="56" height="16" /><text class="felabel__text" x="1735" y="213" text-anchor="middle">Windows</text></g> + </svg> + </div> +</figure> ## Section Index diff --git a/src/content/sheets/pentest-workflow/attacking-common-services.md b/src/content/sheets/pentest-workflow/attacking-common-services.md @@ -28,16 +28,26 @@ The reusable playbook for the services that dominate internal and perimeter netw > 2. Spray with lockout awareness: **one password across all users**, watch the domain lockout policy, never a full wordlist per account on a live AD. > 3. Record every credential as sensitive evidence; don't paste secrets into permanent notes. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A["Enumerate\n(nmap -sC -sV)"] --> B["Anonymous / null\naccess?"] - B --> C["Default creds\n→ weak combos"] - C --> D["Reuse anything found\n(even a filename)\nacross every service"] - D --> E["Spray / brute\n(lockout-aware)"] - E --> F["Exploit misconfig / CVE\n→ RCE or creds"] - F --> G["Loot → feed\ncredential hunting"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Service attack method</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="lr"> + <div class="flow-rank"><div class="flow-node is-entry">Enumerate<span class="sub">(nmap -sC -sV)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Anonymous / null<span class="sub">access?</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Default creds<span class="sub">→ weak combos</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Reuse anything found<span class="sub">(even a filename)</span><span class="sub">across every service</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Spray / brute<span class="sub">(lockout-aware)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Exploit misconfig / CVE<span class="sub">→ RCE or creds</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">Loot → feed<span class="sub">credential hunting</span></div></div> + </div> + </div> +</figure> --- diff --git a/src/content/sheets/pentest-workflow/attacking-enterprise-networks.md b/src/content/sheets/pentest-workflow/attacking-enterprise-networks.md @@ -69,18 +69,34 @@ export PIVOT="10.129.203.111" # DMZ01 ## Kill chain -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["PWNBOX<br/>proxychains + tools"] -->|"ssh -D / -L"| P["DMZ01<br/>SSH pivot · SOCKS :8083"] - P -->|"SOCKS + RDP"| D["DEV01<br/>DNN · RDP foothold"] - D -->|"BloodHound · shares"| DC["DC01<br/>Domain Controller"] - D -->|"cred reuse · WinRM"| M["MS01<br/>SQL · privesc to SYSTEM"] - M -->|"DCSync · tickets"| DA["Domain Admin"] - DC -.->|"Kerberoast · spray"| M - classDef dom fill:#31748f,stroke:#9ccfd8,color:#e0def4; - class DA dom; -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Kill chain</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 560 620" role="img" aria-label="PWNBOX pivots through DMZ01 to DEV01, which reaches DC01 and MS01; MS01 escalates to Domain Admin, and DC01 feeds Kerberoast and spray back to MS01"> + <!-- edges --> + <path class="fedge" d="M280,106 L280,178" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M280,226 L280,298" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M280,346 L120,418" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M280,346 L440,418" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M440,466 L440,538" marker-end="url(#flow-arrow)" /> + <path class="fedge is-dotted" d="M195,442 L365,442" marker-end="url(#flow-arrow)" /> + <!-- nodes --> + <g class="fnode is-entry"><rect class="fnode__box" x="205" y="58" width="150" height="48" /><text class="fnode__label" x="280" y="79" text-anchor="middle">PWNBOX<tspan class="sub" x="280" dy="15">proxychains + tools</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="205" y="178" width="150" height="48" /><text class="fnode__label" x="280" y="199" text-anchor="middle">DMZ01<tspan class="sub" x="280" dy="15">SSH pivot · SOCKS :8083</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="205" y="298" width="150" height="48" /><text class="fnode__label" x="280" y="319" text-anchor="middle">DEV01<tspan class="sub" x="280" dy="15">DNN · RDP foothold</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="45" y="418" width="150" height="48" /><text class="fnode__label" x="120" y="439" text-anchor="middle">DC01<tspan class="sub" x="120" dy="15">Domain Controller</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="365" y="418" width="150" height="48" /><text class="fnode__label" x="440" y="439" text-anchor="middle">MS01<tspan class="sub" x="440" dy="15">SQL · privesc to SYSTEM</tspan></text></g> + <g class="fnode is-goal"><rect class="fnode__box" x="365" y="538" width="150" height="48" /><text class="fnode__label" x="440" y="566" text-anchor="middle">Domain Admin</text></g> + <!-- edge labels --> + <g class="felabel"><rect class="felabel__box" x="239" y="134" width="82" height="16" /><text class="felabel__text" x="280" y="145" text-anchor="middle">ssh -D / -L</text></g> + <g class="felabel"><rect class="felabel__box" x="239" y="254" width="82" height="16" /><text class="felabel__text" x="280" y="265" text-anchor="middle">SOCKS + RDP</text></g> + <g class="felabel"><rect class="felabel__box" x="135" y="374" width="130" height="16" /><text class="felabel__text" x="200" y="385" text-anchor="middle">BloodHound · shares</text></g> + <g class="felabel"><rect class="felabel__box" x="298" y="374" width="124" height="16" /><text class="felabel__text" x="360" y="385" text-anchor="middle">cred reuse · WinRM</text></g> + <g class="felabel"><rect class="felabel__box" x="384" y="494" width="112" height="16" /><text class="felabel__text" x="440" y="505" text-anchor="middle">DCSync · tickets</text></g> + <g class="felabel"><rect class="felabel__box" x="218" y="434" width="124" height="16" /><text class="felabel__text" x="280" y="445" text-anchor="middle">Kerberoast · spray</text></g> + </svg> + </div> +</figure> ## 1. BloodHound recon diff --git a/src/content/sheets/pentest-workflow/cpts-exam-attack-flow.md b/src/content/sheets/pentest-workflow/cpts-exam-attack-flow.md @@ -69,39 +69,53 @@ source: "vault:Pentest Attack Flow/Companion Guides/CPTS-Exam-Attack-Flow.md" ## // NETWORK_MAP (example) -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - K["KALI<br/>10.10.14.x"] -->|"exploit"| DMZ["WEB-DMZ01<br/>(public)"] - DMZ -->|"ligolo tun"| S1["172.16.139.0/24<br/>DC01 · SRV01"] - S1 -->|"ligolo double"| S2["172.16.210.0/24<br/>DC02 · DEV01 · MGMT01"] - style DMZ fill:#26233a,stroke:#f6c177,color:#f6c177 - style S1 fill:#26233a,stroke:#c4a7e7,color:#c4a7e7 - style S2 fill:#26233a,stroke:#eb6f92,color:#eb6f92 -``` +<figure class="flow plate corners"> +<figcaption class="flow__cap"><span class="flow__kind">Engagement network map</span><span class="flow__dir">LR</span></figcaption> +<div class="flow__body"> +<div class="flow__diagram" data-dir="lr"> +<div class="flow-rank"><div class="flow-node is-entry">KALI<span class="sub">10.10.14.x</span></div></div> +<div class="flow-edge"><span class="flow-edge__label">exploit</span></div> +<div class="flow-rank"><div class="flow-node">WEB-DMZ01<span class="sub">(public)</span></div></div> +<div class="flow-edge"><span class="flow-edge__label">ligolo tun</span></div> +<div class="flow-rank"><div class="flow-node">172.16.139.0/24<span class="sub">DC01 · SRV01</span></div></div> +<div class="flow-edge"><span class="flow-edge__label">ligolo double</span></div> +<div class="flow-rank"><div class="flow-node">172.16.210.0/24<span class="sub">DC02 · DEV01 · MGMT01</span></div></div> +</div> +</div> +</figure> --- ## // MASTER_FLOW -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["1. EXTERNAL RECON<br/>AXFR + vhost fuzz"] --> B["2. WEB FOOTHOLD<br/>SQLi -> creds -> shell"] - B --> C["3. LINUX PRIVESC<br/>uftpd traversal + sudo GTFObin"] - C --> D["4. PIVOT (Ligolo)<br/>ping sweep + route add"] - D --> E["5. LOOT PIVOT HOSTS<br/>NFS scripts / notes / hashes"] - E --> F["6. AD FOOTHOLD<br/>LaZagne/Inveigh -> first domain user"] - F --> G["7. ACL CHAIN (BloodHound)<br/>ForceChangePW -> GenericWrite -> Kerberoast"] - G --> H["8. SHARE LOOT<br/>AxCrypt / OneNote / vault -> svc creds"] - H --> I["9. DCSYNC<br/>Account Operators -> Exchange TS -> DA"] - I --> J["10. FOREST TRUST<br/>gMSA read -> svc account"] - J --> K["11. DEV APPS<br/>SonarQube / Anuko / Webmin -> root"] - style B fill:#26233a,stroke:#f6c177,color:#f6c177 - style G fill:#26233a,stroke:#c4a7e7,color:#c4a7e7 - style I fill:#26233a,stroke:#eb6f92,color:#eb6f92 - style K fill:#26233a,stroke:#31748f,color:#9ccfd8 -``` +<figure class="flow plate corners"> +<figcaption class="flow__cap"><span class="flow__kind">Master engagement flow</span><span class="flow__dir">TD</span></figcaption> +<div class="flow__body"> +<div class="flow__diagram" data-dir="td"> +<div class="flow-rank"><div class="flow-node is-entry">1. EXTERNAL RECON<span class="sub">AXFR + vhost fuzz</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">2. WEB FOOTHOLD<span class="sub">SQLi -&gt; creds -&gt; shell</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">3. LINUX PRIVESC<span class="sub">uftpd traversal + sudo GTFObin</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">4. PIVOT (Ligolo)<span class="sub">ping sweep + route add</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">5. LOOT PIVOT HOSTS<span class="sub">NFS scripts / notes / hashes</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">6. AD FOOTHOLD<span class="sub">LaZagne/Inveigh -&gt; first domain user</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">7. ACL CHAIN (BloodHound)<span class="sub">ForceChangePW -&gt; GenericWrite -&gt; Kerberoast</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">8. SHARE LOOT<span class="sub">AxCrypt / OneNote / vault -&gt; svc creds</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node is-goal">9. DCSYNC<span class="sub">Account Operators -&gt; Exchange TS -&gt; DA</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">10. FOREST TRUST<span class="sub">gMSA read -&gt; svc account</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">11. DEV APPS<span class="sub">SonarQube / Anuko / Webmin -&gt; root</span></div></div> +</div> +</div> +</figure> --- @@ -222,18 +236,26 @@ flowchart TD > [!info] **This is the exam's core.** Own each account, mark it owned, read **Outbound Object Control**, abuse the edge, get the next account, repeat. The trilocor chain: -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["phernandez<br/>(cracked)"] -->|"HelpDesk TierIII<br/>AllExtendedRights"| B["reset ghiggins"] - B -->|"IT Support Mgrs<br/>GenericWrite"| C["add self to Contractors"] - C -->|"Contractors<br/>GenericWrite over user"| D["set SPN on divanov<br/>targeted Kerberoast"] - D -->|"crack TGS"| E["divanov"] - E -->|"share loot"| F["svc_trilocoradm<br/>(AxCrypt/OneNote)"] - F -->|"Account Operators<br/>+ Exchange Trusted Subsystem"| G["DCSync -> DA"] - style D fill:#26233a,stroke:#f6c177,color:#f6c177 - style G fill:#26233a,stroke:#eb6f92,color:#eb6f92 -``` +<figure class="flow plate corners"> +<figcaption class="flow__cap"><span class="flow__kind">BloodHound ACL chain</span><span class="flow__dir">TD</span></figcaption> +<div class="flow__body"> +<div class="flow__diagram" data-dir="td"> +<div class="flow-rank"><div class="flow-node is-entry">phernandez<span class="sub">(cracked)</span></div></div> +<div class="flow-edge"><span class="flow-edge__label">HelpDesk TierIII<br/>AllExtendedRights</span></div> +<div class="flow-rank"><div class="flow-node">reset ghiggins</div></div> +<div class="flow-edge"><span class="flow-edge__label">IT Support Mgrs<br/>GenericWrite</span></div> +<div class="flow-rank"><div class="flow-node">add self to Contractors</div></div> +<div class="flow-edge"><span class="flow-edge__label">Contractors<br/>GenericWrite over user</span></div> +<div class="flow-rank"><div class="flow-node">set SPN on divanov<span class="sub">targeted Kerberoast</span></div></div> +<div class="flow-edge"><span class="flow-edge__label">crack TGS</span></div> +<div class="flow-rank"><div class="flow-node">divanov</div></div> +<div class="flow-edge"><span class="flow-edge__label">share loot</span></div> +<div class="flow-rank"><div class="flow-node">svc_trilocoradm<span class="sub">(AxCrypt/OneNote)</span></div></div> +<div class="flow-edge"><span class="flow-edge__label">Account Operators<br/>+ Exchange Trusted Subsystem</span></div> +<div class="flow-rank"><div class="flow-node is-goal">DCSync -&gt; DA</div></div> +</div> +</div> +</figure> > [!terminal]+ The abuse commands (bloodyAD + targetedKerberoast) > ```bash diff --git a/src/content/sheets/pentest-workflow/domain-trusts-and-cross-forest.md b/src/content/sheets/pentest-workflow/domain-trusts-and-cross-forest.md @@ -266,19 +266,54 @@ nxc ldap "$DC" -u "$U" -p "$P" --query "(objectClass=foreignSecurityPrincipal)" ### Technique picker — decision flow -```mermaid -flowchart TD - A[DA in a domain] --> B{Trust type?} - B -->|Parent-Child / Tree-Root<br/>SID filtering OFF| C[Forge child golden ticket<br/>+ parentSID-519 ExtraSids<br/>ticketer.py / mimikatz /sid] - C --> C1[Enterprise Admin<br/>DCSync forest root] - B -->|Forest / External<br/>SID filtering ON| D{Anything explicitly shared?} - D -->|Foreign group membership / ACL| E[Use legit cross-trust access<br/>BloodHound Foreign nodes] - D -->|SPNs in other forest| F[Kerberoast across trust<br/>crack offline] - D -->|Unconstrained delegation host| G[Coerce partner-forest principals<br/>harvest TGTs] - D -->|ADCS enrollment rights| H[Enroll as foreign identity<br/>cert auth across trust] - D -->|Nothing shared| I[Own the trust key anyway:<br/>referral TGT for auth,<br/>then enumerate what IS reachable] - B -->|PAM / bastion| J[Shadow principal mapping<br/>bastion SID -> prod DA SID] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Cross-forest technique picker</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">DA in a domain</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Trust type?</div></div> + <div class="flow-branches"> + <div class="flow-lane"> + <div class="flow-edge"><span class="flow-edge__label">Parent-Child / Tree-Root<br/>SID filtering OFF</span></div> + <div class="flow-node">Forge child golden ticket<span class="sub">+ parentSID-519 ExtraSids</span><span class="sub">ticketer.py / mimikatz /sid</span></div> + <div class="flow-edge"></div> + <div class="flow-node is-goal">Enterprise Admin<span class="sub">DCSync forest root</span></div> + </div> + <div class="flow-lane"> + <div class="flow-edge"><span class="flow-edge__label">Forest / External<br/>SID filtering ON</span></div> + <div class="flow-node is-decision">Anything explicitly shared?</div> + <div class="flow-branches"> + <div class="flow-lane"> + <div class="flow-edge"><span class="flow-edge__label">Foreign group membership / ACL</span></div> + <div class="flow-node">Use legit cross-trust access<span class="sub">BloodHound Foreign nodes</span></div> + </div> + <div class="flow-lane"> + <div class="flow-edge"><span class="flow-edge__label">SPNs in other forest</span></div> + <div class="flow-node">Kerberoast across trust<span class="sub">crack offline</span></div> + </div> + <div class="flow-lane"> + <div class="flow-edge"><span class="flow-edge__label">Unconstrained delegation host</span></div> + <div class="flow-node">Coerce partner-forest principals<span class="sub">harvest TGTs</span></div> + </div> + <div class="flow-lane"> + <div class="flow-edge"><span class="flow-edge__label">ADCS enrollment rights</span></div> + <div class="flow-node">Enroll as foreign identity<span class="sub">cert auth across trust</span></div> + </div> + <div class="flow-lane"> + <div class="flow-edge"><span class="flow-edge__label">Nothing shared</span></div> + <div class="flow-node">Own the trust key anyway:<span class="sub">referral TGT for auth,</span><span class="sub">then enumerate what IS reachable</span></div> + </div> + </div> + </div> + <div class="flow-lane"> + <div class="flow-edge"><span class="flow-edge__label">PAM / bastion</span></div> + <div class="flow-node">Shadow principal mapping<span class="sub">bastion SID -&gt; prod DA SID</span></div> + </div> + </div> + </div> + </div> +</figure> --- diff --git a/src/content/sheets/pentest-workflow/foothold-shells-payloads-metasploit.md b/src/content/sheets/pentest-workflow/foothold-shells-payloads-metasploit.md @@ -37,19 +37,28 @@ The bridge between "I have code execution" and "I have a shell I can actually wo | Already in a meterpreter session, need more reach | `autoroute` + `socks_proxy`, or ligolo-ng/chisel | | Fragile/lossy link | Stageless payload, or `reverse_https` | -```mermaid -flowchart LR - A[Execution primitive<br/>RCE / upload / injection] --> B{Egress open?} - B -- yes --> C[Reverse shell<br/>nc / socat catch] - B -- no --> D[Bind shell<br/>target listens] - C --> E[TTY upgrade<br/>pty / script / ConPty] - D --> E - E --> F{Need post-ex?} - F -- yes --> G[msfvenom meterpreter<br/>+ multi/handler] - F -- no --> H[Manual enum<br/>Stage 09] - G --> I[Pivot<br/>autoroute / ligolo-ng / chisel] - I --> J[Stage 10] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Foothold decision flow</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Execution primitive<span class="sub">RCE / upload / injection</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Egress open?</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">yes</span></div><div class="flow-node">Reverse shell<span class="sub">nc / socat catch</span></div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">no</span></div><div class="flow-node">Bind shell<span class="sub">target listens</span></div></div> + </div> + <div class="flow-join"></div> + <div class="flow-rank"><div class="flow-node">TTY upgrade<span class="sub">pty / script / ConPty</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Need post-ex?</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">yes</span></div><div class="flow-node">msfvenom meterpreter<span class="sub">+ multi/handler</span></div><div class="flow-edge"></div><div class="flow-node">Pivot<span class="sub">autoroute / ligolo-ng / chisel</span></div><div class="flow-edge"></div><div class="flow-node">Stage 10</div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">no</span></div><div class="flow-node">Manual enum<span class="sub">Stage 09</span></div></div> + </div> + </div> + </div> +</figure> --- diff --git a/src/content/sheets/pentest-workflow/htb-attack-flow-playbook.md b/src/content/sheets/pentest-workflow/htb-attack-flow-playbook.md @@ -49,36 +49,55 @@ printf '%s\t%s %s %s\n' \ ## Kill Chain -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - O["0. PASSIVE RECON<br/>crt.sh · Shodan · dorks · git"] --> S["SETUP<br/>hosts · realm · clock"] - S --> R["1. RECON<br/>RustScan → Nmap"] - R --> Q{"Attack surface?"} - Q -->|"80/443"| W["2. WEB<br/>ffuf · Burp · app testing"] - Q -->|"445/139 · 135"| SM["3. SERVICES<br/>NetExec · enum4linux-ng"] - Q -->|"389/88"| AE["4. AD ENUM<br/>LDAP · BloodHound"] - W --> TK["FOOTHOLD TOOLKITS<br/>transfer · payload · shell"] - SM --> TK - TK --> F["Foothold or credentials"] - AE --> K["5. KERBEROS<br/>roast · AS-REP · tickets"] - K --> ACL["6. ACL ABUSE<br/>BloodHound edges"] - ACL --> C["7. ADCS<br/>Certipy"] - F --> PW["8. CREDENTIALS<br/>hunt · spray · crack"] - PW --> PE["9. PRIVESC<br/>Linux / Windows"] - PE --> LM["10. LATERAL / PIVOT / LOOT"] - C --> DA["Domain Admin"] - ACL --> DA - K --> F - LM --> DA - DA --> T["TRUSTS<br/>domain · forest"] - T --> REP["11. REPORT<br/>evidence · findings · retest"] - - classDef dom fill:#31748f,stroke:#9ccfd8,color:#e0def4; - classDef rep fill:#403d52,stroke:#c4a7e7,color:#e0def4; - class DA dom; - class REP rep; -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Engagement kill chain</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 840 1410" role="img" aria-label="Passive recon and setup lead to recon, then an attack-surface decision fans out to web, services and AD enumeration; the foothold and AD paths run through credentials, privesc, lateral movement, Kerberos, ACL and ADCS abuse and converge on Domain Admin, then trusts and reporting"> + <path class="fedge" d="M400,78 L400,138" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M400,186 L400,246" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M400,294 L400,354" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M400,402 L150,462" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M400,402 L400,462" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M400,402 L650,462" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M150,510 L255,570" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M400,510 L295,570" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M275,618 L275,678" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M650,510 L650,570" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M650,618 L650,678" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M650,726 L650,786" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M275,726 L275,786" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M275,834 L275,894" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M275,942 L275,1002" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M650,834 L650,1082 L380,1082 L380,1110" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M725,702 L790,702 L790,1092 L420,1092 L420,1110" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M575,594 L462,594 L462,702 L350,702" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M275,1050 L400,1110" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M400,1158 L400,1218" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M400,1266 L400,1326" marker-end="url(#flow-arrow)" /> + <g class="fnode is-entry"><rect class="fnode__box" x="325" y="30" width="150" height="48" /><text class="fnode__label" x="400" y="51" text-anchor="middle">0. PASSIVE RECON<tspan class="sub" x="400" dy="15">crt.sh · Shodan · dorks · git</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="325" y="138" width="150" height="48" /><text class="fnode__label" x="400" y="159" text-anchor="middle">SETUP<tspan class="sub" x="400" dy="15">hosts · realm · clock</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="325" y="246" width="150" height="48" /><text class="fnode__label" x="400" y="267" text-anchor="middle">1. RECON<tspan class="sub" x="400" dy="15">RustScan → Nmap</tspan></text></g> + <g class="fnode is-decision"><rect class="fnode__box" x="325" y="354" width="150" height="48" /><text class="fnode__label" x="400" y="382" text-anchor="middle">Attack surface?</text></g> + <g class="fnode"><rect class="fnode__box" x="75" y="462" width="150" height="48" /><text class="fnode__label" x="150" y="483" text-anchor="middle">2. WEB<tspan class="sub" x="150" dy="15">ffuf · Burp · app testing</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="325" y="462" width="150" height="48" /><text class="fnode__label" x="400" y="483" text-anchor="middle">3. SERVICES<tspan class="sub" x="400" dy="15">NetExec · enum4linux-ng</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="575" y="462" width="150" height="48" /><text class="fnode__label" x="650" y="483" text-anchor="middle">4. AD ENUM<tspan class="sub" x="650" dy="15">LDAP · BloodHound</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="200" y="570" width="150" height="48" /><text class="fnode__label" x="275" y="591" text-anchor="middle">FOOTHOLD TOOLKITS<tspan class="sub" x="275" dy="15">transfer · payload · shell</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="575" y="570" width="150" height="48" /><text class="fnode__label" x="650" y="591" text-anchor="middle">5. KERBEROS<tspan class="sub" x="650" dy="15">roast · AS-REP · tickets</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="200" y="678" width="150" height="48" /><text class="fnode__label" x="275" y="706" text-anchor="middle">Foothold or credentials</text></g> + <g class="fnode"><rect class="fnode__box" x="575" y="678" width="150" height="48" /><text class="fnode__label" x="650" y="699" text-anchor="middle">6. ACL ABUSE<tspan class="sub" x="650" dy="15">BloodHound edges</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="200" y="786" width="150" height="48" /><text class="fnode__label" x="275" y="807" text-anchor="middle">8. CREDENTIALS<tspan class="sub" x="275" dy="15">hunt · spray · crack</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="575" y="786" width="150" height="48" /><text class="fnode__label" x="650" y="807" text-anchor="middle">7. ADCS<tspan class="sub" x="650" dy="15">Certipy</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="200" y="894" width="150" height="48" /><text class="fnode__label" x="275" y="915" text-anchor="middle">9. PRIVESC<tspan class="sub" x="275" dy="15">Linux / Windows</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="200" y="1002" width="150" height="48" /><text class="fnode__label" x="275" y="1030" text-anchor="middle">10. LATERAL / PIVOT / LOOT</text></g> + <g class="fnode is-goal"><rect class="fnode__box" x="325" y="1110" width="150" height="48" /><text class="fnode__label" x="400" y="1138" text-anchor="middle">Domain Admin</text></g> + <g class="fnode"><rect class="fnode__box" x="325" y="1218" width="150" height="48" /><text class="fnode__label" x="400" y="1239" text-anchor="middle">TRUSTS<tspan class="sub" x="400" dy="15">domain · forest</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="325" y="1326" width="150" height="48" /><text class="fnode__label" x="400" y="1347" text-anchor="middle">11. REPORT<tspan class="sub" x="400" dy="15">evidence · findings · retest</tspan></text></g> + <g class="felabel"><rect class="felabel__box" x="250" y="424" width="50" height="16" /><text class="felabel__text" x="275" y="435" text-anchor="middle">80/443</text></g> + <g class="felabel"><rect class="felabel__box" x="353" y="424" width="94" height="16" /><text class="felabel__text" x="400" y="435" text-anchor="middle">445/139 · 135</text></g> + <g class="felabel"><rect class="felabel__box" x="500" y="424" width="50" height="16" /><text class="felabel__text" x="525" y="435" text-anchor="middle">389/88</text></g> + </svg> + </div> +</figure> > [!tip] How to use the flow > Treat each stage as a question, not a mandatory sequence. New credentials, routes, hostnames, or privileges should send you back to the lowest-noise relevant enumeration stage. On an HTB box you may begin at Stage 01; a real engagement or CPTS-style assessment usually begins at Stage 00 and ends only after Stage 11. diff --git a/src/content/sheets/pentest-workflow/kerberos-attacks.md b/src/content/sheets/pentest-workflow/kerberos-attacks.md @@ -36,20 +36,24 @@ Once I hold **any** valid domain creds (from spraying/roasting) I pivot to Kerbe ### ⏱️ Kerberos in 60 seconds — the flow every attack hangs off -```mermaid -sequenceDiagram - autonumber - participant C as Client (me) - participant K as KDC / DC (port 88) - participant S as Service (cifs/http/mssql…) - - C->>K: AS-REQ — prove identity (timestamp encrypted with my key) - K-->>C: AS-REP — TGT (encrypted with krbtgt key) + session key - C->>K: TGS-REQ — TGT + SPN of the service I want - K-->>C: TGS-REP — service ticket (encrypted with the SERVICE account's key) - C->>S: AP-REQ — present service ticket - S-->>C: access granted -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Kerberos auth exchange</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Client &rarr; KDC<span class="sub">AS-REQ — prove identity (timestamp encrypted with my key)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">KDC &rarr; Client<span class="sub">AS-REP — TGT (encrypted with krbtgt key) + session key</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Client &rarr; KDC<span class="sub">TGS-REQ — TGT + SPN of the service I want</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">KDC &rarr; Client<span class="sub">TGS-REP — service ticket (encrypted with the SERVICE account&apos;s key)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Client &rarr; Service<span class="sub">AP-REQ — present service ticket</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">Service &rarr; Client<span class="sub">access granted</span></div></div> + </div> + </div> +</figure> **Why each attack exists, mapped to a step:** diff --git a/src/content/sheets/pentest-workflow/lateral-movement-pivoting-and-loot.md b/src/content/sheets/pentest-workflow/lateral-movement-pivoting-and-loot.md @@ -434,17 +434,32 @@ proxychains4 secretsdump.py "$DOMAIN/Administrator:$P@$DC" -just-dc-user krbtgt > [!warning] Watch out > SOCKS is **TCP only** — nmap must be `-sT -Pn` (no ICMP, no SYN). **UDP dies** through proxychains: that kills DNS unless `proxy_dns` is set (and even then it's slow), and it kills pure-UDP tools entirely. `nmap --dns-servers $DC` still won't fix UDP under SOCKS5 — prefer IP literals and `/etc/hosts` entries, or use Ligolo when name resolution matters. Static binaries only: proxychains hooks libc, so Go binaries and some .NET tools ignore it. Prefer **Ligolo** when I want raw L3 (full nmap, no proxychains). Full tables in Tunneling. -```mermaid -graph LR - A[Attack host<br/>ligolo-proxy :11601] -->|agent dials back| P1[Pivot 1 — DMZ web<br/>172.16.10.10] - P1 -->|listener :4444 relay| A - P2[Pivot 2 — app tier<br/>10.20.30.5] -->|agent 2 dials 172.16.10.10:4444| P1 - A -.->|iface ligolo: 172.16.10.0/24| P1 - A -.->|iface ligolo2: 10.20.30.0/24| P2 - P2 --> T1[(Deep target<br/>10.20.30.20)] - P2 --> T2[(Deep DC<br/>10.20.30.10)] - T1 -.->|reverse shell → pivot2:5555<br/>→ listener → my nc :4444| A -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Ligolo double-pivot topology</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 975 340" role="img" aria-label="Attack host and two ligolo pivots reaching deep targets, with agent callbacks, a listener relay, tunnel interfaces and a reverse shell routing back to the attack host"> + <path class="fedge" d="M185,154 L283,154" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M685,154 L783,104" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M685,154 L783,224" marker-end="url(#flow-arrow)" /> + <path class="fedge is-back" d="M350,130 L350,95 L110,95 L110,128" marker-end="url(#flow-arrow)" /> + <path class="fedge is-back" d="M610,130 L610,60 L370,60 L370,128" marker-end="url(#flow-arrow)" /> + <path class="fedge is-dotted" d="M95,178 L95,205 L360,205 L360,180" marker-end="url(#flow-arrow)" /> + <path class="fedge is-dotted" d="M110,178 L110,240 L610,240 L610,180" marker-end="url(#flow-arrow)" /> + <path class="fedge is-back is-dotted" d="M860,248 L860,290 L125,290 L125,180" marker-end="url(#flow-arrow)" /> + <g class="fnode is-entry"><rect class="fnode__box" x="35" y="130" width="150" height="48" /><text class="fnode__label" x="110" y="151" text-anchor="middle">Attack host<tspan class="sub" x="110" dy="15">ligolo-proxy :11601</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="285" y="130" width="150" height="48" /><text class="fnode__label" x="360" y="151" text-anchor="middle">Pivot 1 — DMZ web<tspan class="sub" x="360" dy="15">172.16.10.10</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="535" y="130" width="150" height="48" /><text class="fnode__label" x="610" y="151" text-anchor="middle">Pivot 2 — app tier<tspan class="sub" x="610" dy="15">10.20.30.5</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="785" y="80" width="150" height="48" /><text class="fnode__label" x="860" y="101" text-anchor="middle">Deep target<tspan class="sub" x="860" dy="15">10.20.30.20</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="785" y="200" width="150" height="48" /><text class="fnode__label" x="860" y="221" text-anchor="middle">Deep DC<tspan class="sub" x="860" dy="15">10.20.30.10</tspan></text></g> + <g class="felabel"><rect class="felabel__box" x="181" y="146" width="106" height="16" /><text class="felabel__text" x="234" y="157" text-anchor="middle">agent dials back</text></g> + <g class="felabel"><rect class="felabel__box" x="156" y="87" width="148" height="16" /><text class="felabel__text" x="230" y="98" text-anchor="middle">listener :4444 relay</text></g> + <g class="felabel"><rect class="felabel__box" x="383" y="52" width="214" height="16" /><text class="felabel__text" x="490" y="63" text-anchor="middle">agent 2 dials 172.16.10.10:4444</text></g> + <g class="felabel"><rect class="felabel__box" x="128" y="197" width="200" height="16" /><text class="felabel__text" x="228" y="208" text-anchor="middle">iface ligolo: 172.16.10.0/24</text></g> + <g class="felabel"><rect class="felabel__box" x="257" y="232" width="206" height="16" /><text class="felabel__text" x="360" y="243" text-anchor="middle">iface ligolo2: 10.20.30.0/24</text></g> + <g class="felabel"><rect class="felabel__box" x="395" y="275" width="196" height="30" /><text class="felabel__text" x="493" y="286" text-anchor="middle">reverse shell → pivot2:5555<tspan x="493" dy="15">→ listener → my nc :4444</tspan></text></g> + </svg> + </div> +</figure> --- diff --git a/src/content/sheets/pentest-workflow/linux-privesc-cpts.md b/src/content/sheets/pentest-workflow/linux-privesc-cpts.md @@ -36,21 +36,29 @@ From a low-privilege shell to `root`. The loop is always the same: **enumerate b > > A listed binary is not automatically exploitable. Match the page's required permissions and invocation to `sudo -l`, SUID/capability state, file ACLs and installed version. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A["whoami / id / sudo -l\nuname -a"] --> B["Run LinPEAS / lse.sh\n+ pspy for timing"] - B --> C{"Vector?"} - C --> D["sudo/GTFOBins · groups\n(lxd/docker/disk)"] - C --> E["cron / writable script\n/ PATH / wildcard"] - C --> F["SUID-SGID / capability\n/ SO hijack"] - C --> G["kernel CVE (last resort)"] - D --> H["root"] - E --> H - F --> H - G --> H - H --> I["pivot host\nchisel / ligolo-ng"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Linux privesc methodology</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="lr"> + <div class="flow-rank"><div class="flow-node is-entry">whoami / id / sudo -l<span class="sub">uname -a</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Run LinPEAS / lse.sh<span class="sub">+ pspy for timing</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Vector?</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"> + <div class="flow-node">sudo/GTFOBins · groups<span class="sub">(lxd/docker/disk)</span></div> + <div class="flow-node">cron / writable script<span class="sub">/ PATH / wildcard</span></div> + <div class="flow-node">SUID-SGID / capability<span class="sub">/ SO hijack</span></div> + <div class="flow-node is-danger">kernel CVE (last resort)</div> + </div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">root</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">pivot host<span class="sub">chisel / ligolo-ng</span></div></div> + </div> + </div> +</figure> --- diff --git a/src/content/sheets/pentest-workflow/most-used-commands.md b/src/content/sheets/pentest-workflow/most-used-commands.md @@ -21,33 +21,38 @@ source: "vault:Pentest Attack Flow/Companion Guides/Most-Used-Commands.md" The order I actually work a box. Windows/AD path is the spine, web/Linux detours branch off recon. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["0. SETUP<br/>hosts + krb5 + ntpdate"] --> B["1. RECON<br/>rustscan / nmap"] - B --> C{"Attack surface?"} - C -->|"AD / SMB / LDAP"| D["2. AD ENUM<br/>netexec + bloodhound-ce-python"] - C -->|"Web"| W["Web: ffuf / sqlmap / LFI"] - C -->|"Linux svc"| L["Linux: NFS / DNS / redis"] - D --> E["3. FOOTHOLD CREDS<br/>kerberoast / asrep / shares / spray"] - W --> E - L --> E - E --> F["4. BLOODHOUND PATH<br/>ACLs: GenericWrite / ForceChangePW"] - F --> G["5. ESCALATE ID<br/>shadow creds / gMSA / DPAPI / recycle bin"] - G --> H{"Path to DA?"} - H -->|"ADCS"| I["6a. CERTIPY<br/>ESC1 / ESC8 / ESC15 / ESC16"] - H -->|"Delegation"| J["6b. RBCD / constrained<br/>impacket getST"] - H -->|"Creds/priv"| K["6c. SeImpersonate / SeDebug<br/>secretsdump / DCSync"] - I --> Z["7. DOMAIN ADMIN<br/>evil-winrm / psexec"] - J --> Z - K --> Z - - style A fill:#26233a,stroke:#9ccfd8,color:#e0def4 - style E fill:#26233a,stroke:#f6c177,color:#f6c177 - style F fill:#26233a,stroke:#c4a7e7,color:#c4a7e7 - style I fill:#26233a,stroke:#eb6f92,color:#eb6f92 - style Z fill:#26233a,stroke:#eb6f92,color:#eb6f92 -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Box attack workflow</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">0. SETUP<span class="sub">hosts + krb5 + ntpdate</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">1. RECON<span class="sub">rustscan / nmap</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Attack surface?</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">AD / SMB / LDAP</span></div><div class="flow-node">2. AD ENUM<span class="sub">netexec + bloodhound-ce-python</span></div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Web</span></div><div class="flow-node">Web: ffuf / sqlmap / LFI</div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Linux svc</span></div><div class="flow-node">Linux: NFS / DNS / redis</div></div> + </div> + <div class="flow-join"></div> + <div class="flow-rank"><div class="flow-node">3. FOOTHOLD CREDS<span class="sub">kerberoast / asrep / shares / spray</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">4. BLOODHOUND PATH<span class="sub">ACLs: GenericWrite / ForceChangePW</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">5. ESCALATE ID<span class="sub">shadow creds / gMSA / DPAPI / recycle bin</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Path to DA?</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">ADCS</span></div><div class="flow-node">6a. CERTIPY<span class="sub">ESC1 / ESC8 / ESC15 / ESC16</span></div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Delegation</span></div><div class="flow-node">6b. RBCD / constrained<span class="sub">impacket getST</span></div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Creds/priv</span></div><div class="flow-node">6c. SeImpersonate / SeDebug<span class="sub">secretsdump / DCSync</span></div></div> + </div> + <div class="flow-join"></div> + <div class="flow-rank"><div class="flow-node is-goal">7. DOMAIN ADMIN<span class="sub">evil-winrm / psexec</span></div></div> + </div> + </div> +</figure> > [!tip]+ `> THE_LOOP` (what to do first, then again) > 1. **Every time you get new creds or a new hash** → re-run BloodHound as that principal, re-spray across SMB/WinRM, and re-check ADCS with certipy. New identity = new outbound control. diff --git a/src/content/sheets/pentest-workflow/network-service-attack-manual.md b/src/content/sheets/pentest-workflow/network-service-attack-manual.md @@ -89,14 +89,22 @@ The source module uses four questions for any vulnerability. This guide renames 3. **Security context:** Which operating-system account, database role, group, policy, or container identity runs the handler? 4. **Effect:** Does the result reach a local file, local process, database row, another host, or an outbound connection? -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A["Entry\ninput, file, config, library"] --> B["Handler\nparser, function, service logic"] - B --> C["Security context\naccount, group, role, policy"] - C --> D["Effect\nfile, process, data, network"] - D -. "feeds a second cycle" .-> A -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Attack path model</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 1080 200" role="img" aria-label="Entry to handler to security context to effect, with the effect feeding a second cycle back to entry"> + <path class="fedge" d="M255,82 L293,82" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M515,82 L553,82" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M775,82 L813,82" marker-end="url(#flow-arrow)" /> + <path class="fedge is-back" d="M925,106 L925,172 L145,172 L145,108" marker-end="url(#flow-arrow)" /> + <g class="fnode is-entry"><rect class="fnode__box" x="35" y="58" width="220" height="48" /><text class="fnode__label" x="145" y="79" text-anchor="middle">Entry<tspan class="sub" x="145" dy="15">input, file, config, library</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="295" y="58" width="220" height="48" /><text class="fnode__label" x="405" y="79" text-anchor="middle">Handler<tspan class="sub" x="405" dy="15">parser, function, service logic</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="555" y="58" width="220" height="48" /><text class="fnode__label" x="665" y="79" text-anchor="middle">Security context<tspan class="sub" x="665" dy="15">account, group, role, policy</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="815" y="58" width="220" height="48" /><text class="fnode__label" x="925" y="79" text-anchor="middle">Effect<tspan class="sub" x="925" dy="15">file, process, data, network</tspan></text></g> + <g class="felabel"><rect class="felabel__box" x="463" y="164" width="144" height="16" /><text class="felabel__text" x="535" y="175" text-anchor="middle">feeds a second cycle</text></g> + </svg> + </div> +</figure> Most exploit chains contain two passes through this model. The first discloses data or creates a foothold. Its output becomes the entry for the second pass, which reaches code execution or a more privileged identity. @@ -959,19 +967,33 @@ Affected OpenSMTPD versions mishandled shell metacharacters in an attacker-contr The fastest path through a multi-service host is a state machine. Each new identity or secret returns to the authentication stage for every compatible service. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["Full TCP plus targeted UDP scan"] --> B["Unauthenticated checks\nanonymous, null, records, capabilities"] - B --> C["Collect names and scoped files"] - C --> D["Update identity and credential matrix"] - D --> E["Validate against every compatible service"] - E --> F["Enumerate effective permissions"] - F --> G{"New host, account, secret, or trust?"} - G -->|yes| D - G -->|no| H["Version-gated exploit review"] - H --> I["Minimal proof, cleanup, report"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Multi-service state machine</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 460 1100" role="img" aria-label="Full scan, unauthenticated checks, collect files, update credential matrix, validate services, enumerate permissions, then a decision: if a new host account secret or trust is found loop back to the credential matrix, otherwise proceed to version-gated exploit review then minimal proof, cleanup and report"> + <path class="fedge" d="M200,88 L200,156" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M200,206 L200,274" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M200,324 L200,392" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M200,442 L200,510" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M200,560 L200,628" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M200,678 L200,746" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M200,832 L200,900" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M200,950 L200,1018" marker-end="url(#flow-arrow)" /> + <path class="fedge is-back" d="M380,790 L410,790 L410,418 L372,418" marker-end="url(#flow-arrow)" /> + <g class="fnode is-entry"><rect class="fnode__box" x="30" y="40" width="340" height="48" /><text class="fnode__label" x="200" y="68" text-anchor="middle">Full TCP plus targeted UDP scan</text></g> + <g class="fnode"><rect class="fnode__box" x="30" y="158" width="340" height="48" /><text class="fnode__label" x="200" y="178" text-anchor="middle">Unauthenticated checks<tspan class="sub" x="200" dy="15">anonymous, null, records, capabilities</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="30" y="276" width="340" height="48" /><text class="fnode__label" x="200" y="304" text-anchor="middle">Collect names and scoped files</text></g> + <g class="fnode"><rect class="fnode__box" x="30" y="394" width="340" height="48" /><text class="fnode__label" x="200" y="422" text-anchor="middle">Update identity and credential matrix</text></g> + <g class="fnode"><rect class="fnode__box" x="30" y="512" width="340" height="48" /><text class="fnode__label" x="200" y="540" text-anchor="middle">Validate against every compatible service</text></g> + <g class="fnode"><rect class="fnode__box" x="30" y="630" width="340" height="48" /><text class="fnode__label" x="200" y="658" text-anchor="middle">Enumerate effective permissions</text></g> + <g class="fnode is-decision"><polygon class="fdecision__poly" points="200,748 380,790 200,832 20,790" /><text class="fdecision__label" x="200" y="794" text-anchor="middle">New host, account, secret, or trust?</text></g> + <g class="fnode"><rect class="fnode__box" x="30" y="902" width="340" height="48" /><text class="fnode__label" x="200" y="930" text-anchor="middle">Version-gated exploit review</text></g> + <g class="fnode"><rect class="fnode__box" x="30" y="1020" width="340" height="48" /><text class="fnode__label" x="200" y="1048" text-anchor="middle">Minimal proof, cleanup, report</text></g> + <g class="felabel"><rect class="felabel__box" x="394" y="596" width="32" height="16" /><text class="felabel__text" x="410" y="607" text-anchor="middle">yes</text></g> + <g class="felabel"><rect class="felabel__box" x="187" y="858" width="26" height="16" /><text class="felabel__text" x="200" y="869" text-anchor="middle">no</text></g> + </svg> + </div> +</figure> ### Chain A: file service to mail to database diff --git a/src/content/sheets/pentest-workflow/potato-attacks-and-ads-guide.md b/src/content/sheets/pentest-workflow/potato-attacks-and-ads-guide.md @@ -43,13 +43,20 @@ You are looking for either of these in the **Enabled** state: Every tool below follows the same three beats. Only step 1 changes between them. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A["1 · Coerce SYSTEM to authenticate\nto a listener you control\n(Spooler pipe / DCOM OXID / EFS RPC)"] --> B["2 · Catch the auth and negotiate\na SYSTEM security context\n(NTLM / SSPI)"] - B --> C["3 · Impersonate the SYSTEM token\n(needs SeImpersonate)"] - C --> D["4 · CreateProcessWithToken / AsUser\n→ your command runs as SYSTEM"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">The potato pattern — four beats</span><span class="flow__dir">LR</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="lr"> + <div class="flow-rank"><div class="flow-node is-entry">1 · Coerce SYSTEM to authenticate<span class="sub">to a listener you control</span><span class="sub">(Spooler pipe / DCOM OXID / EFS RPC)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">2 · Catch the auth and negotiate<span class="sub">a SYSTEM security context</span><span class="sub">(NTLM / SSPI)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">3 · Impersonate the SYSTEM token<span class="sub">(needs SeImpersonate)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">4 · CreateProcessWithToken / AsUser<span class="sub">→ your command runs as SYSTEM</span></div></div> + </div> + </div> +</figure> The named difference — Print Spooler bug, DCOM/RPC OXID resolver, MS-EFSR — is just *the coercion trick in step 1*. When one is patched or disabled, you switch tools, not techniques. @@ -80,18 +87,37 @@ Confirm the build first — `[environment]::OSVersion.Version` (PowerShell) or ` | **EfsPotato** | MS-EFSR (EFS RPC) local coercion | SeImpersonate or SeAssignPrimaryToken | Modern builds; multiple RPC interfaces to dodge patches | Great from `xp_cmdshell` / web shells; small, self-contained, swaps RPC pipes when one is patched. | | **SweetPotato** | Bundles several (EfsRpc, PrintSpoofer, RottenPotato, DCOM) | SeImpersonate | Modern builds | You want one binary with a fallback `-e` selector; good "if this fails, switch mode" tool. | -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - P{"whoami /priv:\nSeImpersonate or\nSeAssignPrimaryToken?"} -->|No| STOP["Not a potato box —\nservices / registry / creds / kernel"] - P -->|Yes| SPOOL{"Print Spooler\nservice running?"} - SPOOL -->|Yes| PS["PrintSpoofer\n(interactive SYSTEM shell)"] - SPOOL -->|No| GP["GodPotato\n(pick NET4 / NET35 by runtime)"] - PS -->|fails| GP - GP -->|fails| SW["SweetPotato -e EfsRpc\nor EfsPotato (swap RPC pipe)"] - SW -->|fails| NG["JuicyPotatoNG\n(-s to seek a CLSID)"] - NG -->|DCOM blocked outbound| RG["RoguePotato\n(+ socat :135 redirector)"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Which potato? — a fallback ladder</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 630 720" role="img" aria-label="Decision tree for choosing a potato privilege-escalation tool, falling through PrintSpoofer, GodPotato, SweetPotato, JuicyPotatoNG and RoguePotato as each fails"> + <path class="fedge" d="M360,90 L360,150" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M300,90 L300,120 L120,120 L120,150" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M300,210 L300,240 L120,240 L120,270" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M420,210 L420,240 L470,240 L470,270" marker-end="url(#flow-arrow)" /> + <path class="fedge is-back" d="M235,300 L355,300" marker-end="url(#flow-arrow)" /> + <path class="fedge is-back" d="M470,330 L470,390" marker-end="url(#flow-arrow)" /> + <path class="fedge is-back" d="M470,450 L470,510" marker-end="url(#flow-arrow)" /> + <path class="fedge is-back" d="M470,570 L470,630" marker-end="url(#flow-arrow)" /> + <g class="fnode is-decision"><rect class="fnode__box" x="245" y="30" width="230" height="60" /><text class="fnode__label" x="360" y="48" text-anchor="middle">whoami /priv:<tspan class="sub" x="360" dy="14">SeImpersonate or</tspan><tspan class="sub" x="360" dy="14">SeAssignPrimaryToken?</tspan></text></g> + <g class="fnode is-note"><rect class="fnode__box" x="5" y="150" width="230" height="60" /><text class="fnode__label" x="120" y="176" text-anchor="middle">Not a potato box —<tspan class="sub" x="120" dy="15">services / registry / creds / kernel</tspan></text></g> + <g class="fnode is-decision"><rect class="fnode__box" x="245" y="150" width="230" height="60" /><text class="fnode__label" x="360" y="176" text-anchor="middle">Print Spooler<tspan class="sub" x="360" dy="15">service running?</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="5" y="270" width="230" height="60" /><text class="fnode__label" x="120" y="296" text-anchor="middle">PrintSpoofer<tspan class="sub" x="120" dy="15">(interactive SYSTEM shell)</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="355" y="270" width="230" height="60" /><text class="fnode__label" x="470" y="296" text-anchor="middle">GodPotato<tspan class="sub" x="470" dy="15">(pick NET4 / NET35 by runtime)</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="355" y="390" width="230" height="60" /><text class="fnode__label" x="470" y="416" text-anchor="middle">SweetPotato -e EfsRpc<tspan class="sub" x="470" dy="15">or EfsPotato (swap RPC pipe)</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="355" y="510" width="230" height="60" /><text class="fnode__label" x="470" y="536" text-anchor="middle">JuicyPotatoNG<tspan class="sub" x="470" dy="15">(-s to seek a CLSID)</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="355" y="630" width="230" height="60" /><text class="fnode__label" x="470" y="656" text-anchor="middle">RoguePotato<tspan class="sub" x="470" dy="15">(+ socat :135 redirector)</tspan></text></g> + <g class="felabel"><rect class="felabel__box" x="343" y="112" width="34" height="16" /><text class="felabel__text" x="360" y="123" text-anchor="middle">Yes</text></g> + <g class="felabel"><rect class="felabel__box" x="197" y="112" width="26" height="16" /><text class="felabel__text" x="210" y="123" text-anchor="middle">No</text></g> + <g class="felabel"><rect class="felabel__box" x="193" y="232" width="34" height="16" /><text class="felabel__text" x="210" y="243" text-anchor="middle">Yes</text></g> + <g class="felabel"><rect class="felabel__box" x="432" y="232" width="26" height="16" /><text class="felabel__text" x="445" y="243" text-anchor="middle">No</text></g> + <g class="felabel"><rect class="felabel__box" x="274" y="292" width="42" height="16" /><text class="felabel__text" x="295" y="303" text-anchor="middle">fails</text></g> + <g class="felabel"><rect class="felabel__box" x="449" y="352" width="42" height="16" /><text class="felabel__text" x="470" y="363" text-anchor="middle">fails</text></g> + <g class="felabel"><rect class="felabel__box" x="449" y="472" width="42" height="16" /><text class="felabel__text" x="470" y="483" text-anchor="middle">fails</text></g> + <g class="felabel"><rect class="felabel__box" x="395" y="592" width="150" height="16" /><text class="felabel__text" x="470" y="603" text-anchor="middle">DCOM blocked outbound</text></g> + </svg> + </div> +</figure> --- @@ -505,17 +531,29 @@ Remove-Item C:\Windows\Temp\notes.txt -Stream stash The potatoes are the easy part. The skill is the four steps *around* them: recognise that your shell holds impersonation rights, fingerprint the host so you pick a tool that actually fires on **this** build, get the binary across when the box has no download tools, then drive it non-interactively and read the result. Below is that method as a repeatable loop. A single awkward old box — HTB Jeeves, Windows 10 build 10586 — runs underneath as a case study, because the boxes where the *newest* potato fails are exactly the ones that teach you why fingerprinting matters. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart TD - A["1 · whoami /priv + /groups\nSeImpersonate? SERVICE token?"] --> B["2 · systeminfo → OS build\nchoose tool by DCOM era"] - B --> C["3 · Transfer the binary\ncertutil / IWR / SMB share"] - C --> D["4 · Fire non-interactively\noutput → a file you can read"] - D --> E{"authresult 0 /\nNT AUTHORITY\\SYSTEM?"} - E -->|No| B2["Wrong tool for the era —\nswitch potato, not port"] - B2 --> B - E -->|Yes| F["5 · SYSTEM recon:\ndir /r other profiles → read ADS,\ncreds, hives, flags"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Run a potato — the loop</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 790 700" role="img" aria-label="Enumerate privileges, pick a tool by OS era, transfer and fire it, check for SYSTEM; on failure switch tool and retry, on success move to SYSTEM recon"> + <path class="fedge" d="M300,90 L300,140" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M300,200 L300,250" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M300,310 L300,360" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M300,420 L300,470" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M300,530 L300,600" marker-end="url(#flow-arrow)" /> + <path class="fedge is-back" d="M425,500 L620,500 L620,200" marker-end="url(#flow-arrow)" /> + <path class="fedge is-back" d="M495,170 L427,170" marker-end="url(#flow-arrow)" /> + <g class="fnode is-entry"><rect class="fnode__box" x="175" y="30" width="250" height="60" /><text class="fnode__label" x="300" y="56" text-anchor="middle">1 · whoami /priv + /groups<tspan class="sub" x="300" dy="15">SeImpersonate? SERVICE token?</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="175" y="140" width="250" height="60" /><text class="fnode__label" x="300" y="166" text-anchor="middle">2 · systeminfo → OS build<tspan class="sub" x="300" dy="15">choose tool by DCOM era</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="175" y="250" width="250" height="60" /><text class="fnode__label" x="300" y="276" text-anchor="middle">3 · Transfer the binary<tspan class="sub" x="300" dy="15">certutil / IWR / SMB share</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="175" y="360" width="250" height="60" /><text class="fnode__label" x="300" y="386" text-anchor="middle">4 · Fire non-interactively<tspan class="sub" x="300" dy="15">output → a file you can read</tspan></text></g> + <g class="fnode is-decision"><rect class="fnode__box" x="175" y="470" width="250" height="60" /><text class="fnode__label" x="300" y="496" text-anchor="middle">authresult 0 /<tspan class="sub" x="300" dy="15">NT AUTHORITY\SYSTEM?</tspan></text></g> + <g class="fnode is-note"><rect class="fnode__box" x="495" y="140" width="250" height="60" /><text class="fnode__label" x="620" y="166" text-anchor="middle">Wrong tool for the era —<tspan class="sub" x="620" dy="15">switch potato, not port</tspan></text></g> + <g class="fnode is-goal"><rect class="fnode__box" x="175" y="600" width="250" height="66" /><text class="fnode__label" x="300" y="622" text-anchor="middle">5 · SYSTEM recon:<tspan class="sub" x="300" dy="14">dir /r other profiles → read ADS,</tspan><tspan class="sub" x="300" dy="14">creds, hives, flags</tspan></text></g> + <g class="felabel"><rect class="felabel__box" x="283" y="557" width="34" height="16" /><text class="felabel__text" x="300" y="568" text-anchor="middle">Yes</text></g> + <g class="felabel"><rect class="felabel__box" x="507" y="492" width="26" height="16" /><text class="felabel__text" x="520" y="503" text-anchor="middle">No</text></g> + </svg> + </div> +</figure> ### 1 · Spot the opportunity — is your token weaponisable? `fas:Terminal` diff --git a/src/content/sheets/pentest-workflow/tty-upgrades-and-restricted-shells.md b/src/content/sheets/pentest-workflow/tty-upgrades-and-restricted-shells.md @@ -44,21 +44,39 @@ A raw reverse shell carries bytes, but it usually has no controlling terminal, j | `TERM` | Terminal capability name | Tells full-screen programs how to render | | Geometry | Rows and columns | Prevents wrapping and broken ncurses displays | -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A["Raw shell"] --> B{"tty?"} - B -->|"not a tty"| C{"PTY allocator present?"} - C -->|"python / script"| D["Spawn PTY"] - C -->|"socat"| E["Start PTY-backed socat shell"] - C -->|"none"| F["Interactive shell only\nor transfer a reviewed tool"] - D --> G["Ctrl+Z"] - G --> H["Local raw mode + fg"] - H --> I["reset · TERM · rows/cols"] - E --> I - F --> J["Limited shell\nno reliable job control"] - I --> K["Verify tty + signals"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Shell upgrade decision flow</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <svg class="flow-svg" viewBox="0 0 730 830" role="img" aria-label="From a raw shell: check for a tty, pick a PTY allocator (python or script, socat, or none), then background, enter local raw mode and foreground, reset TERM and geometry, and verify tty plus signals; without an allocator you get only a limited shell."> + <path class="fedge" d="M360,70 L360,125" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M360,175 L360,230" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M360,280 L360,335" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M460,255 L600,255 L600,335" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M260,255 L120,255 L120,335" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M360,385 L360,440" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M360,490 L360,545" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M360,595 L360,650" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M600,385 L600,675 L460,675" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M120,385 L120,440" marker-end="url(#flow-arrow)" /> + <path class="fedge" d="M360,700 L360,755" marker-end="url(#flow-arrow)" /> + <g class="fnode is-entry"><rect class="fnode__box" x="260" y="20" width="200" height="50" /><text class="fnode__label" x="360" y="50" text-anchor="middle">Raw shell</text></g> + <g class="fnode is-decision"><rect class="fnode__box" x="260" y="125" width="200" height="50" /><text class="fnode__label" x="360" y="155" text-anchor="middle">tty?</text></g> + <g class="fnode is-decision"><rect class="fnode__box" x="260" y="230" width="200" height="50" /><text class="fnode__label" x="360" y="260" text-anchor="middle">PTY allocator present?</text></g> + <g class="fnode"><rect class="fnode__box" x="260" y="335" width="200" height="50" /><text class="fnode__label" x="360" y="365" text-anchor="middle">Spawn PTY</text></g> + <g class="fnode"><rect class="fnode__box" x="500" y="335" width="200" height="50" /><text class="fnode__label" x="600" y="356" text-anchor="middle">Start PTY-backed<tspan class="sub" x="600" dy="15">socat shell</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="20" y="335" width="200" height="50" /><text class="fnode__label" x="120" y="356" text-anchor="middle">Interactive shell only<tspan class="sub" x="120" dy="15">or transfer a reviewed tool</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="260" y="440" width="200" height="50" /><text class="fnode__label" x="360" y="470" text-anchor="middle">Ctrl+Z</text></g> + <g class="fnode"><rect class="fnode__box" x="20" y="440" width="200" height="50" /><text class="fnode__label" x="120" y="461" text-anchor="middle">Limited shell<tspan class="sub" x="120" dy="15">no reliable job control</tspan></text></g> + <g class="fnode"><rect class="fnode__box" x="260" y="545" width="200" height="50" /><text class="fnode__label" x="360" y="575" text-anchor="middle">Local raw mode + fg</text></g> + <g class="fnode"><rect class="fnode__box" x="260" y="650" width="200" height="50" /><text class="fnode__label" x="360" y="680" text-anchor="middle">reset · TERM · rows/cols</text></g> + <g class="fnode is-goal"><rect class="fnode__box" x="260" y="755" width="200" height="50" /><text class="fnode__label" x="360" y="785" text-anchor="middle">Verify tty + signals</text></g> + <g class="felabel"><rect class="felabel__box" x="326" y="194" width="68" height="16" /><text class="felabel__text" x="360" y="205" text-anchor="middle">not a tty</text></g> + <g class="felabel"><rect class="felabel__box" x="307" y="299" width="105" height="16" /><text class="felabel__text" x="360" y="310" text-anchor="middle">python / script</text></g> + <g class="felabel"><rect class="felabel__box" x="509" y="247" width="43" height="16" /><text class="felabel__text" x="530" y="258" text-anchor="middle">socat</text></g> + <g class="felabel"><rect class="felabel__box" x="172" y="247" width="37" height="16" /><text class="felabel__text" x="190" y="258" text-anchor="middle">none</text></g> + </svg> + </div> +</figure> --- diff --git a/src/content/sheets/pentest-workflow/web-enumeration-and-exploitation.md b/src/content/sheets/pentest-workflow/web-enumeration-and-exploitation.md @@ -27,24 +27,41 @@ Everything after a live web port. Content discovery first, then vhosts, then the **The methodology at a glance** -```mermaid -flowchart TD - A[Live web port found<br>Stage 01] --> B[Fingerprint<br>whatweb / httpx / headers] - B --> C{Vhosts?} - C -->|Host-header fuzz| D[admin./dev./internal.<br>add to /etc/hosts] - C -->|single site| E[Content discovery<br>ffuf/feroxbuster + right extension] - D --> E - E --> F[Param mining<br>arjun / gau / JS analysis] - F --> G[Read the app<br>Burp walkthrough, map every input] - G --> H{Input class?} - H -->|auth| I[defaults → brute → JWT/reset flaws] - H -->|query param| J[SQLi / NoSQLi / cmd-inject] - H -->|file load| K[LFI / SSRF / XXE] - H -->|upload| L[Upload bypass → webshell] - H -->|rendered| M[XSS → cookie theft / blind] - I & J & K & L & M --> N[Shell as service account] - N --> O[File transfer + upgrade<br>Stage 03 → PrivEsc Stage 09] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Web exploitation methodology</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Live web port found<span class="sub">Stage 01</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Fingerprint<span class="sub">whatweb / httpx / headers</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Vhosts?</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Host-header fuzz</span></div><div class="flow-node">admin./dev./internal.<span class="sub">add to /etc/hosts</span></div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">single site</span></div></div> + </div> + <div class="flow-join"></div> + <div class="flow-rank"><div class="flow-node">Content discovery<span class="sub">ffuf/feroxbuster + right extension</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Param mining<span class="sub">arjun / gau / JS analysis</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Read the app<span class="sub">Burp walkthrough, map every input</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Input class?</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">auth</span></div><div class="flow-node">defaults → brute → JWT/reset flaws</div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">query param</span></div><div class="flow-node">SQLi / NoSQLi / cmd-inject</div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">file load</span></div><div class="flow-node">LFI / SSRF / XXE</div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">upload</span></div><div class="flow-node">Upload bypass → webshell</div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">rendered</span></div><div class="flow-node">XSS → cookie theft / blind</div></div> + </div> + <div class="flow-join"></div> + <div class="flow-rank"><div class="flow-node is-goal">Shell as service account</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">File transfer + upgrade<span class="sub">Stage 03 → PrivEsc Stage 09</span></div></div> + </div> + </div> +</figure> > [!success] CPTS exam tips > - **/etc/hosts discipline** — half of all "dead ends" on the exam are unfuzzed vhosts. If the landing page is a static placeholder, vhost-fuzz immediately. diff --git a/src/content/sheets/pentest-workflow/web-shells.md b/src/content/sheets/pentest-workflow/web-shells.md @@ -112,19 +112,27 @@ export LPORT="4444" > `fas:Lightbulb` > Uploading `shell.php` to an IIS/ASP.NET box gets you a downloadable text file, not execution. Confirm the stack first (banner, extensions, `whatweb`/`nmap -sV`), then pick the language. When unsure, drop a probe file (`test.php` containing `<?php echo 7*7; ?>`) and check whether it renders `49` or the source. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A["Fingerprint stack\n(banner / ext / whatweb)"] --> B["Craft shell in\nserver's language"] - B --> C{"Delivery vector?"} - C -->|"file upload"| D["Upload\n(bypass filter if any)"] - C -->|"LFI / log / SQLi"| E["Write to webroot\nor poison + include"] - C -->|"mgmt iface"| F["Tomcat/JBoss WAR,\nWebDAV PUT, CMS editor"] - D --> G["Browse to path"] - E --> G - F --> G - G --> H["Run cmds → upgrade\nto reverse shell (revx/wshx)"] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Web shell workflow</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Fingerprint stack<span class="sub">(banner / ext / whatweb)</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Craft shell in<span class="sub">server's language</span></div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-decision">Delivery vector?</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">file upload</span></div><div class="flow-node">Upload<span class="sub">(bypass filter if any)</span></div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">LFI / log / SQLi</span></div><div class="flow-node">Write to webroot<span class="sub">or poison + include</span></div></div> + <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">mgmt iface</span></div><div class="flow-node">Tomcat/JBoss WAR,<span class="sub">WebDAV PUT, CMS editor</span></div></div> + </div> + <div class="flow-join"></div> + <div class="flow-rank"><div class="flow-node">Browse to path</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node is-goal">Run cmds → upgrade<span class="sub">to reverse shell (revx/wshx)</span></div></div> + </div> + </div> +</figure> --- diff --git a/src/content/sheets/pentest-workflow/windows-privesc-cpts.md b/src/content/sheets/pentest-workflow/windows-privesc-cpts.md @@ -35,21 +35,24 @@ From a low-privilege Windows shell to `SYSTEM` / local admin. Run the bundled au > > Presence is not a privilege-escalation finding by itself. Confirm the binary path, arguments, integrity level, token privileges, ACLs, application-control policy and network reachability required by the selected technique. -```mermaid -%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% -flowchart LR - A["whoami /priv + /groups\nsysteminfo"] --> B["Bundled enum kit:\nwinPEAS / PowerUp / WES-NG"] - B --> C{"Vector?"} - C --> D["Token: SeImpersonate\nSeDebug / SeBackup"] - C --> E["Group: DnsAdmins\nBackup/Server Operators"] - C --> F["Service / registry\nweak ACL / unquoted"] - C --> G["Creds hunt · UAC bypass\n· kernel CVE"] - D --> H["SYSTEM / admin"] - E --> H - F --> H - G --> H - H --> I["Pillage again as SYSTEM\n→ pivot (chisel / ligolo-ng)"] -``` +<figure class="flow plate corners"> +<figcaption class="flow__cap"><span class="flow__kind">PrivEsc decision path</span><span class="flow__dir">LR</span></figcaption> +<div class="flow__body"> +<div class="flow__diagram" data-dir="lr"> +<div class="flow-rank"><div class="flow-node is-entry">whoami /priv + /groups<span class="sub">systeminfo</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">Bundled enum kit:<span class="sub">winPEAS / PowerUp / WES-NG</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node is-decision">Vector?</div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">Token: SeImpersonate<span class="sub">SeDebug / SeBackup</span></div><div class="flow-node">Group: DnsAdmins<span class="sub">Backup/Server Operators</span></div><div class="flow-node">Service / registry<span class="sub">weak ACL / unquoted</span></div><div class="flow-node">Creds hunt · UAC bypass<span class="sub">· kernel CVE</span></div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node is-goal">SYSTEM / admin</div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">Pillage again as SYSTEM<span class="sub">→ pivot (chisel / ligolo-ng)</span></div></div> +</div> +</div> +</figure> --- diff --git a/src/content/sheets/pentest-workflow/worked-chains.md b/src/content/sheets/pentest-workflow/worked-chains.md @@ -27,20 +27,28 @@ Stage map: `[S0]`=[Passive Recon](/sheets/pentest-workflow/passive-external-reco > [!tip] The universal AD shape > `[S1]` scan → `[S3/S4]` null/anon enum for users+shares → a **first credential** (share loot, AS-REP roast, password in a description, a poisoned hash) → `[S4]` BloodHound *as that user* → `[S5/S6/S7]` the one edge that escalates (roast / ACL / delegation / ESC) → `[S10]` DCSync + PtH the Administrator. Every new cred = re-run BloodHound. -```mermaid -flowchart LR - W[Web foothold] --> L[Local privesc] - L --> AD[AD enum + BloodHound] - AD --> E1[Kerberoast] - AD --> E2[ACL edge] - AD --> E3[ADCS ESC] - AD --> E4[Relay / RBCD] - E1 --> DA[DCSync / DA] - E2 --> DA - E3 --> DA - E4 --> DA - DA --> T[Cross-forest via trusts] -``` +<figure class="flow plate corners"> + <figcaption class="flow__cap"><span class="flow__kind">Universal AD chain</span><span class="flow__dir">TD</span></figcaption> + <div class="flow__body"> + <div class="flow__diagram" data-dir="td"> + <div class="flow-rank"><div class="flow-node is-entry">Web foothold</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Local privesc</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">AD enum + BloodHound</div></div> + <div class="flow-branches"> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Kerberoast</div></div> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">ACL edge</div></div> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">ADCS ESC</div></div> + <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Relay / RBCD</div></div> + </div> + <div class="flow-join"></div> + <div class="flow-rank"><div class="flow-node is-goal">DCSync / DA</div></div> + <div class="flow-edge"></div> + <div class="flow-rank"><div class="flow-node">Cross-forest via trusts</div></div> + </div> + </div> +</figure> > [!warning] Authorized lab use > All chains below assume an authorized HTB/CPTS-style lab. Every AD write (ACEs, SPNs, RBCD, shadow creds) is reversible — record what you change and revert it ([Stage 06 OPSEC](/sheets/pentest-workflow/acl-and-object-abuse)). diff --git a/src/content/sheets/web/dalfox.md b/src/content/sheets/web/dalfox.md @@ -232,14 +232,24 @@ This routes Dalfox traffic through Burp so each generated request can be inspect The vulnerable support ticket is rendered later by an administrator or automated agent. The submission response cannot show the privileged DOM, so immediate reflection analysis may report little or nothing. The useful signal is a unique outbound callback created when the stored record is viewed. -```mermaid -flowchart LR - A["Burp captures normal ticket POST"] --> B["Dalfox injects blind canary"] - B --> C["Support app stores ticket"] - C --> D["Admin agent opens ticket later"] - D --> E["Payload requests unique OOB address"] - E --> F["Callback proves execution and reachability"] -``` +<figure class="flow plate corners"> +<figcaption class="flow__cap"><span class="flow__kind">Blind stored XSS chain</span><span class="flow__dir">LR</span></figcaption> +<div class="flow__body"> +<div class="flow__diagram" data-dir="lr"> +<div class="flow-rank"><div class="flow-node is-entry">Burp captures normal ticket POST</div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">Dalfox injects blind canary</div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">Support app stores ticket</div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">Admin agent opens ticket later</div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node">Payload requests unique OOB address</div></div> +<div class="flow-edge"></div> +<div class="flow-rank"><div class="flow-node is-goal">Callback proves execution and reachability</div></div> +</div> +</div> +</figure> ### Option A — Dalfox-Managed OOB Check diff --git a/src/layouts/Base.astro b/src/layouts/Base.astro @@ -79,6 +79,18 @@ const canonical = new URL(Astro.url.pathname, Astro.site).href; <ClientRouter /> </head> <body> + <!-- Shared arrowhead for every inline-SVG flowchart (src/styles/flow.css). + Defined once here so a diagram only has to reference `url(#flow-arrow)`. + `context-stroke` makes the head take each edge's own stroke colour, so + one marker serves foam forward edges and love back-edges alike. --> + <svg width="0" height="0" aria-hidden="true" style="position:absolute" focusable="false"> + <defs> + <marker id="flow-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" + markerHeight="7" orient="auto-start-reverse" markerUnits="userSpaceOnUse"> + <path class="flow-arrow" d="M0,0 L10,5 L0,10 z" fill="context-stroke" /> + </marker> + </defs> + </svg> <!-- The film over the whole page. It is what keeps a flat colour reading as stock rather than as a swatch, and it stands in for the texture the old glass build got from blur. --> diff --git a/src/styles/app.css b/src/styles/app.css @@ -2,4 +2,5 @@ @import './chrome.css'; @import './global.css'; @import './prose.css'; +@import './flow.css'; @import './daemon.css'; diff --git a/src/styles/flow.css b/src/styles/flow.css @@ -0,0 +1,344 @@ +/* ============================================================================ + Flow — native, on-theme flowcharts. + + These replace the old ```mermaid fences, which never rendered (Shiki has no + mermaid grammar, so a fence printed its own source as a dead code listing). + Nothing here is JavaScript and nothing fetches: a flow is hand-authored HTML + (or inline SVG) drawn straight onto the page at build time. + + A flow reads as *terminal art*: the same dark plate the code panes ride, in + both site themes, so a diagram sits in the same register as the listings it + sits between (see prose.css — "terminal output pasted into a printed + document"). The wrapper carries `.plate` (pins the Rosé Pine night palette + for its subtree) and `.corners` (the cyberdeck brackets), exactly like a + code pane, so every accent below — `--foam`, `--iris`, `--gold`, `--love`, + `--pine` — resolves to its night value on the cream page without a single + hardcoded hex. + + Two primitives, one look: + • CSS-flow — ranks of `.flow-node` boxes joined by `.flow-edge` + connectors. Flexbox does the layout; there are no coordinates to get + wrong. Use it for linear chains, decision fan-outs and merges. + • SVG-flow — an inline `<svg class="flow-svg">` using the shared node / + edge / label classes. Use it only when the graph has back-edges, skip + edges or many-into-one merges that a rank layout would misdraw. + A `.flow-node` box and an `.fnode` rect share the same fill, hairline and + font, so a reader can't tell which engine drew a given box. + ========================================================================== */ + +/* ---- Wrapper ------------------------------------------------------------- */ +.prose .flow { + position: relative; + margin-block: 1.7rem; + max-width: min(100%, 94ch); + background: var(--plate); + border: 0; + overflow: hidden; + color: var(--fg); +} +/* Runs to the prose measure; a wide flow scrolls inside its own body rather + than pushing the page. */ +.prose .flow > * { position: relative; z-index: 2; } +.prose .flow > .scanlines { z-index: 1; opacity: 0.5; } + +/* The caption behaves like a code pane's titlebar: a kind mark at the left, + the flow direction at the right, both in the 9.5px terminal mono. */ +.prose .flow__cap { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding: 0.7rem 1.15rem; + border-bottom: 1px solid var(--rule); + font-family: var(--font-term); + font-size: 9.5px; + letter-spacing: 0.18em; + text-transform: uppercase; + line-height: 1; +} +.prose .flow__cap .flow__kind { color: var(--iris); } +.prose .flow__cap .flow__kind::before { content: '◇ '; opacity: 0.8; } +.prose .flow__cap .flow__dir { color: var(--fg-faint); } + +.prose .flow__body { + padding: clamp(1.05rem, 3.2vw, 1.9rem); + overflow-x: auto; +} + +/* ---- CSS-flow: ranks + edges -------------------------------------------- */ +.prose .flow__diagram { + display: flex; + align-items: center; + justify-content: center; + gap: 0; + min-width: min-content; +} +.prose .flow__diagram[data-dir='td'] { flex-direction: column; } +.prose .flow__diagram[data-dir='lr'] { flex-direction: row; flex-wrap: wrap; } + +/* A rank is one layer of the graph — a row (TD) or column (LR) of sibling + nodes that sit at the same depth. */ +.prose .flow-rank { + display: flex; + gap: clamp(0.7rem, 2.4vw, 1.6rem); + align-items: stretch; + justify-content: center; +} +.prose .flow__diagram[data-dir='lr'] .flow-rank { flex-direction: column; } + +/* ---- Node --------------------------------------------------------------- */ +.prose .flow-node { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 0.15rem; + text-align: center; + min-width: 8.5rem; + max-width: 16rem; + padding: 0.6rem 0.9rem; + background: var(--surface); + border: 1px solid var(--rule-hi); + color: var(--text); + font-family: var(--font-term); + font-size: 12.5px; + line-height: 1.32; +} +/* The second line of a node — what was `<br/>` in the mermaid source — reads + as a caption under the label. Mark it up as `<span class="sub">`. */ +.prose .flow-node .sub { + color: var(--subtle); + font-size: 10.5px; + letter-spacing: 0.01em; +} +.prose .flow-node code { + font-family: var(--font-term); + font-size: 0.95em; + background: none; + border: 0; + padding: 0; + color: var(--foam); +} + +/* Node roles — colour keyed the same way the SVG kit keys `.fnode` variants. */ +.prose .flow-node.is-entry { border-color: var(--iris); } +.prose .flow-node.is-entry::before { + content: 'START'; + font-size: 8px; letter-spacing: 0.2em; color: var(--iris); + margin-bottom: 0.1rem; +} +.prose .flow-node.is-goal { + background: color-mix(in srgb, var(--pine) 32%, var(--surface)); + border-color: var(--foam); + color: var(--text); +} +.prose .flow-node.is-decision { border-color: var(--gold); } +.prose .flow-node.is-decision::before { + content: '◆ DECIDE'; + font-size: 8px; letter-spacing: 0.18em; color: var(--gold); + margin-bottom: 0.15rem; +} +.prose .flow-node.is-note { + background: var(--overlay); + border-style: dashed; + color: var(--subtle); +} +.prose .flow-node.is-danger { border-color: var(--love); } +.prose .flow-node.is-danger::before { + content: '! '; + color: var(--love); +} + +/* ---- Edge (connector) --------------------------------------------------- */ +.prose .flow-edge { + position: relative; + align-self: center; + flex: none; + --edge: var(--foam); +} +/* Vertical connector (TD): a hairline with a triangle arrowhead. */ +.prose .flow__diagram[data-dir='td'] > .flow-edge, +.prose .flow-lane > .flow-edge { + width: 1px; + height: 2.3rem; + background: var(--edge); + margin: 0.05rem 0; +} +.prose .flow__diagram[data-dir='td'] > .flow-edge::after, +.prose .flow-lane > .flow-edge::after { + content: ''; + position: absolute; + left: 50%; bottom: -1px; + transform: translateX(-50%); + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 6px solid var(--edge); +} +/* Horizontal connector (LR). */ +.prose .flow__diagram[data-dir='lr'] > .flow-edge { + height: 1px; + width: clamp(1.8rem, 5vw, 3rem); + background: var(--edge); + margin: 0 0.05rem; +} +.prose .flow__diagram[data-dir='lr'] > .flow-edge::after { + content: ''; + position: absolute; + top: 50%; right: -1px; + transform: translateY(-50%); + border-top: 4px solid transparent; + border-bottom: 4px solid transparent; + border-left: 6px solid var(--edge); +} +/* The label a mermaid `-->|text|` edge carried — a knockout chip centred on + the connector so the line reads through it. */ +.prose .flow-edge__label { + position: absolute; + left: 50%; top: 50%; + transform: translate(-50%, -50%); + background: var(--plate); + border: 1px solid var(--rule); + color: var(--foam); + font-family: var(--font-term); + font-size: 9.5px; + letter-spacing: 0.04em; + line-height: 1.1; + padding: 0.1rem 0.4rem; + white-space: nowrap; + z-index: 3; +} +.prose .flow-edge.is-back { --edge: var(--love); background: none; } +.prose .flow-edge.is-back.is-vert, +.prose .flow__diagram[data-dir='td'] > .flow-edge.is-back { border-left: 1px dashed var(--love); width: 0; background: none; } +.prose .flow-edge.is-dotted { background: none; border-top: 1px dashed var(--foam); } + +/* ---- Branch / merge ----------------------------------------------------- */ +/* A decision fans out into lanes; each lane is its own little TD sub-flow + (labelled edge → node → …). */ +.prose .flow-branches { + display: flex; + gap: clamp(0.9rem, 4vw, 2.6rem); + align-items: flex-start; + justify-content: center; +} +.prose .flow-lane { + display: flex; + flex-direction: column; + align-items: center; +} +/* A join bar collects several lanes back into one node: a hairline spanning + the lanes with a single arrow dropping to the shared node below. */ +.prose .flow-join { + position: relative; + align-self: stretch; + height: 1.6rem; + margin-top: 0.1rem; + border-top: 1px solid var(--foam); + border-left: 1px solid var(--foam); + border-right: 1px solid var(--foam); +} +.prose .flow-join::after { + content: ''; + position: absolute; + left: 50%; bottom: -1.5rem; + width: 1px; height: 1.5rem; + background: var(--foam); + transform: translateX(-50%); +} +/* Arrowhead where the gather-bracket drops into the shared node below. */ +.prose .flow-join::before { + content: ''; + position: absolute; + left: 50%; bottom: -1.55rem; + transform: translateX(-50%); + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 6px solid var(--foam); + z-index: 1; +} + +/* ---- SVG-flow ----------------------------------------------------------- */ +/* One inline <svg class="flow-svg"> per complex graph, drawn on an orthogonal + grid. Every colour comes from a token resolved in the `.plate` subtree, so + the diagram flips with the theme like everything else. */ +.prose .flow-svg { + display: block; + width: 100%; + height: auto; + max-width: 100%; + min-width: 0; + font-family: var(--font-term); + overflow: visible; +} +.prose .flow-svg text { fill: var(--text); } + +/* Node box + label. */ +.prose .flow-svg .fnode__box { + fill: var(--surface); + stroke: var(--rule-hi); + stroke-width: 1; +} +.prose .flow-svg .fnode__label { fill: var(--text); font-size: 13px; } +.prose .flow-svg .fnode__label .sub { fill: var(--subtle); font-size: 11px; } + +/* Node roles mirror the CSS-flow ones. */ +.prose .flow-svg .is-entry .fnode__box { stroke: var(--iris); stroke-width: 1.4; } +.prose .flow-svg .is-goal .fnode__box { fill: color-mix(in srgb, var(--pine) 34%, var(--surface)); stroke: var(--foam); } +.prose .flow-svg .is-note .fnode__box { fill: var(--overlay); stroke: var(--rule); stroke-dasharray: 4 3; } +.prose .flow-svg .is-note .fnode__label { fill: var(--subtle); } +.prose .flow-svg .is-danger .fnode__box { stroke: var(--love); } + +/* Decision diamond. */ +.prose .flow-svg .fdecision__poly { fill: var(--overlay); stroke: var(--gold); stroke-width: 1; } +.prose .flow-svg .fdecision__label { fill: var(--text); font-size: 12px; } +/* A text-heavy decision that won't fit a diamond: a gold-bordered rect node, + matching the CSS-flow `.is-decision` box. */ +.prose .flow-svg .is-decision .fnode__box { fill: var(--overlay); stroke: var(--gold); } + +/* Edges. `context-stroke` on the arrowhead makes one shared marker take each + edge's own colour, so a foam forward edge and a love back-edge point in + their own ink from a single <marker> def. */ +.prose .flow-svg .fedge { + fill: none; + stroke: var(--foam); + stroke-width: 1.5; +} +.prose .flow-svg .fedge.is-back { stroke: var(--love); stroke-dasharray: 5 3; } +.prose .flow-svg .fedge.is-dotted { stroke: var(--foam); stroke-dasharray: 2 3; } +.prose .flow-svg .fedge.is-thick { stroke: var(--iris); stroke-width: 2.4; } + +/* Edge label — a knockout chip like the CSS-flow one. */ +.prose .flow-svg .felabel__box { fill: var(--plate); stroke: var(--rule); stroke-width: 1; } +.prose .flow-svg .felabel__text { fill: var(--foam); font-size: 11px; } + +/* The shared arrowhead marker lives once, hidden, in the sheet layout + (see Base.astro). These fallbacks apply if a diagram ships its own <defs>. */ +.prose .flow-svg .flow-arrow { fill: context-stroke; } + +/* ---- Responsive --------------------------------------------------------- */ +@media (max-width: 620px) { + /* An LR chain becomes a TD stack on a phone: the row wraps and each edge + turns to point down. */ + .prose .flow__diagram[data-dir='lr'] { flex-direction: column; } + .prose .flow__diagram[data-dir='lr'] > .flow-edge { + width: 1px; + height: 1.9rem; + margin: 0.05rem 0; + } + .prose .flow__diagram[data-dir='lr'] > .flow-edge::after { + top: auto; right: auto; + left: 50%; bottom: -1px; + transform: translateX(-50%); + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 6px solid var(--edge); + border-bottom: 0; + } + .prose .flow-node { min-width: 7rem; font-size: 12px; } +} + +@media (prefers-reduced-motion: no-preference) { + /* Motion is opt-in across the site; the flow is static furniture and adds + none of its own. */ +}