FLOW ^: Pentest Workflow

Stage 11 — Documentation and Reporting

CPTS attack-flow reference for stage 11 — documentation and reporting in an authorised engagement.

intermediate updated 2026-08-29 Markdown · Obsidian

[!dashboard] Attack-flow navigation Dashboard: HTB Pentest Attack Flow

Section: 15 of 17 · Focus: Stage 11 — Documentation and Reporting

Previous: Domain Trusts and Cross-Forest · Next: Appendix — Worked Chains


📝 STAGE 11 — Documentation & Reporting

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.

[!note] The snapshot-in-time overview — paste this at the top of every report 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:

All testing activities were performed between <START> and <END> from source IP(s) <IP/RANGE>,
[remotely over VPN | onsite | from inside the client's internal network].
This report represents a snapshot in time during the aforementioned testing period.
<Firm> cannot attest to the state of any client asset outside of this testing window.

0. SETUP — scaffold evidence dirs + tmux logging BEFORE you touch the box

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.

export ENG="CPTS-Exam"          # or client codename
mkdir -p "$ENG"/{Admin,Deliverables,Evidence/{Findings,Scans/{Vuln,Service,Web,AD},Notes,OSINT,'Logging output','Misc Files'},Retest}
tree "$ENG"                      # Admin=SoW/RoE/notes · Findings=one subfolder per finding · Retest=post-remediation

Tmux session logging is the cheapest insurance against lost command evidence — enable it before testing, not after something interesting scrolls off:

git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
cat >> ~/.tmux.conf <<'EOF'
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-logging'
set -g history-limit 50000        # so retroactive logging still has scrollback
run '~/.tmux/plugins/tpm/tpm'
EOF
tmux source ~/.tmux.conf
tmux new -s exam                  # inside: Ctrl+B then Shift+I to install plugins

Log-pane keybinds once inside tmux (prefix = Ctrl+B):

prefix + Shift+P        start/stop logging this pane   (file only fills once logging stops / session exits)
prefix + Alt+Shift+P    dump the ENTIRE scrollback retroactively  (needs the raised history-limit above)
prefix + Alt+P          clean screen-capture of ONE pane  (use for split panes: Responder | ntlmrelayx)

Session-recording alternatives / complements:

# script — zero-install typescript capture of a whole shell session (timestamped with -T)
script -T timing.log -a "session-$(date -u +%Y%m%dT%H%M%SZ).log"
# asciinema — replayable terminal recording, ideal for review calls / live demos
asciinema rec finding-03-sqli.cast            # asciinema play finding-03-sqli.cast

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.

[!warning] Watch out 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.


Capture-as-you-go — the per-finding evidence packet

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):

## Activity / Evidence Log   (chronological, for alert correlation & dispute defence)
| Time (UTC)         | Host / Target        | Action                      | Result / Artefact        |
|--------------------|----------------------|-----------------------------|--------------------------|
| 2026-08-27 14:03Z  | 10.129.x (WEB01)     | Responder -I tun0 -wv       | NTLMv2 bsmith → hashes/  |

## Payload Log
| Date | Host | File Path | SHA256 | Cleaned Up |
| ...  | WEB01| C:\Windows\Temp\svc.exe | <hash> | Yes |

## System Modifications Log
| Date | Host | Change | Location | Account Created | Password |
| ...  | DC01 | added local admin pentest01 | SAM | pentest01 | <REDACTED> |

Evidence discipline rules:

  • 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.
  • 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?”
  • 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:
    gowitness scan file -f web-targets.txt --screenshot-path ./shots/
    gowitness scan nmap --file nmap.xml --service-name http --service-name https
    gowitness report server                                 # browse the gallery locally

[!tools] Stage this gowitness_linux_amd64 (SHA-256 · GPG signature)

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):

IDOR         baseline: own profile under my session   →  proof: same session, only ID changed, other user's data
Upload       baseline: normal/rejected multipart       →  proof: MIME-only change stores .php, then SEPARATE exec request
SQLi         baseline: normal search + true/false ctrl  →  proof: repeatable UNION/boolean/time result
Cmd inject   baseline: normal ping + blocked probes     →  proof: encoded/quoted input yields appended `id` output

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.

[!warning] Watch out — redaction must be DESTRUCTIVE 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.


Artefact naming + integrity — boring, but it’s what survives QA

Naming:   <finding#>-<seq>-<host>-<desc>.<ext>
          03-02-web01-union-proof.png   07-01-dc01-dcsync-output.txt   01-03-10.129.4.12-ntlmv2-capture.log
