Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SPY-CRACK, a calibrated cracking toolkit by spydirbyte

SPY-CRACK

Developed by SPYDIRBYTE

A calibrated cracking toolkit, four modes: HTTP login form auditing, SSH, FTP, and offline hash cracking. Hydra needs you to hand it an exact failure string and hope it never changes. It'll burn your entire wordlist against an account that got locked on attempt six. Its http-post-form module breaks on any site with a dynamic anti-CSRF token. This does none of that, and every "success" it reports ships with the actual evidence, re-verified before it's called confirmed.

Run it against targets you own or have explicit written authorization to test.


The thing nothing else does: coordinated spray with offline-to-online chaining

Hashcat cracks a hash. Hydra sprays one protocol. Nothing connects them. spray.py does: crack a password offline (from a leaked backup file, a cracked ZIP, a JWT secret) and it feeds straight in as the top priority candidate for a coordinated spray across every discovered live service at once, HTTP login forms, SSH, FTP, HTTP Basic Auth, in actual spray order, every account gets tried against candidate #1 across every service before anyone sees candidate #2, the real technique that avoids tripping per-account lockout thresholds, not three separate uncoordinated brute-force runs with no shared memory between them.

The output that matters most: a cross-service credential reuse map, proof that the same password works on more than one service, not just that it's weak in one place. Tested against three real, independent local services (an HTTP login form, a real SSH server, an HTTP Basic Auth endpoint) where the same password was deliberately reused on two of the three and a different one used on the third, it correctly flagged the real reuse and correctly stayed silent on the one that wasn't actually shared.

python cli.py spray -y \\
  --service "http:main login:https://example.com/login" \\
  --service "ssh:internal jumpbox:203.0.113.5:22" \\
  --service "basic:legacy admin panel:https://old.example.com/" \\
  -u alice -u bob \\
  --seed-password "CrackedFromLeakedBackup2026!" \\
  --seed-origin "cracked from an exposed backup.zip"

The core idea: calibration, not guessing

HTTP login forms. A couple of deliberately bad login attempts get sampled first (fuzzy matched, not exact string comparison), and that becomes the baseline every real attempt gets compared against. Lockout, rate-limiting, and CAPTCHA aren't sampled deliberately (triggering a real lockout just to learn its shape would be the exact problem this avoids), they're caught by keyword and status heuristics during the run itself. The login page gets refreshed before every single attempt, fresh session, fresh CSRF token, whatever the page is actually serving right now.

SSH and FTP work differently, and better. Both protocols have explicit, unambiguous success/failure signals built in, SSH raises a real exception on rejected auth and gives you a live connection on success, FTP returns numeric codes (230 for success, 530 for rejected). No fuzzy inference needed at all here, which means false positives on the classification itself are close to structurally impossible, the only real ambiguity left is lockout/tarpit detection, handled via explicit server disconnects and response-timing comparisons against a baseline.

Offline hash cracking is exact-match, always. hash(candidate) == target, either true or false, no similarity scoring anywhere in this path. Every format (MD5, SHA1, SHA256, SHA512, NTLM, bcrypt) was verified against independently-sourced test vectors before being trusted, NTLM's MD4 dependency in particular ships with a pure Python fallback and was cross-validated against passlib's implementation across multiple test words, since a lot of modern OpenSSL builds disable MD4 outright and silently produce nothing without one.

A possible HTTP-form success gets re-verified before it's reported as confirmed. A genuine hit reproduces reliably on a second, independent attempt. Something that looked like a hit because of a race condition or a session artifact usually doesn't. Anything that doesn't reproduce still gets reported, just honestly labeled "possible, unconfirmed" instead of quietly upgraded to a false certainty.

The explainable rule engine

Hashcat's rule syntax (c $1 $2 $! r) is powerful and completely opaque unless you've memorized it. rules.py does the same job, turn a base word into plausible variants, but every rule has a plain English name (append-year, leet-full, toggle-case) and every candidate it produces remembers exactly which rule made it. Rules can chain two deep (capitalize then append-year turns summer into Summer2026, the single most common real password shape), bounded at two on purpose, past that the candidate space explodes for very little real payoff. The same engine drives both the HTTP --mutate flag and the hash --rules/--chain-rules flags.

More protocols, all with real protocol-level signals

