Whole packet length Scapy - python

I am capturing WiFi traffic with tcpdump using the parameter -s 100 (which means I am only capturing the headers of the packets).
When I load the .pcap file and process it with Scapy I do:
pkts = rdpcap(pcapfile)
totalbytes = 0
for pkt in pkts:
totalbytes += len(pkt)
However, as I am truncating the capture, doing len(pkt) will not give me the whole packet length (frame length), it will give me the captured packet length. How can I get the real packet length?
Extra: as I have done in some occasions before, I open the pcap file in wireshark and search for the hex values of interest. But in this case (frame.len) will show the value I am looking for, but I can't find the way wireshark obtains this real packet length without having the whole packet captured.

The rdpcap function uses the PcapReader class for reading packets. Unfortunately this class discards the information you are looking for in the read_packet method, even though it is to be found in the pcap file. So you have to use the RawPcapReader directly.
totalbytes = 0
for pkt, (sec, usec, wirelen) in RawPcapReader(pcapfile):
totalbytes += wirelen

With modern Scapy versions, the proper answer would be to use pkt.wirelen. This only exists in packets read from a pcap

If for some reason you don't want to use RawPcapReader, you can use the len attribute for IPv4 packets.
real_length = pkt[IP].len
truncated_length = len(pkt)
Strangely, the IPv6 layer in Scapy doesn't have the same attribute, but it does have an attribute called plen which is the length of the payload:
payload_length = pkt[IPv6].plen
real_length = payload_length + 40
truncated_length = len(pkt)

Related

How to get the number of packets in a pcap file using scapy and python , without iterating

I need to obtain the number of packets in a pcap file using python and scapy, in an efficent way.
I now use the following python code:
from scapy import *
pcap_file = "path/to/pcap/file.pcap"
count = 0
for packet in scapy.PcapReader(pcap_file):
count += 1
But with big pcap files (hundreds of MB) it is not an efficient solution. Is there another way to obtain packets number without iterating all over them?
You can't. The pcap file format consists only of a file header followed by all the packet payloads preceded by a packet record header. Neither the file header contains a count of all packets, nor a packet record header contains the index of the current packet.
And while the pcapng format is more flexible it does not seem to be possible to get the number of packets without iterating either.

Modify bytes in Scapy script

I have a pcap file where I have packets like this :
Ether()/IP()/TCP()/Raw (this one for example)
I'd like to choose random 10 packets in the pcap file and modify 3 bytes in the Raw layer located at the same position in the whole 10 packets, and then save the pcap.
I did some tests but didn't achieve anything, I don't think it's the right way to do:
pkt = rdpcap('file.pcap')
for i in pkt:
if i.haslayer(TCP) and i.haslayer(Raw):
list_pkt.append(i)
rdm_list = random.sample(list_pkt,10)
for i in rdm_list:
org = i[Raw].load
new = org[:15] + '\xdd\xdd\xdd' + org[18:]
i[Raw].load = new
Any help please?

Raw load found, how to access?

To start off, I have read through other raw answers pertaining to scapy on here, however none have been useful, maybe I am just doing something wrong and thats what has brought me here today.
So, for starters, I have a pcap file, which started corrupted with some retransmissions, to my belief I have gotten it back to gether correctly.
It contains Radiotap header, IEEE 802.11 (dot11), logical-link control, IPv4, UDP, and DNS.
To my understanding, the udp packets being transmitted hold this raw data, however, do to a some recent quirks, maybe the raw is in Radiotap/raw.
Using scapy, I'm iterating through the packets, and when a packet with the Raw layer is found, I am using the .show() function of scapy to view it.
As such, I can see that there is a raw load available
###[ Raw ]###
\load \
|###[ Raw ]###
| load = '#\x00\x00\x00\xff\xff\xff\xff\xff\xff\x10h?'
So, I suppose my question is, how can I capture this payload to receive whatever this may be, To my knowledge the load is supposed to be an image file, however I have trouble believing such, so I assume I have misstepped somewhere.
Here is the code I'm using to achieve the above result
from scapy.all import *
from scapy.utils import *
pack = rdpcap('/home/username/Downloads/new.pcap')
for packet in pack:
if packet.getlayer(Raw):
print '[+] Found Raw' + '\n'
l = packet.getlayer(Raw)
rawr = Raw(l)
rawr.show()
Any help, or insight for further reading would be appreciated, I am new to scapy and no expert in packet dissection.
*Side note, previously I had tried (using separate code and server) to replay the packets and send them to myself, to no avail. However I feel thats due to my lack of knowledge in receipt of UDP packets.
UPDATES - I have now tested my pcap file with a scapy reassembler, and I've confirmed I have no fragmented packets, or anything of the sort, so I assume all should go smoothly...
Upon opening my pcap in wireshark, I can see that there are retransmissions, but I'm not sure how much that will affect my goals since no fragmentation occurred?
Also, I have tried the getlayer(Raw).load, if I use print on it I get some gibberish to the screen, I'm assuming its the data to my would-be-image, however I need to now get it into a usable format.
You can do:
data = packet[Raw].load
You should be able to access the field in this way:
l = packet.getlayer(Raw).load
Using Scapy’s interactive shell I was successful doing this:
pcap = rdpcap('sniffed_packets.pcap')
s = pcap.sessions()
for key, value in s.iteritems():
# Looking for telnet sessions
if ':23' in key:
for v in value:
try:
v.getlayer(Raw).load
except AttributeError:
pass
If you are trying to get the load part of the packet only, you can try :
def handle_pkt(pkt):
if TCP in pkt and pkt[TCP].dport == 5201:
#print("got a packet")
print(pkt[IP])
load_part = pkt[IP].load
print("Load#",load_part)
pkt.show2()
sys.stdout.flush()

Writing raw IP data to an interface (linux)

