I followed the tutorial below to implement a packet sniffer in Python:
http://www.binarytides.com/python-packet-sniffer-code-linux/
On receiving each UDP packet, I would like to send an already saved pcap file (test.pcap). The following snippet shows my implementation:
# receive a packet
while True:
packet = s.recvfrom(65565)
#packet string from tuple
packet = packet[0]
#parse ethernet header
eth_length = 14
eth_header = packet[:eth_length]
eth = unpack('!6s6sH' , eth_header)
eth_protocol = socket.ntohs(eth[2])
print 'Destination MAC : ' + eth_addr(packet[0:6]) + ' Source MAC : ' +
eth_addr(packet[6:12]) + ' Protocol : ' + str(eth_protocol)
if eth_addr(packet[6:12]) != my_MAC_address:
#Parse IP packets, IP Protocol number = 8
if eth_protocol == 8 :
#Parse IP header
#take first 20 characters for the ip header
ip_header = packet[eth_length:20+eth_length]
#now unpack them :)
iph = unpack('!BBHHHBBH4s4s' , ip_header)
version_ihl = iph[0]
version = version_ihl >> 4
ihl = version_ihl & 0xF
iph_length = ihl * 4
ttl = iph[5]
protocol = iph[6]
s_addr = socket.inet_ntoa(iph[8]);
d_addr = socket.inet_ntoa(iph[9]);
print 'Version : ' + str(version) + ' IP Header Length : ' + str(ihl) + ' TTL : ' + str(ttl) + ' Protocol : ' + str(protocol) + ' Source Address : ' + str(s_addr) + ' Destination Address : ' + str(d_addr)
#UDP packets
if protocol == 17 :
u = iph_length + eth_length
udph_length = 8
udp_header = packet[u:u+8]
#now unpack them :)
udph = unpack('!HHHH' , udp_header)
source_port = udph[0]
dest_port = udph[1]
length = udph[2]
checksum = udph[3]
print 'Source Port : ' + str(source_port) + ' Dest Port : ' + str(dest_port) + ' Length : ' + str(length) + ' Checksum : ' + str(checksum)
h_size = eth_length + iph_length + udph_length
data_size = len(packet) - h_size
#get data from the packet
data = packet[h_size:]
print 'Data : ' + data
my_pkt = rdpcap("test.pcap")
sendp(my_pkt)
Test.pcap contains a UDP packet with UDP_src=7777 and UDP_dest=9999.
Traffic is generated using netcat as follows:
nc -u -p 7777 ip_dst_addr 9999
The sniffer can receive only first netcat msg and send test.pcap in response. But subsequent netcat msgs are not received at all. However, using any other combination of UDP ports in netcat, the sniffer works fine. For example: running netcat as:
nc -u -p 8888 ip_dst_addr 9999
there is no problem and I am able to send test.pcap in response to each UDP packet/msg.
Any help would be greatly appreciated!
Scapy has several built-in sniffers, that are really easy to use.
>>> help(sniff)
Help on function sniff in module scapy.arch.windows.compatibility:
sniff(count=0, store=1, offline=None, prn=None, stop_filter=None, lfilter=None, L2socket=None, timeout=None, *arg, **karg)
Sniff packets
sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets
Select interface to sniff by setting conf.iface. Use show_interfaces() to see interface names.
count: number of packets to capture. 0 means infinity
store: whether to store sniffed packets or discard them
prn: function to apply to each packet. If something is returned,
it is displayed. Ex:
ex: prn = lambda x: x.summary()
filter: provide a BPF filter
lfilter: python function applied to each packet to determine
if further action may be done
ex: lfilter = lambda x: x.haslayer(Padding)
offline: pcap file to read packets from, instead of sniffing them
timeout: stop sniffing after a given time (default: None)
L2socket: use the provided L2socket
stop_filter: python function applied to each packet to determine
if we have to stop the capture after this packet
ex: stop_filter = lambda x: x.haslayer(TCP)
Which means you could simply do:
packets = rdpcap("test.pcap")
sniff(lfilter=lambda x: x.haslayer(UDP) and x[Ether].src==sending_mac and x[UDP].sport==port, prn=lambda x: send(packets))
This will append all UDP packets to the test.pcap file
Related
I tried to sniff DNS request packets on mon0 interface, using scapy.
I wanted to send back a spoofed IP.
But I get an error:
AttributeError: 'Ether' object has no attribute 'FCfield'
Code:
def send_response(x):
x.show()
req_domain = x[DNS].qd.qname
logger.info('Found request for ' + req_domain)
# First, we delete the existing lengths and checksums..
# We will let Scapy re-create them
del(x[UDP].len)
del(x[UDP].chksum)
del(x[IP].len)
del(x[IP].chksum)
response = x.copy()
response.FCfield = '2L'
response.addr1, response.addr2 = x.addr2, x.addr1
# Switch the IP addresses
response.src, response.dst = x.dst, x.src
# Switch the ports
response.sport, response.dport = x.dport, x.sport
# Set the DNS flags
response[DNS].qr = '1L'
response[DNS].ra = '1L'
response[DNS].ancount = 1
response[DNS].an = DNSRR(
rrname = req_domain,
type = 'A',
rclass = 'IN',
ttl = 900,
rdata = spoofed_ip
)
#inject the response
sendp(response)
logger.info('Sent response: ' + req_domain + ' -> ' + spoofed_ip + '\n')
def main():
logger.info('Starting to intercept [CTRL+C to stop]')
sniff(prn=lambda x: send_response(x), lfilter=lambda x:x.haslayer(UDP) and x.dport == 53)
Your interface is probably not configured in monitor mode, that's why you get an ethernet (Ether) layer, and not a WiFi (Dot11) layer.
I'm attempting to read incoming/outgoing TCP packets through an interface on the host for a project I'm working on. I really want this to be done using sockets instead of using a library like scapy or pypcap. To have a better understanding of what is happening as well as more control over what is happening. This is on a Windows10 system.
import socket
import threading
from PacketParse import PacketParse
host = socket.gethostbyname(socket.gethostname())
sniff = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
sniff.bind((host, 0))
#include ip headers - IP PROTOCOL, IP HEADER INCLUDE
sniff.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
#receive all packages - INPUT OUTPUT CONTROL
sniff.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
def start_sniffing():
while True:
raw_packet = sniff.recvfrom(2000)
packet = PacketParse(raw_packet)
if packet:
print(packet.src_addr + ":" + str(packet.src_port) + " --> " + packet.dst_addr + ":" + str(packet.dst_port) + " Protocol: " + packet.ip_prot + "(" + str(packet.ip_prot_raw) + ")")
print("Data(" + str(packet.data_size) + "): " + str(packet.data))
#file.write(packet.src_addr + ":" + str(packet.src_port) + " --> " + packet.dst_addr + ":" + str(packet.dst_port) + " Protocol: " + packet.ip_prot + "(" + str(packet.ip_prot_raw) + ")")
#file.write("Data(" + str(packet.data_size) + "): " + str(packet.data))'''
file = open("dump.txt", "a")
t = threading.Thread(target=start_sniffing)
t.start()
t.join()
file.close()
sniff.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
PacketParse is a class I made to 'unpack' the packet. I've been using Python documentation for most of this script and tutorials for sniffing packets from many sources.
from struct import unpack
class PacketParse:
def __init__(self, packet):
self.extract(packet)
def extract(self, packet):
# extract ip header
packet = packet[0]
self.packet_raw = packet
'''
eth_raw = packet[:14]
eth_hdr = unpack('!6s6sH', eth_raw)
self.eth_prot = socket.ntohs(eth_hdr[2])
self.src_mac =
'''
ip_raw = packet[0:20]
ip_hdr = unpack('!BBHHHBBH4s4s', ip_raw)
#self.ip_length = ip_hdr[5]
self.ip_prot_raw = ip_hdr[6]
self.ip_prot = self.ip_prot_parse(ip_hdr[6])
self.src_addr = socket.inet_ntoa(ip_hdr[8])
self.dst_addr = socket.inet_ntoa(ip_hdr[9])
version = ip_hdr[0] >> 4
ihl_length = version & 0xF
iph_len = ihl_length * 4
tcp_raw = packet[20:40]
tcp_hdr = unpack('!HHLLBBHHH', tcp_raw)
self.src_port = tcp_hdr[0]
self.dst_port = tcp_hdr[1]
self.seq_num = tcp_hdr[2]
self.ack_num = tcp_hdr[3]
doff_reserved = tcp_hdr[4]
tcp_length = doff_reserved >> 4
header_size = (iph_len) + (tcp_length * 4)
self.data_size = len(packet) - header_size
self.data = packet[header_size:]
def ip_prot_parse(self, num):
return {
1: 'ICMP',
6: 'TCP',
17: 'UDP',
}.get(num, "Unknown")
The issue is this only shows packets being sent out from this host. Incoming packets are not displayed. A different script I've tried using scapy is capable of displaying incoming packets as well. Why is this happening? SIO_RCVALL should be allowing ALL packets being touched by the interface to be seen. I haven't tried a Linux equivalent of this script... so I don't know if the problem is specific on Windows. Most TCP reading scripts I've found have been Linux specific.
Alright... so it seems the problem was my firewall. When I turn it off, I can see all incoming packets just fine. That was a bit annoying. I believe there is a python library that allows you to edit firewall settings.
https://github.com/austin-taylor/bluewall
I haven't played around with it yet... it could be interesting. I haven't read into it enough yet to understand if this is what it seems. I believe it only gives you the configuration on Windows without changing anything. It could be fun on a Linux system.
I want to build "SIP sniffer" for my project to alert incoming call from VoIP communication.I try to call from my smartphone to my notebook and check incoming packet by wireshark. I see all SIP-message ( INVITE , BYE , TRYING ). I know basic of SIP ,it use UDP port 5060.
Next, I use this code from http://www.binarytides.com/python-packet-sniffer-code-linux/ <<--- last code , longest code ( I try to paste but I can't paste code in box ) run with Raspberry PI connect to notebook by LAN cable.
This program can sniff UDP packet, I check in wireshark it correct 90% ( IP address and IP destination not correct ) port and payload are correct. I checking header from ethernet header ===> ip header ===> udp header
it not different from SIP-INVITE , they different only payload ( check by wireshark ).
but i try to VoIP call to my notebook, It's not work , it never sniff 5060 or SIP packet ( one time i see outgoing call data : "sip:xxxx#linphone.org" )
Why i can sniff other but VoIP can't.
Sorry for my poor english.
thank you for your advice.
From the quick look , I see that your packets are UDP.
But the python code only sniffs for TCP.
#create an INET, raw socket s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
change socket.IPPROTO_TCP to socket.IPPROTO_UDP
#UDP packets
elif protocol == 17 :
u = iph_length + eth_length
udph_length = 8
udp_header = packet[u:u+8]
#now unpack them :)
udph = unpack('!HHHH' , udp_header)
source_port = udph[0]
dest_port = udph[1]
length = udph[2]
checksum = udph[3]
print 'Source Port : ' + str(source_port) + ' Dest Port : ' + str(dest_port) + ' Length : ' + str(length) + ' Checksum : ' + str(checksum)
h_size = eth_length + iph_length + udph_length
data_size = len(packet) - h_size
#get data from the packet
data = packet[h_size:]
print 'Data : ' + data
#some other IP packet like IGMP
else :
print 'Protocol other than TCP/UDP/ICMP'
print
I have captured some traffic and stored on a .pcap file. In there, an ARP poisoning attack occured.
Is there a way of detecting the attacker's IP and MAC adress and victim's IP and MAC adress using scapy in a python script?
I believe a script like this one would do the job
#! /usr/bin/python
from scapy.all import *
pkts = rdpcap('capture2.pcap')
#these are from wireshark
ipadr=['192.168.0.1','192.168.0.2','192.168.0.3','192.168.0.30']
macadr['00:03:ff:98:98:01','00:03:ff:98:98:02','00:03:ff:98:98:03','00:03:ff:98:98:30']
c=-1
for p in pkts:
c=c+1
if p.haslayer(ARP):
#find a packet where p.dst and p.pdst isn't a valid pair
if p.dst != 'ff:ff:ff:ff:ff:ff':
if not(( ipadr[0]==p.pdst and macadr[0]==p.dst ) or ( ipadr[1]==p.pdst and macadr[1]==p.dst) or ( ipadr[2]==p.pdst and macadr[2]==p.dst ) or ( ipadr[3]==p.pdst and macadr[3]==p.dst )) :
print 'packet data ' +p.psrc +" "+p.src+" " + p.pdst + " " + p.dst +" "+str(c)
print 'packet number = ' + str(c)
print 'MAC of attacker = ' + p.dst
print 'IP of attacker = ' + ipadr[macadr.index(p.dst)]
print 'MAC of target = ' + p.src
print 'IP of target = ' + p.psrc
I'm trying to write a socket server in Python that can receive ICMP packets.
Here's my code:
s = socket.socket(socket.AF_INET,socket.SOCK_RAW, socket.IPPROTO_ICMP)
host = socket.gethostbyname(socket.gethostname())
s.bind((host,0))
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
However, I dont know how to receive the packets - I tried using s.listen but it failed.
What am I missing or am I completly in the wrong direction?
Thanks!
I've done this before in twisted and I set the socket up like this:
import socket
def listen():
s = socket.socket(socket.AF_INET,socket.SOCK_RAW,socket.IPPROTO_ICMP)
s.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1)
while 1:
data, addr = s.recvfrom(1508)
print "Packet from %r: %r" % (addr,data)
Building on the accepted answer, this code unpacks the received ICMP header and displays its data (ICMP type, code, etc)
s = socket.socket(socket.AF_INET,socket.SOCK_RAW,socket.IPPROTO_ICMP)
s.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1)
while 1:
recPacket, addr = s.recvfrom(1024)
icmp_header = recPacket[20:28]
type, code, checksum, p_id, sequence = struct.unpack('bbHHh', icmp_header)
print "type: [" + str(type) + "] code: [" + str(code) + "] checksum: [" + str(checksum) + "] p_id: [" + str(p_id) + "] sequence: [" + str(sequence) + "]"