Async, concurrent SSH credential testing tool built on asyncssh. Supports configurable parallelism, retry logic with exponential backoff, progress tracking with ETA, banner grabbing, and multiple output formats.
⚠️ Legal Notice — This tool is intended solely for authorized security testing and education. Unauthorized access to computer systems is illegal. Always obtain explicit permission before testing any target.
- Async concurrency — Configurable worker pool (default 20) using
asyncioproducer/consumer pattern - Retry with backoff — Exponential backoff + jitter on transient connection errors and timeouts
- Progress monitoring — Real-time attempt count, percentage, rate (tries/s), ETA, and elapsed time
- Banner grabbing — Optionally retrieve and display the SSH server banner before starting
- Connectivity pre-check — Verifies the target is reachable before launching the attack
- Multiple output formats —
colon(user:password),csv, orjson(JSONL) - Continue-after-success —
--no-stopflag to keep searching after finding valid credentials - Graceful shutdown — Handles SIGINT/SIGTERM, drains remaining results, prints summary
- Comment-aware wordlists — Lines starting with
#in wordlist files are skipped - Colored terminal output — ANSI-colored log levels when running in a terminal
- Python 3.9+
- asyncssh
pip install asyncsshusage: ssh_brute_force.py [-h] [-u USER] [-U USERLIST] -w WORDLIST [-p PORT]
[-c CONCURRENCY] [-t TIMEOUT] [--delay DELAY]
[--jitter JITTER] [--max-retries MAX_RETRIES]
[-o OUTPUT] [--format {colon,json,csv}] [--no-stop]
[--banner] [-v] [-q]
target
| Argument | Description |
|---|---|
target |
Target IP or hostname |
| Flag | Default | Description |
|---|---|---|
-u, --user |
— | Single username to test |
-U, --userlist |
— | File with usernames (one per line) |
-w, --wordlist |
wordlist.txt |
Password wordlist file |
-p, --port |
22 |
SSH port |
-c, --concurrency |
20 |
Number of parallel workers |
-t, --timeout |
5 |
Per-connection timeout (seconds) |
--delay |
0 |
Seconds between queued attempts |
--jitter |
0 |
±seconds of random jitter on delay |
--max-retries |
2 |
Retries on connection errors/timeouts |
-o, --output |
— | Write found credentials to file |
--format |
colon |
Output format: colon, json, csv |
--no-stop |
off | Continue after finding a valid credential |
--banner |
off | Grab and display SSH server banner |
-v, --verbose |
off | Debug-level logging |
-q, --quiet |
off | Warning-level logging only |
Basic — single user, default wordlist:
python ssh_brute_force.py 10.10.10.10 -u adminCustom wordlist:
python ssh_brute_force.py 10.10.10.10 -u admin -w rockyou.txtMultiple users, throttled concurrency:
python ssh_brute_force.py 10.10.10.10 -U users.txt -w pass.txt -c 10 --delay 0.5Custom port, save results:
python ssh_brute_force.py 10.10.10.10 -u root -w words.txt -o found.txt --port 2222JSON output, find all valid credentials:
python ssh_brute_force.py 10.10.10.10 -u admin -w pass.txt --format json -o creds.jsonl --no-stopVerbose mode with banner grab:
python ssh_brute_force.py 10.10.10.10 -u root -w words.txt --banner -vWhen -o is specified, found credentials are written in the chosen format:
Colon (default):
admin:password123
root:toor
CSV (with header):
"username","password"
"admin","password123"
"root","toor"JSON (JSONL — one JSON object per line):
{"username": "admin", "password": "password123"}
{"username": "root", "password": "toor"}The tool uses an async producer/consumer pattern:
┌──────────┐ ┌──────────────────────────────────┐ ┌──────────────────┐
│ Producer │────▶│ CredQueue (username, password) │────▶│ Worker Pool (N) │
│ (feeder) │ │ asyncio.Queue, maxsize=2×N │ │ attempt_login() │
└──────────┘ └──────────────────────────────────┘ └────────┬─────────┘
│
ResultQueue (Attempt)
│
▼
┌──────────────────┐
│ Progress Monitor │
│ (stats, logging, │
│ file output) │
└──────────────────┘
-
Producer — Iterates all
user × passwordcombinations and pushes them into theCredQueue, with optional delay + jitter between items. PushesNsentinelNonevalues when done. -
Workers — Each worker pulls from
CredQueue, callsattempt_login(), and pushes theAttemptresult toResultQueue. On success (orstop_event), the worker exits. -
Progress Monitor — Drains
ResultQueue, updatesStats, logs progress periodically, writes found credentials to the output file, and signalsstop_eventwhen--stop-on-successis set. -
Main — Orchestrates startup, handles signals (SIGINT/SIGTERM), waits for completion, cancels remaining tasks, drains final results, and prints the summary.
| Class | Purpose |
|---|---|
AttemptResult |
Enum: SUCCESS, AUTH_FAILED, CONNECTION_ERROR, TIMEOUT |
OutputFormat |
Enum: COLON, JSON, CSV |
Attempt |
Dataclass: username, password, result, retries_used, error |
Stats |
Dataclass: counters + computed properties (elapsed, rate, pct, eta) |
CredQueue |
Type alias: asyncio.Queue[Optional[Tuple[str, str]]] |
ResultQueue |
Type alias: asyncio.Queue[Attempt] |
Transient errors (connection lost, disconnect, timeouts, OS errors) trigger up to --max-retries retries with exponential backoff:
backoff = 0.5 × 2^attempt_num + random(0, 0.3) seconds
PermissionDenied is not retried — it's an immediate AUTH_FAILED.
One entry per line. Lines starting with # are treated as comments and skipped. Blank lines are ignored.
# Common passwords
password123
admin
letmein
qwerty
| Code | Condition |
|---|---|
0 |
Normal exit (completed or interrupted) |
1 |
Missing dependency (asyncssh not installed) |
1 |
Missing --user or --userlist |
1 |
Wordlist or userlist file not found |
1 |
Empty user or password list |
1 |
Target unreachable |
This project is provided for educational and authorized testing purposes only. Use responsibly and in compliance with all applicable laws.