Python - Pcapy to Scapy on SPAN port, odd behaviour - python

I built a network sniffer in Scapy but it can't handle the rate of packets I am sniffing (it adds 15-20 minutes of latency which is just unacceptable). I have used Pcapy before in the past at this speed with success, but this time to save me having to re-write all my parsing code that uses Scapy, I want to convert a packet received by Pcapy into a Scapy IP object. The problem is when I try to do this, the IP's and protocol numbers I get are scrambled/unusable, like Scapy is reading the wrong section of the packet.
Some example code below:
#!/usr/bin/python
from pcapy import findalldevs, open_live
from impacket import ImpactDecoder, ImpactPacket
from scapy.all import *
def sniff():
interface = "eth3"
print "Listening on: %s" % interface
# Open a live capture
reader = open_live(interface, 65535, 1, 100)
# Set a filter to be notified only for TCP packets
reader.setfilter('ip proto \\tcp')
# Run the packet capture loop
reader.loop(0, callback)
def callback(hdr, data):
pkt = IP(data)
if IP in pkt:
print pkt[IP].dst
# Parse the Ethernet packet
#decoder = ImpactDecoder.EthDecoder()
#ether = decoder.decode(data)
# Parse the IP packet inside the Ethernet packet
#iphdr = ether.child()
# Parse the TCP packet inside the IP packet
#tcphdr = iphdr.child()
# Only process SYN packets
#if tcphdr.get_SYN() and not tcphdr.get_ACK():
# # Get the source and destination IP addresses
# src_ip = iphdr.get_ip_src()
# dst_ip = iphdr.get_ip_dst()
# # Print the results
# print "Connection attempt %s -> %s" % (src_ip, dst_ip)
def main():
sniff()
if __name__ == "__main__":
main()
And an example of the output:
30.184.113.84
0.120.231.205
30.184.113.91
5.64.113.97
0.120.231.206
21.248.113.98
0.120.231.207
0.120.231.208
0.120.231.209
0.120.231.210
0.120.231.211
0.48.243.73
As you can see these IP's dont make sense, where do you think I am going wrong. Eth3 is connected to a NetGear mirror port.
Thanks for your time.

Never mind, just me being an idiot, I blame bank-holiday Mondays. I was trying to detect the packet from the wrong layer. Convert raw to Ether and Scapy does the rest of the work for me.
def callback(hdr, data):
pkt = Ether(data)
if IP in pkt:
print pkt[IP].dst
else:
print list(pkt)
Cheers

Related

scapy sniffed udp packets can not be received after sending to another host

I am trying to send udp packets sniffed by scapy to another host. The host address is reachable through my default gateway.
In the host I listen to the destination port 10000 by tcpdump, but the packets are not received.
My code is this:
from scapy.all import *
class Des:
def __init__(self, port):
self.port = port
def send_packets(port):
des = Des(port)
def get_pack(packet):
pkt = packet.copy()
pkt['IP'].dst= "192.168.20.111" # address of the destination host
pkt['IP'].src = "192.168.12.111" # address of my system
pkt['UDP'].dport = des.port
pkt['Ethernet'].dst = dst_mac
pkt['Ethernet'].src = src_mac
send(pkt)
return get_pack
sniff(filter = 'udp and port 50000', prn = send_packets(10000))
If I send the packets to another host 192.168.12.112 in my network the problem still exists. In this scenario if I replace the send line with the following line, these packets will be received in the destination!
send(IP(dst='192.168.12.112')/UDP(dport=10000))
While replacing it with the following line, results in no receiving packets in host 192.168.20.111.
send(IP(dst='192.168.20.111')/UDP(dport=10000))
I searched for the problem but found no result. The firewall in the both side is disabled and scapy has the routing path as the following output.
>>> conf.route
Network Netmask Gateway Iface Output IP
0.0.0.0 0.0.0.0 192.168.12.1 vr0 192.168.12.111
192.168.12.0 255.255.255.0 0.0.0.0 vr0 192.168.12.111
Furthermore, tcpdump on my output interface shows that when using
send(IP(dst='ANY_DST)/UDP(dport=ANY_PORT))
the packets are going out, but when I send the sniffed packets, they don't!
Where did I go wrong?
May the problem be with the changed packets? They are RTP packets containing payload.
I am very new to python and scapy. Any help can be a light to move in the right direction. Thanks for your time.
My OS is FreeBSD9.2 and i am using python 2.7 and scapy (2.2.0).
if I replace the send line with the following line, these packets will
be received in the destination!
send(IP(dst='192.168.12.112')/UDP(dport=10000))
After debugging the code and checking the source of scapy, I found the reason of the above problem. When I call send(pkt), From class L3dnetSocket following function is called.
def send(self, x):
iff,a,gw = x.route()
# Rest of the code is ignored here
Here object x is of class Packet and its route function always returns None for gateway! So the packet will be send in layer 2.
def route(self):
return (None,None,None)
While when I call send(IP(dst='192.168.12.112')/UDP(dport=10000)), type of object x is class IP that it's route function returns the correct gateway.
def route(self):
dst = self.dst
if isinstance(dst,Gen):
dst = iter(dst).next()
return conf.route.route(dst)
Finally, I changed my code as the following and it works correctly :)
def send_packet(port):
des = Des(port)
def get_pack(packet):
udp = UDP()
udp.sport = packet[UDP].sport
udp.dport = des.port
udp.len = packet[UDP].len
ip = IP()
ip.version = packet[IP].version
ip.tos = packet[IP].tos
ip.len = packet[IP].len
ip.id = packet[IP].id
ip.flags = packet[IP].flags
ip.frag = packet[IP].frag
ip.ttl = packet[IP].ttl
ip.proto = packet[IP].proto
ip.dst = '192.168.12.112'
payload = packet[Raw].load
pkt = ip/udp/payload
pkt = pkt.__class__(bytes(pkt))
send(pkt)
return get_pack
Furthermore, the reason that the packets were not received in my reachable networks, was from my network :)

