Specifying packet length with scapy - python

I'm trying to send a specific packet size (100 bytes) with scapy but cant seem to get it.
I'm using this to start.
sr(IP(dst="192.168.1.1")/TCP(dport=443))
Looking at the docs / help I cant tell if I can use PacketLenField to specify the length of the packet. I can do it with NMAP & NSE but would like to do it outside of NMAP.
Any ideas on this one?
Thanks!

You can just add on the required number of bytes as a String when crafting the packet e.g.:
payload = 'ZZZZZZZZZZZZZZZZZZZZZ'
pkt = Ether() / IP() / TCP() / payload
will work. You just need to adjust the length of the payload as you require.

Scapy's Raw() function populates the payload of the packet. If you know your header size, you only need to fill in the remaining bytes with random data.
You can use RandString() to generate random padding. The following command sends a packet of length 100 (and listens for a response):
sr(IP(dst="192.168.1.1")/TCP(dport=443)/Raw(RandString(size=72))

You may use inet.Padding() from scapy library:
packet = IP(dst="192.168.1.1")/TCP(dport=443)
if len(packet)<100:
#"\x00" is a single zero byte
myString = "\x00"*(100 - len(packet))
packet = packet/inet.Padding(myString)

Related

Scapy: get/set frequency or channel of a packet

I have been trying to capture WIFI packets with Linux and see the frequency/channel at which packet was captured. I tried Wireshark and there was no luck and no help. Though using a sample packets from Wireshark, I can see the frequency/channel.
So now I'm experimenting with Scapy. I wanted to figure out the frequency/channel of a sniffed packet, but still no luck. Is there a way to do this with Scapy.
P.S.
If there is a better tool than Scapy, or Python, I appreciate comments
I found out that RadioTab headers are not part of any Dot11 protocol but are merely added by the network interface. And the reason I got the RadioTab headers on sample packets from Wireshark.org and not from my live wireshark capture is because some network adapters do not add RadioTap while others do and the network adapter of my laptop does not add RadioTab headers. I checked this with a new external WiFi adapter and it did add the RadioTap headers.
If the adapter does not inject the additional information as it captures frames, then no radiotap headers will be added.
So to my main question, how to get/set frequency of a packet.
I expected Scapy to have this option but it doesn't, and it shouldn't. The reason is that the frequency depends on what is set on the network adapter. So what I did was to set the frequency/channel of my WiFi adapter to a different one. My external WiFi adapter can work in various channels so I changed each and confirmed with the RadioTap header. There are a simple linux commands/tools that helped me check the supported channels of my WiFi interface, and switch to a particular channel.
To capture/send packets at a certain frequency or channel, you need to change the working channel of your interface and set the sniffer/sender interface in scapy to that interface.
EDIT - Other problems I faced and solutions:
If you are on linux, and you want to change the working channel of your interface you need to disable network-manager for that interface and to do this
First
Add the following snippet to /etc/network/interfaces
auto $iface
iface $iface inet dhcp
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
replace $iface with your interface name. This will let you control the interface by yourself. And then add the following lines to /etc/wpa_supplicant/wpa_supplicant.conf
ctrl_interface=/var/run/wpa_supplicant
network={
ssid="Your_AP_SSID"
psk="Your_Passphrase"
freq_list=2412 2437 2462
}
Note that 2412 2437 2462 are the frequencies (channel 1, 6, 11 in this case) for your interface to choose from. You can edit them to desired frequency. Source. But first you have to check that your interface supports these frequencies. To check that
iwlist channel
Finally after everything is done.
sendp(Ether()/IP(dst="1.2.3.4",ttl=(1,4)), iface="wlp3s0")
This will send you packets at the frequency that wlp3s0 is set.
This answer is scoped to the question's title and content: Providing getters and setters for frequency and channel of a packet.
For this solution, use the wpa-Induction.pcap file in Wireshark's Sample Captures.
Poking around
It's useful to poke around one packet to see what fields Scapy has access to in the Scapy interpreter.
>>> pkts = rdpcap('wpa-Induction.pcap')
>>> pkts[0].summary()
"RadioTap / Dot11FCS / Dot11Beacon / Dot11Elt / Dot11EltRates / Dot11Elt / Dot11Elt / Dot11Elt / Dot11Elt / Dot11EltRSN / Dot11Elt / Dot11EltVendorSpecific / Dot11EltMicrosoftWPA / SSID=''"
>>> pkts[0].show()
###[ RadioTap dummy ]###
version= 0
pad= 0
len= 24
present= Flags+Rate+Channel+Lock_Quality+Antenna+dB_AntSignal+RXFlags
Flags= FCS
Rate= 2
Channel= 2412
ChannelFlags= CCK+2GHz
Antenna= 84
notdecoded= '\x00\x00+\x00\x00\x9fa\xc9\\'
... <output truncated> ...
While 2412 is a frequency and NOT a channel, this is the data we want. RadioTap is the layer per pkts[0].summary(). Putting it together,
>>> frequency = pkts[0][RadioTap].Channel
>>> print(frequency)
2412
Scapy does not provide access to the channel, but it's trivial to convert frequency to channel.
Putting it Together
Getting the Frequency
Given a file and packet number, we can now get the channel and frequency for a packet.
from scapy.all import RadioTap, rdpcap
def getChannel(frequency):
base = 2407 # 2.4Ghz
if frequency//1000 == 5:
base = 5000 # 5Ghz
# 2.4 and 5Ghz channels increment by 5
return (frequency-base)//5
def getFrequency(file, packet_number):
pkts = rdpcap(file)
# Scapy mixes up Channel/Frequency here
frequency = pkts[packet_number][RadioTap].Channel
return frequency
freq = getFrequency('wpa-Induction.pcap', 0)
chan = getChannel(freq)
print("Channel: {0} \nFrequency: {1}".format(freq, chan))
Setting the Frequency
Let's say we wanted to change the frequency to 5300 and save it. This would only require iterating over the packet list, change the frequency for every packet, and saving the result. In the scapy interpreter:
>>> for i in range(len(pkts)):
... pkts[i][RadioTap].Channel = 5300
>>> wrpcap('temp.pcap', pkts)
>>> pkts2 = rdpcap('temp.pcap')
>>> pkts[0].Channel
5300

Is there an efficienct way to get field offset in pyshark

Is there an efficient way to get the offset of some field in a packet captured with pyshark?
For example, I need to get the offset of the source IP within the whole packet or within some layer header in the packet. Is it possible?
I was able to solve my issue. Here is a sample code:
import pyshark
packets = pyshark.FileCapture(input_file=pcap_file_dir)
print(int(packets[0].ip.src.pos)) # Prints the offset of source IP

How to extract an SSL/TLS message using scapy and python?

I'm trying to read a TLS message. Specifically, the one with the certificate details (handshake_type = 11). What I'm doing is first checking that the message contains Raw. If so, I'm extracting the payload like so: b = bytes(pkt[Raw].load). Next, I'm checking that the first byte is 0x16 and the following two bytes need to be a proper TLS version.
The problem is that this message doesn't pass these conditions. WireShark is showing me that \x16\x03\x03 are the bytes at position 0000 (picture is attached), but I guess it is done for convenience.
So is my assumption that the payload MUST start with 0x16 wrong?
P.S
I don't want to use scapy-ssl_tls library.
EDIT
This is the code:
def handle_tls_packet(pkt):
if pkt.haslayer(Raw):
b = bytes(pkt[Raw].load)
if b[0] == 0x16:
version = int.from_bytes(b[1:3], 'big')
message_len = int.from_bytes(b[3:5], 'big')
handshake_type = b[5]
handshake_length = int.from_bytes(b[6:9], 'big')
print("v = ", version, " len = ", message_len, " htype =", handshake_type
, "hlen =", handshake_length)
if handshake_type == 11:
# never happens - Why?
certs_len = int.from_bytes(b[7:11], 'big')
EDIT2:
As suggested by Cukic0d, I used load_layer("ssl").
Apparently, pkt[TLS].msg is a list (to hold multiple TLS messages in one packet?). Anyways, I printed the type of every such message like so:
def handle_tls_packet(pkt):
for tls_msg in pkt[TLS].msg:
print(type(tls_msg))
I expected to see a TLSCertificate object, yet such object is never seen.
Why?
EDIT3:
I'm willing to use scapy-ssl_tls if that would make life easier.
If you want to play with TLS handshake, enable TLS on scapy using load_layer("tls").
That enables the TLS module, which supports handshake (requires scapy >= 2.4.0). Scapy will then correctly dissect TLS handshake/key... packets
You should first try
load_layer("tls")
packets = sniff(prn=lambda x:x.summary(), lfilter=lambda x: TLS in x)
And if you're using Scapy 2.4.4+, for better consistency you can even use
sniff([...], session=TLSSession)
Have a look on how the packets are built:
Example:
There is also a quite fancy guide here: https://github.com/secdev/scapy/blob/master/doc/notebooks/tls/notebook2_tls_protected.ipynb
So summarize:
You will find each packet when using load_layer("tls").
Note that there are a lot of packets and that TLSCertificate will only appear once. msg is a list because many informations can be contained in a single TLS packet

Scapy: fields to recompute when forging packets

I'm forging with Scapy the TTL value in the IP header in some data packet that I captured. Besides the checksum in both IP and transport layer headers, is there anything else I should recompute?
Right now I'm doing:
for p in myPackets:
p[IP].ttl = targetTTL
del(p[IP].chksum)
del(p[IP].payload.chksum)
for i in range(len(myPackets)):
myPackets[i] = myPackets[i].__class__(str(myPackets[i]))
I'm asking this because Scapy's sr function, which matches packets with their responses (ICMP in my case) has been returning data with a few RTTs > 1 second, which is absurd since I'm using ttl=1.
Have you tried just sending the packet? Scapy should recompute the checksums for you automatically.You could also try setting them to None, but I don't believe that's necessary.
I believe scapy will automatically recalculate the checksums if you call the show2() command on the packet. So if you have a packet at index 0 in the object pckt, you should call pckt.show2() and the checksum should be correct. At least that's my understanding.
pkt.show2() same as show but on the assembled packet (checksum is calculated, for instance) Source

How to Send Packets to a Remote Minecraft Classic Server in Python?

Hello kind folks of StackOverflow.
I am trying to make a sort of 'bot' which can connect to a Minecraft Classic server, post messages and possibly build.
Anyway, I'm having some trouble understanding how to send packets in python, and how to correctly encode them.
Here are the packets I need to send, I want to send the 'Player Identification' one: http://www.minecraftwiki.net/wiki/Classic_server_protocol#Client_.E2.86.92_Server_packets
I know I need to be using sockets, and I need to be using struct.pack, but how exactly can I send it?
An example piece code that sends a login packet would be marvellous.
Thanks.
I'll get the ball rolling:
import socket
import struct
username = "username_value"
verification_key = "verification_key"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # boilerplate
s.connect(("example.com", 1234)) # adjust accordingly
# now for the packet
# note that the String type is specified as having a length of 64, we'll pad that
packet = ""
packet += struct.pack("B", 1) # packet type
packet += struct.pack("B", 7) # protocol version
packet += "%-64s" % username # magic!
packet += "%-64s" % verification_key
packet += struct.pack("B", 0) # that unused byte, assuming a NULL byte here
# send what we've crafted
s.send(packet)
The "%-20s" may be weird for you if you've never used format strings. Essentially..
print "%s" % 5
.. would print out 5 ..
print "%10s" % 5
.. would pad the output to be exactly 10 characters in width. But it pads them on the right side, we want that padding on the left -- hence the - ..
print "%-10s" % s, "<this will be 9 spaces away from the '5'>"
.. play around with it.
If anything is unclear, let me know. I like what you're doing, reminds me of an old project of mine. Except that I didn't have a neat protocol specification like you did, lucky bastard. ;)

Categories