I have a file which contains raw IP packets in binary form. The data in the file contains a full IP header, TCP\UDP header, and data. I would like to use any language (preferably python) to read this file and dump the data onto the line.
In Linux I know you can write to some devices directly (echo "DATA" > /dev/device_handle). Would using python to do an open on /dev/eth1 achieve the same effect (i.e. could I do echo "DATA" > /dev/eth1)
Something like:
#!/usr/bin/env python
import socket
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
s.bind(("ethX", 0))
blocksize = 100;
with open('filename.txt') as fh:
while True:
block = fh.read(blocksize)
if block == "": break #EOF
s.send(block)
Should work, haven't tested it however.
ethX needs to be changed to your interface (e.g. eth1, eth2, wlan1, etc.)
You may want to play around with blocksize. 100 bytes at a time should be fine, you may consider going up but I'd stay below the 1500 byte Ethernet PDU.
It's possible you'll need root/sudoer permissions for this. I've needed them before when reading from a raw socket, never tried simply writing to one.
This is provided that you literally have the packet (and only the packet) dumped to file. Not in any sort of encoding (e.g. hex) either. If a byte is 0x30 it should be '0' in your text file, not "0x30", "30" or anything like that. If this is not the case you'll need to replace the while loop with some processing, but the send is still the same.
Since I just read that you're trying to send IP packets -- In this case, it's also likely that you need to build the entire packet at once, and then push that to the socket. The simple while loop won't be sufficient.
No; there is no /dev/eth1 device node -- network devices are in a different namespace from character/block devices like terminals and hard drives. You must create an AF_PACKET socket to send raw IP packets.

Capture TCP-Packets with Python

I try to capture an HTTP-download with Python using dpkt and pcap. The code looks like
...
pc = pcap.pcap(iface)
for ts, pkt in pc:
handle_packet(pkt)
def handle_packet(pkt):
eth = dpkt.ethernet.Ethernet(pkt)
# Ignore non-IP and non-TCP packets
if eth.type != dpkt.ethernet.ETH_TYPE_IP:
return
ip = eth.data
if ip.p != dpkt.ip.IP_PROTO_TCP:
return
tcp = ip.data
data = tcp.data
# current connection
c = (ip.src, ip.dst, tcp.sport, tcp.dport)
# Handle only new HTTP-responses and TCP-packets
# of existing connections.
if c in conn:
handle_tcp_packet(c, tcp)
elif data[:4] == 'HTTP':
handle_http_response(c, tcp)
...
In handle_http_response() and handle_tcp_packet() i read the data of the tcp-packets (tcp.data) and write them to a file. However i noticed that i often get packets with the same TCP sequence number (tcp.seq) (on the same connection) but it seems that they contain the same data. Moreover it seems that not all packets are captured. For example if i sum up the packet-sizes the resulting value is lower than the one listed in the http-header (content-length). But in Wireshark i can see all packages.
Does anyone has an idea why i get those duplicate packets and how i can capture every packet belonging to the http-response?
EDIT:
Here you can find the complete code: pastebin.com.
When running it prints something like that to stdout:
Waiting for HTTP-Audio-responses ...
...
New TCP-Packet, len=1440, tcp-payload=5107680, con-len=5197150 , dups=57 , dup-bytes=82080
New TCP-Packet, len=1440, tcp-payload=5109120, con-len=5197150 , dups=57 , dup-bytes=82080
New TCP-Packet, len=1440, tcp-payload=5110560, con-len=5197150 , dups=57 , dup-bytes=82080
----------> FIN <----------
New TCP-Packet, len=1937, tcp-payload=5112497, con-len=5197150 , dups=57 , dup-bytes=82080
New TCP-Packet, len=0, tcp-payload=5112497, con-len=5197150 , dups=57 , dup-bytes=82080
As you can see the TCP-payload plus the duplicate received bytes (5112497+82080=5194577) are lower than the filesize of the download (5197150). Moreover you can see that i receive 57 duplicate packages (same SEQ and same TCP-data) and that still packages are received after the packet with the FIN-flag.
So does anyone have an idea how i can capture all packets belonging to the connection? Wireshark sees all packets and i think it uses libpcap too.
I don't even know if i do something wrong or if the pcap-library does something wrong.
EDIT2:
OK, it seems that my code is correct: In Wireshark I saved the captured packets and used the capture-file in my code (pcap.pcap('/home/path/filename') instead of pcap.pcap('eth0')). My code read perfectly all packages (on multiple tests)! Since Wireshark uses libpcap too (afaik), i think the problem is the lib pypcap which does not provide me all packages.
Any idea on how to test that?
I already compiled pypcap by myself (trunk) but that didn't change anything -.-
EDIT3:
OK, I changed my code to work with pcapy instead of pypcap and have the same problem:
When reading the packets from a previous captured file (created with Wireshark) then everything is fine, but when I capture the packets directly from eth0 I miss some packets.
Interesting: When running both programs (the one using pypcap and the one using pcapy) in parallel they capture different packets. e.g. one programm receives one packet more.
But I have still no idea why -.-
I thought Wireshark uses the same base-lib (libpcap).
Please help :)
Here's a couple of things to watch out for:
make sure you have a big snaplen - for pcapy you can set it on open_live (second parameter)
make sure you handle fragmented packets - this will not be done automatically - you need to check the details
check statistics - unfortunately I don't think this is exposed to pcapy interface, but it's possible that you're not handling all packets; if you're too late you will not know that you missed something (although you can get the same information by tracking the length / position of tcp stream) libpcap itself does expose those statistics, so you might be able to add the function for it
Set the snaplen to 65535. Apparently this is the default for Wireshark:
http://www.wireshark.org/docs/wsug_html_chunked/ChCustCommandLine.html

Categories

Resources