What is the best way to fork scapy in order to duplicate packets

I have a pretty simple script which supposed to duplicate packets using scapy:
from scapy.all import *
import pprint
ips = [
"192.168.0.1",
"192.168.0.2",
"192.168.0.3",
"192.168.0.4",
"192.168.0.5",
"192.168.0.6",
"192.168.0.7"
]
def dup_pkt(pkt):
pprint.pprint(pkt)
if pkt[IP].dst == "10.0.0.1":
for ip in ips:
pkt2 = copy.deepcopy(pkt)
pkt2[IP].dst = ip
print "Packet1:",pkt[IP].dst,"Packet2:",pkt2[IP].dst
send(pkt2)
pkts = sniff(prn=dup_pkt, filter="port 53", store=0, count=2)
Instead of the for loop, I wish to send it to the multiple destination all at once. I thought about forking processes which each one will send the packets but it still leaves me with the for loop.
Also - send() is very slow, but sendp() does not fit as I have different destinations.
I've read this one: how to send one udp packet multiple time in scapy ? but there is no answer there.
How can I send multiple packets at once?
Thanks
The send() function can receive a list of packets to send:
def dup_pkt(pkt):
pprint.pprint(pkt)
if pkt[IP].dst == '10.0.0.1':
pkts = []
for ip in ips:
pkt2 = pkt.copy() # use the copy method rather than copy.deepcopy
pkt2[IP].dst = ip
pkts.append(pkt2)
print "Packet1: ", pkt[IP].dst, " Packet2: ", pkt2[IP].dst
send(pkts) # send all packets at once

Sending a ICMPv6 Packet with VLAN while using Impacket