Rules:  [ ] finding number matches the report finding ID — renaming later breaks every reference
        [ ] SHA256 every artefact at capture:  sha256sum file >> Evidence/hashes.txt
        [ ] never rename/move after the finding references it — fix the reference instead
        [ ] one folder per finding; nothing loose in Evidence/ root

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.


The Obsidian note stack — engagement vault layout

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:

ENG-Vault/
├── 00 - Admin/            SoW · RoE · scope list · exclusion list · contacts
├── 10 - Targets/          one note per host: IP · OS · ports · creds(REDACTED pointer) · flags
├── 20 - Credentials/      account · source · where valid · notes (passwords in the VAULT, not here)
├── 30 - Findings/         one note per finding, created from the finding template at discovery
├── 40 - Attack Chain/     running narrative + mermaid diagram, updated per pivot
├── 50 - Loot/             hashes, tickets, dumps — filenames + SHA256, content in Evidence/
├── 60 - Logs/             Activity / Payload / Modifications tables (live, UTC)
└── 70 - Report/           exec summary draft · appendix fodder · QA checklist

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.

[!tip] Templates do the heavy lifting 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.


Common report pitfalls — the grader’s red-flag list

PitfallWhy it failsFix
Flags listed, no narrativeproves exploitation skill, not consulting skillattack-chain chapter tying findings into business risk
Screenshots without provenancecan’t be attributed to host/timeaddress bar / hostname / timestamp in every figure
“Tool X found Y” languageexec summary must be tool-freedescribe the weakness, not the scanner
Stock remediation textwrong for the platform observedplatform-specific fix + test-before-deploy note
Severity eyeballingindefensible under client pushbackCVSS vector string on every finding
Missing affected-scope listclient can’t patch what they can’t findfull host list, appendix if long
No cleanup appendixclient mistakes your artefacts for an intrusionevery leftover documented with removal instructions
Plaintext creds in the reportdata-handling violationtruncate/redact; full values only via secure channel
Conclusions beyond evidence“attacker could also…” with no proofclaim only what was demonstrated; label the rest as risk
DRAFT watermark at deliverysome auditors reject it outrightFINAL only after review meeting feedback is incorporated

The report skeleton — sections in order

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.

1. Executive Summary        non-technical, 1.5-2 pages, impact in business terms
2. Summary of Recommendations   near / medium / long-term, environment-specific
3. Attack Chain (narrative)   the story of how DA fell, technical, ties findings together
4. Findings                  one per issue, full detail + reproducible evidence
5. Appendices                Static: Scope · Methodology · Severity Ratings · Biographies (PCI)
                             Dynamic: Compromised Creds · Config Changes · Payloads (hash/path) ·
                                      Domain Password Analysis (DPAT) · OSINT · Additional Affected Scope

Executive summary — do / don’t (the “can your parents follow it” test):

DO    exact numbers not "several" · impact = what was accessed (HR data, banking) · describe what broke DOWN procedurally
DON'T name commercial vendors · use acronyms (SNMP/MitM/SPN) · use tool names · bury criticals under lows · send reader into Findings

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".

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:

1. Captured NTLMv2 for `bsmith` via Responder (LLMNR/NBT-NS poisoning).   → STAGE 3
2. Cracked offline with hashcat → standard-user foothold.                  → STAGE 8
3. BloodHound mapped the domain; Kerberoasted `mssqlsvc` (local admin SQL01). → STAGE 4/5
4. Cracked the TGS, dumped LSA on SQL01 → cleartext `srvadmin` (autologon). → STAGE 8
5. As srvadmin found `pramirez` (DCSync rights) logged in; PtT his TGT.     → STAGE 5/6
6. DCSync as pramirez → Administrator NT hash → domain compromise.          → STAGE 6

[!tip] The chain is reusable evidence 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.


Writing a single finding — the template

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:

FieldWhat goes in itGrader/client trap to avoid
Titlespecific + technical root cause: “LLMNR/NBT-NS Poisoning Enables Credential Theft”vague titles (“Weak Security”) or vendor-shaming
SeverityCVSS score + vector string (below), mapped to Critical/High/Medium/Loweyeballing the band — score from the vector
CVSS vectore.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
ATT&CK mappingtechnique IDs per finding (T1110.003 password spray, T1003.001 LSASS, T1558.003 kerberoast)mapping the tool instead of the behaviour
Affected assetshosts/IPs/URLs/OU scopelong lists inline — use the “Additional Affected Scope” appendix
Evidence refspath to each artefact: Evidence/Findings/03-sqli/02-union-proof.pngscreenshots with no provenance (no host, no timestamp)
Business impactwhat an attacker achieves — concrete: “full domain compromise → access to payroll DB”generic “could lead to data breach”
Remediationspecific + actionable; free path alongside any commercial one“harden the registry” / “buy X”
Retestexpected verification method + date for the retest windowno retest criteria → client “fixed” it by renaming the page
## <Finding Title> — <Critical/High/Medium/Low/Info>
**CVSS:** <score/vector>   **CWE / OWASP / MITRE ATT&CK:** <IDs>

