Skip to content

Ferramentas de Sniffing - Criação, Captura e Análise de Pacotes

Uma ferramenta de sniffing (ou analisador de pacotes) funciona como um "grampo" digital, interceptando e registrando o tráfego que passa por uma interface de rede. Elas são essenciais para o diagnóstico de problemas de conexão, auditoria de segurança e estudo de protocolos, pois permitem visualizar exatamente o que está sendo transmitido entre dois pontos. Normalmente, essas ferramentas operam colocando a placa de rede em modo promíscuo, o que permite capturar pacotes mesmo que o destino final não seja a máquina que está monitorando, sendo frequentemente desenvolvidas em linguagens como C (pela performance de baixo nível) ou Python (pela flexibilidade na análise de dados).

Ferramentas de Snifing

TCPDUMP

O tcpdump é a ferramenta de linha de comando para captura de pacotes. Em ambientes de servidor ou containers (onde não há interface gráfica), ele é o padrão para capturar tudo o que acontece na rede e o salva em um arquivo de extensão .pcap (Packet Capture).

tcpdump -i any -w /app/laboratorio.pcap
  • -i any: Escuta em todas as interfaces de rede do roteador.
  • -w: Escreve (salva) o resultado em um arquivo para análise posterior em outras ferramentas.

Além de gravar o tráfego total, o tcpdump permite aplicar filtros em tempo real para capturar apenas pacotes específicos. Isso é essencial em redes com muito tráfego. Por exemplo, filtrar por Porta Específica. Útil para monitorar apenas um serviço (ex: apenas tráfego Web ou apenas Banco de Dados).

# Escuta apenas o tráfego na porta 80 (HTTP)
tcpdump -i any port 80

Filtrar por Endereço IP. Ideal para isolar o que um cliente específico está fazendo ou o que está chegando em um servidor.

# Captura apenas pacotes que tenham o IP 10.0.2.2 como origem ou destino
tcpdump -i any host 10.0.2.2

Filtrar por Origem e Destino (Fluxo Direcionado). Para ser ainda mais específico e ver apenas o que sai de um ponto A para um ponto B.

# Captura pacotes que saem do Cliente (src) para o Servidor (dst)
tcpdump -i any src 10.0.2.2 and dst 10.0.1.2

NGREP

O ngrep (Network Grep) aplica a lógica de busca de texto do comando grep diretamente nos pacotes que estão trafegando na placa de rede em tempo real. Ele combina a capacidade de captura do tcpdump com a facilidade de busca de texto do comando grep. Ele permite que você escute a rede e filtre apenas os pacotes que contêm palavras-chave específicas.

Comando Principal (Monitoramento de Telnet).

ngrep -q -W byline port 23

  • -q (Quiet): Oculta os caracteres de controle e metadados irrelevantes, focando apenas no conteúdo útil.
  • -W byline: Formata a saída quebrando as linhas de forma legível, simulando como o texto aparece na tela do usuário.
  • port 23: Filtra o tráfego do protocolo Telnet.

Perceba que é possível visualizar o tráfego e captrar o login e senha de usuário.

Captura de Padrões Específicos (Filtro de Conteúdo).

# Busca apenas requisições GET na porta 80
ngrep -q -W byline "^GET" port 80

# Busca qualquer pacote que contenha a palavra "aluno" ou "lab123"
ngrep -i "aluno|lab123" any

  • "^GET": Usa expressões regulares para identificar o início de uma requisição web.
  • -i: Ignora a diferença entre maiúsculas e minúsculas (case-insensitive).

Wireshark

O Wireshark é a ferramenta da análise de redes com interface gráfica. Enquanto o tcpdump e o ngrep nos dão recortes rápidos no terminal, o Wireshark nos oferece o "Raio-X" completo de toda a comunicação. No nosso laboratório, como os containers não possuem interface gráfica, utilizamos a estratégia de capturar o tráfego no roteador e exportar o arquivo .pcap para análise na nossa máquina real.

