How to get my own local IP using scapy? - python

I couldn't find a way to find my local IP address using ONLY scapy (and not the Python's stdlib).
The only workaround I found is sending a dummy package and using it to retrieve the address from the source field, but I don't feel like it is a good solution.

If you have a look at https://scapy.readthedocs.io/en/latest/routing.html#get-local-ip-ip-of-an-interface
you can get the local IP of any of your interfaces using
>>> ip = get_if_addr(conf.iface) # default interface
>>> ip = get_if_addr("eth0")
>>> ip
'10.0.0.5'

Quick reminder: you might have more then one IP address. There's one for each interface you have. To get the IP address for scapy's current working interface you should do get_if_addr(conf.iface) as suggested by Cukic0d in his comment.
Here's a way that will work in both windows and linux. This will get you the ip address for all your interfaces.
Working in scapy shell
>>> s = set() # there will be redundencies so we'll use set to remove them
>>> for line in read_routes():
...: s.add(line[4])
...:
>>> s
{'10.0.0.4',
'169.254.106.110',
'169.254.17.51',
'169.254.177.137',
'192.168.56.1',
'192.168.99.1'}
In python shell
>>> import scapy.all as S
>>> s = set() # there will be redundencies so we'll use set to remove them
>>> for line in S.read_routes():
...: s.add(line[4])
...:
>>> s
{'10.0.0.4',
'169.254.106.110',
'169.254.17.51',
'169.254.177.137',
'192.168.56.1',
'192.168.99.1'}

Related

How to filter packets using IP source and destination addresses with Pyshark

I've just try to use PYSHARK and filtering using BPF_filter = 'tcp' packets, however I am looking for filtering by source and destination IP addresses. The spript is shown below:
import pyshark
capture = pyshark.LiveCapture(interface=r'\Device\NPF_{707B2864-16B6-4E63-A44E-18BA00FC87EA}', bpf_filter='tcp and src.address=192.168.74.253 and dst.address=172.16.0.121', output_file=('../logs_capture/20221013_cap1.xdoc'))
capture.sniff(timeout=5)
capture
capture[3]
#<UDP/HTTP Packet>
for packet in capture.sniff_continuously(packet_count=5):
print ('Just arrived:', packet)
Can anyone give me an hint?
BPF filters are specified using pcap-filter syntax. So in your case you'd use 'ip and tcp and src host 192.168.74.253 and dst host 172.16.0.121'.

How to get my network adapter IP with python?

If I type "ipconfig" in cmd, its gives some IPs... I need the one who belongs to my network adapter\internal IP.
So. for example:
If I have 3 Ips:
10.100.102.2
192.168.231.1
192.168.233.1
And I need the first one. How do I make python know that this is the one I need\The one belongs to my internal IP?
The solution for extracting the first IPv4 address of ethernet adapter (Python on Windows):
- used modules: os, re
import os, re
addresses = os.popen('IPCONFIG | FINDSTR /R "Ethernet adapter Local Area Connection .* Address.*[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*"')
first_eth_address = re.search(r'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b', addresses.read()).group()
print(first_eth_address)

Python based network sniffer (scapy not good enough?)

I am looking for the specific task:
Grab the payload/data from a packet -> Append to a file... BUT. I want specifically to follow packets according to flags/ICMP types/etc... So lets say I want specifically to take the payload of "echo" packets and not the rest.
My (ineffective) code is the following:
from scapy.all import *
f= open('filecaptured', 'a+')
def pkt_diam(pkt):
raw = pkt.getlayer(Raw).load
print raw
# pkt.show()
# fo = open("payload", "wb")
f.write(raw);
sniff (filter="icmp" , store=0, prn=pkt_diam, timeout = 120 )
The problem here is that I cannot find a way to sniff specifically for "type = echo request" and the only parameters that I can use is 'protocol' and host or 'and not host 127.0.0.1'.
Is there a way around this?
I think for this one I need to use ctypes and libpcap.so but I am not sure... (I didnt find any [other] libraries for python - sniffing )
I don't have scapy installed right now, but what if you simply check for the type echo-reply in your callback-function pkt_diam:
if not "echo-reply" in pkt.show():
return
Try filter="icmp[0]=8" for filtering during capture or
if pkt[ICMP].type==8:
in callback function.

Sniffing UDP packets using scapy in Mac

I am trying to sniff UDP packets using scapy sniff function, I send the packets in the Looback interface, the sending code is simple as follows:
from socket import *
IPv4 = "127.0.0.1"
Port = 45943
ClientSock = socket(AF_INET, SOCK_DGRAM)
while True:
MESSAGE = raw_input()
ClientSock.sendto(MESSAGE, (IPv4, Port))
However when i run (in another terminal tab after importing scapy):
a = sniff(iface="lo0", count = 5)
I get the following result:
>>> a.nsummary()
0000 Raw
0001 Raw
0002 Raw
0003 Raw
0004 Raw
whereas i am supposed to get UDP packets!, can any one point out to anything that i am missing here.
thanks
Unable to guess datalink type (interface=lo0 linktype=0)
That message translates as "Scapy doesn't understand the DLT_NULL link-layer header type, as used on the loopback device in *BSD and OS X, so it doesn't support the loopback device on *BSD and OS X".
So you're out of luck if you want to use Scapy on OS X to capture on the loopback device, unless and until Scapy is enhanced to handle DLT_NULL. (DLT_NULL is not that hard to handle, so presumably the only reason it's not handled is that most of the people using it on a loopback device are doing so on Linux, where the link-layer header type value on the loopback device is DLT_EN10MB, i.e. Ethernet, so nobody's bothered to fix it. I'll see if I can get it working and, if so, send them a patch.)
Some suggestions.
Instead of a.nsummary(), you can print out more information on individual packets using something like
a[1].show()
a[1].show2()
hexdump(a[1])
to examine the first packet.
2) You can force the protocol decoding to a particular type of packet format. For instance, a RAW_IP packet capture (link layer header type = 101) can be forced to be IPv6 using
conf.l2types.register(101, IPv6)
If you want to add a new layer on top of UDP, you can add a new dissector based on the port used.

