Generate 100% custom layer2 payload with python / scapy - python-3.x

I want to create a python3 script which uses a wireless active connection (the bssid which the interface is attached at the moment) to send a 100% custom layer 2 payload (or in other words, a 100% custom layer 3 or 2.5 protocol).
I have tried a lot of ways with scapy, with scripts like the following:
from scapy.all import *
import os
interfaces = os.listdir('/sys/class/net')
interface = interfaces[1] # which is the wireless interface
send(Dot11(addr1 = 'aa:aa:aa:aa:aa:aa'), iface = str(interface)) # I pretend here to send an empty frame to addr1 destination, using the wireless card and the existing bssid on which i'm currently connected
Always I get the destination MAC address as broadcast. And of course I don't understand the proper way to do what I want.
Any suggestion or clarification is welcome.
Thanks in advance.

The answer, the key is use sendp instead send, for example a IEEE1905 Ethertype:
import os
from scapy.all import *
dest_MAC = aa:aa:aa:aa:aa:aa # the mac address you want to send it
interfaces = os.listdir('/sys/class/net') interface = interfaces[3] #select one interface from the array, it could be Ethernet or an existing Wireless STA connection
p = Ether(type=0x893a, dst = dest_MAC)/b"\x00\x00\x00" #we send just three "zero" bytes
sendp(p, iface=interface) #using sendp instead send, which is layer2 abstracted

Related

Read and notification issues with gattlib BLE?

I am writing a Linux application using the gattlib library in python3 to send and receive user inputted data between a BlueSnap DB9 BLE adapter and my Linux device. I have been able to successfully send a String of data to the adapter from my device and seen the output on the adapter's terminal, but I am having issues receiving data from the adapter.
I am following this example for reading and writing data using the gattlib library. I can write data using the write_cmd and write_by_handle functions but I am unable to read data or enable notifications with gattlib using any of the read functions mentioned there. Notifications don't appear to be enabled when using gattlib because the on_notification function I overwrote doesn't print out the print statement I added there.
I have determined that the handles for writing and reading data are 0x0043 and 0x0046, respectively. Here are the UUIDs for writing and reading that serialio provided to me: UUIDs.
When using bluetoothctl, after selecting the characteristic, I am able to write data to the adapter. Only after enabling notifications on bluetoothctl, only then am I able to read data as well. Once I disable notifications, attempting to read manually prints out all 0s instead of the data I want to read. What is the proper way to select a characteristic and enable notifications using gattlib in python3?
UPDATE: I was able to get notifications enabled. I ran hcidump on both bluetoothctl and my python code and determined the handle I had used for enabling notifications was incorrect. The correct handle for enabling notifications is 0x0047. Once I realized this mistake, I ran enable_notifications using the correct handle and set both parameters to True and was able to enable notifications and see incoming data on my device's terminal as I typed it on my adapter's terminal.
Not using gattlib but here is an example of using the Python3 D-Bus bindings and the GLib event loop to read, write and get notifications from GATT characteristics.
from time import sleep
import pydbus
from gi.repository import GLib
# Setup of device specific values
dev_id = 'DE:82:35:E7:43:BE'
adapter_path = '/org/bluez/hci0'
device_path = f"{adapter_path}/dev_{dev_id.replace(':', '_')}"
temp_reading_uuid = 'e95d9250-251d-470a-a062-fa1922dfa9a8'
temp_period_uuid = 'e95d1b25-251d-470a-a062-fa1922dfa9a8'
# Setup DBus informaton for adapter and remote device
bus = pydbus.SystemBus()
mngr = bus.get('org.bluez', '/')
adapter = bus.get('org.bluez', adapter_path)
device = bus.get('org.bluez', device_path)
# Connect to device (needs to have already been paired via bluetoothctl)
device.Connect()
# wait for GATT services to be discovered
while not device.ServicesResolved:
sleep(0.5)
# Some helper functions
def get_characteristic_path(device_path, uuid):
"""Find DBus path for UUID on a device"""
mng_objs = mngr.GetManagedObjects()
for path in mng_objs:
chr_uuid = mng_objs[path].get('org.bluez.GattCharacteristic1', {}).get('UUID')
if path.startswith(device_path) and chr_uuid == uuid:
return path
def as_int(value):
"""Create integer from bytes"""
return int.from_bytes(value, byteorder='little')
# Get a couple of characteristics on the device we are connected to
temp_reading_path = get_characteristic_path(device._path, temp_reading_uuid)
temp_period_path = get_characteristic_path(device._path, temp_period_uuid)
temp = bus.get('org.bluez', temp_reading_path)
period = bus.get('org.bluez', temp_period_path)
# Read value of characteristics
print(temp.ReadValue({}))
# [0]
print(period.ReadValue({}))
# [232, 3]
print(as_int(period.ReadValue({})))
# 1000
# Write a new value to one of the characteristics
new_value = int(1500).to_bytes(2, byteorder='little')
period.WriteValue(new_value, {})
# Enable eventloop for notifications
def temp_handler(iface, prop_changed, prop_removed):
"""Notify event handler for temperature"""
if 'Value' in prop_changed:
print(f"Temp value: {as_int(prop_changed['Value'])} \u00B0C")
mainloop = GLib.MainLoop()
temp.onPropertiesChanged = temp_handler
temp.StartNotify()
try:
mainloop.run()
except KeyboardInterrupt:
mainloop.quit()
temp.StopNotify()
device.Disconnect()

Trying to use raw socket in Python 3 to blindly send an IP package, But keep getting ARP lookups how to disable

I am trying to send an IP package in Python 3 on a point to point network IE Host and Client are connected directly to each other with static IP.
I'm using the following code:
import socket
class Client:
def __init__(self):
self._sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
self._sock.bind(('192.168.1.10',0))
def send(self, data):
data_to_send = bytes([0x0,0x1C,0x23,0x17,0x4A,0xCB,0x00,0x50,0xB6,0x0D,0x35,0x9F,0x08,0x00,0x45,0x00,0x00,0x2E,0x00,0x00,0x40,0x00,0x40,0x00,0xB7,0x6A,0xC0,0xA8,0x01,0x0A,0xC0,0xA8,0x01,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])
self._sock.sendto(data_to_send, ('192.168.1.11', 0))
However every time I try and send the package I always get ARP lookups (and the package never gets transmittet).
1 0.000000 GoodWayI_0d:35:9f Broadcast ARP 42 Who has 192.168.1.11? Tell 192.168.1.10
2 0.981801 GoodWayI_0d:35:9f Broadcast ARP 42 Who has 192.168.1.11? Tell 192.168.1.10
3 1.981830 GoodWayI_0d:35:9f Broadcast ARP 42 Who has 192.168.1.11? Tell 192.168.1.10
How do I avoid these lookups and just send the package blindly ?
It seems my search fu is broken because I cant find much documentation on Python 3 Sockets.
Regards
I did get around this issue by adding the IP/MAC to the ARP list
using
netsh interface ip add neighbors "Ethernet 3" "192.168.1.11" "00-1C-23-17-4A-CB"
However I would like to be able to switch it off in python
regards

SSDP M-search does not work for unicast - single IP

SSDP M-search request for discovery works great for multicast address 239.255.255.250. However, I have a requirement to send this request to a specific IP. It does not work. As per the UPnP architecture document unicast discover message is supported, with a small difference from the multicast message
The multi-cast message is
M-SEARCH * HTTP/1.1
HOST:239.255.255.250:1900
MAN:ssdp:discover
ST:ssdp:all
MX:1
Unicast message is similar - except that the multicast IP is changed to specific IP and MX:1 is removed (as per the specification - did not find any code sample for unicast discover m-search)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32)
msg = 'M-SEARCH * HTTP/1.1\r\nHOST:239.255.255.250:1900\r\nMAN:\"ssdp:discover\"\r\nST:ssdp:all\r\nMX:1\r\n\r\n'
s.sendto(msg.encode('utf-8'), ('239.255.255.250', 1900))
resp = s.recv(1024)
print (resp)
This works great. But the following doesn't - the recv() call times out
sock_1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
msg = 'M-SEARCH * HTTP/1.1\r\nHOST:<specific ip>:1900\r\nMAN:\"ssdp:discover\"\r\nST:ssdp:all\r\n\r\n'
sock_1.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32)
sock_1.settimeout(30)
sock_1.sendto(msg.encode('utf-8'), ('<specific ip>', 1900))
resp = sock_1.recv(1024)
I have tried a few more variations of 'setsockopt' which did not work.
Please share if there are any clues for possible reasons - could it be from the device side that it responds to the multicast on 1900 but not to the unicast message?
Thanks in advance!
msg = 'M-SEARCH * HTTP/1.1\r\nHOST:<specific ip>:1900\r\nMAN:\"ssdp:discover\"\r\nST:ssdp:all\r\n'
You're missing a final \r\n in the end (it's for the empty line signaling end of headers: without it the receiver will just keep waiting for more).
The only difference with a unicast m-search is the HOST, like you've got.
Are you binding the socket? It should be bound to port 0. Here's an example of setting up a socket for ssdp: https://github.com/lbryio/aioupnp/blob/master/aioupnp/protocols/multicast.py#L64
In addition to the final \r\n pointed out by Jussi, you may find you need to try different permutations of the M-SEARCH format, some gateways are very finicky. For some the value for MAN must be in quotes, for others it must not. Additional quirks are the order of MAN, MX, ST and the capitalization of HOST/Host and MAN/Man . You may also need to try a variety of search targets.

Bluetoothctl or gatttool for BLE notifications from multiple devices

I have read many questions on the topic but found no information on how to best (or if it is even possible) to receive notifications from more than 1 device at a time using any library or API (preferably command line or Python library).
After connecting to different devices e.g. Heart Rate monitor and Phone, or two HR monitors, is there a way to receive data from 1 service from each device at the same time?
EDIT:
I have managed to connect different devices of the same characteristics and been able to get notifications from them using Bluetoothctl (part of Bluez) so long as I don't request the same service, which answers my question partially; still, does anyone know of a better way to do this?
1) First of all there is a github python project that does just that in Linux on Raspberry Pi: https://github.com/IanHarvey/bluepy
2) Second this snipet from Anthony Chiu uses that API to communicate with multiple devices using notifications:
from bluepy.btle import Scanner, DefaultDelegate, Peripheral
import threading
class NotificationDelegate(DefaultDelegate):
def __init__(self, number):
DefaultDelegate.__init__(self)
self.number = number
def handleNotification(self, cHandle, data):
print 'Notification:\nConnection:'+str(self.number)+ \nHandler:'+str(cHandle)+'\nMsg:'+data
bt_addrs = ['00:15:83:00:45:98', '00:15:83:00:86:72']
connections = []
connection_threads = []
scanner = Scanner(0)
class ConnectionHandlerThread (threading.Thread):
def __init__(self, connection_index):
threading.Thread.__init__(self)
self.connection_index = connection_index
def run(self):
connection = connections[self.connection_index]
connection.setDelegate(NotificationDelegate(self.connection_index))
while True:
if connection.waitForNotifications(1):
connection.writeCharacteristic(37, 'Thank you for the notification!')
while True:
print'Connected: '+str(len(connection_threads))
print 'Scanning...'
devices = scanner.scan(2)
for d in devices:
print(d.addr)
if d.addr in bt_addrs:
p = Peripheral(d)
connections.append(p)
t = ConnectionHandlerThread(len(connections)-1)
t.start()
connection_threads.append(t)
3) I will just write the manual connection option with bluetoothctl that you probably tried. Since it wasn't listed here, I will add that too:
**Manual connection with bluetoothctl: ** To get the list of characteristics you can use the “list-attributes” command after establing connection and entering Generic Attribute Submenu through menu gatt in bluetoothctl, which should print the same list as above:
list-attributes 00:61:61:15:8D:60
To read an attribute you first select it, with the -you guessed it- “select-attribute” command:
select-attribute /org/bluez/hci0/dev_00_61_61_15_8D_60/service000a/char000b
After that you can issue the “read” command, without any parameters.
To read a characteristic continuously (if characteristic supports it) , use the “notify” command:
notify on
PS: This is my first answer on stackoverflow :)
I am also new to BLE, so bear with me. Am interested in your project, any links / contact are appreciated :)
You can find me on alexandrudancu.com

linux raw ethernet socket bind to specific protocol

I'm writing code to send raw Ethernet frames between two Linux boxes. To test this I just want to get a simple client-send and server-receive.
I have the client correctly making packets (I can see them using a packet sniffer).
On the server side I initialize the socket like so:
fd = socket(PF_PACKET, SOCK_RAW, htons(MY_ETH_PROTOCOL));
where MY_ETH_PROTOCOL is a 2 byte constant I use as an ethertype so I don't hear extraneous network traffic.
when I bind this socket to my interface I must pass it a protocol again in the socket_addr struct:
socket_address.sll_protocol = htons(MY_ETH_PROTOCOL);
If I compile and run the code like this then it fails. My server does not see the packet. However if I change the code like so:
socket_address.sll_protocol = htons(ETH_P_ALL);
The server then can see the packet sent from the client (as well as many other packets) so I have to do some checking of the packet to see that it matches MY_ETH_PROTOCOL.
But I don't want my server to hear traffic that isn't being sent on the specified protocol so this isn't a solution. How do I do this?
I have resolved the issue.
According to http://linuxreviews.org/dictionary/Ethernet/ referring to the 2 byte field following the MAC addresses:
"values of that field between 64 and 1522 indicated the use of the new 802.3 Ethernet format with a length field, while values of 1536 decimal (0600 hexadecimal) and greater indicated the use of the original DIX or Ethernet II frame format with an EtherType sub-protocol identifier."
so I have to make sure my ethertype is >= 0x0600.
According to http://standards.ieee.org/regauth/ethertype/eth.txt use of 0x88b5 and 0x88b6 is "available for public use for prototype and vendor-specific protocol development." So this is what I am going to use as an ethertype. I shouldn't need any further filtering as the kernel should make sure to only pick up ethernet frames with the right destination MAC address and using that protocol.
I've worked around this problem in the past by using a packet filter.
Hand Waving (untested pseudocode)
struct bpf_insn my_filter[] = {
...
}
s = socket(PF_PACKET, SOCK_DGRAM, htons(protocol));
struct sock_fprog pf;
pf.filter = my_filter;
pf.len = my_filter_len;
setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &pf, sizeof(pf));
sll.sll_family = PF_PACKET;
sll.sll_protocol = htons(protocol);
sll.sll_ifindex = if_nametoindex("eth0");
bind(s, &sll, sizeof(sll));
Error checking and getting the packet filter right is left as an exercise for the reader...
Depending on your application, an alternative that may be easier to get working is libpcap.

Resources