Ao iniciar o Wireshark, a primeira coisa que fazemos é carregar o arquivo que gravamos anteriormente. Diferente de um editor de texto, o Wireshark entende a estrutura binária dos pacotes e já os organiza cronologicamente.

A força do Wireshark está na sua organização em três seções principais, que permitem navegar do geral para o específico:

  1. Lista de Pacotes (Topo): Cada linha é um pacote. As cores ajudam a identificar o protocolo (ex: azul para DNS, verde para HTTP, roxo para TCP).

  2. Detalhes do Pacote (Meio): O Wireshark decodifica as camadas (Ethernet, IP, TCP) e permite que você abra cada uma para ver os campos, como endereços e portas.

  3. Bytes do Pacote (Base): Mostra o dado bruto em hexadecimal e ASCII. É a prova final do que realmente passou pelo fio.

Como o TCP envia dados em muitos pacotes pequenos, ler um por um é difícil. A função Follow TCP Stream recria a conversa inteira em uma única janela, como se fosse um chat.

Para fazer isso, clicamos com o botão direito em um pacote MariaDB e selecionamos Follow -> TCP Stream.

Ao abrir o fluxo TCP do MariaDB, a vulnerabilidade do protocolo fica exposta. O Wireshark exibe em cores diferentes o que o cliente enviou e o que o servidor respondeu. Conseguimos ver as queries envidas do cliente para servidor

Scapy

!pip install scapy

Scapy é uma ferramenta poderosa para análise e manipulação de pacotes de rede. Através dela conseguimos criar as ferramentas sniffers como wireshark e similares.

Normalmente, quando um pacote chega na placa de rede, o Kernel do Linux faz todo o trabalho. Ele abre a camada Ethernet, depois a IP, depois a TCP e entrega apenas o "conteúdo" (o dado) para o aplicativo.

O Scapy utiliza Raw Sockets. Isso permite que ele ignore o processamento padrão do Kernel e pegue o pacote "cru".

  • Modo Promíscuo: O Scapy coloca a placa de rede em um estado onde ela não descarta nada, mesmo pacotes que não são para aquele computador.
  • Cópia de Fluxo: O pacote continua indo para o destino original, mas o Scapy faz uma cópia binária exata para análise.
from scapy.all import (
    # Camadas de protocolo
    Ether, IP, IPv6, TCP, UDP, ICMP, Raw,
    # Funções de envio
    send, sendp, sr1, srp1, sr, srp,
    # Funções de captura
    sniff, rdpcap, wrpcap,
    # Utilitários
    ls, conf, hexdump, get_if_list, get_if_addr,
    # Tipos especiais
    DNS, DNSQR,
)
import time
import sys

No Scapy, um pacote não é uma string de texto, mas um objeto composto por fatias.

A estrutura visual que o Scapy usa é: Ether() / IP() / TCP() / Raw() - Ether(): Camada 2 (Endereços MAC). - IP(): Camada 3 (Endereços IP, TTL, etc). - TCP() / UDP(): Camada 4 (Portas, Flags, Sequência). - Raw(): Onde os dados reais (payload) residem.

Usando o CMD do Scapy

basta digitar scapy no terminal. Isso abre um shell Python onde você pode interagir com pacotes em tempo real:

  1. ls(): Lista todos os protocolos suportados (são centenas!).
  2. ls(IP): Mostra todos os campos que existem dentro da camada IP.
  3. p = IP(dst="10.0.1.2")/TCP(dport=80): Cria um pacote manualmente (Forge).
  4. p.show(): Mostra a estrutura detalhada e "mastigada" do pacote.

Vamos agora criar um sniffer que tenta capturar um pacote de um serviço rodando no ambiente. Para isso você precisa iniciar o ambiente do aluno do laboratório 2.

ls(IP)

version    : BitField  (4 bits)                  = ('4')
ihl        : BitField  (4 bits)                  = ('None')
tos        : XByteField                          = ('0')
len        : ShortField                          = ('None')
id         : ShortField                          = ('1')
flags      : FlagsField                          = ('<Flag 0 ()>')
frag       : BitField  (13 bits)                 = ('0')
ttl        : ByteField                           = ('64')
proto      : ByteEnumField                       = ('0')
chksum     : XShortField                         = ('None')
src        : SourceIPField                       = ('None')
dst        : DestIPField                         = ('None')
options    : PacketListField                     = ('[]')

ls(TCP)

sport      : ShortEnumField                      = ('20')
dport      : ShortEnumField                      = ('80')
seq        : IntField                            = ('0')
ack        : IntField                            = ('0')
dataofs    : BitField  (4 bits)                  = ('None')
reserved   : BitField  (3 bits)                  = ('0')
flags      : FlagsField                          = ('<Flag 2 (S)>')
window     : ShortField                          = ('8192')
chksum     : XShortField                         = ('None')
urgptr     : ShortField                          = ('0')
options    : TCPOptionsField                     = ("b''")

Listar Interfaces Disponíveis

for iface in get_if_list():
    print(f"  → {iface}")

Criando Pacotes com Scapy

Pacote IP Simples

pkt_ip = IP(dst="8.8.8.8")
print(f"  Destino: {pkt_ip.dst}")
print(f"  TTL padrão: {pkt_ip.ttl}")
print(f"  Protocolo: {pkt_ip.proto}")

Pacote ICMP (Ping)

pkt_ping = IP(dst="8.8.8.8", ttl=64) / ICMP()
pkt_ping.show()
Pacote UDP com payload

pkt_udp = IP(src="192.168.1.10", dst="192.168.1.20") \
              / UDP(sport=5000, dport=9999) \
              / Raw(load="Olá, Scapy!")
pkt_udp.show()

Acessando campos individualmente

print(f" IP src  : {pkt_udp[IP].src}")
print(f" IP dst  : {pkt_udp[IP].dst}")
print(f" UDP sport: {pkt_udp[UDP].sport}")
print(f" UDP dport: {pkt_udp[UDP].dport}")
print(f" Payload  : {pkt_udp[Raw].load}")

Modificando Uma Cópia dos Pacotes

pkt_mod = pkt_udp.copy()
pkt_mod[IP].dst     = "10.0.0.1"
pkt_mod[UDP].dport  = 8080
pkt_mod[Raw].load   = b"Mensagem modificada"

print(f"  Novo dst: {pkt_mod[IP].dst}, nova porta: {pkt_mod[UDP].dport}")
print(f"  Payload: {pkt_mod[Raw].load}")

Visualizando Pacotes

show()

pkt_udp.show()

###[ IP ]###
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     = 
  frag      = 0
  ttl       = 64
  proto     = udp
  chksum    = None
  src       = 192.168.1.10
  dst       = 192.168.1.20
  \options   \
###[ UDP ]###
     sport     = commplex_main
     dport     = distinct
     len       = None
     chksum    = None
###[ Raw ]###
        load      = b'Ol\xc3\xa1, Scapy!'

show2() - visualização com campos preenchidos

pkt_udp.show2()
###[ IP ]###
  version   = 4
  ihl       = 5
  tos       = 0x0
  len       = 40
  id        = 1
  flags     = 
  frag      = 0
  ttl       = 64
  proto     = udp
  chksum    = 0xf755
  src       = 192.168.1.10
  dst       = 192.168.1.20
  \options   \
###[ UDP ]###
     sport     = commplex_main
     dport     = distinct
     len       = 20
     chksum    = 0xd49c
###[ Raw ]###
        load      = b'Ol\xc3\xa1, Scapy!'

Summary - Resumo do pacote em uma linha

pkt_udp.summary()

'IP / UDP 192.168.1.10:commplex_main > 192.168.1.20:distinct / Raw'

hexdump() — bytes do pacote em hexa + ASCII

hexdump(pkt_udp)

