documentation-and-reporting.md (34631B)
1 --- 2 title: "Stage 11 — Documentation and Reporting" 3 description: "CPTS attack-flow reference for stage 11 — documentation and reporting in an authorised engagement." 4 category: pentest-workflow 5 subcategory: "CPTS Attack Flow" 6 order: 15 7 tags: ["htb", "cpts", "htb-attack-flow", "htb-attack-flow-stage-11", "pentest-workflow"] 8 tools: ["Markdown", "Obsidian"] 9 difficulty: intermediate 10 updated: "2026-08-29" 11 source: "vault:Pentest Attack Flow/15 - Stage 11 - Documentation and Reporting.md" 12 --- 13 > [!dashboard] Attack-flow navigation 14 > **Dashboard:** [HTB Pentest Attack Flow](/sheets/pentest-workflow/attack-flow-dashboard) 15 > 16 > **Section:** 15 of 17 · **Focus:** Stage 11 — Documentation and Reporting 17 > 18 > **Previous:** [Domain Trusts and Cross-Forest](/sheets/pentest-workflow/domain-trusts-and-cross-forest) · **Next:** [Appendix — Worked Chains](/sheets/pentest-workflow/worked-chains) 19 20 --- 21 # 📝 STAGE 11 — Documentation & Reporting 22 23 The exam isn't over at DA. **CPTS is graded on the report, not the shell** — you hand in a commercial-grade pentest report modelled on the AEN sample, and a technically perfect compromise with a sloppy write-up fails. Treat the report as ~50% of the grade and write it *as you go*, not in a panic on day 10. This stage is the wrapper around STAGES 1-10: scaffold + log before first packet, capture an evidence packet per finding, then assemble exec summary → attack chain → findings → appendices. Deep dives: 1 - Introduction to Documentation and Reporting · 10 - Proof of Concept & Post-Engagement. 24 25 > [!note] The snapshot-in-time overview — paste this at the top of every report 26 > A pentest is a point-in-time snapshot. Open the report with the window + source + disclaimer so scope-creep in either direction can't be pinned on you: 27 > ```text 28 > All testing activities were performed between <START> and <END> from source IP(s) <IP/RANGE>, 29 > [remotely over VPN | onsite | from inside the client's internal network]. 30 > This report represents a snapshot in time during the aforementioned testing period. 31 > <Firm> cannot attest to the state of any client asset outside of this testing window. 32 > ``` 33 34 --- 35 36 ### 0. SETUP — scaffold evidence dirs + tmux logging BEFORE you touch the box 37 38 **What to look for** → a structured home for evidence *before* anything interesting happens. Skip this and you'll be reconstructing which host a screenshot came from at 2am on submission day. Mirror STAGE 1's "do this first" discipline: run the scaffold, start logging, *then* scan. 39 40 ```bash 41 export ENG="CPTS-Exam" # or client codename 42 mkdir -p "$ENG"/{Admin,Deliverables,Evidence/{Findings,Scans/{Vuln,Service,Web,AD},Notes,OSINT,'Logging output','Misc Files'},Retest} 43 tree "$ENG" # Admin=SoW/RoE/notes · Findings=one subfolder per finding · Retest=post-remediation 44 ``` 45 46 Tmux session logging is the cheapest insurance against lost command evidence — enable it *before* testing, not after something interesting scrolls off: 47 48 ```bash 49 git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm 50 cat >> ~/.tmux.conf <<'EOF' 51 set -g @plugin 'tmux-plugins/tpm' 52 set -g @plugin 'tmux-plugins/tmux-logging' 53 set -g history-limit 50000 # so retroactive logging still has scrollback 54 run '~/.tmux/plugins/tpm/tpm' 55 EOF 56 tmux source ~/.tmux.conf 57 tmux new -s exam # inside: Ctrl+B then Shift+I to install plugins 58 ``` 59 60 Log-pane keybinds once inside tmux (prefix = `Ctrl+B`): 61 ```text 62 prefix + Shift+P start/stop logging this pane (file only fills once logging stops / session exits) 63 prefix + Alt+Shift+P dump the ENTIRE scrollback retroactively (needs the raised history-limit above) 64 prefix + Alt+P clean screen-capture of ONE pane (use for split panes: Responder | ntlmrelayx) 65 ``` 66 67 **Session-recording alternatives / complements:** 68 ```bash 69 # script — zero-install typescript capture of a whole shell session (timestamped with -T) 70 script -T timing.log -a "session-$(date -u +%Y%m%dT%H%M%SZ).log" 71 # asciinema — replayable terminal recording, ideal for review calls / live demos 72 asciinema rec finding-03-sqli.cast # asciinema play finding-03-sqli.cast 73 ``` 74 `script` files are plain text with control codes (`col -b < file.log > clean.txt` strips them); asciinema `.cast` files upload to a local player for the client walkthrough. Both give you **defensible timestamps** for every action — the raw material for the timeline section below. 75 76 > [!warning] Watch out 77 > The default tmux `history-limit` is tiny — if you enable logging halfway through, everything before it is already gone unless you raised the limit at the start. Also: get **written client approval before creating accounts / changing config**, and log every one live in the Payload + Modifications tables below. Reconstructing "what did I leave on disk" from memory is how you fail the cleanup section. Full setup: 2 - Notetaking and Organisation. 78 79 --- 80 81 ### Capture-as-you-go — the per-finding evidence packet 82 83 **What to look for** → for *every* finding, five things captured the moment you prove it: **the command, its output, a screenshot, a timestamp, and the affected host**. An unattributed screenshot with no host/command context is worthless at report time. Keep three running logs as live notes (never reconstructed afterward): 84 85 ```text 86 ## Activity / Evidence Log (chronological, for alert correlation & dispute defence) 87 | Time (UTC) | Host / Target | Action | Result / Artefact | 88 |--------------------|----------------------|-----------------------------|--------------------------| 89 | 2026-08-27 14:03Z | 10.129.x (WEB01) | Responder -I tun0 -wv | NTLMv2 bsmith → hashes/ | 90 91 ## Payload Log 92 | Date | Host | File Path | SHA256 | Cleaned Up | 93 | ... | WEB01| C:\Windows\Temp\svc.exe | <hash> | Yes | 94 95 ## System Modifications Log 96 | Date | Host | Change | Location | Account Created | Password | 97 | ... | DC01 | added local admin pentest01 | SAM | pentest01 | <REDACTED> | 98 ``` 99 100 **Evidence discipline rules:** 101 - **Raw output stays raw.** Tool output files (`nmap` XML, `nxc` logs, BloodHound zips) live untouched in `Evidence/Scans/`; conclusions live in notes. Never edit a raw artefact to "clean it up" — if a client disputes a finding, the pristine raw file is your defence. 102 - **Timestamp everything** in UTC (`date -u` habit, tmux logging, `script`). Your Activity Log is what answers the client's SOC when they call mid-engagement: "was 14:03Z you, or an incident?" 103 - **Screenshot hygiene for web surfaces at scale:** instead of 40 manual browser shots, screenshot the whole web scope in one pass with gowitness, then pick the figures you need: 104 ```bash 105 gowitness scan file -f web-targets.txt --screenshot-path ./shots/ 106 gowitness scan nmap --file nmap.xml --service-name http --service-name https 107 gowitness report server # browse the gallery locally 108 ``` 109 110 > [!tools] Stage this 111 > [gowitness_linux_amd64](/downloads/pentest-workflow/gowitness_linux_amd64) ([SHA-256](/downloads/pentest-workflow/gowitness_linux_amd64.sha256) · [GPG signature](/downloads/pentest-workflow/gowitness_linux_amd64.sha256.asc)) 112 113 **Evidence pair standard** — pair every exploit request with a *normal baseline* so the causal change is visible. This is what makes a finding reproducible by the client's team (and what CPTS graders look for): 114 115 ```text 116 IDOR baseline: own profile under my session → proof: same session, only ID changed, other user's data 117 Upload baseline: normal/rejected multipart → proof: MIME-only change stores .php, then SEPARATE exec request 118 SQLi baseline: normal search + true/false ctrl → proof: repeatable UNION/boolean/time result 119 Cmd inject baseline: normal ping + blocked probes → proof: encoded/quoted input yields appended `id` output 120 ``` 121 Burp Suite's Repeater history is the natural home for HTTP evidence pairs — save the project file per engagement, and export the specific request/response pairs into the finding folder rather than screenshotting the Burp UI. 122 123 > [!warning] Watch out — redaction must be DESTRUCTIVE 124 > Never pixelate or blur to redact — tools like **Unredacter** reverse it. Bake a **solid black bar into the image file** (not a shape layered in Word). In terminal text replace secrets with `<REDACTED>`; for hashes keep first/last 3-4 chars only: `5f4dcc3b...ee6c`. Never hide text with black-on-black CSS — highlight or view-source defeats it instantly. Claim only what the evidence proves: `/etc/passwd` read ≠ full FS access; an uploaded file ≠ RCE until the server *executes* it. See Note 5 - Lessons Evidence and Reporting Cheat Sheet. 125 126 --- 127 128 ### Artefact naming + integrity — boring, but it's what survives QA 129 130 ```text 131 Naming: <finding#>-<seq>-<host>-<desc>.<ext> 132 03-02-web01-union-proof.png 07-01-dc01-dcsync-output.txt 01-03-10.129.4.12-ntlmv2-capture.log 133 Rules: [ ] finding number matches the report finding ID — renaming later breaks every reference 134 [ ] SHA256 every artefact at capture: sha256sum file >> Evidence/hashes.txt 135 [ ] never rename/move after the finding references it — fix the reference instead 136 [ ] one folder per finding; nothing loose in Evidence/ root 137 ``` 138 Hashing at capture gives you chain-of-custody for anything the client later questions ("that screenshot doesn't match our logs"), and it feeds the Payload Log's SHA256 column for free. 139 140 --- 141 142 ### The Obsidian note stack — engagement vault layout 143 144 **What to look for** → notes are written *during* testing, so structure them for retrieval under pressure, not for the report. One vault per engagement (never mix clients), mirroring the evidence scaffold: 145 146 ```text 147 ENG-Vault/ 148 ├── 00 - Admin/ SoW · RoE · scope list · exclusion list · contacts 149 ├── 10 - Targets/ one note per host: IP · OS · ports · creds(REDACTED pointer) · flags 150 ├── 20 - Credentials/ account · source · where valid · notes (passwords in the VAULT, not here) 151 ├── 30 - Findings/ one note per finding, created from the finding template at discovery 152 ├── 40 - Attack Chain/ running narrative + mermaid diagram, updated per pivot 153 ├── 50 - Loot/ hashes, tickets, dumps — filenames + SHA256, content in Evidence/ 154 ├── 60 - Logs/ Activity / Payload / Modifications tables (live, UTC) 155 └── 70 - Report/ exec summary draft · appendix fodder · QA checklist 156 ``` 157 Daily habit (15 min at stop-notification time): every interesting shell output got filed, every new host got a note, every new cred got a Credentials entry + vault entry, every modification got a Modifications row. This daily close-out is what makes the final report assembly a *merge*, not an *archaeological dig*. 158 159 > [!tip] Templates do the heavy lifting 160 > Keep Obsidian templates for: host note, finding write-up (the table above), cred entry. Hotkey a new note from template the moment a shell lands — 30 seconds now saves 30 minutes at report time and guarantees no field (provenance, timestamp, evidence path) is forgotten. 161 162 --- 163 164 ### Common report pitfalls — the grader's red-flag list 165 166 | Pitfall | Why it fails | Fix | 167 | :-- | :-- | :-- | 168 | Flags listed, no narrative | proves exploitation skill, not consulting skill | attack-chain chapter tying findings into business risk | 169 | Screenshots without provenance | can't be attributed to host/time | address bar / hostname / timestamp in every figure | 170 | "Tool X found Y" language | exec summary must be tool-free | describe the *weakness*, not the scanner | 171 | Stock remediation text | wrong for the platform observed | platform-specific fix + test-before-deploy note | 172 | Severity eyeballing | indefensible under client pushback | CVSS vector string on every finding | 173 | Missing affected-scope list | client can't patch what they can't find | full host list, appendix if long | 174 | No cleanup appendix | client mistakes your artefacts for an intrusion | every leftover documented with removal instructions | 175 | Plaintext creds in the report | data-handling violation | truncate/redact; full values only via secure channel | 176 | Conclusions beyond evidence | "attacker could also…" with no proof | claim only what was demonstrated; label the rest as risk | 177 | DRAFT watermark at delivery | some auditors reject it outright | FINAL only after review meeting feedback is incorporated | 178 179 --- 180 181 ### The report skeleton — sections in order 182 183 **What to look for** → the standard layout, front-loaded for a non-technical reader. Decide which appendices apply from the engagement *type* at kickoff (VA vs pentest, internal vs external, box colour — see 3 - Types of Reports), don't retrofit them. 184 185 ```text 186 1. Executive Summary non-technical, 1.5-2 pages, impact in business terms 187 2. Summary of Recommendations near / medium / long-term, environment-specific 188 3. Attack Chain (narrative) the story of how DA fell, technical, ties findings together 189 4. Findings one per issue, full detail + reproducible evidence 190 5. Appendices Static: Scope · Methodology · Severity Ratings · Biographies (PCI) 191 Dynamic: Compromised Creds · Config Changes · Payloads (hash/path) · 192 Domain Password Analysis (DPAT) · OSINT · Additional Affected Scope 193 ``` 194 195 **Executive summary — do / don't** (the "can your parents follow it" test): 196 ```text 197 DO exact numbers not "several" · impact = what was accessed (HR data, banking) · describe what broke DOWN procedurally 198 DON'T name commercial vendors · use acronyms (SNMP/MitM/SPN) · use tool names · bury criticals under lows · send reader into Findings 199 ``` 200 Substitute the jargon: `password spraying → "one guessable password tried against many harvested accounts"`, `hash → "output of an algorithm used to validate file integrity"`, `SQLi/XSS → "unsanitised user input manipulates the app's logic"`. 201 202 **Attack chain skeleton** — write the numbered high-level story first, *then* back each step with one evidence figure. Reference the playbook stages instead of re-explaining the attack: 203 ```text 204 1. Captured NTLMv2 for `bsmith` via Responder (LLMNR/NBT-NS poisoning). → STAGE 3 205 2. Cracked offline with hashcat → standard-user foothold. → STAGE 8 206 3. BloodHound mapped the domain; Kerberoasted `mssqlsvc` (local admin SQL01). → STAGE 4/5 207 4. Cracked the TGS, dumped LSA on SQL01 → cleartext `srvadmin` (autologon). → STAGE 8 208 5. As srvadmin found `pramirez` (DCSync rights) logged in; PtT his TGT. → STAGE 5/6 209 6. DCSync as pramirez → Administrator NT hash → domain compromise. → STAGE 6 210 ``` 211 212 > [!tip] The chain is reusable evidence 213 > It shows how several *medium* findings combine into *critical* overall risk — and that breaking any one link stops the chain. The same figures paste straight into the individual findings, so format each once. Always name the **root cause not the symptom**: DA with `Password123` is a **password-policy** finding, not "one bad password". Full anatomy: 4 - Components of a Report. 214 215 --- 216 217 ### Writing a single finding — the template 218 219 **What to look for** → every finding needs, at minimum: Description, Impact, Affected systems, Recommendation, References, and reproducible evidence. Missing one weakens its defensibility. Field-by-field: 220 221 | Field | What goes in it | Grader/client trap to avoid | 222 | :-- | :-- | :-- | 223 | **Title** | specific + technical root cause: "LLMNR/NBT-NS Poisoning Enables Credential Theft" | vague titles ("Weak Security") or vendor-shaming | 224 | **Severity** | CVSS score + vector string (below), mapped to Critical/High/Medium/Low | eyeballing the band — score from the vector | 225 | **CVSS vector** | e.g. `CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/...` | mixing 3.1 and 4.0 conventions in one report — pick one and say which | 226 | **ATT&CK mapping** | technique IDs per finding (T1110.003 password spray, T1003.001 LSASS, T1558.003 kerberoast) | mapping the *tool* instead of the *behaviour* | 227 | **Affected assets** | hosts/IPs/URLs/OU scope | long lists inline — use the "Additional Affected Scope" appendix | 228 | **Evidence refs** | path to each artefact: `Evidence/Findings/03-sqli/02-union-proof.png` | screenshots with no provenance (no host, no timestamp) | 229 | **Business impact** | what an attacker achieves — concrete: "full domain compromise → access to payroll DB" | generic "could lead to data breach" | 230 | **Remediation** | specific + actionable; free path alongside any commercial one | "harden the registry" / "buy X" | 231 | **Retest** | expected verification method + date for the retest window | no retest criteria → client "fixed" it by renaming the page | 232 233 ```markdown 234 ## <Finding Title> — <Critical/High/Medium/Low/Info> 235 **CVSS:** <score/vector> **CWE / OWASP / MITRE ATT&CK:** <IDs> 236 237 ### Description what the issue is, platform(s) affected, root cause 238 ### Impact what an attacker achieves if unresolved — concrete, not generic 239 ### Affected Systems hosts/IPs/URLs (long lists → "Additional Affected Scope" appendix) 240 ### Reproduction numbered, ONE action per figure, narrative between figures 241 ### Recommendation specific + actionable; offer a free path alongside any commercial one 242 ### References vendor-agnostic, current, free, no-paywall 243 ``` 244 245 Reproduction & remediation rules that graders actually check: 246 ```text 247 [ ] One action per figure — never cram multiple commands/results into one block 248 [ ] Show full exploit/module CONFIG before execution output (two figures, esp. Metasploit) 249 [ ] Narrative paragraph between figures — don't let consecutive screenshots carry the story 250 [ ] Prefer copy/paste terminal TEXT over screenshots of a terminal 251 [ ] Prove WHERE evidence came from: address bar visible / ifconfig alongside a GUI capture 252 ``` 253 ```text 254 Remediation BAD: "Reconfigure your registry to harden against X." 255 GOOD: "Set [full hive path] value X → Y. Test on a small group first." 256 BAD: "Buy [commercial tool]." 257 GOOD: "[Vendor] published a free workaround (ref); commercial tools also exist but may be cost-prohibitive." 258 ``` 259 260 **ATT&CK mapping per finding:** map each finding to technique IDs from [MITRE ATT&CK](https://attack.mitre.org) — it gives the client's blue team a shared vocabulary for detections and turns your report into a detection backlog. Quick mapping examples from this playbook: LLMNR poisoning → T1557.001 · password spraying → T1110.003 · kerberoasting → T1558.003 · LSASS dumping → T1003.001 · DCSync → T1003.006 · golden ticket → T1558.001 · SID history injection → T1134.005. One technique per finding, the *behaviour* not the tool name. 261 262 > [!warning] Watch out 263 > A findings database of "stock" write-ups saves time, but **never ship a template unedited** — "Default Credentials" means something very different on a DeskJet vs an HVAC controller vs a public web app. Tailor severity, impact language, and scope to what you actually observed. Structure + quality gate: 5 - How to Write Up a Finding. 264 265 --- 266 267 ### CVSS scoring + Domain Password Analysis appendix 268 269 **What to look for** → a defensible severity number. Score it from the vector, don't eyeball the band — it *will* get client pushback. Current default is **CVSS v4.0** ([FIRST calculator](https://www.first.org/cvss/calculator/4.0)); many clients/templates still require v3.1 — support both, but state which standard each score uses. 270 271 ```bash 272 pip install cvss 273 python3 -c "from cvss import CVSS4; c=CVSS4('CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N'); print(c.scores(), c.severities())" 274 python3 -c "from cvss import CVSS3; c=CVSS3('CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H'); print(c.scores(), c.severities())" 275 # → ((9.8, ...), ('Critical', ...)) # or use the calculator at first.org/cvss/calculator/3.1 276 ``` 277 v3.1 → v4.0 gotchas: `AC:H` splits into `AC` + **Attack Requirements (`AT`)**; Scope (`S`) is gone, replaced by separate Vulnerable/Subsequent-system impact (`VC/VI/VA` + `SC/SI/SA`); scores shift — re-score old template findings rather than carrying the number across. 278 279 If you cracked NTDS (STAGE 8), generate the **Domain Password Analysis** appendix — cracked %, privileged-account cracks, reuse, top passwords: 280 ```bash 281 git clone https://github.com/clr2of8/DPAT && cd DPAT 282 python3 dpat.py -n ntds.dit -c hashcat.potfile -g "Domain Admins.txt" -o dpat-report # from the STAGE 8 crack 283 ``` 284 285 > [!note] Severity ≠ foothold value 286 > Record both dimensions. A *critical* data-exposure finding may yield no internal access; a *lower*-severity command injection on a dual-homed host may be your only route to the internal network. Don't force every result into one ranking — and report the dead ends too (hypothesis, prerequisites checked, mismatch, revisit trigger). 287 288 --- 289 290 ### Timeline building 291 292 **What to look for** → the Activity Log (UTC) + `script`/tmux session logs become the report's **testing timeline**: kickoff → first foothold → lateral movement milestones → DA/EA → exfiltration proof → close-out. It does three jobs: proves coverage of the window, lets the SOC correlate your actions against their alerts (and *excludes* anything that wasn't you — that's an incident, say so), and anchors the attack-chain narrative in real times. 293 294 ```text 295 | Date/Time (UTC) | Milestone | Evidence ref | 296 | 2026-08-27 09:12| Testing commenced (start notification sent) | Admin/comms-01 | 297 | 2026-08-27 14:03| NTLMv2 captured (bsmith) via LLMNR poisoning| Findings/01/03-... | 298 | 2026-08-28 11:40| Domain Admin via DCSync as pramirez | Findings/09/02-... | 299 | 2026-08-29 17:00| Testing concluded (stop notification sent) | Admin/comms-14 | 300 ``` 301 302 --- 303 304 ### Appendices deep-dive — static vs dynamic 305 306 **Static appendices** (same skeleton every engagement — build them once, reuse): 307 - **Scope** — the *tested* scope as signed in the SoW/RoE, plus the exclusion list. If you discovered in-scope assets mid-engagement, note when they were added. 308 - **Methodology** — which standard you followed (PTES / OSSTMM / NIST 800-115 / OWASP WSTG for web) and the phases executed. One page; don't pad. 309 - **Severity ratings** — your CVSS version + the score→band mapping table, so a "7.4 High" is self-explanatory. 310 - **Biographies** — required by some compliance regimes (e.g. PCI DSS); tester names, certs, roles. 311 312 **Dynamic appendices** (built per engagement from your logs): 313 - **Compromised Credentials** — account, privilege level, source, how obtained, disclosure/rotation status. Passwords truncated. 314 - **Configuration Changes** — every System Modifications Log row, with revert status. 315 - **Payloads / Artefacts** — Payload Log rows: filename, path, SHA256, cleanup status. 316 - **Domain Password Analysis** — DPAT output if NTDS was cracked (Stage 08). 317 - **OSINT findings** — exposed data found pre-engagement (breach corpora, public repos, exposed buckets) with collection dates. 318 - **Additional Affected Scope** — long host/URL lists pulled out of individual findings. 319 - **Cleanup exceptions** — anything that could NOT be reverted, with removal instructions for the client. 320 321 > [!warning] Watch out 322 > The appendices are where disputes get settled. If the client's SOC finds a `pentest01` account or a stray `svc.exe` six months later, the Payload/Changes appendices are the difference between "sanctioned testing artefact, documented" and "undeclared persistence — incident". Every row in those logs must be resolvable to an appendix entry. 323 324 --- 325 326 ### Tooling — where to actually write it 327 328 **What to look for** → a local-first tool for client data (cloud sync may violate the client's data-storage policy). Note-taking during the engagement, then a reporting platform for assembly. 329 330 ```text 331 Notes (during): Obsidian (local, Markdown, git-friendly — this vault) · CherryTree (hierarchical, no backlinks) 332 Report platforms: SysReptor · pwndoc · Ghostwriter · Dradis · WriteHat (free / self-hostable) 333 PlexTrac · AttackForge · VECTR (commercial) 334 Redaction/shots: Greenshot (solid-shape annotation) · asciinema (full session replay for review calls) 335 ``` 336 [SysReptor](https://github.com/Syslifters/sysreptor) spins up fast and closes the gap between "Word + macros" and a full platform (findings DB, Markdown findings → PDF/HTML, self-hosted): 337 ```bash 338 curl -s https://docs.sysreptor.com/install.sh | bash # docker-compose stack → https://localhost:8000 339 ``` 340 [pwndoc](https://github.com/pwndoc/pwndoc) is the other mature self-hosted option: Node + Mongo, customizable DOCX templates, audit/vuln database with per-client reuse — better when the deliverable must be a branded Word document. 341 342 > [!warning] Watch out 343 > Cloud note tools (Notion, Evernote, hosted Obsidian sync) are fine for labs/CTFs — **check the data-handling terms before using them on live client data**, and the same applies to Grammarly/LanguageTool (they may transmit content to the cloud). For the CPTS exam itself, any tool that produces a clean PDF is fine — content beats platform. Comparison: 6 - Reporting Tips Tricks and Client Communication. 344 345 --- 346 347 ### Client comms during the engagement (real-world, not exam-graded) 348 349 **What to look for** → a start notification at kickoff and a stop notification at the end of each testing day, so the client can correlate their alerts against your activity. Escalate *out of cadence* immediately for: new scope worth adding, a critical/RCE external finding, a host that looks down, or reaching Domain/Enterprise Admin. 350 351 ```text 352 Subject: [Firm] - <Client> <Type> - Testing Start Notification 353 Tester(s) · Engagement type · Scope summary (see signed SoW) · Source IP(s) · Dates · Primary+Secondary contact 354 Testing commences ~<time>. Daily stop notifications will follow. Contact us immediately re: unexpected behaviour. 355 ``` 356 ```text 357 Subject: [Firm] - <Client> <Type> - Day <N> Stop Notification 358 Testing concluded for <date>. Today: <one line per activity area>. No unexpected availability impact observed. 359 ``` 360 361 > [!tip] QA is not optional 362 > Every report gets ≥1 round of *independent* QA (ideally two: technical accuracy, then cosmetics). Solo? Sleep on it and re-review after stepping away. Pre-delivery scan: acronyms spelled on first use · creds/PII/hashes redacted · screenshots cropped with a **professional hostname** (never `azzkicker@clientsmasher`) · strip tool banners like CrackMapExec's `(Pwn3d!)` · scan hashcat candidate passwords for offensive strings. 363 364 --- 365 366 ### Credential handling policy — the report is not a secrets store 367 368 **What to look for** → every credential recovered in Stage 08 is live client data. Policy, end to end: 369 370 ```text 371 [ ] During: creds land in ONE dedicated secrets store (encrypted KeePassXC DB / team vault) — 372 never in Obsidian notes, chat, screenshots, or the Payload Log (use <REDACTED>) 373 [ ] Report: Compromised Credentials appendix lists account + source + how obtained, 374 passwords TRUNCATED or redacted (e.g. Summer…!); report PDF is encrypted in transit 375 (client-provided PGP key or a password out-of-band — never same channel) 376 [ ] DPAT: statistics only (cracked %, top patterns) — full plaintext passwords never ship 377 [ ] Close-out: every recovered credential goes on the forced-rotation disclosure list; 378 client confirms rotation; then the secrets store is wiped per data-retention policy 379 [ ] Evidence: raw dumps (NTDS, LSASS, SAM) encrypted at rest; destroyed on schedule after retest 380 ``` 381 382 --- 383 384 ### Cleanup + the retest — closing the engagement out 385 386 **What to look for** → the engagement ends at *close-out*, not at DA. The cleanup register is written *from the Payload + Modifications logs you kept since day one*, not from memory. 387 388 **Artifact cleanup checklist:** 389 ```text 390 [ ] Uploaded tools/binaries deleted (Payload Log: every row "Cleaned Up = Yes" + how) 391 [ ] Webshells removed (every .aspx/.jsp/.php planted — check vhosts + staging dirs) 392 [ ] SMB/temp shares removed; impacket-smbserver artefacts off target disks 393 [ ] Scheduled tasks / services created for persistence — deleted 394 [ ] Added ACEs / group memberships / shadow creds / SPNs — REVERTED (Stage 06: reverse every AD write) 395 [ ] Test accounts removed — or exact usernames handed to the admin in the report appendix 396 [ ] Added firewall/EDR exclusions reverted; PSExec-style services (PSEXESVC) gone 397 [ ] vssadmin shadow copies created for NTDS.dit — deleted 398 [ ] Listeners, dev servers, port-forwards, ligolo/chisel tunnels — stopped + uninstalled 399 [ ] Anything that COULDN'T be reverted → documented in an appendix so the client 400 doesn't mistake it for a real intrusion 401 ``` 402 403 ```text 404 Report lifecycle: DRAFT → Report Review Meeting (walk findings high-level, gather clarifications) 405 → incorporate feedback → FINAL (some auditors reject a "DRAFT"-labelled report) 406 407 Post-remediation retest — retest ONLY the original findings/hosts, with a time limit. Before/after table: 408 | # | Severity | Finding | Status | 409 | 1 | High | SQL Injection | Remediated | 410 | 4 | High | Inadequate Egress Filt | Not Remediated| 411 ``` 412 413 **Retest guidance:** 414 - Retest **only** the original findings, on the originally affected hosts, with the same PoC steps — a finding is "Remediated" only if the *exact* original exploit path now fails. 415 - Time-box it (typically 1-2 days) and state the retest window in the report. 416 - Statuses: `Remediated` / `Partially Remediated` (root cause fixed, variant still works — explain) / `Not Remediated` / `Risk Accepted` (client signs off in writing — that's their call to make, not yours). 417 - Update severity only on the retest report, never silently edit the original finding — the original report is the point-in-time record. 418 419 > [!warning] Watch out 420 > Don't let a retest become a new assessment — no fresh large-scale scans, no auditing the whole environment for new hosts hit by an old finding. If the environment changed significantly, *say so explicitly* rather than quietly rescoping. Stay an **impartial third party**: you *advise* remediation ("parameterise queries"), you never implement fixes or hand over rewritten code — that's a conflict-of-interest and an independence problem. Wipe the tester VM at close-out; encrypt retained evidence at rest. Pointers: 10 - Proof of Concept & Post-Engagement. 421 422 > [!note] The paperwork that made it legal (pre-flight bookend) 423 > Reporting is the back half of the engagement wrapper; the front half is signed contracts. Nothing proceeds before the **NDA** (bilateral is standard). Confirm the requester actually has signatory authority (CEO/CTO/CISO tier), then the doc set: NDA → Scoping Questionnaire → Scoping Document → Proposal/SoW → **Rules of Engagement** → Contractors Agreement (physical only) → Reports. Get a written **exclusion list** at kickoff even inside a confirmed scope. Detail: 5 - Pre-Engagement. 424 425 --- 426 427 ### 🔬 PoC, Cleanup & the Post-Engagement Lifecycle 428 429 The report is graded on more than findings — the assessor wants proof, a clean environment, and a closed loop. This is methodology, not tooling. 430 431 - **Proof of Concept** — reproducible evidence *per finding*, scaled to risk: documented step-by-step at minimum, an automated exploit script for the serious ones. Admins won't remediate a business-critical system on your word alone — the PoC is what forces the fix. 432 - **Cleanup log** — keep a running list as you go: every uploaded tool/webshell/binary removed, every config change reverted. Anything you **can't** revert (a created local-admin account, an added ACL, a planted SPN) goes in a report appendix so the client can tell sanctioned testing from a real intrusion. This is also why [STAGE 6](/sheets/pentest-workflow/acl-and-object-abuse) says *reverse every AD write*. 433 - **Lifecycle** — draft report → deliverable-acceptance/review with the client → final report → **post-remediation retest** with a before/after status table per finding (Open → Remediated / Risk Accepted). 434 - **Stay in your lane** — you *advise* the fix ("parameterise the query", "enforce SMB signing") but never implement it — independence / conflict-of-interest. 435 436 > [!tip] Capture the cleanup evidence *as you plant it*, not from memory at the end — a screenshot of the added account plus the exact removal command in one note. Deep dive: 10 - Proof of Concept & Post-Engagement. 437 438 --- 439 440 ### 🎓 CPTS exam reporting tips 441 442 - **Flags ≠ report.** Every flag captured is one line of the attack chain; the grade comes from a commercial-grade report: exec summary, attack path narrative, findings with reproduction steps, appendices. A candidate with 12/14 flags and a strong report passes; 14/14 flags with a thin report fails. 443 - **Reproduce yourself:** write every finding's steps so a stranger could redo them from the report alone — exact commands, full config, expected output. The grader *will* replay steps. 444 - **Write as you go:** fill each finding template the day you prove it. Day-10 report-writing from memory is where evidence gaps appear. 445 - **Standard domain-attack findings to expect:** LLMNR poisoning, password spraying hits, kerberoastable accounts, GPP cpassword, ASREProastable users, unconstrained delegation, weak ACL chains — pre-draft template skeletons for all of them before the exam and tailor on the day. 446 - **Include a Domain Password Analysis** if you DCSync — graders expect the DPAT-style appendix and it's nearly free once you have the potfile. 447 - **Deliverable hygiene:** exact filename per the exam briefing, PDF format, submitted before the deadline — late or misnamed submissions fail regardless of technical content. 448 - **Report format:** clean PDF from any toolchain (Word, SysReptor, Obsidian export). Label the deliverable exactly as instructed in the exam briefing and respect the deadline — late = fail, regardless of content. 449 450 --- 451 452 > [!navigation] Continue the attack flow 453 > **Previous:** [Domain Trusts and Cross-Forest](/sheets/pentest-workflow/domain-trusts-and-cross-forest) 454 > 455 > **Dashboard:** [HTB Pentest Attack Flow](/sheets/pentest-workflow/attack-flow-dashboard) 456 > 457 > **Next:** [Appendix — Worked Chains](/sheets/pentest-workflow/worked-chains)