Guest gnoo Posted December 31, 2018 Posted December 31, 2018 Saudações, 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... Os conceitos de redes aqui apresentados foram retirados do livro: neste tópico vamos ver como analisar um pacote UDP, este pacote vem encapsulado no payload / carga, do pacote IP e circula no protocolo 17. A análise do pacote UDP pode ser importante por várias razões, uma delas é porque é através dele que nós chegamos ao DNS que pode ser encontrado na carga deste pacote, e isso para os “hackers” de serviço pode ser importante. Antes de fazer a função para tratar os dados que vêm neste pacote vamos ver algumas características do ser formato. ATENÇÃO: O conteúdo que segue deve ser complementado com a leitura de um livro da especialidade Formato de mensagem UDP Citar Usamos o termo user datagram para descrever uma mensagem UDP; a ênfase no user destina-se a distinguir datagramas UDP de datagramas IP. Conceitualmente, um user datagram consiste de duas partes: um cabeçalho que contém metainformação, tal como números de porta de protocolo de origem e de destino, e uma área de carga que contém os dados que estão sendo enviados. A Figura 10.1 ilustra a organização. Citar O cabeçalho de um user datagram é extremamente pequeno: é composto por quatro campos que especificam a porta de protocolo a partir da qual a mensagem foi enviada, a porta de protocolo para a qual a mensagem é destinada, o tamanho da mensagem e um checksum UDP. Cada campo tem um tamanho de 16 bits, o que significa que todo o cabeçalho ocupa apenas um total de 8 octetos. A Figura 10.2 ilustra o formato do cabeçalho. Citar O campo PORTA DE ORIGEM UDP contém um número de porta de protocolo de 16 bits usado pelo aplicativo de envio, e o campo de PORTA DE DESTINO UDP contém o número da porta UDP de 16 bits do aplicativo de recebimento. Em essência, o software de protocolo usa os números de porta para demultiplexar datagramas entre os aplicativos que estãoesperando para recebê-los. Curiosamente, a PORTA DE ORIGEM UDP é opcional. Nós pensamos nela como identificadora da porta à qual a resposta deve ser enviada. Em uma transferência de mão única, onde o receptor não envia uma resposta, a porta de origem não é necessária e pode ser ajustada para zero. O campo TAMANHO DA MENSAGEM UDP (UDP MESSAGE LENGTH) contém uma contagem de octetos no datagrama UDP, incluindo o cabeçalho UDP e os dados do usuário. Assim, o valor mínimo é oito, tamanho só do cabeçalho. O campo TAMANHO DA MENSAGEM UDP é composto por 16 bits, o que significa que o valor máximo que pode ser representado é 65.535. Como uma questão prática, no entanto, veremos que uma mensagem UDP deve caber na área de carga útil de um datagrama IP. Por conseguinte, o tamanho máximo permitido depende do tamanho do(s) cabeçalho(s) de IP, o qual é consideravelmente maior em um datagrama IPv6 do que num datagrama Ipv4. Função para tratar os dados do cabeçalho UDP def dados_pacote_udp(carga): tupla_dados_udp = struct.unpack('! H H H H', carga[:8]) porta_fonte = tupla_dados_udp[0] porta_destino = tupla_dados_udp[1] udp_len = tupla_dados_udp[2] udp_checksum = tupla_dados_udp[3] return porta_fonte, porta_destino, udp_len, udp_checksum, carga[8:] 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)]) def dados_pacote_ipv4(carga): tupla_dados_ipv4 = struct.unpack("!BBHHHBBH4s4s", carga[:20]) versao = tupla_dados_ipv4[0] header_len = versao >> 4 tipo_servico = tupla_dados_ipv4[1] tamanho_total = tupla_dados_ipv4[2] identificacao = tupla_dados_ipv4[3] offset_fragmento = tupla_dados_ipv4[4] tempo_vida_ttl = tupla_dados_ipv4[5] protocolos = tupla_dados_ipv4[6] checksum_cabecalho = tupla_dados_ipv4[7] ip_origem = inet_ntoa(tupla_dados_ipv4[8]) ip_destino = inet_ntoa(tupla_dados_ipv4[9]) # correção tamanho_header_bytes = (versao & 15) * 4 # Cálculo Tamanho do header em bytes return versao, header_len, tipo_servico, + \ tamanho_total, identificacao, offset_fragmento, + \ tempo_vida_ttl, protocolos, checksum_cabecalho, ip_origem, ip_destino, carga[tamanho_header_bytes:] def dados_pacote_tcp(carga): tupla_dados_tcp = struct.unpack('! HHLLBBHHH', carga[:20]) porta_fonte = tupla_dados_tcp[0] porta_destino = tupla_dados_tcp[1] numero_sequencia = tupla_dados_tcp[2] numero_confirmacao = tupla_dados_tcp[3] # Esta linha recebe dois campos do cabeçalho ( HLEN & RESERVADO ) hlen_e_reservado = tupla_dados_tcp[4] # Esta linha recebe campo HLEN header_len = (hlen_e_reservado >> 4) * 4 flags = tupla_dados_tcp[5] flag_FIN = flags & 1 flag_SYN = (flags >> 1) & 1 flag_RST = (flags >> 2) & 1 flag_PSH = (flags >> 3) & 1 flag_ACK = (flags >> 4) & 1 flag_URG = (flags >> 5) & 1 flag_ECE = (flags >> 6) & 1 flag_CWR = (flags >> 7) & 1 window_size = tupla_dados_tcp[6] checksum = tupla_dados_tcp[7] urgent_pointer = tupla_dados_tcp[8] return porta_fonte, porta_destino ,numero_sequencia, + \ numero_confirmacao, hlen_e_reservado, header_len, + \ flags, flag_FIN, flag_SYN, flag_RST, flag_PSH, flag_ACK, + \ flag_URG, flag_ECE, flag_CWR, window_size, checksum, urgent_pointer , carga[:20] def dados_pacote_udp(carga): tupla_dados_udp = struct.unpack('! H H H H', carga[:8]) porta_fonte = tupla_dados_udp[0] porta_destino = tupla_dados_udp[1] udp_len = tupla_dados_udp[2] udp_checksum = tupla_dados_udp[3] return porta_fonte, porta_destino, udp_len, udp_checksum, carga[8:] 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("------- FRAME ETHERNET-----------") 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)) # A variavel (protocolo) está a referir-se ao # tipo de frame # Se for 8 vem ai pacote IP \0/ if protocolo == 8: """ Para desempacotar os valores da função dados_pacote_ipv4 com as variáveis aninhadas, necessáriamente elas têm que estar entre parênteses... """ ( versao, header_len, tipo_servico, tamanho_total, identificacao, offset_fragmento, tempo_vida_ttl, protocolos, checksum_cabecalho, ip_origem, ip_destino, carga ) = dados_pacote_ipv4(carga_util) print("--------- HEADER IPV4----------") print("Versão : {}".format(versao)) print("Header_len : {}".format(header_len)) print("Tipo Serviço : {}".format(tipo_servico)) print("Tamanho Total : {}".format(tamanho_total)) print("Identificação : {}".format(identificacao)) print("Offset Fragmento : {}".format(offset_fragmento)) print("Tempo vida TTL : {}".format(tempo_vida_ttl)) print("Protocolo : {}".format(protocolos)) print("checksum Cabeçalho : {}".format(checksum_cabecalho)) print("IP Origem: {}".format(ip_origem)) print("IP Destino: {}\n".format(ip_destino)) print("Carga : {}\n".format(carga)) if protocolos == 6: (porta_fonte, porta_destino, numero_sequencia, numero_confirmacao, hlen_e_reservado, header_len, flags, flag_FIN, flag_SYN, flag_RST, flag_PSH, flag_ACK, flag_URG, flag_ECE, flag_CWR, window_size, checksum, urgent_pointer, carga ) = dados_pacote_tcp(carga) print("--------- HEADER TCP----------") print("Porta Fonte : {}".format(porta_fonte)) print("Porta Destino : {}".format(porta_destino)) print("Número Sequência : {}".format(numero_sequencia)) print("Número Confirmação : {}".format(numero_confirmacao)) print("Hlen_e_reservado : {}".format(hlen_e_reservado)) print("Header_len : {}".format(header_len)) print("Flags : {}".format(flags)) print("Flag FIN : {}".format(flag_FIN)) print("Flag SYN : {}".format(flag_SYN)) print("Flag RST : {}".format(flag_RST)) print("Flag PSH : {}".format(flag_PSH)) print("Flag ACK : {}".format(flag_ACK)) print("Flag URG : {}".format(flag_URG)) print("Flag ECE : {}".format(flag_ECE)) print("Flag CWR : {}".format(flag_CWR)) print("window size : {}".format(window_size)) print("checksum : {}".format(checksum)) print("urgent pointer : {}\n".format(urgent_pointer)) print("carga : {}\n".format(carga)) elif protocolos == 17: porta_fonte, porta_destino, udp_len, udp_checksum, carga = dados_pacote_udp(carga) print("--------- HEADER UDP ----------") print("Porta Fonte : {}".format(porta_fonte)) print("Porta Destino : {}".format(porta_destino)) print("UDP Length : {}".format(udp_len)) print("UDP Checksum : {}\n".format(udp_checksum)) print("Carga : {}\n".format(carga)) """ 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. """ na função que fizemos para tratar os dados do pacote UDP, estamos a retornar o valor carga[8:], é nesses dados que vamos buscar o DNS, ao aceder ao site: https://www.mentebinaria.com.br podemos ver o dominio e o DNS... são esses dados que temos que tratar... abraços.
Recommended Posts
Archived
This topic is now archived and is closed to further replies.