Detect Application layer protocols, python? - python

I have a application which capture's and displays the network packets. The packets are represented in two forms in a TableView and as a TreeView. I am using scapy to capture the network packets.
I wish to display the highest protocol level of the packet (highest being application layer for any packet) , the problem that i am facing is that some packets have their final payload named as the protocol itself (for example , DNS payload is named as DNS) , but some payloads are just named as Raw (for example , HTTP payload is named as Raw).
So i was wondering is their any way i could detect these protocols, in python .
This is the output for a DNS packet.
This is the output for a HTTP packet.
Here is the code that generates the Tree .
def packet2Tree(self,pkt):
if len(pkt.fields.keys()) == 0 or pkt.name == "":
return
self.rootNode = Node(pkt.name , self.RootNode )
field = pkt.fields_desc
for xfield in field:
self.childNode = Node(xfield.name , self.rootNode , str(pkt.getfieldval(xfield.name)))
self.packet2Tree(pkt.payload)
return self.RootNode
Any guess how to solve this problem

I'm not sure if there is a built in way to do this, but you could look at the port numbers and take a guess? Scapy seems to understand the port numbers for most TCP packets (ie when you call repr(layer)) so maybe look to the source?
EDIT This question explains that the socket module can do this for you:
python-scapy: how to translate port numbers to service names?
>>> import socket
>>> socket.getservbyport(80)
'http'
>>> socket.getservbyport(21)
'ftp'
>>> socket.getservbyport(53, 'udp')
'domain'

Related

Reading TCP packets to and from a specific port in Python 3

I am trying to replicate the data I am seeing in Wireshark using this filter tcp.port == 25565. I have tried using socket and pyshark, however, I cannot seem to find a simple tutorial which explains how to do this.
As you can probably tell by the port, I am trying to decode Minecraft packets. Advice on how to get the payload and get a start on parsing that data would be very helpful.
So far, I have this code:
from scapy.all import *
def test(pkt):
print(pkt)
if __name__ == '__main__':
single = sniff(filter="tcp.port == 25565", prn=test)
Any help is greatly appreciated.
You want sniff(filter="tcp port 25565", prn=test).
Look at the scapy documentation.
We can add filtering to capture only packets that are interesting to us. Use standard tcpdump/libpcap syntax:
That syntax is specified in the pcap-filter man page.
qualifiers restrict the match to a particular protocol.
Possible protos are: ether, fddi, tr, wlan, ip, ip6, arp, rarp, decnet, tcp and udp. E.g., 'ether src foo', 'arp net 128.3', 'tcp port 21',
I don't think the syntax is well explained in it (or I'm not reading the right part), but as you can see, tcp port 21 is a valid filter and what you're looking for. For an alternative syntax that uses an and, you'll see this further down:
Primitives may be combined using:
A parenthesized group of primitives and operators (parentheses are special to the Shell and must be escaped).
Negation ('!' or 'not').
Concatenation ('&&' or 'and').
Alternation ('||' or 'or').
As you can see, your filter options (or primitives) should be grouped using an operator. In this case, you want both to be true, so you want tcp and port 25565, or alternatively, tcp && port 25565.

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

Python: wrong ip is shown in packet header

I'm forwarding a machine's packets through mine. I tested with tcpdump host <machine_ip> to see if everything is alright, and it is. Now I need to capture these packets. I chose to do this with Python. Right now I'm trying to filter the packets, but the ip that is printed is different from the right one. It should've been 192.168.0.8:
import socket
from struct import *
print("Started")
with socket.socket(socket.AF_PACKET,socket.SOCK_RAW, socket.ntohs(0x0003)) as s:
while True:
packet=s.recvfrom(65565)
content=packet[0]
ip_header=unpack('!BBHHHBBH4s4s', content[:20])
source_ip=socket.inet_ntoa(ip_header[8])
print(source_ip)
The printed ones are 8.0.69.0 and 8.0.69.16, which none of these matches the expected form.
This is because in front of the raw data is the MAC header.
If You change the line:
ip_header=unpack('!BBHHHBBH4s4s', content[:20])
to
ip_header=unpack('!BBHHHBBH4s4s', content[14:34])
You will probably get your ip address. I said probably becase it really depends on the link layer, as there might be a vlan tag present, thus shifting the ip header even further.