MySQL, PostgreSQL, IMAP, SMTP, and LDAP all work the same calibrated, lockout-aware way as everything else, each verified against a real running server during development, not mocked: a real MariaDB and PostgreSQL instance, a real Dovecot IMAP login, a real Postfix SMTP AUTH exchange (wired up with Dovecot's SASL backend), a real OpenLDAP bind. SMB was verified against an actually installed and configured Samba server, reading real NT status codes.

Telnet's module is written (protocol_telnet.py) using the same approach, but couldn't be verified against a real telnetd instance in the environment this was built in, that specific package expects to run under inetd/xinetd socket activation rather than standalone, and getting that working cleanly didn't happen in the time available. Treat Telnet as less battle-tested than the others until you've run it against something real yourself.

RDP isn't included at all, the only Python library for it needs a Rust compiler toolchain that wasn't available to properly build and test against, rather than ship something unverified, it's left out entirely.

2FA/MFA-aware classification

A login response that says "enter the verification code we just sent you" isn't a failure and isn't really a success either, the password was almost certainly correct and a second factor is what's actually in the way. That's now its own distinct classification (mfa_required) instead of getting lost as an ambiguous "possible success" or miscounted as a wrong password, verified against a target where the correct password triggers exactly that response.

Post-login session probing

Once an HTTP login succeeds, the same session that just authenticated gets a bounded, careful check against a handful of commonly over-exposed paths (an admin panel, a user list, an export endpoint). A weak password is one finding, "this account can also reach the admin panel" is very often the more important one. Verified against a target where a regular user's session could reach an admin panel that should have been access-controlled and wasn't.

Usage

pip install -r requirements.txt

# HTTP login form
python cli.py http https://example.com/login -u admin -P wordlists/common-passwords.txt
python cli.py http https://example.com/login -U usernames.txt -P passwords.txt --mutate
python cli.py http https://example.com/login -u admin --org-term "Acme Corp"

# SSH
python cli.py ssh 203.0.113.5 -u root -P passwords.txt --concurrency 3

# FTP
python cli.py ftp 203.0.113.5 -u admin -P passwords.txt

# offline hash cracking, type auto-detected from the hash's shape when unambiguous
python cli.py hash 5f4dcc3b5aa765d61d8327deb882cf99 -P wordlist.txt
python cli.py hash <ntlm-hash> --type ntlm -P wordlist.txt --rules --chain-rules
python cli.py hash '$2b$12$...' --type bcrypt -P wordlist.txt
python cli.py hash '$6$...' --type sha512crypt -P wordlist.txt   # real /etc/shadow style hashes
python cli.py hash <sha256-hash> --parallel -P bigwordlist.txt    # split across CPU cores

# password-protected files
python cli.py file secret.zip --type zip -P wordlist.txt --rules
python cli.py file secret.pdf --type pdf -P wordlist.txt

# JWT weak-secret cracking
python cli.py jwt eyJhbGciOiJIUzI1NiIs... -P wordlist.txt --rules

# SMB
python cli.py smb 203.0.113.5 -u administrator -P wordlist.txt

# HTTP Basic Auth
python cli.py basic https://example.com/admin -u admin -P wordlist.txt

# auto target-aware wordlist, scrapes the target's own site for names/terms
# instead of typing them in with --org-term
python cli.py http https://example.com/login -u admin --scrape-terms

# after a confirmed hit, check whether that session can reach commonly
# over-exposed paths, an admin panel, a user list, an export endpoint
python cli.py http https://example.com/login -u admin -P wordlist.txt --probe-session

# databases
python cli.py mysql 203.0.113.5 -u root -P wordlist.txt
python cli.py postgres 203.0.113.5 -u postgres -P wordlist.txt --database postgres

# mail
python cli.py imap 203.0.113.5 -u user@example.com -P wordlist.txt
python cli.py smtp 203.0.113.5 -u user@example.com -P wordlist.txt

# LDAP, needs a full bind DN, not just a username
python cli.py ldap 203.0.113.5 --bind-dn "cn=admin,dc=example,dc=com" -P wordlist.txt

# coordinated spray across multiple services, with cross-service reuse detection
python cli.py spray -y \
  --service "http:main login:https://example.com/login" \
  --service "ssh:internal jumpbox:203.0.113.5:22" \
  -u alice --seed-password "CrackedPassword!" --seed-origin "cracked from a leaked backup"

--rps on the HTTP module defaults to a conservative 3 requests/sec on purpose, this is a live authentication endpoint, not a static page. SSH and FTP default to a low concurrency for the same reason.

Structure

.
├── fetcher.py             # async HTTP layer, fresh session per attempt
├── response_classify.py    # HTTP baseline + defense signature classification
├── login_form.py            # CSRF-aware login page parsing, refreshed per attempt
├── protocol_ssh.py            # SSH auth, protocol-level success/failure signals
├── protocol_ftp.py             # FTP auth, raw asyncio, numeric response codes
├── protocol_smb.py              # SMB auth via impacket, real NT status codes
├── protocol_basic_auth.py        # HTTP Basic Auth, status-code based
├── protocol_mysql.py               # MySQL/MariaDB auth, real error codes
├── protocol_postgres.py             # PostgreSQL auth, real SQLSTATE codes
├── protocol_mail.py                   # IMAP + SMTP auth (stdlib, thread-wrapped)
├── protocol_ldap.py                     # LDAP bind auth, real result codes
├── protocol_telnet.py                     # Telnet auth, written but not server-verified
├── session_probe.py                         # post-login check for over-exposed paths
├── hash_crack.py                              # offline exact-match hash cracking, MD5 through bcrypt/crypt
├── file_crack.py                                # offline ZIP/PDF password cracking
├── jwt_crack.py                                    # offline JWT HMAC secret cracking
├── mp_crack.py                                        # multiprocessing wrapper for offline cracking
├── scrape_terms.py                                       # CeWL-style target-aware term scraping
├── spray.py                                                 # cross-protocol spray orchestrator + reuse detection
├── rules.py                                                    # the explainable mutation/rule engine
├── candidates.py                                                  # wordlist loading, target-aware generation
├── engine.py                                                          # HTTP calibration + lockout-aware loop + re-verification
├── cli.py                                                                # terminal front end, fourteen subcommands
└── requirements.txt

What this doesn't do

This tests provided credential lists against systems you're authorized to test, the same category as Hydra, Medusa, Ncrack, or Hashcat. It doesn't attempt to defeat a CAPTCHA, and it stops itself the moment it detects a lockout rather than pushing through it. Offline hash cracking never generates a false positive by design (exact match only), but a "possible" or "confirmed" success on the live HTTP/SSH/FTP side is still a strong signal worth your own verification, not an unconditional guarantee.

Limits worth knowing

  • mfa_required classification is keyword-based, like the lockout and CAPTCHA detection it's built on, a target phrasing its 2FA prompt in unusual language or a language other than English might not match the built-in hint list
  • --probe-session checks a fixed, small list of commonly over-exposed paths (admin, users, export, and similar), it's a lead worth following, not a substitute for the kind of thorough authenticated crawl SPY-VECTOR is actually built for
  • The spray orchestrator's per-service handlers reuse the same detection logic as the standalone http/ssh/ftp/basic subcommands, HTTP spray hits go through the same re-verification step, SSH/FTP/Basic Auth rely on their protocol-level signals, same strengths and same caveats as those modules individually
  • RDP support isn't included, the only Python library for it needs a Rust compiler toolchain that wasn't available to build and properly test against here, rather than fake support that was never actually verified, it's left out
  • mp_crack.py's multiprocessing speedup is real and functionally verified, but the actual speedup you see depends entirely on how many CPU cores the machine running it has, none on a single-core box
  • The wordlist scraper (scrape_terms.py) reads what a site's own pages actually say, a site with very generic, non-distinctive content won't produce much worth generating candidates from, this augments --org-term, it doesn't replace knowing something real about the target
  • Hash cracking speed is Python-native, it will never out-speed Hashcat's GPU acceleration on a large hash set, that's a hardware gap no amount of engineering here closes, the value is candidate quality, explainability, and the offline-to-online chain, not raw throughput
  • Calibration on the HTTP module sends real login attempts, a target with an unusually aggressive lockout policy (locks after 1-2 failures) could trip on calibration itself, --calibration-attempts 1 reduces that risk at some cost to baseline quality
  • SSH/FTP lockout detection relies on the server actually saying something recognizable or dropping the connection, a server that silently rate-limits without any signal at all won't be caught
  • The rule engine's chain depth is capped at two by design, a password needing three or more stacked transforms to reach won't be found without a wordlist that already contains a closer starting point
  • NTLM's pure Python MD4 fallback is slower than the OpenSSL path when available, noticeable on very large wordlists, negligible for typical dictionary sizes

License

MIT

About

Calibrated cracking toolkit that connects offline and online: crack a password from a leaked file, spray it live across HTTP, SSH, FTP, SMB, LDAP, and more, and get a cross-service reuse map back. Lockout-aware, evidence-based, no false positives by design.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages