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 FTPS
  • port: Defaults to 21
  • persistent: 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_publickey when a keyfile is provided
  • auth_password for standard password authentication
  • auth_interactive for 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 fallback
  • keyfile: Path to private key for public-key authentication
  • port: Defaults to 22

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 optional ssl flags
  • 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 ftplib with 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_Cache in src/patator/patator.py but override connect() and execute() 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →