Filter on OPC UA packets using Scapy in Python - scapy

How can I filter on the incoming packets via the protocol of the packet? I am using Scapy in Python, and I want to filter on OPC-UA packets specifically. I have only found examples on TCP packets.
from scapy.all import *
from scapy.layers.inet import IP,TCP,ICMP, Ether, UDP
interface = "eth0" #Name of interface to be sniffed
sniff(iface=interface, prn=check_pkt, store=0, filter="opc")

Sadly scapy doesnt support OpcUa currently.
However you can achieve your goal by using the standart opc ua port for filtering, which is 4840.
filter = "port 4840"
It is also possible to check the bytes contained in the package for more detailed filtering on opc ua packages.
For Example:
filter = "(port 4840) " \
"and (tcp[20:4] = 0x4d534746) " \
"and ((tcp[46:2] = 0x3a03) or (tcp[46:2] = 0x7702)) "
which will filter all Opc Ua packages whith message_type="MSG" and chunk_type="F" who are either ReadRequests or PublishRequests.
In this case tcp[20:4] means "In the Tcp packet start at byte 20 and take the next 4 bytes" and 0x4d534746 is the hexadecimal representaion of MSGF.
More information on the berkeley packet filter syntax can be found here.

Related

s.bind((hostMACAddress,port)). OSError: [WinError 10049] The requested address is not valid in its context

I am trying to use the Bluetooth library in python 3 to enable me to allow a robot I am making to communicate with my PC. I have created a Bluetooth server that uses MAC addresses. unfortunately I have hit a halt in my program on this line:
s.bind((hostMACAddress,port))
OSError: [WinError 10049] The requested address is not valid in its context
For some reason it does not seem to like the MAC address (I have checked over the MAC address several times now and it is definitely correct). Personally, I would rather not want to use python 2 as the robot I am using is only compatible with python 3 and by using python 2 the whole idea would not work.
"""
A simple Python script to receive messages from a client over
Bluetooth using Python sockets (with Python 3.3 or above).
"""
import socket
hostMACAddress = 'xx:xx:xx:xx:xx:xx' # The MAC address of a Bluetooth adapter on the server. The server might have multiple Bluetooth adapters.
port = 3 # 3 is an arbitrary choice. However, it must match the port used by the client.
backlog = 1
size = 1024
s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM)
s.bind((hostMACAddress,port))
s.listen(backlog)
try:
client, address = s.accept()
while 1:
data = client.recv(size)
if data:
print(data)
client.send(data)
except:
print("Closing socket")
client.close()
s.close()
Here is the guide I have been following:
https://blog.kevindoran.co/bluetooth-programming-with-python-3/
These lines I have used alternatively to using MAC addresses (I am have tried using both):
hostIPAddress = "x.x.x.x"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((hostIPAddress,22))

How to capture wifi packets with a specific channel using Pyshark?

I use codes below to capture wifi packets, and save the pcap file to a text file.
However in the text file it only shows packets with channel 1, even no channel 2 or more.
I'm using python2.7 and pyshark-0.3.8 .
capture = pyshark.LiveCapture(interface = network_card +'mon',output_file=pathfile +'.pcap')
capture.set_debug()
capture.sniff(timeout = scanner_time)
list = str(capture).split('(')[1]
list1 = list.split(' ')[0]
print(list1)
with open(pathfile +'.txt', 'w') as f:
for pkt in range(int(list1)):
f.write(str(capture[pkt]))
Is there any way to capture from a specific channel not just channel 1?
The image is a part of a packet in the text file which shows current channel.
image
I found this command that can change network card in monitor mode and switch to a certain channel.
sudo airmon-ng start 'network_card' 'channel'
Then run the code in my question, pyshark will search the channel you input.
When you want to stop monitoring, just type below:
sudo airmon-ng stop 'network_card'+'mon'

Win32api for serial communication in excel VBA