How to combine decoded packet data and header output into a single variable/dictionary for string searches

I'm somewhat of a Python novice, but I've taken up a small personal project to teach myself a bit more. Basically, I'm writing a packet sniffer using sockets and impacket. However, where I am getting stuck at is one particular point: combining the output from header and packet into one variable (I was thinking of a dictionary, but it didn't like that...) so that I can simply search out the IP header for one particular partial source IP (i.e., the first two octets). Or would there be a more efficient way of handling this? Any help is appreciated. :-)
EDIT: When I was trying the dictionary, I was doing
ip_dict = { header: packet }
However, the output I get is akin to this:
{<impacket.ImpactPacket.IP instance at 0x02563440>: <impacket.ImpactPacket.Data instance at 0x02563530>}
As opposed to the actual output of said IP header and data.
HOST = socket.gethostbyname(socket.gethostname())
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
s.bind((HOST, 0))
while True:
# Include IP headers
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
# receive all packages
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
# receive a packet
packet = s.recvfrom(42028)[0]
# look at IP info
h_decode = ImpactDecoder.IPDecoder()
header = h_decode.decode(packet)
# disabled promiscuous mode
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
decoder = ImpactDecoder.DataDecoder()
packet = decoder.decode(packet)
print header
print packet
time.sleep(1)
Dictionaries are sets of key/value pairs. When you used
ip_dict = { header: packet }
You told it to build a dictionary with the header instance as the key and the packet instance as the value, which is what it did:
{<impacket.ImpactPacket.IP instance at 0x02563440>: <impacket.ImpactPacket.Data instance at 0x02563530>}
If you want something from inside those instances, you have to extract it yourself. For example, although I've never used the impacket library before, the objects seem to have lots of methods living inside them. For example [suppressing the real numbers and data and replacing them with nonsense]:
In [25]: z
Out[25]: <impacket.ImpactPacket.IP instance at 0xb6151fac>
In [26]: z.[here I hit TAB in the IPython interpreter]
z.add_option z.get_ip_offmask z.set_bytes_from_string
z.auto_checksum z.get_ip_p z.set_checksum_from_data
z.calculate_checksum z.get_ip_rf z.set_ip_address
z.child z.get_ip_src z.set_ip_df
z.compute_checksum z.get_ip_sum z.set_ip_dst
z.contains z.get_ip_tos z.set_ip_hl
z.ethertype z.get_ip_ttl z.set_ip_id
z.fragment_by_list z.get_ip_v z.set_ip_len
z.fragment_by_size z.get_long z.set_ip_mf
z.get_buffer_as_string z.get_packet z.set_ip_off
z.get_byte z.get_pseudo_header z.set_ip_offmask
z.get_bytes z.get_size z.set_ip_p
z.get_data_as_string z.get_word z.set_ip_rf
z.get_header_size z.is_BSD z.set_ip_src
z.get_ip_address z.list_as_hex z.set_ip_sum
z.get_ip_df z.load_header z.set_ip_tos
z.get_ip_dst z.normalize_checksum z.set_ip_ttl
z.get_ip_hl z.packet_printable z.set_ip_v
z.get_ip_id z.parent z.set_long
z.get_ip_len z.protocol z.set_parent
z.get_ip_mf z.set_byte z.set_word
z.get_ip_off z.set_bytes
In [26]: z.get_ip_src()
Out[26]: '1.2.3.4' # fake
In [27]: z.get_ip_dst()
Out[27]: '5.6.7.8' # fake
In [29]: z.get_data_as_string()
Out[29]: '\x00abcde' # fake
I have no idea what half of the methods do, or which of them are important, but you can easily build a dictionary out of whatever you like:
In [31]: {(z.get_ip_src(), z.get_ip_dst()): z.get_bytes()}
Out[31]:
{('1.2.3.4',
'5.6.7.8'): array('B', [1,2,3,4,5,6,7,8])} # fake
or combine bits from the IPDecoder and the DataDecoder, whatever. The point is that the issue isn't about Python dictionaries, it's about the impacket library's data structures, and what information you want to extract from them. The docs will probably describe how to get what you need.

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

Categories