Differences Between Patator FTP Login, SSH Login, and Other Credential Guessing Modules
While all Patator credential-guessing modules inherit from the TCP_Cache base class, the FTP_login and SSH_login modules implement protocol-specific connection handling, distinct authentication mechanisms, and unique response normalization that distinguish them from simpler modules like POP_login or IMAP_login.
The lanjelot/patator repository provides a modular brute-force framework where each service extends a common controller architecture. Understanding the specific differences between Patator FTP login, SSH login, and other credential guessing modules enables security researchers to optimize penetration testing workflows and troubleshoot protocol-specific behaviors effectively.
Shared Foundation: The TCP_Cache Base Class
All credential-guessing modules in src/patator/patator.py inherit from the TCP_Cache class, which provides connection caching, bind() helpers, and reset() functionality. This shared infrastructure handles payload iteration, logging, and parallel execution, but individual modules override critical methods like connect() and execute() to implement protocol-specific logic.
FTP_login: ftplib and Split-Phase Authentication
Located at approximately line 1785 in src/patator/patator.py, the FTP_login class wraps Python’s built-in ftplib library.
Connection Setup: The connect() method instantiates either FTP or FTP_TLS objects depending on the tls option, optionally negotiates TLS via fp.auth(), and returns a TCP_Connection object containing the socket and server banner.
Authentication Flow: The execute() method sends USER and PASS commands separately rather than as a single atomic operation. It catches ftplib.Error exceptions, splits the server response on the first space (code, mesg = resp.split(' ', 1)), and logs the raw FTP numeric code (e.g., 530 for login failure).
Protocol Options:
tls: Toggle between plain FTP and FTPSport: Defaults to21persistent: Defaults to'1'(connection reuse enabled)
SSH_login: Paramiko and Synthetic Response Normalization
Defined at approximately line 1867, the SSH_login class utilizes the Paramiko library (paramiko.Transport) instead of standard library modules.
Transport Handling: The connect() method instantiates a Transport object, starts the SSH client, and wraps it in a TCP_Connection along with the remote version string.
Authentication Logic: Unlike other modules, execute() implements conditional authentication paths:
auth_publickeywhen akeyfileis providedauth_passwordfor standard password authenticationauth_interactivefor keyboard-interactive challenges
Unique Reset Behavior: To prevent privilege escalation from reusing an authenticated transport, the module always calls self.reset() after successful authentication, even when persistent='1'.
Error Handling: Rather than parsing server numeric codes, SSH_login catches paramiko.AuthenticationException and returns synthetic codes: '0' for success and '1' for failure, attaching the SSH banner as the message.
Protocol Options:
auth_type: Selects password, keyboard-interactive, or auto fallbackkeyfile: Path to private key for public-key authenticationport: Defaults to22
Other Modules: POP, IMAP, and SMTP Simplicity
Modules like POP_login (line ~2495), IMAP_login (line ~2608), and SMTP_login (line ~2109) follow a simpler pattern:
- Single-Library Calls: They invoke one method (e.g.,
fp.login(user, password)) that handles both connection and authentication - Direct Response Parsing: They parse server responses directly from library exceptions (e.g.,
pop_error) without synthetic code generation - Limited Options: Typically expose only
host,port,user,password, and optionalsslflags - Standard Behaviors: Most default to
persistent='1'except protocols like Telnet that cannot cleanly reuse connections
Architectural Comparison
| Feature | FTP_login | SSH_login | Other Modules (POP/IMAP/SMTP) |
|---|---|---|---|
| Library | ftplib (FTP/FTP_TLS) | Paramiko (Transport) | poplib, imaplib, smtplib |
| Connection Object | FTP/FTP_TLS instance |
paramiko.Transport |
Standard socket wrappers |
| Auth Method | Separate USER/PASS commands | Conditional auth_publickey/auth_password/auth_interactive | Single login() call |
| Response Codes | Parsed from server (e.g., 530) |
Synthetic (0/1) |
Parsed directly from server response |
| Reset Behavior | Persists unless error | Always resets after success | Persists unless error |
| Special Options | tls |
auth_type, keyfile |
Usually ssl only |
| Default Port | 21 | 22 | Protocol-specific (110, 143, 25) |
Practical Usage Examples
Brute-Forcing FTP with TLS Support
patator ftp_login host=10.0.0.5 \
user=FILE0 password=FILE1 \
0=logins.txt 1=passwords.txt \
tls=1 \
-x ignore:mesg='Login incorrect.' \
-x ignore,reset,retry:code=500
This example enables FTPS (tls=1), ignores "Login incorrect" messages, and resets the connection on 500 series server errors.
SSH with Public Key Authentication
patator ssh_login host=10.0.0.5 \
user=FILE0 keyfile=FILE1 \
0=logins.txt 1=keys.txt \
auth_type=auto \
-x ignore:mesg='Authentication failed.'
The auth_type=auto attempts password authentication first, then falls back to public-key. Note that the module internally resets the transport after each attempt regardless of success.
Standard POP3 Brute-Force
patator pop_login host=10.0.0.5 \
user=FILE0 password=FILE1 \
0=logins.txt 1=passwords.txt \
-x ignore:code=-ERR
POP3 modules parse the -ERR or +OK codes directly from the server response without synthetic normalization.
Summary
- FTP_login uses
ftplibwith separate USER/PASS commands and parses numeric FTP response codes directly from the server. - SSH_login employs Paramiko with conditional authentication methods, generates synthetic success/failure codes (
0/1), and forces connection resets after successful authentication to prevent transport reuse. - Other modules (POP, IMAP, SMTP) utilize standard library single-call authentication with direct response parsing and fewer protocol-specific options.
- All modules inherit from
TCP_Cacheinsrc/patator/patator.pybut overrideconnect()andexecute()to handle protocol-specific requirements.
Frequently Asked Questions
Why does SSH_login reset connections after successful authentication while FTP_login does not?
The SSH protocol maintains state within the Transport object; reusing an authenticated transport would leave the connection in a privileged state, skewing subsequent brute-force attempts. According to the source code in src/patator/patator.py at line ~1867, SSH_login explicitly calls self.reset() after successful auth_password or auth_publickey calls to ensure each credential pair tests against a fresh unauthenticated transport.
Can FTP_login handle both plain FTP and FTPS?
Yes. The FTP_login module accepts a tls option that switches between Python's FTP and FTP_TLS classes. When tls=1 is specified, the module negotiates TLS immediately after the TCP connection using fp.auth(), allowing testing of both encrypted and unencrypted FTP services on the default port 21 or custom ports.
How does Patator handle different authentication methods for SSH?
The SSH_login module exposes an auth_type parameter supporting three modes: password for standard credential passing, keyboard-interactive for challenge-response authentication, and auto which attempts password first then falls back to keyboard-interactive. Additionally, supplying a keyfile triggers auth_publickey via Paramiko's transport layer.
Where do the response codes come from in FTP_login versus SSH_login?
FTP_login extracts codes directly from the server's textual response (e.g., 530 Login incorrect) by catching ftplib.Error and splitting on the first space. SSH_login instead catches paramiko.AuthenticationException and manufactures its own codes—returning '0' for successful authentication and '1' for failure—because the SSH protocol does not expose numeric status codes equivalent to FTP or POP3.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →