Ir para conteúdo
  • Cadastre-se
Entre para seguir isso  
gnoo

Análise de pacotes na prática[ Parte 1 ] - "O inicio" Raw Sockets python

Posts Recomendados

Saudações,

venho por este meio, partilhar convosco alguns dos conhecimentos que tenho vindo a adquirir ao longo do tempo, na manipulação de pacotes e sua análise com python, aquilo que sei não é nada demasiado avançado, mas acho que pode ajudar algumas pessoas a alargar horizontes, para outras matérias que estão relacionadas com isto, e também vai-me permitir consolidar conceitos e explorar mais, e adquirir mais conhecimentos, blá blá blá.... 

Este conteúdo vai estar  dividido em vários posts dai o titulo ser "O inicio",  não sei quantos posts vão ser nem sei com que regularidade irei fazer esses posts... Vai estar dividido em vários posts porque acho que sendo conteúdo mais pequeno com mais detalhes possiveis( dentro dos meus conhecimentos), é mais fácil, para quem tem menos conhecimento sobre o assunto, pode amadurecer as ideias que serão passadas.

 

Este conteúdo está sujeito a erros de interpretação por parte da minha pessoa, se vires algum erro ou achas que tens algo a acrescentar deixa nos comentários para ser corrigido/adicionado...

Algum do texto que explica alguns conceitos relacionado com redes e formatos de pacotes foi retirado deste livro que já recomendei anteriormente...

 

 

Vamos iniciar, boa sorte...

 

581758266_Capturadeecr_2018-12-18_17-07-42.png.37856fb85998ba5ea37995f1de08b5df.png

 

Apenas consegues receber os pacotes que chegam à tua máquina o código deve ser executado como root.

#coding:utf-8  
#!/usr/bin/env python3




from socket import *
import struct

# AF_PACKET Familia protocolo (everywere)

# ntohs(0x0003) - Permite capturar todos os pacotes com frames ethernet


sock = socket(AF_PACKET, SOCK_RAW, ntohs(0x0003))

while True:
    raw_dados, addr = sock.recvfrom(65536)
    print(raw_dados)

    
"""
socket.ntohs( x ) 
Converte inteiros positivos de 16 bits da rede para a ordem de bytes do host.
Nas máquinas em que a ordem de bytes do host é igual à ordem de bytes da rede,
isso é um não operacional; caso contrário, ele executará uma operação de troca
de 2 bytes.
“””

 

A variável raw_dados recebe uma string com os dados recebidos.

83313250_Capturadeecr_2018-12-17_22-46-39.png.fa77be263ad2d44ee5de585fe44d60f5.png

 

Relaxa irmão o que acabaste de ver não é voodoo ….

É apenas a string que vamos extrair os dados do frame ethernet.

Vamos ver que tipo de dados recebe a variável raw_dados fazendo um print com a função built-in do python type()...

#coding:utf-8  
#!/usr/bin/env python3




from socket import *
import struct

# AF_PACKET Familia protocolo (everywere)

# ntohs(0x0003) - Permite capturar todos os pacotes com frames ethernet


sock = socket(AF_PACKET, SOCK_RAW, ntohs(0x0003))

while True:
    raw_dados, addr = sock.recvfrom(65536)
    print(type(raw_dados))

    
"""
socket.ntohs( x ) 
Converte inteiros positivos de 16 bits da rede para a ordem de bytes do host.
Nas máquinas em que a ordem de bytes do host é igual à ordem de bytes da rede,
isso é um não operacional; caso contrário, ele executará uma operação de troca
de 2 bytes.
“””

bytes.png.c30dd3461da0e7ee40be11b3f153e339.png

 

Podemos ver que está a chegar em formato de bytes, byte-order..

Então temos que tratar esses bytes para extrair os valores que vêm no frame ethernet, para isso temos fazer uma função para esse efeito.

Mas antes vamos ver alguns conceitos sobre frame ethernet e algumas características do pacote.

 

Formato do frame Ethernet e tamanho de pacote

Citar

Devido ao termo pacote ser genérico e poder se referir a qualquer tipo de pacote, usaremos o termo frame para nos referirmos ao pacote que é definido por tecnologias de hardware.* Os frames Ethernet têm comprimentos variáveis, sem frames menores que 64 octetos** ou maioresque 1514 octetos (cabeçalho e data). Como esperado, cada frame Ethernet contém um  campo que guarda o endereço 48-bit de um destino e outro campo que guarda o endereço 48-bit do emissor. Quando transmitido, o frame inclui também um 4-octet Cyclic Redundancy Check (CRC), que é usado para verificar erros de transmissão. Como o campo CRC é adicionado pelo hardware de envio e verificado pelo hardware de recebimento, não é visível para o software de camadas mais altas do protocolo. A Figura 2.2 ilustra as partes pertinentes de um frame Ethernet.

1956491332_Capturadeecr_2018-12-18_13-25-23.thumb.png.c73ce5fa010ce1cf2bf581bb2706b3ab.png

Citar

Na figura, os três primeiros campos constituem em cabeçalho para o frame, e os campos restantes são a carga útil. Os pacotes usados na maioria  das tecnologias de rede seguem o mesmo padrão: o pacote consiste de um pequeno cabeçalho com campos fixos seguido por um campo de carga útil com tamanho variável. O tamanho máximo de carga útil em um frame Ethernet é 1500 octetos. Como a Ethernet foi adotada de forma universal, a maioria dos ISPs mudou suas redes para se ajustar com a carga Ethernet. Além dos campos que identificam a fonte e o destino do frame, um frame Ethernet contém um 16-bit inteiro que identifica o tipo de dado que está sendo transportado. A maioria das tecnologias de pacote inclui um campo de tipo. Do ponto de vista da Internet, o tipo do frame é essencial, pois significa que frames Ethernet são autoidentificáveis. Quando um frame chega a uma determinada máquina, o software do protocolo define qual módulo de protocolo deve processar esse tipo de frame. As maiores vantagens dos frames autoidentificáveis são que eles permitem que protocolos múltiplos sejam usados em conjunto em um único computador e múltiplos protocolos sejam misturados na mesma rede física sem interferência. Por exemplo, pode-se ter um programa de aplicação em um computador usando protocolos Internet, enquanto outra aplicação no mesmo computador usa um protocolo experimental local. O sistema operacional verifica o campo do tipo de cada frame que chega e decide qual módulo deve processar seu conteúdo. Veremos que o campo de tipo pode ser usado para definir protocolos múltiplos na mesma família. Por exemplo, devido aos protocolos TCP/IP incluírem diversos protocolos que podem ser enviados por uma Ethernet, o TCP/IP define vários tipos de Ethernet.

Bibliografia: INTERLIGAÇÃO DE REDES COM TCP/IP  Capitulo 2

 

Visto isto já sabemos o tamanho campos de um frame ethernet, vamos ver a quantidade de bytes que temos que extrair usando a função struct do python….

808488056_tamnahocampos.png.ddf4d7f2fb802c3d1d7ec663ce8bd9b2.png

 

O campo tipo de frame diz-nos que tipo de pacote está a chegar e em que protocolo se desloca, a carga útil de frames é os dados e informação relacionada com esses pacotes.

198953988_Capturadeecr_2018-12-20_11-27-51.png.73dacd5ca5bd774a1183c9b94d911924.png

 

 

Então vamos fazer a função para trabalhar os frames ethernet…

# Na função struct
# 6s -> indica tamanho 6 bytes dos campos endereço destino e endereço fonte com o MAC
# H -> indica tamanho 2 bytes do campo tipo de frame

def ethernet_frame(raw_dados):
    
    mac_destino, mac_fonte, protocolo = struct.unpack('! 6s 6s H', raw_dados[:14])

    return mac_destino, mac_fonte, protocolo, raw_dados[14:]
  

O que estamos a fazer é passar a variável raw_dados onde é feito o fatiamento dos primeiros 14 ( raw_dados[:14] ) bytes do pacote dos campos endereço destino, endereço fonte, tipo de frame, e é feito o seu desempacotamento, retornando os valores referidos,o resto dos dados dos pacote relacionado com a carga util, é extraida com um fatiamento dos primeiros 14 bytes para a frente ( raw_dados[14:], é aqui que vamos buscar a informação dos cabeçalhos dos pacotes que chegam ).

script:

#coding:utf-8  
#!/usr/bin/env python3

from socket import *
import struct

# AF_PACKET Familia protocolo (everywere)
# ntohs(3) - Permite capturar todos os pacotes com frames ethernet

def ethernet_frame(raw_dados):
    
    mac_destino, mac_fonte, protocolo = struct.unpack('! 6s 6s H', raw_dados[:14])

    return mac_destino, mac_fonte, protocolo, raw_dados[14:]


sock = socket(AF_PACKET, SOCK_RAW, ntohs(0x0003))

while True:
    raw_dados, addr = sock.recvfrom(65536)
    mac_destino, mac_fonte, protocolo, carga_util = ethernet_frame(raw_dados)

    print("Endereço MAC destino : {}".format(mac_destino))
    print("Endereço MAC fonte : {}".format(mac_fonte))
    print("Protocolo : {}\n".format(protocolo))
    print("Carga útil -> {}\n".format(carga_util))
    
