# Differences Between Patator FTP Login, SSH Login, and Other Credential Guessing Modules

> Explore the differences between Patator FTP login, SSH login, and other credential guessing modules. Understand protocol-specific handling and authentication mechanisms.

- Repository: [lanjelot/patator](https://github.com/lanjelot/patator)
- Tags: deep-dive
- Published: 2026-03-05

---

**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`](https://github.com/lanjelot/patator/blob/main/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`](https://github.com/lanjelot/patator/blob/main/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

```bash
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

```bash
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

```bash
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`](https://github.com/lanjelot/patator/blob/main/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`](https://github.com/lanjelot/patator/blob/main/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.