Obtain MAC Address from Devices using Python

I'm looking for a way (with python) to obtain the layer II address from a device on my local network. Layer III addresses are known.
The goal is to build a script that will poll a databases of IP addresses on regular intervals ensuring that the mac addresses have not changed and if they have, email alerts to myself.
To answer the question with Python depends on your platform. I don't have Windows handy, so the following solution works on the Linux box I wrote it on. A small change to the regular expression will make it work in OS X.
First, you must ping the target. That will place the target -- as long as it's within your netmask, which it sounds like in this situation it will be -- in your system's ARP cache. Observe:
13:40 jsmith#undertow% ping 97.107.138.15
PING 97.107.138.15 (97.107.138.15) 56(84) bytes of data.
64 bytes from 97.107.138.15: icmp_seq=1 ttl=64 time=1.25 ms
^C
13:40 jsmith#undertow% arp -n 97.107.138.15
Address HWtype HWaddress Flags Mask Iface
97.107.138.15 ether fe:fd:61:6b:8a:0f C eth0
Knowing that, you do a little subprocess magic -- otherwise you're writing ARP cache checking code yourself, and you don't want to do that:
>>> from subprocess import Popen, PIPE
>>> import re
>>> IP = "1.2.3.4"
>>> # do_ping(IP)
>>> # The time between ping and arp check must be small, as ARP may not cache long
>>> pid = Popen(["arp", "-n", IP], stdout=PIPE)
>>> s = pid.communicate()[0]
>>> mac = re.search(r"(([a-f\d]{1,2}\:){5}[a-f\d]{1,2})", s).groups()[0]
>>> mac
"fe:fd:61:6b:8a:0f"
There was a similar question answered not too long ago on this site. As mentioned in the answer chosen by the asker of that question, Python doesn't have a built-in way to do it. You must either call a system command such as arp to get ARP information, or generate your own packets using Scapy.
Edit: An example using Scapy from their website:
Here is another tool that will
constantly monitor all interfaces on a
machine and print all ARP request it
sees, even on 802.11 frames from a
Wi-Fi card in monitor mode. Note the
store=0 parameter to sniff() to avoid
storing all packets in memory for
nothing.
#! /usr/bin/env python
from scapy import *
def arp_monitor_callback(pkt):
if ARP in pkt and pkt[ARP].op in (1,2): #who-has or is-at
return pkt.sprintf("%ARP.hwsrc% %ARP.psrc%")
sniff(prn=arp_monitor_callback, filter="arp", store=0)
You could also do something similar to the verified answer. See https://scapy.readthedocs.io/en/latest/routing.html
>>> mac = getmacbyip("10.0.0.1")
>>> mac
'f3:ae:5e:76:31:9b'
This is fully cross platform.
Not exactly what you're looking for, but definitely on the right track. Enjoy!
In Linux sometimems you miss the command line util "arp". A base yocto linux embedded environment image for instance.
An alternative way without the "arp" tool would be to read and parse the file /proc/net/arp:
root#raspberrypi:~# cat /proc/net/arp
IP address HW type Flags HW address Mask Device
192.168.1.1 0x1 0x2 xx:xx:xx:xx:xx:xx * wlan0
192.168.1.33 0x1 0x2 yy:yy:yy:yy:yy:yy * wlan0
A simple solution using scapy, to scan the 192.168.0.0/24 subnet is as follows:
from scapy.all import *
ans,unans = arping("192.168.0.0/24", verbose=0)
for s,r in ans:
print("{} {}".format(r[Ether].src,s[ARP].pdst))
Sounds like you want to monitor ARP spoofers? In this case, all you need is arpwatch, available in every well-supplied Linux distribution near you. Download sources here: http://ee.lbl.gov/
for Unix based systems:
#!/usr/bin/env python2.7
import re
import subprocess
arp_out =subprocess.check_output(['arp','-lan'])
re.findall(r"((\w{2,2}\:{0,1}){6})",arp_out)
will return list of tuples with macs.
scapy is an amazing tool , but seems to be overkill for this case
an easier way, if on linux:
print os.system('arp -n ' + str(remoteIP))
you will get:
Address HWtype HWaddress Flags Mask Iface
192.168..... ether 9B:39:15:f2:45:51 C wlan0
General update for Python 3.7. Remark: the option -n for arp does not provide the arp list on windows systems as provided with certain answers for linux based systems. Use the option -a as stated in the answer here.
from subprocess import Popen, PIPE
pid = Popen(['arp', '-a', ip], stdout=PIPE, stderr=PIPE)
IP, MAC, var = ((pid.communicate()[0].decode('utf-8').split('Type\r\n'))[1]).split(' ')
IP = IP.strip(' ')
MAC = MAC.strip(' ')
if ip == IP:
print ('Remote Host : %s\n MAC : %s' % (IP, MAC))

Categories