### Description        what the issue is, platform(s) affected, root cause
### Impact             what an attacker achieves if unresolved — concrete, not generic
### Affected Systems   hosts/IPs/URLs (long lists → "Additional Affected Scope" appendix)
### Reproduction       numbered, ONE action per figure, narrative between figures
### Recommendation     specific + actionable; offer a free path alongside any commercial one
### References         vendor-agnostic, current, free, no-paywall

Reproduction & remediation rules that graders actually check:

[ ] One action per figure — never cram multiple commands/results into one block
[ ] Show full exploit/module CONFIG before execution output (two figures, esp. Metasploit)
[ ] Narrative paragraph between figures — don't let consecutive screenshots carry the story
[ ] Prefer copy/paste terminal TEXT over screenshots of a terminal
[ ] Prove WHERE evidence came from: address bar visible / ifconfig alongside a GUI capture
Remediation  BAD:  "Reconfigure your registry to harden against X."
             GOOD: "Set [full hive path] value X → Y. Test on a small group first."
             BAD:  "Buy [commercial tool]."
             GOOD: "[Vendor] published a free workaround (ref); commercial tools also exist but may be cost-prohibitive."

ATT&CK mapping per finding: map each finding to technique IDs from MITRE ATT&CK — 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.

[!warning] Watch out 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.


CVSS scoring + Domain Password Analysis appendix

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); many clients/templates still require v3.1 — support both, but state which standard each score uses.

pip install cvss
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())"
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())"
# → ((9.8, ...), ('Critical', ...))   # or use the calculator at first.org/cvss/calculator/3.1

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.

If you cracked NTDS (STAGE 8), generate the Domain Password Analysis appendix — cracked %, privileged-account cracks, reuse, top passwords:

git clone https://github.com/clr2of8/DPAT && cd DPAT
python3 dpat.py -n ntds.dit -c hashcat.potfile -g "Domain Admins.txt" -o dpat-report   # from the STAGE 8 crack

[!note] Severity ≠ foothold value 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).


Timeline building

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.

| Date/Time (UTC) | Milestone                                   | Evidence ref            |
| 2026-08-27 09:12| Testing commenced (start notification sent) | Admin/comms-01          |
| 2026-08-27 14:03| NTLMv2 captured (bsmith) via LLMNR poisoning| Findings/01/03-...      |
| 2026-08-28 11:40| Domain Admin via DCSync as pramirez         | Findings/09/02-...      |
| 2026-08-29 17:00| Testing concluded (stop notification sent)  | Admin/comms-14          |

Appendices deep-dive — static vs dynamic

Static appendices (same skeleton every engagement — build them once, reuse):

  • 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.
  • Methodology — which standard you followed (PTES / OSSTMM / NIST 800-115 / OWASP WSTG for web) and the phases executed. One page; don’t pad.
  • Severity ratings — your CVSS version + the score→band mapping table, so a “7.4 High” is self-explanatory.
  • Biographies — required by some compliance regimes (e.g. PCI DSS); tester names, certs, roles.

Dynamic appendices (built per engagement from your logs):

  • Compromised Credentials — account, privilege level, source, how obtained, disclosure/rotation status. Passwords truncated.
  • Configuration Changes — every System Modifications Log row, with revert status.
  • Payloads / Artefacts — Payload Log rows: filename, path, SHA256, cleanup status.
  • Domain Password Analysis — DPAT output if NTDS was cracked (Stage 08).
  • OSINT findings — exposed data found pre-engagement (breach corpora, public repos, exposed buckets) with collection dates.
  • Additional Affected Scope — long host/URL lists pulled out of individual findings.
  • Cleanup exceptions — anything that could NOT be reverted, with removal instructions for the client.

[!warning] Watch out 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.


Tooling — where to actually write it

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.

Notes (during):   Obsidian (local, Markdown, git-friendly — this vault) · CherryTree (hierarchical, no backlinks)
Report platforms: SysReptor · pwndoc · Ghostwriter · Dradis · WriteHat   (free / self-hostable)
                  PlexTrac · AttackForge · VECTR                          (commercial)
Redaction/shots:  Greenshot (solid-shape annotation) · asciinema (full session replay for review calls)