"""
socket.ntohs( x ) 
Converte inteiros positivos de 16 bits da rede para a ordem de bytes do host.
Nas máquinas em que a ordem de bytes do host é igual à ordem de bytes da rede,
isso é um não operacional; caso contrário, ele executará uma operação de troca
de 2 bytes.
"""

 

Com isto já podemos ver alguma coisa…

z.thumb.png.c05d4cb501dd17b1e4a9a6d7e1c43c7e.png

 

seja como for ainda não conseguimos ver nada que seja legivel para nós humanos, pelo menos para as pessoas normais 😛 .

Temos que tratar os endereços MAC, e o protocolo, vamos fazer uma função para trabalhar o MAC.

A função que segue pode ser feito de várias maneiras, se conheces outra, faz como achares melhor para ti.

def byte_to_hex_mac(mac_em_bytes):
    endereco = binascii.hexlify(mac_em_bytes).decode("ascii")
    return ":".join([endereco[i:i+2] for i in range(0,12,2)])

Agora vamos à função ethernet_frame passar os valores do mac em bytes que estão a ser retornados nessa função, como argumentos para a função byte_to_hex_mac .

E já agora tratamos também da variável protocolo passando-a como argumento pela função htons da lib socket.

socket.htons

Converte inteiros positivos de 16 bits da ordem de bytes do host para a rede. Nas máquinas em que a ordem de bytes do host é igual à ordem de bytes da rede, isso é um não operacional; caso contrário, ele executará uma operação de troca de 2 bytes.

 

Deve ficar assim…

def ethernet_frame(raw_dados):
    
    mac_destino, mac_fonte, protocolo = struct.unpack('! 6s 6s H', raw_dados[:14])

    return byte_to_hex_mac(mac_destino), byte_to_hex_mac(mac_fonte), htons(protocolo), raw_dados[14:]

 

Script completo ….

#coding:utf-8  
#!/usr/bin/env python3

from socket import *
import struct
import binascii

# AF_PACKET Familia protocolo (everywere)
# ntohs(3) - Permite capturar todos os pacotes com frames ethernet

def ethernet_frame(raw_dados):
    
    mac_destino, mac_fonte, protocolo = struct.unpack('! 6s 6s H', raw_dados[:14])

    return byte_to_hex_mac(mac_destino), byte_to_hex_mac(mac_fonte), htons(protocolo), raw_dados[14:]




def byte_to_hex_mac(mac_em_bytes):
    endereco = binascii.hexlify(mac_em_bytes).decode("ascii")
    return ":".join([endereco[i:i+2] for i in range(0,12,2)])

sock = socket(AF_PACKET, SOCK_RAW, ntohs(0x0003))    

while True:
    raw_dados, addr = sock.recvfrom(65536)
    mac_destino, mac_fonte, protocolo, carga_util = ethernet_frame(raw_dados)

    print("Endereço MAC destino : {}".format(mac_destino))
    print("Endereço MAC fonte : {}".format(mac_fonte))
    print("Protocolo : {}\n".format(protocolo))
    print("Carga útil -> {}\n".format(carga_util))
  
"""
socket.ntohs( x ) 
Converte inteiros positivos de 16 bits da rede para a ordem de bytes do host.
Nas máquinas em que a ordem de bytes do host é igual à ordem de bytes da rede,
isso é um não operacional; caso contrário, ele executará uma operação de troca
de 2 bytes.
------------------------------------------------------------------------------

socket.htons( x ) 
Converte inteiros positivos de 16 bits da ordem de bytes do host para a rede.
Nas máquinas em que a ordem de bytes do host é igual à ordem de bytes da rede,
isso é um não operacional; caso contrário, ele executará uma operação de troca
de 2 bytes.
"""

Executar-mos o script...

ls.png.8ee46bbd6662532e861f391df7f725e8.png

 

Já conseguimos ver que há um endereço MAC da placa de rede que recebe os pacotes, podemos ver também que é o router que está a fazer esse envio, e também já temos um número de protocolo... esse número de protocolo está associado ao protocolo em que o pacote se desloca... 

Depois é só fazer funções para analisar a carga util que lá vem.

Mas isso fica para uma próxima, agora treina bem os conceitos anteriores, não vale fazer copy / paste, tens que escrever código.

Abraço.

Editado por gnoo
  • Agradecer 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Visitante
Responder

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emoticons no total são permitidos.

×   Seu link foi automaticamente incorporado.   Mostrar como link

×   Seu conteúdo anterior foi restaurado.   Limpar o editor

×   Não é possível colar imagens diretamente. Carregar ou inserir imagens do URL.

Entre para seguir isso  

  • Quem Está Navegando   0 membros estão online

    Nenhum usuário registrado visualizando esta página.

×
×
  • Criar Novo...