import socket
import os
import struct
import sys
from ctypes import *
# host to listen on
host = sys.argv[1]
class IP(Structure):
_fields_ = [
("ihl", c_ubyte, 4),
("version", c_ubyte, 4),
("tos", c_ubyte),
("len", c_ushort),
("id", c_ushort),
("offset", c_ushort),
("ttl", c_ubyte),
("protocol_num", c_ubyte),
("sum", c_ushort),
("src", c_ulong),
("dst", c_ulong)
]
def __new__(self, socket_buffer=None):
return self.from_buffer_copy(socket_buffer)
def __init__(self, socket_buffer=None):
# map protocol constants to their names
self.protocol_map = {1:"ICMP", 6:"TCP", 17:"UDP"}
# human readable IP addresses
self.src_address = socket.inet_ntoa(struct.pack("<L",self.src))
self.dst_address = socket.inet_ntoa(struct.pack("<L",self.dst))
# human readable protocol
try:
self.protocol = self.protocol_map[self.protocol_num]
except:
self.protocol = str(self.protocol_num)
# create a raw socket and bind it to the public interface
if os.name == "nt":
socket_protocol = socket.IPPROTO_IP
else:
socket_protocol = socket.IPPROTO_ICMP
sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
sniffer.bind((host, 0))
# we want the IP headers included in the capture
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
# if we're on Windows we need to send some ioctls
# to setup promiscuous mode
if os.name == "nt":
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
try:
while True:
# read in a single packet
raw_buffer = sniffer.recvfrom(65565)[0]
# create an IP header from the first 20 bytes of the buffer
ip_header = IP(raw_buffer[0:20])
print "Protocol: %s %s -> %s" % (ip_header.protocol, ip_header.src_address, ip_header.dst_address)
except KeyboardInterrupt:
# if we're on Windows turn off promiscuous mode
if os.name == "nt":
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
Questo è il codice dal libro Black Hat Python. Questo codice dovrebbe annusare i socket grezzi e visualizzare le informazioni dall'intestazione IP. Funziona bene per me su Windows (usando Windows 8.1 a 64 bit). Quando si tenta di eseguire questo su Linux (Kali linux 1.1.0-amd64) ottengo il seguente errorePython Sniffing da Black Hat Python book
ValueError: Buffer size too small (20 instead of at least 32 bytes)
Per aggirare questo ho aggiunto 12 spazi per il buffer come questo
ip_header = IP(raw_buffer[0:20]+' '*12)
Quando lo faccio che ottengo il seguente errore
struct.error: 'L' format requires 0 <= number <= 4294967295
Ciò si verifica sulla linea
self.src_address = socket.inet_ntoa(struct.pack("<L",self.src))
Ho provato a cambiare il simbolo prima della L su> e! e l'ho provato con L tutti mi danno lo stesso problema. Ho anche provato self.src avvolgendoli in ntohs in questo modo
self.src_address = socket.inet_ntoa(struct.pack("<L",socket.ntohs(self.src)))
sto pensando questo ha qualcosa a che fare con endianness ma non sono sicuro. Qualsiasi aiuto sarebbe molto apprezzato.
NOTA: su Windows è necessario eseguire come amministratore e su Linux è necessario eseguire come superutente a causa dei socket non elaborati. Se lo esegui su Linux, apri un altro terminale e fai ping a www.google.com in modo da poter generare alcuni pacchetti ICMP da acquisire.
EDIT: Ho provato anche invertendo il buffer con
ip_header = IP(raw_buffer[0:20][::-1]+' '*12)
EDIT 2: ho provato sia 65535 e 65534 nella riga sotto prima di fare qualsiasi degli altri elementi che ho elencato qui.
raw_buffer = sniffer.recvfrom(65565)[0]
EDIT 3: Questo ha lavorato su una macchina Ubuntu in esecuzione pitone 2.7.6 e il mio kali distro era 2.7.3 così ho deciso di ottenere l'ultima versione di Python sulla mia casella di Kali che sembra essere 2.7.9 . Ancora senza fortuna.
ho messo il seguente codice alla nuova funzione nella mia struttura per visualizzare la dimensione di buffer
print sizeof(self)
Sulle mia macchine Ubuntu e finestre era 20 però sulla mia macchina kali era 32
il tuo codice funziona. sys.version '2.7.6 (predefinito, 22 marzo 2014, 22:59:38) \ n [GCC 4.8.2]'. 'uname -a' 'laptop Linux 3.16.0-25-generiC# 33-Ubuntu SMP mar 4 nov 12:05:25 UTC 2014 i686 i686 i686 GNU/Linux' –
prova a passare l'intero buffer' IP (raw_buffer) 'oppure 'IP (raw_buffer [: 32])' –
Interessante .. ho appena visto la versione di python che ho sulla mia macchina Linux che è 2.7.3 e la mia finestra è 2.7.8 ... proverò ad aggiornare e vedere cosa accade. –