Python CDP client using Scapy and Pyinstaller - python

I am trying to write a Python-based CDP client, similar to WinCDP for those familiar. For the purposes of troubleshooting compilation I have a significantly shortened version:
# Suppress Scapy IPv6 warning
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
import re from scapy.all import *
load_contrib("cdp") class main:
def __init__(self):
self.filter = "ether host 01:00:0c:cc:cc:cc"
self.interfaces = str(ifaces)
print(self.interfaces)
try:
self.p = sniff(count=1,iface='Intel(R) 82578DM Gigabit Network Connection',filter=self.filter,timeout=60)
except:
print('OUCH! Something went wrong.')
else:
print('Finished processing...')
print("DeviceID: {}".format(self.p[0].payload["CDPMsgDeviceID"].val.decode('utf-8')))
print("PortID: {}".format(self.p[0].payload["CDPMsgPortID"].iface.decode('utf-8')))
print("NativeVLAN: {}".format(self.p[0].payload["CDPMsgNativeVLAN"].vlan))
print("IPv4addr: {}".format(self.p[0].payload["CDPAddrRecordIPv4"].addr))
print("Model: {}".format(self.p[0].payload["CDPMsgPlatform"].val.decode('utf-8')))
print("Duplex: {}".format(self.p[0].payload["CDPMsgDuplex"].duplex))
print("VTP Domain: {}".format(self.p[0].payload["CDPMsgVTPMgmtDomain"].val.decode('utf-8')))
if __name__ == "__main__": main()
On all versions of Python I've tried this produces results similar to the following:
INDEX IFACE IP MAC
10 Hyper-V Virtual Ethernet Adapter 172.31.253.241 78:15:27:01:22:F1
11 Intel(R) 82578DM Gigabit Network Connection 10.X.Y.Z 78:2B:CB:00:11:22
21 Hyper-V Virtual Ethernet Adapter #2 10.0.75.1 00:15:5D:CD:BE:03
26 Npcap Loopback Adapter 127.0.0.1 00:00:00:00:00:00
4 VirtualBox Host-Only Ethernet Adapter #2 192.168.56.1 0A:00:27:00:00:04
9 NETGEAR WNA3100M N300 Wireless Mini USB Adapter 2C:B0:5D:00:11:22
Finished processing...
DeviceID: switch01
PortID: GigabitEthernet5/0/29
NativeVLAN: 120
IPv4addr: 10.X.Y.Z
Model: cisco WS-C2960X-48FPD-L
Duplex: 1
VTP Domain: XYZ
I have managed to get the script to compile and it will run with the following:
pyinstaller -F cdpscript.py --hidden-import=queue
But, when the executable is run the output is:
INDEX IFACE IP MAC
OUCH! Something went wrong.
Which leads me to believe that enough of Scapy is running to print the headers of the ifaces command, but nothing else works. This was done on Python 3.6.6 as the Pyinstaller documentation indicates this is the most recent version supported, with Scapy 2.4.0 and PyInstaller 3.3.1.
I'm hoping to be able to give my techs an executable on a USB drive they can run and get CDP information without having to install anything locally, similarly to how we had been using WinCDP. Except, WinCDP has not been playing well with Windows 10 lately. I am hoping to create our own version so we can do fancier stuff like stick information in a database to track our machines. At any rate, none of this fun can happen if I can't get the script to compile into a working exe. Also, does anyone familiar with Scapy know if NPcap is going to have to be installed on the target machines? Any help would be greatly appreciated.

Related

How to implement ARP ping with Scapy?

