Guest gnoo Posted December 31, 2018 at 10:59 PM Share Posted December 31, 2018 at 10:59 PM 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. Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.