0000  45 00 00 28 00 01 00 00 40 11 F7 55 C0 A8 01 0A  E..(....@..U....
0010  C0 A8 01 14 13 88 27 0F 00 14 D4 9C 4F 6C C3 A1  ......'.....Ol..
0020  2C 20 53 63 61 70 79 21                          , Scapy!

Acessando cabeçalhos pelo índice ou por nome

print(f"  pkt[IP]   → src={pkt_udp[IP].src}, dst={pkt_udp[IP].dst}")
print(f"  pkt[UDP]  → sport={pkt_udp[UDP].sport}, dport={pkt_udp[UDP].dport}")
print(f"  pkt[Raw]  → load={pkt_udp[Raw].load}")

Verificar se uma camada existe no pacote

print(f"\n  Tem camada TCP? {TCP in pkt_udp}")
print(f"  Tem camada UDP? {UDP in pkt_udp}")
print(f"  Tem camada Raw? {Raw in pkt_udp}")

Enviando Pacotes

send() — envia pacote sem aguardar resposta

dst_ip = "127.0.0.1"

pkt_ping = IP(dst=dst_ip) / ICMP()
print(f"Enviando ping para {dst_ip}...")

send(pkt_ping, verbose=0)

envia e aguarda resposta (ping)

dst_ip = "127.0.0.1"

pkt_ping = IP(dst=dst_ip) / ICMP()
print(f"Enviando ping para {dst_ip}...")

resp = sr1(pkt_ping, timeout=2, verbose=0)
resp.summary()
'IP / ICMP 127.0.0.1 > 127.0.0.1 echo-reply 0'

Capturando Pacotes - Sniff

Parâmetros sniff()

  • count=N → captura exatamente N pacotes (0 = infinito)
  • timeout=T → para após T segundos
  • iface='eth0' → captura apenas nessa interface
  • filter='...' → filtro BPF (mesma sintaxe do tcpdump)
  • prn=função → callback chamado para cada pacote capturado
  • store=False → não armazena na memória (use com prn)
  • lfilter=lambda → filtro Python (mais flexível que BPF)

Exemplos de Filtros - BPF:

  • 'tcp' → apenas TCP
  • 'udp port 9999' → UDP na porta 9999
  • 'host 192.168.1.10' → apenas host específico
  • 'tcp and dst port 80' → TCP indo para porta 80
  • 'icmp' → apenas ICMP
  • 'not arp' → ignora ARP
  • 'tcp port 80 or tcp port 443' → HTTP e HTTPS

Digite o comando abaixo. Ele coloca o Scapy em modo de espera escutando a porta 23:

pacote_unico = sniff(filter="tcp port 23", count=1)

O Scapy não retorna o pacote diretamente, mas sim um objeto do tipo PacketList.

> pacote
<Sniffed: TCP:1 UDP:0 ICMP:0 Other:0>
Ele contém todos os pacotes capturados. Note que ele já identifica automaticamente que o pacote capturado pertence ao protocolo TCP.

Você pode ver uma representação simplificada da "pilha" de protocolos com o seguinte comando.

>>> pacote.summary()
Ether / IP / TCP 10.0.2.2:43688 > 10.0.1.2:telnet PA / Raw
Aqui vemos a hierarquia de encapsulamento: Ethernet → IP → TCP. O Scapy identifica o IP de origem, a porta efêmera do cliente (43688), o destino e as flags TCP (PA significa Push e Ack, indicando que há dados sendo enviados).

Esse script, é basicamente o tcpdump.

from scapy.all import sniff, IP, TCP

def analisar_pacote(pacote):
    if pacote.haslayer(IP):
        ip_origem = pacote[IP].src
        ip_destino = pactoe[IP].dst

        if pacote.haslayer(TCP):
            porta_origem = pacote[TCP].sport
            porta_destino = pacote[TCP].dport

        print(f"[TCP] {ip_origem}:{porta_origem} ---> {ip_destino}:{porta_destino}")

print("Iniciando o Sniffer do Roteador...")
print("Pressione Ctrl+C para interromper.\n")

# prn=analisar_pacote: Diz ao sniff para jogar cada pacote dentro da nossa função.
# store=0: Extremamente importante! Diz ao Scapy para NÃO guardar os pacotes na RAM, 
# caso contrário seu roteador travaria por falta de memória em poucos minutos.
sniff(prn=analisar_pacote, store=0)

Salvando e Lendo Arquivos .pcap

Criando pacotes de exemplo e salvando em PCAP

pacotes_para_salvar = [
    IP(src="10.0.0.1", dst="10.0.0.2") / UDP(sport=1001, dport=9999) / Raw(load="Mensagem 1"),
    IP(src="10.0.0.2", dst="10.0.0.1") / UDP(sport=9999, dport=1001) / Raw(load="Resposta 1"),
    IP(src="10.0.0.1", dst="10.0.0.2") / TCP(sport=2001, dport=80, flags="S"),
    IP(src="10.0.0.2", dst="10.0.0.1") / TCP(sport=80, dport=2001, flags="SA"),
    IP(src="10.0.0.1", dst="10.0.0.2") / ICMP() / Raw(load="ping"),
]

arquivo_pcap = "captura_lab.pcap"
wrpcap(arquivo_pcap, pacotes_para_salvar)
print(f"  {len(pacotes_para_salvar)} pacotes salvos em '{arquivo_pcap}'")

Lendo arquivos .pcap

pkts_lidos = rdpcap(arquivo_pcap)
print(f"  Total de pacotes lidos: {len(pkts_lidos)}")

print("\n  Sumário de cada pacote:")
for i, pkt in enumerate(pkts_lidos):
    print(f"    [{i+1}] {pkt.summary()}")

  Total de pacotes lidos: 5

  Sumário de cada pacote:
    [1] IP / UDP 10.0.0.1:1001 > 10.0.0.2:9999 / Raw
    [2] IP / UDP 10.0.0.2:9999 > 10.0.0.1:1001 / Raw
    [3] IP / TCP 10.0.0.1:2001 > 10.0.0.2:http S
    [4] IP / TCP 10.0.0.2:http > 10.0.0.1:2001 SA
    [5] IP / ICMP 10.0.0.1 > 10.0.0.2 echo-request 0 / Raw

Praticando ...

EXERCÍCIO 1 — Criação de pacotes:

  • a) Crie um pacote ICMP Echo Request para o endereço "1.1.1.1" com TTL=128 e exiba com show2().
  • b) Crie um pacote UDP com src="192.168.0.5", dst="192.168.0.10", porta origem 6000, porta destino 6001 e payload "Exercicio1".
  • c) Crie um pacote TCP SYN+FIN para a porta 443 e observe os flags.

EXERCÍCIO 2 — Manipulação de campos:

  • a) A partir do pacote do exercício 1b, modifique apenas o payload para "Alterado" sem recriar o pacote.
  • b) Exiba o hexdump antes e depois da modificação.

EXERCÍCIO 3 — Captura e análise:

  • a) Capture 10 pacotes IP com sniff() e liste as 3 IPs de origem mais frequentes.
  • b) Use um filtro BPF para capturar apenas tráfego na porta 80 (HTTP) por 15 segundos e conte quantos pacotes têm payload.

EXERCÍCIO 4 — PCAP:

  • a) Capture 20 pacotes com sniff() e salve em "minha_captura.pcap".
  • b) Reabra o arquivo e separe os pacotes por protocolo (TCP/UDP/ICMP).
  • c) Calcule o tamanho médio dos pacotes TCP capturados.

EXERCÍCIO 5 — Chat Scapy:

  • a) Execute o servidor (chat_server_scapy.py) em um terminal.
  • b) Execute o cliente (chat_client_scapy.py) em outro terminal.
  • c) Troque mensagens e observe os pacotes capturados.
  • d) Capture a sessão de chat e analise o arquivo PCAP no Wireshark.