skills/credential-attack/SKILL.md
Password spray methodology for bug bounty — when to do it vs web-vuln hunting, the wordlist-gen + breach-check + osint-employees + spray pipeline, mode selection (http-form / oauth / o365 / okta), rate-limit + lockout tactics, BBP legal guardrails, success detection, and the spray → authenticated /hunt chain pattern. Use when assessing whether credential attack is worth running on a target, picking the right mode, or recovering from common pitfalls.
npx skillsauth add shuvonsec/claude-bug-bounty credential-attackInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Real-world initial-access vector. Verizon DBIR consistently ranks Stolen Credentials in the top 3 incident types. Most BB hunters skip this because they only try rockyou.txt and get rate-limited.
Core principle: humans pick lazy passwords. {CompanyName}{Year}!, {ProductName}{Season}, {City}123. Harvesting company-specific vocabulary (product names, office cities, internal project codes) before spraying is what makes the hit-rate go from 0.01% to 1%+.
This skill covers WHEN to use credential attack, HOW to chain the 4 commands, and the legal/operational guardrails.
Credential attack is a parallel branch to /hunt, not a replacement. Both come after /recon:
/recon ──┬──▶ /hunt (web vuln scan) ──┐
│ ├──▶ /validate ──▶ /report
└──▶ /wordlist-gen → ... → /spray ──┘
Run it when:
Skip it when:
KILL signals (don't even start):
/wordlist-gen ──▶ /breach-check ──▶ /osint-employees ──▶ /spray
(company words) (rank by HIBP) (real usernames) (live attempts)
You can run stages 1+2 in parallel with stage 3 (they share no inputs).
/wordlist-gen <target>Crawls the target website with cewler, deduplicates, applies hashcat rules to mutate (flexdemo → flexdemo!, Flexdemo, flexdemo123, flexdemo2025...).
Mode selection:
| Mode | Rules | When |
|---|---|---|
| minimal | top10_2025 (10 rules) | Cautious spray, paranoid program |
| balanced (default) | best66 (66 rules) | Standard — best signal/noise |
| aggressive | OneRuleToRuleThemAll (52k) | Offline cracking only, NOT spray (too many candidates) |
Filter selection:
| Filter | When |
|---|---|
| strict (default) | API-doc-heavy sites (Twilio, Stripe). Drops CSS hex colors, URL slugs, random API tokens that cewler harvests as "words" |
| loose | Marketing sites without API examples — keeps everything cewler found |
Output: recon/<target>/wordlists/ranked.txt — typically 50k-500k candidates depending on site size.
/breach-check <wordlist>Sends only first 5 chars of SHA-1 to HIBP (k-anonymity), enriches each password with its real-world breach count. Free, no API key, full passwords never leave your machine.
Breach-count interpretation:
| Range | Meaning | Spray strategy |
|---|---|---|
| 0 | Never leaked | Could be company-specific OR truly random |
| 1-1000 | "Sweet spot" — proven human use, not yet in every spray list | Prioritize |
| 1k-1M | Mainstream | Usually already tried by previous attackers |
| >1M | Generic (password, 123456) | Skip — every WAF expects these |
Standard filter for spray prep: --max-count 1000000 drops the boring generic stuff while keeping the sweet spot.
Performance: ~5 minutes for 10k passwords, ~50 minutes for 100k. Use --limit N --shuffle to sample if your wordlist is huge.
/osint-employees <target>theHarvester (search engines + CT logs) → derive names from email local-parts → username-anarchy permutations.
Default mode is conservative:
duckduckgo,brave,yahoo,mojeek,crtsh,certspotter,hackertarget,otxOpt-in flags:
--with-linkedin — adds CrossLinked (Google/Bing dorks against site:linkedin.com). Read program policy first — some BBPs forbid employee identification.--with-pydictor-social — pydictor generates name-derived password candidates (john2025, john!2024).Realistic expectations:
| Target type | Expected emails | Expected names | |---|---|---| | US/EU SaaS (Twilio, Stripe) | 5-50 | depends — many CTOs are public | | State utility (Taipower, etc.) | 0 | 0 (no English-named LinkedIn profiles) | | Local SME | 0-10 | 0-5 |
For mature security-conscious targets, expect very few emails. The CT-log hostnames theHarvester finds are separate value — feed them back into /recon for more attack surface (this happened in our Taipower run: 0 emails but 59 new subdomains).
/spray <login-url> --mode <mode>The most dangerous command. Real auth attempts against live accounts. Read HARD GUARDS before running.
Mode selection:
| Mode | Use case | Engine |
|---|---|---|
| http-form | Custom login page (most BB targets) | Pure Python urllib |
| oauth | OAuth password grant (grant_type=password) | Pure Python urllib |
| o365 | Microsoft 365 / Azure AD | trevorspray |
| okta | Okta SSO | trevorspray |
Hard guards (no override possible without --i-understand):
--passes size, warns if it exceeds typical thresholds.recon/<host>/spray/attempts-<ts>.jsonl. Passwords logged as SHA-256 prefix only, never plaintext.pass[i] × all_users per round. Each user sees at most 1 failed attempt per round, well under typical 5-10 lockout threshold.Default rate-limit: --delay 1800 --jitter 60 (30 min/round + ±60s).
| Lockout policy (typical) | Threshold | Reset window | |---|---|---| | Azure AD smart lockout | 10 failed in 10 min sliding | 10-min window | | Okta default | 10 in 10 min | configurable | | Custom apps | usually 5-10 per hour | varies wildly |
A spray with default delay tries 1 password per user per 30 min — keeps every user at 0 strikes within any sliding window.
--aggressive (60s/10s) is fast spray: use ONLY with explicit program permission. Against O365, it almost certainly triggers smart lockout.
WRONG (brute-force order, will lockout):
alice: pass1, pass2, pass3, ... ← alice gets 8 failed attempts in seconds, lockout
bob: pass1, pass2, pass3, ...
RIGHT (spray order, distributes failures):
Round 1: pass1 → alice, bob, charlie (1 failed each)
[delay 30 min]
Round 2: pass2 → alice, bob, charlie (2 failed total each, still under threshold)
...
Our tools/_spray_http_form.py and _spray_oauth.py enforce spray order.
Checked in this order:
--success-regex <body-regex> matches response → success--fail-regex <body-regex> set AND body does NOT match → successFalse positive risk: Without --success-regex or --fail-regex, heuristic 3 can mis-fire on sites that always redirect even on failure. Always supply --fail-regex "Invalid|incorrect|wrong" for production sprays.
"access_token" field in JSON body → successinvalid_grant / 401) → failThis is unambiguous; no regex needed.
Output parsing. Less granular than our http-form / oauth handlers but well-tested upstream.
The real payout play:
/spray finds valid creds (low-payout finding by itself if reported as ATO)
↓
Re-run /hunt with the session cookie or bearer token
↓
Authenticated /hunt sees admin pages, internal APIs, IDOR on user data
↓
Find a P1/P2 IDOR or business-logic bug behind the login wall
↓
Chain report: "ATO via spray + IDOR exposes all user PII" (high payout)
The spray-only finding alone is usually rejected by mature BBPs (they treat it as "user's bad password choice, not our bug"). The chain is what pays.
Not yet wired in this branch: /hunt --authenticated-session <cookie> is a future PR. For now, after spray finds creds, manually feed the session into Burp / curl-based probing.
Before running /spray against ANY target, verify:
Program policy explicitly allows credential testing. Look for keywords:
The wordlist does not contain plaintext breach data. Using DeHashed-style plaintext passwords from real breaches to log into real accounts is illegal in most jurisdictions even with BB scope. HIBP hash-prefix is fine (we use this); plaintext breach corpus is not (we don't bundle this).
Stop on first hit by default. Don't keep spraying after you have one valid set of creds — that's not testing, it's grinding for lulz. --continue-on-hit exists but should only be used to evidence multiple users sharing a default password.
Report the lockout impact. If your spray locked accounts, tell the program immediately with timestamps from the audit log. Don't make them discover it themselves.
/wordlist-gen with --filter loose against an API-heavy site gives you 500k candidates, 95% of which are CSS selectors, URL slugs, and example API tokens from docs.
Fix: Stick with the default --filter strict. Verified on Twilio: 56k loose → 34k strict (-39%), all noise dropped, real terms (flexdemo, webhook, programmable) preserved.
--limit N biases the sampleThe wordlist is sort -u'd alphabetically (ASCII order: digits < uppercase < lowercase). Naïve --limit 5000 samples ONLY digit/symbol-prefix entries.
Fix: Always use --shuffle when sampling. Verified on Twilio: without shuffle, top 5000 were 100% l33t variants (1nc0rr3t0, $m@rt...); with shuffle, you get representative coverage including a-z prefix candidates.
{PASSWORD} vs {PASS} placeholderNatural user instinct is --post-data "username={USER}&password={PASSWORD}". Our code accepts BOTH aliases ({USER}/{USERNAME} and {PASS}/{PASSWORD}). Unknown placeholders stay literal in the request — visible to you, not a crash.
theHarvester -f recon/<target>/osint/theharvester does NOT write to that path. It writes theharvester.json to $PWD (the directory you ran the command from).
Fix: tools/osint_employees.sh wraps the call in (cd "$OUT_DIR" && theHarvester ... -f theharvester). If you invoke theHarvester directly, cd first.
Two distinct scenarios:
/recon.urllib.request.urlopen() accepts context= kwarg. opener.open() does NOT. If you customize a build_opener, attach the SSL context to an HTTPSHandler instead. Our http-form handler does this; this bug bit us during live test.
Before pressing enter on /spray:
/scope <login-host> returns IN SCOPE--filter strict) and HIBP-ranked (--max-count 1000000)/osint-employees) — not users.txt from a tutorial--delay 1800 --jitter 60) unless program permits faster--dry-run passed once to verify post-data template is correctDuring spray:
After spray:
When our default tool fails or you want to swap, here's the practical ladder. Tools marked ❌ were deliberately rejected — don't try them as drop-in subs.
| Tool | Status | Why | |---|---|---| | cewler | ✓ Primary | Python rewrite of CeWL; Scrapy-backed; faster on JS-heavy sites | | CeWL | ⚠ Backup | Ruby; not in brew on macOS; older but more battle-tested. Use only if cewler fails on a specific site | | dirtywords | Alternative | Newer, BB-focused; try if cewler misses dynamic content | | getjswords | Complement | Pulls words from JS bundles specifically — useful when target has rich SPA |
| Tool | Status | Why |
|---|---|---|
| hashcat top10_2025.rule / best66.rule / OneRuleToRuleThemAll | ✓ Primary | Industry standard, modes selectable in /wordlist-gen |
| pydictor (-extend) | Reserved for Stage 3 | Best with OSINT inputs (birthdays/names); overlaps hashcat on raw words |
| wister | ❌ Dropped | Variant logic overlaps pydictor; no clear advantage |
| Mentalist | ❌ Dropped | GUI-only — not scriptable for CI |
| rsmangler | Minor alt | Simple prefix/suffix mutation; less complete than hashcat rules |
| Tool | Status | Why | |---|---|---| | HIBP Pwned Passwords (k-anonymity) | ✓ Primary | Free, no API key, hash-prefix only — safe legal posture | | HIBP Breach API v3 | Optional ($3.50/mo) | Per-email leak lookup; useful for high-priority account triage | | DeHashed / Intelligence Security | ❌ NOT for spray | Contains plaintext passwords from real breaches. Using plaintext breach credentials against live accounts is illegal in most jurisdictions even with BB scope. Use only for reading, never for login attempts | | weakpass.com (28GB dump) | Offline cracking only | Too large for spray; usable for hash cracking after a hit | | SecLists Passwords/ | Generic fallback | Use ONLY when target has no website to crawl from |
| Tool | Status | Why |
|---|---|---|
| theHarvester | ✓ Primary | Multi-source (search engines + CT logs + DNS), free, ~43 sources available |
| CrossLinked | ✓ Opt-in via --with-linkedin | Google/Bing dorks against LinkedIn — no LinkedIn auth needed |
| username-anarchy | ✓ Primary | Expands names into 30+ username formats |
| LinkedInDumper | ❌ Dropped | Requires LinkedIn account auth — OPSEC cost, account ban risk |
| NameSpi | Alternative | Combines LinkedIn + Hunter.io — useful if you have Hunter.io |
| Hunter.io | Optional (paid) | Best email-format inference ({first}.{last}@); valuable for high-value targets |
| Kerbrute | Internal-network only | Validates AD usernames via Kerberos pre-auth — useless against external BB targets |
| Tool | Status | Why |
|---|---|---|
| Built-in http-form / oauth modules | ✓ Primary | Pure Python urllib; under our full control; auditable JSONL |
| TREVORspray (o365, okta) | ✓ Primary for enterprise SSO | Most complete O365/Okta engine; built-in SSH proxy rotation; mature |
| CredMaster | Alternative | AWS FireProx IP rotation — useful if program rate-limits per-IP heavily |
| MSOLSpray | ❌ Dropped | TREVORspray already covers O365 with better tooling |
| Spray365 | ❌ Dropped | Only M365; TREVORspray + CredMaster covers spray needs |
| SprayingToolkit | Alternative | Lync / S4B / OWA niche — try only if you hit those specific targets |
cewler + hashcat top10_2025 + theHarvester (no LinkedIn) + /spray http-formcewler + theHarvester + --with-linkedin + /spray o365cewler (depth 1, JS bundles often have the wordlist) + /spray oauthkerbrute userenum before sprayFor the underlying tools' own docs:
tools/wordlist_engine.sh -htools/osint_employees.sh -htools/breach_checker.py -htools/spray_orchestrator.sh -hbug-bounty — master workflow (this skill is a sub-pipeline)web2-recon — produces the URL list that surfaces login endpointstriage-validation — run 7-Question Gate on any spray-discovered creds before reportingreport-writing — ATO-via-spray report templates (H1/Bugcrowd format)tools
Complete bug bounty workflow — recon (subdomain enumeration, asset discovery, fingerprinting, HackerOne scope, source code audit), pre-hunt learning (disclosed reports, tech stack research, mind maps, threat modeling), vulnerability hunting (IDOR, SSRF, XSS, auth bypass, CSRF, race conditions, SQLi, XXE, file upload, business logic, GraphQL, HTTP smuggling, cache poisoning, OAuth, timing side-channels, OIDC, SSTI, subdomain takeover, cloud misconfig, ATO chains, agentic AI), LLM/AI security testing (chatbot IDOR, prompt injection, indirect injection, ASCII smuggling, exfil channels, RCE via code tools, system prompt extraction, ASI01-ASI10), A-to-B bug chaining (IDOR→auth bypass, SSRF→cloud metadata, XSS→ATO, open redirect→OAuth theft, S3→bundle→secret→OAuth), bypass tables (SSRF IP bypass, open redirect bypass, file upload bypass), language-specific grep (JS prototype pollution, Python pickle, PHP type juggling, Go template.HTML, Ruby YAML.load, Rust unwrap), and reporting (7-Question Gate, 4 validation gates, human-tone writing, templates by vuln class, CVSS 3.1, PoC generation, always-rejected list, conditional chain table, submission checklist). Use for ANY bug bounty task — starting a new target, doing recon, hunting specific vulns, auditing source code, testing AI features, validating findings, or writing reports. 中文触发词:漏洞赏金、安全测试、渗透测试、漏洞挖掘、信息收集、子域名枚举、XSS测试、SQL注入、SSRF、安全审计、漏洞报告
tools
Complete reference for 22 web2 bug classes with root causes, detection patterns, bypass tables, exploit techniques, and real paid examples. Covers IDOR, auth bypass, XSS, SSRF (11 IP bypass techniques), SQLi, business logic, race conditions, OAuth/OIDC, file upload (10 bypass techniques), GraphQL, LLM/AI (ASI01-ASI10 agentic framework), API misconfig (mass assignment, JWT attacks, prototype pollution, CORS), ATO taxonomy (9 paths), SSTI (Jinja2/Twig/Freemarker/ERB/Spring), subdomain takeover, cloud/infra misconfigs, HTTP smuggling (CL.TE/TE.CL/H2.CL), cache poisoning, MFA bypass (7 patterns), SAML attacks (XSW/comment injection/signature stripping), error disclosure / debug endpoints (stack trace regex per framework, chain templates), CSS injection (attribute-selector exfiltration, opacity clickjacking, @import). Use when hunting a specific vuln class or studying what makes bugs pay.
development
Web2 recon pipeline — subdomain enumeration (subfinder, Chaos API, assetfinder), live host discovery (dnsx, httpx), URL crawling (katana, waybackurls, gau), directory fuzzing (ffuf), JS analysis (LinkFinder, SecretFinder), continuous monitoring (new subdomain alerts, JS change detection, GitHub commit watch). Use when starting recon on any web2 target or when asked about asset discovery, subdomain enum, or attack surface mapping.
testing
Finding validation before writing any report — 7-Question Gate (all 7 questions), 4 pre-submission gates, always-rejected list, conditionally valid with chain table, CVSS 3.1 quick reference, severity decision guide, report title formula, 60-second pre-submit checklist. Use BEFORE writing any report. One wrong answer = kill the finding and move on. Saves N/A ratio.