I've been trying to create a network scanner similar to netdiscover. I used Python and Scapy module to do that. I'm running my script on Kali linux on virtual box and when I'm scanning my NAT network created by Virtual Box it's showing me devices that are connected, but when I'm using wireless adapter to scan my wifi network the scanner is unable to find any devices, which is strange because netdiscover finds tons of them. However when I'm using arping function implemented by Scapy, devices are also showing, but when I'm running my code it doesn't detect any devices. Why is that?
I used code suggested by Scapy documentation and it's still not showing any devices. Only Scapy arping function detects any devices at all
import scapy.all as scapy
import subprocess as sub
import re
def get_IP():
output=sub.check_output("route -n",shell=True)
ips={}
for row in output.split("\n")[2:]:
found=re.findall("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}",row)
device=re.findall("[a-z]{2,10}\d$",row)
for ip in found:
if ("0.0.0" not in ip and "255.255.255" not in ip):
ips[device[0]]=ip
for device,ip in ips.items():
print("Device: {}\tIP: {}".format(device,ip))
device = raw_input("Choose a device > ")
return(ips[device][:-1]+"1/24")
def scan(ip):
#My code
print("Scanning...")
arp_request=scapy.ARP(pdst=ip)
brodcast=scapy.Ether(dst="ff:ff:ff:ff:ff:ff")
arp=brodcast/arp_request
answered=scapy.srp(arp, timeout=1,verbose=False)[0]
for element in answered:
print("IP:{}".format(element[1].psrc))
print("MAC address: {}\n".format(element[1].hwsrc))
def scan2(ip):
#Code from scapy documentation and it's also not detecting any devices
ans, unans = scapy.srp(scapy.Ether(dst="ff:ff:ff:ff:ff:ff")/scapy.ARP(pdst=ip),timeout=2)
ans.summary(lambda (s,r): r.sprintf("%Ether.src% %ARP.psrc%") )
def scan3(ip):
#This works
scapy.arping(ip)
ip = get_IP()
scan(ip)
scan2(ip)
scan3(ip)
I solved it just by deactivating connection to NAT Network, so I used ifconfig eth0 down. However in some cases it's not the problem. If you're router does not allow net scans you need to change you're MAC address which means that you need to run series of these commands
ifconfig wlan0 down
ifconfig wlan0 hw ether 00:22:44:66:88:33 # Ofcourse you can choose any MAC address you want
ifconfig wlan0 down
ifconfig wlan0 up
service network-manager restart
After that network scanner will detect devices that are currently in the network
Try this way :
from scapy.all import scapy,ARP,Ether,srp,arping
or this way:
from scapy.layers.l2 import *
In both cases remember delete the "scapy.", like this:
#Before
scapy.arping(ip)
#After
arping(ip)

Connecting to a wifi network using python

I have this code that is supposed to connect to wifi using a given ESSID and password. Here is the code:
def wifi_connect(essid, password):
# Connect to the wifi. Based on the example in the micropython
# documentation.
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('connecting to network ' + essid + '...')
wlan.connect(essid, password)
# connect() appears to be async - waiting for it to complete
while not wlan.isconnected():
print('waiting for connection...')
print('checking connection...')
print('Wifi connect successful, network config: %s' % repr(wlan.ifconfig()))
else:
# Note that connection info is stored in non-volatile memory. If
# you are connected to the wrong network, do an explicity disconnect()
# and then reconnect.
print('Wifi already connected, network config: %s' % repr(wlan.ifconfig()))
At first, I got an error message that network was not installed. This was fixed by simply using pip to install network. After I ran this again, it told me that network has no attribute WLAN. How do I fix this? What am I doing wrong?
You are trying to run code designed for the MicroPython language, and it won't work on CPython (the Python version you'd download from Python.org or find installed on most PCs and servers).
MicroPython is designed to run on embeddable specialist hardware, and comes with its own library to support the hardware it is running on, including a network module:
To use this module, a MicroPython variant/build with network capabilities must be installed. Network drivers for specific hardware are available within this module and are used to configure hardware network interface(s).
It tells you so in the comments at the top:
# [...] Based on the example in the micropython
# documentation.
The code can't run on 'regular' CPython. You installed the PyPI network project, which is a very different module, originally designed to help learn coding for the Raspberry PI.
What project could work depends on your operating system (OS). Different OSes use different programming interfaces to let programs change networks. Most have command line tools to let you do this, which should be easy to drive from Python with the subprocess module:
Windows has the netsh command, run netsh wlan connect name=... to connect to a network interface
Mac OS X has the networksetup command, networksetup -setairportnetwork en1 ... connects you to a given WIFI network.
On a PC, you don't need network.py to connect to a Wifi access point as in ESPP32.
You connect normally by OS network connection.
The only library you need is socket. Here an example of code to get data !
import socket
def http_get(url, port):
_, _, host, path = url.split('/', 3)
addr = socket.getaddrinfo(host, port)[0][-1]
s = socket.socket()
s.connect(addr)
s.send(bytes('GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' % (path, host), 'utf8'))
while True:
data = s.recv(100)
if data:
print(str(data, 'utf8'), end='')
else:
break
s.close()
http_get('http://micropython.org/ks/test.html',80)
http_get('http://towel.blinkenlights.nl/',23)

Scapy 2.7.3 in Monitor Mode