SysReptor spins up fast and closes the gap between “Word + macros” and a full platform (findings DB, Markdown findings → PDF/HTML, self-hosted):

curl -s https://docs.sysreptor.com/install.sh | bash    # docker-compose stack → https://localhost:8000

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.

[!warning] Watch out 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.


Client comms during the engagement (real-world, not exam-graded)

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.

Subject: [Firm] - <Client> <Type> - Testing Start Notification
Tester(s) · Engagement type · Scope summary (see signed SoW) · Source IP(s) · Dates · Primary+Secondary contact
Testing commences ~<time>. Daily stop notifications will follow. Contact us immediately re: unexpected behaviour.
Subject: [Firm] - <Client> <Type> - Day <N> Stop Notification
Testing concluded for <date>. Today: <one line per activity area>. No unexpected availability impact observed.

[!tip] QA is not optional 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.


Credential handling policy — the report is not a secrets store

What to look for → every credential recovered in Stage 08 is live client data. Policy, end to end:

[ ] During:   creds land in ONE dedicated secrets store (encrypted KeePassXC DB / team vault) —
              never in Obsidian notes, chat, screenshots, or the Payload Log (use <REDACTED>)
[ ] Report:   Compromised Credentials appendix lists account + source + how obtained,
              passwords TRUNCATED or redacted (e.g. Summer…!); report PDF is encrypted in transit
              (client-provided PGP key or a password out-of-band — never same channel)
[ ] DPAT:     statistics only (cracked %, top patterns) — full plaintext passwords never ship
[ ] Close-out: every recovered credential goes on the forced-rotation disclosure list;
              client confirms rotation; then the secrets store is wiped per data-retention policy
[ ] Evidence:  raw dumps (NTDS, LSASS, SAM) encrypted at rest; destroyed on schedule after retest

Cleanup + the retest — closing the engagement out

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.

Artifact cleanup checklist:

[ ] Uploaded tools/binaries deleted (Payload Log: every row "Cleaned Up = Yes" + how)
[ ] Webshells removed (every .aspx/.jsp/.php planted — check vhosts + staging dirs)
[ ] SMB/temp shares removed; impacket-smbserver artefacts off target disks
[ ] Scheduled tasks / services created for persistence — deleted
[ ] Added ACEs / group memberships / shadow creds / SPNs — REVERTED (Stage 06: reverse every AD write)
[ ] Test accounts removed — or exact usernames handed to the admin in the report appendix
[ ] Added firewall/EDR exclusions reverted; PSExec-style services (PSEXESVC) gone
[ ] vssadmin shadow copies created for NTDS.dit — deleted
[ ] Listeners, dev servers, port-forwards, ligolo/chisel tunnels — stopped + uninstalled
[ ] Anything that COULDN'T be reverted → documented in an appendix so the client
    doesn't mistake it for a real intrusion
Report lifecycle:  DRAFT  →  Report Review Meeting (walk findings high-level, gather clarifications)
                          →  incorporate feedback  →  FINAL   (some auditors reject a "DRAFT"-labelled report)

Post-remediation retest — retest ONLY the original findings/hosts, with a time limit. Before/after table:
| # | Severity | Finding                | Status        |
| 1 | High     | SQL Injection          | Remediated    |
| 4 | High     | Inadequate Egress Filt | Not Remediated|

Retest guidance:

  • 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.
  • Time-box it (typically 1-2 days) and state the retest window in the report.
  • 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).
  • Update severity only on the retest report, never silently edit the original finding — the original report is the point-in-time record.

[!warning] Watch out 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.

[!note] The paperwork that made it legal (pre-flight bookend) 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.


🔬 PoC, Cleanup & the Post-Engagement Lifecycle

The report is graded on more than findings — the assessor wants proof, a clean environment, and a closed loop. This is methodology, not tooling.

  • 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.
  • 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 says reverse every AD write.
  • 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).
  • Stay in your lane — you advise the fix (“parameterise the query”, “enforce SMB signing”) but never implement it — independence / conflict-of-interest.

[!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.


🎓 CPTS exam reporting tips

  • 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.
  • 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.
  • Write as you go: fill each finding template the day you prove it. Day-10 report-writing from memory is where evidence gaps appear.
  • 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.
  • Include a Domain Password Analysis if you DCSync — graders expect the DPAT-style appendix and it’s nearly free once you have the potfile.
  • Deliverable hygiene: exact filename per the exam briefing, PDF format, submitted before the deadline — late or misnamed submissions fail regardless of technical content.
  • 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.

[!navigation] Continue the attack flow Previous: Domain Trusts and Cross-Forest

Dashboard: HTB Pentest Attack Flow

Next: Appendix — Worked Chains