I have data acquisition devices I would like to pull information from. I've started a small project in Python 3.5 using pyserial to communicate to a device. I can send commands and receive data.
import serial
ser = serial.Serial()
ser.port = 'COM1'
ser.baudrate = 9600
ser.parity = PARITY_NONE
ser.timeout=.5
ser.open()
ser.write(b'#02\r')
print(ser.readline())
ser.close()
This sends a command to retrieve data in the buffer, and when I use the readline command, I pull in data.
b'>-999999-999999-999999-999999 -999999\r'
I've created an excel sheet to host data tables and test criteria which I am judging performance of our machines on. This was initially for manual user input, but I decided I'd try and see if I can automate this directly in excel. I've poured over several webpages, found several companies that would ask for payment for code- etc. I've finally settled on work done by The Scarms which uses the WIN32API to deal with serial I/O vs. the original mscomm32.ocx driver.
I've been able to bring his files into my project, and used the sample code to start. I can send a message, and visually verify it from the device I'm communicating through, but I don't get any reply from my end data acquisition device.
strData = "#02\r"
lngSize = Len(strData)
lngStatus = CommWrite(intPortID, strData)
The variable strData is a string. When sending a message using pyserial, it's prefaced by "b" which (to my knowledge) signals it to be encoded to bits before sent through the serial port.
I've been trying to look through the modCOMM code that gets added to VBA from the code provided by the link above, but I can't seem to get an input at all. Am I sending the information incorrectly using the WIN32API?
How do I send this command over the bus properly in order to get a response from the end device?
The end device in question is an Advantech ADAM 4017+.

Can not pass OSC data using IMU manufacturer's python2.7 example script

I am working with a high refresh rate IMU (x-IO technologies NGIMU) which outputs all data in osc format. The manufacturer provides the following python script to serve the data on linux platforms ( I am running Ubuntu 16.04)
'''
NGIMU Demo python v2.7 script written by Tom Mitchell (teamxe.co.uk) 2016
Requires pyOSC https://trac.v2.nl/wiki/pyOSC
'''
import socket, OSC, threading, time
# Change this to the NGIMU IP address
send_address = '192.168.1.1', 9000
# Set the NGIMU to send to this machine's IP address
c = OSC.OSCClient()
c.connect(send_address)
msg = OSC.OSCMessage()
msg.setAddress('/wifi/send/ip')
msg.append(str(socket.gethostbyname(socket.gethostname())))
c.send(msg)
c.close()
# Set up receiver
receive_address = '192.168.1.2', 8000
s = OSC.OSCServer(receive_address)
s.addDefaultHandlers()
def sensorsHandler(add, tags, args, source):
print add + str(args)
def quaternionHandler(add, tags, args, source):
print add + str(args)
def batteryHandler(add, tags, args, source):
print add + str(args)
# Add OSC handlers
s.addMsgHandler("/sensors", sensorsHandler)
s.addMsgHandler("/quaternion", quaternionHandler)
s.addMsgHandler("/battery", batteryHandler)
# Start OSCServer
print "\nUse ctrl-C to quit."
st = threading.Thread(target = s.serve_forever)
st.start()
# Loop while threads are running
try :
while 1 :
time.sleep(10)
except KeyboardInterrupt :
print "\nClosing OSCServer."
s.close()
print "Waiting for Server-thread to finish"
st.join()
print "Done"
The IMU hosts its own network which I connect to with the computer that is to receieve the data.
I have installed pyOSC from the location referenced in the script.
When I run the script, no data is delivered, only the message "Use ctrl-C to quit".
All connections seem to take place properly. When the script is running, I can see the udp connection at the correct ip and port using the Ubuntu firewall configuration gui. I have tried disabling the firewall but that had no effect.
Separately, I have used another computer to send udp packets to that ip and port and confirmed their receipt.
To say that I am a coding novice is far too generous. Nonetheless, I need to get this script running. Any help you can offer is greatly appreciated.
The problem is that
socket.gethostbyname(socket.gethostname())
is not setting the correct IP. You should change to
msg.setAddress('/wifi/send/ip')
msg.append('192.168.1.2')

PySerial "better" port names for Linux?

Followup question to this: permanent USB port names? (Linux)
On Windows the port names don't change between actual physical ports. They are along the lines of "COM3", "COM6", etc.
On Linux, if I plug one USB device first , it will be "ttyUSB0" and if I plug the same device second in any other physical port it will be "ttyUSB1". That won't work if I want to, say, have 2 Arduinos connected via Pyserial to the PC.
In the above answer I was shown a way to get an IP-like "serial name". How can I feed that to the PySerial class instead?
An example:
import serial
ser = serial.Serial(port = "/dev/USBNAME", baudrate=9600)
ser.close()
ser.open()
if ser.isOpen():
ser.write("test")

Resources