Hey guys I am quite a bind I have this function
def send_ra_packet(self,source_link_layer, send_frequency,vlan_id = 0):
ip = IP6.IP6()
ip.set_source_address(self.get_source_address())
ip.set_destination_address(self.get_target_address())
ip.set_traffic_class(0)
ip.set_flow_label(0)
ip.set_hop_limit(64)
s = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_ICMPV6)
payload = self.create_ra_message(source_link_layer)
print send_frequency
for i in range(0, send_frequency):
icmp = ICMP6.ICMP6()
icmp.set_byte(0, 134) # Put Type?
icmp.set_byte(1, 00) # Put Code?
payloadObject = ImpactPacket.Data()
payloadObject.set_data(payload)
icmp.contains(payloadObject)
# Have the IP packet contain the ICMP packet (along with its payload).
ip.contains(icmp)
ip.set_next_header(ip.child().get_ip_protocol_number())
ip.set_payload_length(ip.child().get_size())
eth = ImpactPacket.Ethernet()
vlan = ImpactPacket.EthernetTag()
vlan.set_vid(1)
eth.push_tag(vlan)
icmp.calculate_checksum()
eth.contains(ip)
print icmp.get_packet()
# Send it to the target host.
s.sendto(eth.get_packet(), (self.get_target_address(), 0))
print "Success Sending Packet - %d " % (i)
A quick overview of the function will tell you that I am creating a RA Packet and sending it in my network, my problem here is that I can't seem to send an RA Packet with VLAN.
My additional code starting from eth = ImpacketPacket.Ethernet()
will tell you I created a Header that has a VLAN and made it as a parent of ip which has the instance IPV6.
My problem is that when ever I run the code the resulting packet that will be sent is Uknown (0)
which means that it is either corrupted or cannot be understand.
I am quite stuck with this problem for almost a week now and tried numerous ways to send it. I am not sure anymore what is the bug, if ever I send the packet with icmp instead of eth it works fine`

Python sends malformed UDP Packets

I am having trouble receiving UDP packets on an Android device, so I want to find out if I am sending them properly. Using Wireshark, everytime I try to send a UDP packet to a remote address, the following error message occurs:
232646 311.898009000 172.56.16.78 192.168.0.3 UDP 64 Source port: 31947 Destination port: 5001 [ETHERNET FRAME CHECK SEQUENCE INCORRECT]
Frame check sequence: 0xf5b6d06d [incorrect, should be 0xb0c869e3]
Does anyone know how to fix this? Would this be the cause of why I could not receive UDP packets on my Android device?
Server Code:
import http.server
import socket
import threading
import socketserver
class ThreadedUDPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
data = self.request[0].strip().decode("utf-8")
print("{} Recieved: ".format(self.client_address) + data)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
response = data.upper()
sock.sendto(bytes(response, "utf-8"), self.client_address)
print("{} Sent: {}".format(self.client_address,response))
if __name__ == "__main__":
udpserver = ThreadedUDPServer((HOST,PORT+1), ThreadedUDPRequestHandler)
udp_thread = threading.Thread(target=udpserver.serve_forever)
udp_thread.daemon = True
udp_thread.start()
print("UDP serving at port", PORT+1)
while True:
pass
udpserver.shutdown()
It seems like you're sending packets using regular userspace sockets. In that case, there's very little chance that the packets are being sent malformed since the FCS is generated physically by the network interface card.
What you're probably seeing is an FCS error due to completely different reasons, which can be safely disregarded.
I'd look for other reasons for why the other device doesn't receive the packet, like firewalls or NAT. Start by using netcat or a similar tool for sending and receiving the UDP packets between the two machines.

Python raw socket not receiving ICMP packets

I'm trying to use raw sockets in Python to send UDP packets to a host and then get the ICMP response back for the packet -- basically reimplementing traceroute.
I've managed to correctly construct my IP and UDP headers and send the packet. I can see it in Wireshark. I also see the ICMP response in Wireshark telling me that the TTL exceeded.
I have the following code:
me = gethostbyname(gethostname())
my_socket = socket(AF_INET, SOCK_RAW)
my_socket.setsockopt(IPPROTO_IP, IP_HDRINCL, 1)
my_socket.bind((me, 0))
hostname = 'www.google.com'
hostip = gethostbyname(hostname)
packet = create_packet(hostname)
send_socket.sendto(packet, (hostip , 0))
Then after the packet is sent I call another function to listen for incoming packets which includes this snippet:
while True:
ready = select.select([my_socket], [], [], time_left)
if ready[0] == []:
print "timeout"
time_now = time.time()
rec_packet, addr = my_socket.recvfrom(5120)
unpacked_ip = unpack('!BBHHHBBH4s4s', rec_packet[0:20]) #0-20 is IP header
prot = unpacked_ip[6] #gives the protocol id
if prot == 1:
#this is ICMP , let's do things
I'm able to successfully unpack the IP header and check the protocol, but it is always either 6 or 17 (TCP or UDP). I never get the IP packet containing the ICMP payload even though it appears in Wireshark.
I've tried comparing the ICMP packet in Wireshark to other packets in Wireshark that my program does see and the IP headers are pretty much identical. I don't know what is wrong.
Thanks for the help
Judging from this answer, it looks like you need to pass the IPPROTO_ICMP option in when you create your socket.
You can do this like:
my_socket = socket.socket(socket.AF_INET,socket.SOCK_RAW,socket.IPPROTO_ICMP)

Categories

Resources