I am writing a simple WiFi sniffer with scapy:
from scapy.all import *
ap_list = []
def ssid(pkt):
print(pkt.show())
if pkt.haslayer(Dot11):
if pkt.type == 0 and pkt.subtype == 8:
if pkt.addr2 not in ap_list:
ap_list.append(pkt.addr2)
print("AP: %s SSID: %s" % (pkt.addr2, pkt.info))
sniff(iface='en0', prn=ssid)
Where en0 is wi-fi interface.
My aim is to see the RSSI, noise, SSID for the wireless access points. When I run this script (from sudo or not), while I am connected to some wi-fi - there are many packets captured (no one is Beacon). WireShark shows RadioTap Headers in Monitor mode (airport en0 sniff 1) on my Mac (El Capitan), this script however, produces no output in monitor mode.
Could someone please help me understand what is going wrong here? TIA :)
This is a Mac specific issue. You indeed are correct, you want to be capturing Beacon frames for this type of data. The issue here is that once the airport command finishes running, your interface is returned back to it's standard managed mode, so when you run your scapy script your wifi interface is not in monitor mode. To my knowledge, Mac does not have a native command that will turn on, and leave a card in monitor mode.

Finding active IPv6 interfaces under Mac OS (using Python)

My objective is to write a Python script that provides the user with a series of link-local IPv6 addresses of specific devices. My technique is to send out a multicast ping and then use neighbor discovery to get a list of addresses which I can then filter down.
The first step is this:
output = subprocess.check_output(['ping6', '-c', '2', 'ff02::1%en0'])
The problem is the term en0 at the end. It is not a constant. On MacOS it is en0 but on Linux it will be eth0 or possibly br0. Windows has a different command but the same problem. Without the interface qualifier the ping6 command does not work.
Also, some systems may have multiple interfaces.
So how would a Python script get a list of those interfaces?
Alternatively, can this be done by using the socket package and not subprocess? (I don't want my script to require privileged mode and using ping gets around that.)
Under Linux there's no guarantee that your first Ethernet interface will be named eth0. It might be named p1s3 or em1 or even internal. Or bob.
Under both Linux and OS X you can use the netifaces python module to get a list of available interfaces and addresses associated with those interfaces. For example, consider the following code:
import netifaces
for iface in netifaces.interfaces():
addrs = netifaces.ifaddresses(iface)
for addr in addrs.get(netifaces.AF_INET6, []):
print '%-8s %s' % (iface, addr['addr'])
Which on my Linux system produces:
lo ::1
enp0s25 fe80::3e97:eff:febf:6dce%enp0s25
docker0 fe80::d8d1:31ff:feb2:b6c6%docker0
br-ext fe80::f879:f3ff:fe6b:f445%br-ext
lxcbr0 fe80::fc45:6bff:fefd:543%lxcbr0
vethf8c98b2 fe80::a0a7:3bff:feff:4f9b%vethf8c98b2
vnet0 fe80::fc54:ff:fee5:2818%vnet0
And on my OS X system produces:
lo0 ::1
lo0 fe80::1%lo0
en3 fe80::e2f8:47ff:fe41:866a%en3
I have no idea if this works under Windows or not.

how can i connect and send commands to a serial port while another program is using it?

I am using a telit he910g card. it is connected to my PC directly using a miniPCI slot.
I am using it for 3G internet connection and A-GPS/GPS services.
My system is running linux mint 17.1, the 3G connection is handled using the network manager APP and works great. The 3G connection is started and handled using a module that is part of a program I am writing.
The code I am using in order to connect to the serial port is this:
def _connect_to_device(self):
""" Connect to a serial port """
try:
self._device = serial.Serial(self._filename, baudrate=self._baud_rate)
except StandardError, e:
raise StandardError("Couldn't connect to GPS device. Error: %s" % str(e))
When I use the python program alone it works great. But when I try and use it while the 3G is on i cant connect to the serial device. The wierd thing is that if I try to connect to it using a program like "minicom" while 3G is turned on it DOES work.
So my question is: how can I make both run and work together? since now they are mutually exclusive.
thanks to all who help. :)
Glad you found a way round your problem. Just for completeness:
Normally, serial ports can be opened by multiple processes.
If one of them does ioctl(,TIOCEXCL) on the open file then further opens will return EBUSY until everyone closes the device. Only root can get past this and open the device at all times.
If root opens the device and does an ioctl(,TIOCNXCL), then other processes can open the device too.
In python, TIOCNXCL isnt defined anywhere, but you can do the ioctl (eg on stdin) with:
import fcntl
TIOCEXCL = 0x540c # from /usr/lib64/perl5/asm-generic/ioctls.ph
TIOCNXCL = 0x540d
print fcntl.ioctl(0, TIOCNXCL)
Ok, so it is solved.
the issue was that the telit module has 2 ports /dev/ttyACM0 (high speed) and /dev/ttyACM3 (lower speed).
I tried to connect to the high speed one, but apparently the 3G uses that one and it causes contentions.
So moving to use the lower speed port in my script solved the issue.

Categories

Resources