hikvision sdap tool linux command line

JaceKac

n3wb
May 15, 2023
10
1
Poland
Hi, i often need to find hikvision devices via linux command line. What type of discovery service is sdap tool using to find it? no luck with nmap or avahi-browse. i dont need to use full sdap functions, i want only find ip address of hikvision devices in the network.
is there any port of this protocol or sth which i can use?
 
8000 tcp is default. You may but its not always the case, that port can be changed. If u dont want sadp(or cant). Then make a python script that sends broadcast message and recieves answers.

I can send u later byte array of packet.
 
Code:
import socket

# Configuration
UDP_IP = "255.255.239.250"  # Broadcast IP address
UDP_PORT = 7200  # I need to remember which port it was, you can check what sadp is using

# Create UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

# Send data as UDP broadcast packet
data = bytes([1, 2, 3])  # Will send byte array later, or take from wireshark aswell as port for broadcast packet
sock.sendto(data, (UDP_IP, UDP_PORT))
print("Sent UDP broadcast packet.")

# Receive response from devices
sock.bind(("0.0.0.0", UDP_PORT))
print("Listening for responses...")

while True:
    response, addr = sock.recvfrom(1024)
    print("Received response from {}: {}".format(addr[0], response.decode()))
 
Code:
import socket

# Configuration
UDP_IP = "255.255.239.250"  # Broadcast IP address
UDP_PORT = 7200  # I need to remember which port it was, you can check what sadp is using

# Create UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

# Send data as UDP broadcast packet
data = bytes([1, 2, 3])  # Will send byte array later, or take from wireshark aswell as port for broadcast packet
sock.sendto(data, (UDP_IP, UDP_PORT))
print("Sent UDP broadcast packet.")

# Receive response from devices
sock.bind(("0.0.0.0", UDP_PORT))
print("Listening for responses...")

while True:
    response, addr = sock.recvfrom(1024)
    print("Received response from {}: {}".format(addr[0], response.decode()))


Thank you in my case:
broadcast UDP_IP = "10.30.1.255"

but sock.bind is failing on address 0.0.0.0 i put there also the ip of the machine running the script - the same

Sent UDP broadcast packet.
Traceback (most recent call last):
File "/home/pi/hikvision.py", line 17, in <module>
sock.bind(("10.30.1.246", UDP_PORT))
OSError: [Errno 22] Invalid argument
 
sock.bind(("0.0.0.0", UDP_PORT))
This allows the socket to listen on all network interfaces of the machine, including the broadcast IP address.

Broadcast IP adress is 255.255.239.250 for hikvision i'm 95% sure
 
sock.bind(("0.0.0.0", UDP_PORT))
This allows the socket to listen on all network interfaces of the machine, including the broadcast IP address.

Broadcast IP adress is 255.255.239.250 for hikvision i'm 95% sure

ok i reverted the changes and still get
Sent UDP broadcast packet.
Traceback (most recent call last):
File "/home/pi/hikvision.py", line 17, in <module>
sock.bind(("0.0.0.0", UDP_PORT))
OSError: [Errno 22] Invalid argument
 
I was wrong,

1686655536339.png

Broadcast IP destination is shown on image aswell as port, try with these

Byte array is in txtfile i attached, this is the data you send on the broadcast destination IP on port that is shown on image.
 

Attachments

I was wrong,

View attachment 165375

Broadcast IP destination is shown on image aswell as port, try with these

Byte array is in txtfile i attached, this is the data you send on the broadcast destination IP on port that is shown on image.

The same problem, i googled it also and maybe there is a problem with the destination IP is in different subnet than the local machine? Foud some similar issue when the first ip is not matching the sock.bind
 
Wish i could be more helpfull, this python script is just converted from c# script i used on windows. And it should have worked. I might test it later on my vm and see exactly where it fails.
 
you are more than helpful thank you :) for now i will leave my script version you can double check in a free time

Code:
import socket

# Configuration
UDP_IP = "239.255.255.250"  # Broadcast IP address
UDP_PORT = 202  # I need to remember which port it was, you can check what sadp is using
# Create UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

# Send data as UDP broadcast packet
data = bytes([
  0x3c, 0x3f, 0x78, 0x6d, 0x6c, 0x20, 0x76, 0x65,
  0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31,
  0x2e, 0x30, 0x22, 0x20, 0x65, 0x6e, 0x63, 0x6f,
  0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x55, 0x54,
  0x46, 0x2d, 0x38, 0x22, 0x3f, 0x3e, 0x0d, 0x0a,
  0x3c, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x4d, 0x61,
  0x74, 0x63, 0x68, 0x3e, 0x3c, 0x55, 0x75, 0x69,
  0x64, 0x3e, 0x37, 0x31, 0x39, 0x44, 0x38, 0x32,
  0x45, 0x41, 0x2d, 0x36, 0x33, 0x36, 0x46, 0x2d,
  0x34, 0x44, 0x35, 0x35, 0x2d, 0x42, 0x39, 0x41,
  0x30, 0x2d, 0x30, 0x43, 0x33, 0x38, 0x39, 0x37,
  0x33, 0x34, 0x43, 0x36, 0x38, 0x44, 0x3c, 0x2f,
  0x55, 0x75, 0x69, 0x64, 0x3e, 0x0d, 0x0a, 0x3c,
  0x54, 0x79, 0x70, 0x65, 0x73, 0x3e, 0x69, 0x6e,
  0x71, 0x75, 0x69, 0x72, 0x79, 0x3c, 0x2f, 0x54,
  0x79, 0x70, 0x65, 0x73, 0x3e, 0x0d, 0x0a, 0x3c,
  0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79,
  0x70, 0x65, 0x3e, 0x31, 0x34, 0x30, 0x36, 0x38,
  0x38, 0x3c, 0x2f, 0x44, 0x65, 0x76, 0x69, 0x63,
  0x65, 0x54, 0x79, 0x70, 0x65, 0x3e, 0x0d, 0x0a,
  0x3c, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44,
  0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
  0x6f, 0x6e, 0x3e, 0x44, 0x53, 0x2d, 0x32, 0x43,
  0x44, 0x31, 0x33, 0x34, 0x33, 0x47, 0x30, 0x2d,
  0x49, 0x3c, 0x2f, 0x44, 0x65, 0x76, 0x69, 0x63,
  0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
  0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0d, 0x0a, 0x3c,
  0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x4e,
  0x3e, 0x44, 0x53, 0x2d, 0x32, 0x43, 0x44, 0x31,
  0x33, 0x34, 0x33, 0x47, 0x30, 0x2d, 0x49, 0x32,
  0x30, 0x31, 0x39, 0x31, 0x32, 0x32, 0x32, 0x41,
  0x41, 0x57, 0x52, 0x45, 0x30, 0x34, 0x34, 0x36,
  0x38, 0x31, 0x37, 0x34, 0x3c, 0x2f, 0x44, 0x65,
  0x76, 0x69, 0x63, 0x65, 0x53, 0x4e, 0x3e, 0x0d,
  0x0a, 0x3c, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
  0x64, 0x50, 0x6f, 0x72, 0x74, 0x3e, 0x38, 0x30,
  0x30, 0x30, 0x3c, 0x2f, 0x43, 0x6f, 0x6d, 0x6d,
  0x61, 0x6e, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x3e,
  0x0d, 0x0a, 0x3c, 0x48, 0x74, 0x74, 0x70, 0x50,
  0x6f, 0x72, 0x74, 0x3e, 0x38, 0x30, 0x3c, 0x2f,
  0x48, 0x74, 0x74, 0x70, 0x50, 0x6f, 0x72, 0x74,
  0x3e, 0x0d, 0x0a, 0x3c, 0x4d, 0x41, 0x43, 0x3e,
  0x39, 0x38, 0x2d, 0x64, 0x66, 0x2d, 0x38, 0x32,
  0x2d, 0x36, 0x62, 0x2d, 0x31, 0x62, 0x2d, 0x33,
  0x62, 0x3c, 0x2f, 0x4d, 0x41, 0x43, 0x3e, 0x0d,
  0x0a, 0x3c, 0x49, 0x50, 0x76, 0x34, 0x41, 0x64,
  0x64, 0x72, 0x65, 0x73, 0x73, 0x3e, 0x31, 0x39,
  0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x31, 0x38,
  0x2e, 0x32, 0x30, 0x32, 0x3c, 0x2f, 0x49, 0x50,
  0x76, 0x34, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
  0x73, 0x3e, 0x0d, 0x0a, 0x3c, 0x49, 0x50, 0x76,
  0x34, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x4d,
  0x61, 0x73, 0x6b, 0x3e, 0x32, 0x35, 0x35, 0x2e,
  0x32, 0x35, 0x35, 0x2e, 0x32, 0x35, 0x32, 0x2e,
  0x30, 0x3c, 0x2f, 0x49, 0x50, 0x76, 0x34, 0x53,
  0x75, 0x62, 0x6e, 0x65, 0x74, 0x4d, 0x61, 0x73,
  0x6b, 0x3e, 0x0d, 0x0a, 0x3c, 0x49, 0x50, 0x76,
  0x34, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
  0x3e, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38,
  0x2e, 0x31, 0x36, 0x2e, 0x37, 0x3c, 0x2f, 0x49,
  0x50, 0x76, 0x34, 0x47, 0x61, 0x74, 0x65, 0x77,
  0x61, 0x79, 0x3e, 0x0d, 0x0a, 0x3c, 0x49, 0x50,
  0x76, 0x36, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
  0x73, 0x3e, 0x3a, 0x3a, 0x3c, 0x2f, 0x49, 0x50,
  0x76, 0x36, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
  0x73, 0x3e, 0x0d, 0x0a, 0x3c, 0x49, 0x50, 0x76,
  0x36, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
  0x3e, 0x3a, 0x3a, 0x3c, 0x2f, 0x49, 0x50, 0x76,
  0x36, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
  0x3e, 0x0d, 0x0a, 0x3c, 0x49, 0x50, 0x76, 0x36,
  0x4d, 0x61, 0x73, 0x6b, 0x4c, 0x65, 0x6e, 0x3e,
  0x36, 0x34, 0x3c, 0x2f, 0x49, 0x50, 0x76, 0x36,
  0x4d, 0x61, 0x73, 0x6b, 0x4c, 0x65, 0x6e, 0x3e,
  0x0d, 0x0a, 0x3c, 0x44, 0x48, 0x43, 0x50, 0x3e,
  0x74, 0x72, 0x75, 0x65, 0x3c, 0x2f, 0x44, 0x48,
  0x43, 0x50, 0x3e, 0x0d, 0x0a, 0x3c, 0x41, 0x6e,
  0x61, 0x6c, 0x6f, 0x67, 0x43, 0x68, 0x61, 0x6e,
  0x6e, 0x65, 0x6c, 0x4e, 0x75, 0x6d, 0x3e, 0x30,
  0x3c, 0x2f, 0x41, 0x6e, 0x61, 0x6c, 0x6f, 0x67,
  0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e,
  0x75, 0x6d, 0x3e, 0x0d, 0x0a, 0x3c, 0x44, 0x69,
  0x67, 0x69, 0x74, 0x61, 0x6c, 0x43, 0x68, 0x61,
  0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x75, 0x6d, 0x3e,
  0x31, 0x3c, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x74,
  0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65,
  0x6c, 0x4e, 0x75, 0x6d, 0x3e, 0x0d, 0x0a, 0x3c,
  0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
  0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3e,
  0x56, 0x35, 0x2e, 0x35, 0x2e, 0x38, 0x39, 0x62,
  0x75, 0x69, 0x6c, 0x64, 0x20, 0x32, 0x31, 0x30,
  0x34, 0x32, 0x39, 0x3c, 0x2f, 0x53, 0x6f, 0x66,
  0x74, 0x77, 0x61, 0x72, 0x65, 0x56, 0x65, 0x72,
  0x73, 0x69, 0x6f, 0x6e, 0x3e, 0x0d, 0x0a, 0x3c,
  0x44, 0x53, 0x50, 0x56, 0x65, 0x72, 0x73, 0x69,
  0x6f, 0x6e, 0x3e, 0x56, 0x37, 0x2e, 0x33, 0x20,
  0x62, 0x75, 0x69, 0x6c, 0x64, 0x20, 0x32, 0x31,
  0x30, 0x32, 0x30, 0x37, 0x3c, 0x2f, 0x44, 0x53,
  0x50, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
  0x3e, 0x0d, 0x0a, 0x3c, 0x42, 0x6f, 0x6f, 0x74,
  0x54, 0x69, 0x6d, 0x65, 0x3e, 0x32, 0x30, 0x32,
  0x33, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x37, 0x20,
  0x30, 0x37, 0x3a, 0x34, 0x36, 0x3a, 0x32, 0x34,
  0x3c, 0x2f, 0x42, 0x6f, 0x6f, 0x74, 0x54, 0x69,
  0x6d, 0x65, 0x3e, 0x0d, 0x0a, 0x3c, 0x45, 0x6e,
  0x63, 0x72, 0x79, 0x70, 0x74, 0x3e, 0x74, 0x72,
  0x75, 0x65, 0x3c, 0x2f, 0x45, 0x6e, 0x63, 0x72,
  0x79, 0x70, 0x74, 0x3e, 0x0d, 0x0a, 0x3c, 0x52,
  0x65, 0x73, 0x65, 0x74, 0x41, 0x62, 0x69, 0x6c,
  0x69, 0x74, 0x79, 0x3e, 0x66, 0x61, 0x6c, 0x73,
  0x65, 0x3c, 0x2f, 0x52, 0x65, 0x73, 0x65, 0x74,
  0x41, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x3e,
  0x0d, 0x0a, 0x3c, 0x44, 0x69, 0x73, 0x6b, 0x4e,
  0x75, 0x6d, 0x62, 0x65, 0x72, 0x3e, 0x30, 0x3c,
  0x2f, 0x44, 0x69, 0x73, 0x6b, 0x4e, 0x75, 0x6d,
  0x62, 0x65, 0x72, 0x3e, 0x0d, 0x0a, 0x3c, 0x41,
  0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x64,
  0x3e, 0x74, 0x72, 0x75, 0x65, 0x3c, 0x2f, 0x41,
  0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x64,
  0x3e, 0x0d, 0x0a, 0x3c, 0x50, 0x61, 0x73, 0x73,
  0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x65,
  0x74, 0x41, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79,
  0x3e, 0x74, 0x72, 0x75, 0x65, 0x3c, 0x2f, 0x50,
  0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52,
  0x65, 0x73, 0x65, 0x74, 0x41, 0x62, 0x69, 0x6c,
  0x69, 0x74, 0x79, 0x3e, 0x0d, 0x0a, 0x3c, 0x50,
  0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52,
  0x65, 0x73, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x65,
  0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x3e, 0x74,
  0x72, 0x75, 0x65, 0x3c, 0x2f, 0x50, 0x61, 0x73,
  0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73,
  0x65, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x53, 0x65,
  0x63, 0x6f, 0x6e, 0x64, 0x3e, 0x0d, 0x0a, 0x3c,
  0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x4f, 0x45,
  0x4d, 0x43, 0x6f, 0x64, 0x65, 0x3e, 0x31, 0x3c,
  0x2f, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x4f,
  0x45, 0x4d, 0x43, 0x6f, 0x64, 0x65, 0x3e, 0x0d,
  0x0a, 0x3c, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72,
  0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
  0x79, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f,
  0x6e, 0x3e, 0x74, 0x72, 0x75, 0x65, 0x3c, 0x2f,
  0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x53,
  0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x51,
  0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x3e,
  0x0d, 0x0a, 0x3c, 0x53, 0x75, 0x70, 0x70, 0x6f,
  0x72, 0x74, 0x48, 0x43, 0x50, 0x6c, 0x61, 0x74,
  0x66, 0x6f, 0x72, 0x6d, 0x3e, 0x74, 0x72, 0x75,
  0x65, 0x3c, 0x2f, 0x53, 0x75, 0x70, 0x70, 0x6f,
  0x72, 0x74, 0x48, 0x43, 0x50, 0x6c, 0x61, 0x74,
  0x66, 0x6f, 0x72, 0x6d, 0x3e, 0x0d, 0x0a, 0x3c,
  0x48, 0x43, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f,
  0x72, 0x6d, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65,
  0x3e, 0x74, 0x72, 0x75, 0x65, 0x3c, 0x2f, 0x48,
  0x43, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72,
  0x6d, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x3e,
  0x0d, 0x0a, 0x3c, 0x49, 0x73, 0x4d, 0x6f, 0x64,
  0x69, 0x66, 0x79, 0x56, 0x65, 0x72, 0x69, 0x66,
  0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43,
  0x6f, 0x64, 0x65, 0x3e, 0x66, 0x6c, 0x61, 0x73,
  0x65, 0x3c, 0x2f, 0x49, 0x73, 0x4d, 0x6f, 0x64,
  0x69, 0x66, 0x79, 0x56, 0x65, 0x72, 0x69, 0x66,
  0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43,
  0x6f, 0x64, 0x65, 0x3e, 0x0d, 0x0a, 0x3c, 0x53,
  0x61, 0x6c, 0x74, 0x3e, 0x32, 0x30, 0x64, 0x66,
  0x36, 0x62, 0x31, 0x33, 0x66, 0x36, 0x62, 0x38,
  0x34, 0x62, 0x30, 0x30, 0x63, 0x33, 0x63, 0x31,
  0x66, 0x32, 0x34, 0x61, 0x33, 0x32, 0x64, 0x63,
  0x33, 0x36, 0x62, 0x36, 0x66, 0x30, 0x36, 0x66,
  0x37, 0x34, 0x35, 0x37, 0x36, 0x63, 0x63, 0x61,
  0x35, 0x39, 0x64, 0x31, 0x66, 0x33, 0x33, 0x62,
  0x36, 0x36, 0x39, 0x65, 0x38, 0x32, 0x30, 0x35,
  0x34, 0x31, 0x61, 0x35, 0x3c, 0x2f, 0x53, 0x61,
  0x6c, 0x74, 0x3e, 0x0d, 0x0a, 0x3c, 0x44, 0x65,
  0x76, 0x69, 0x63, 0x65, 0x4c, 0x6f, 0x63, 0x6b,
  0x3e, 0x74, 0x72, 0x75, 0x65, 0x3c, 0x2f, 0x44,
  0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x6f, 0x63,
  0x6b, 0x3e, 0x0d, 0x0a, 0x3c, 0x53, 0x44, 0x4b,
  0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74,
  0x61, 0x74, 0x75, 0x73, 0x3e, 0x74, 0x72, 0x75,
  0x65, 0x3c, 0x2f, 0x53, 0x44, 0x4b, 0x53, 0x65,
  0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74,
  0x75, 0x73, 0x3e, 0x0d, 0x0a, 0x3c, 0x53, 0x44,
  0x4b, 0x4f, 0x76, 0x65, 0x72, 0x54, 0x4c, 0x53,
  0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74,
  0x61, 0x74, 0x75, 0x73, 0x3e, 0x74, 0x72, 0x75,
  0x65, 0x3c, 0x2f, 0x53, 0x44, 0x4b, 0x4f, 0x76,
  0x65, 0x72, 0x54, 0x4c, 0x53, 0x53, 0x65, 0x72,
  0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75,
  0x73, 0x3e, 0x0d, 0x0a, 0x3c, 0x53, 0x44, 0x4b,
  0x4f, 0x76, 0x65, 0x72, 0x54, 0x4c, 0x53, 0x50,
  0x6f, 0x72, 0x74, 0x3e, 0x38, 0x34, 0x34, 0x33,
  0x3c, 0x2f, 0x53, 0x44, 0x4b, 0x4f, 0x76, 0x65,
  0x72, 0x54, 0x4c, 0x53, 0x50, 0x6f, 0x72, 0x74,
  0x3e, 0x0d, 0x0a, 0x3c, 0x53, 0x75, 0x70, 0x70,
  0x6f, 0x72, 0x74, 0x4d, 0x61, 0x69, 0x6c, 0x42,
  0x6f, 0x78, 0x3e, 0x74, 0x72, 0x75, 0x65, 0x3c,
  0x2f, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74,
  0x4d, 0x61, 0x69, 0x6c, 0x42, 0x6f, 0x78, 0x3e,
  0x0d, 0x0a, 0x3c, 0x73, 0x75, 0x70, 0x70, 0x6f,
  0x72, 0x74, 0x45, 0x7a, 0x76, 0x69, 0x7a, 0x55,
  0x6e, 0x62, 0x69, 0x6e, 0x64, 0x3e, 0x74, 0x72,
  0x75, 0x65, 0x3c, 0x2f, 0x73, 0x75, 0x70, 0x70,
  0x6f, 0x72, 0x74, 0x45, 0x7a, 0x76, 0x69, 0x7a,
  0x55, 0x6e, 0x62, 0x69, 0x6e, 0x64, 0x3e, 0x0d,
  0x0a, 0x3c, 0x2f, 0x50, 0x72, 0x6f, 0x62, 0x65,
  0x4d, 0x61, 0x74, 0x63, 0x68, 0x3e, 0x0d, 0x0a])  # Will send byte array later, or take from wireshark aswell as port for broadcast packet
sock.sendto(data, (UDP_IP, UDP_PORT))
print("Sent UDP broadcast packet.")

# Receive response from devices
sock.bind(("0.0.0.0", UDP_PORT))
print("Listening for responses...")

while True:
    response, addr = sock.recvfrom(1024)
    print("Received response from {}: {}".format(addr[0], response.decode()))
 
Working solution:

Windows10
1686673199881.png

Kali linux

1686674795432.png


Code:
import socket
import select

def send_udp_broadcast(packet, port, broadcast_ip, local_ip):
    # Create a UDP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)

    # Bind the socket to the local IP and port
    sock.bind((local_ip, port))

    # Enable broadcasting mode
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

    # Send the byte array to the broadcast address
    sock.sendto(packet, (broadcast_ip, port))

    # Close the socket
    sock.close()

def listen_for_responses(port):
    # Create a UDP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)

    # Bind the socket to listen to all interfaces on the given port
    sock.bind(("", port))

    while True:
        # Wait for a response
        data, addr = sock.recvfrom(1024)
    
        # Print the response
        print(f"Received message from {addr}:\n")
        print(data.decode('utf-8'))  # Assuming the data is in UTF-8 encoding

def get_local_ip():
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    try:
        # Doesn't even have to be reachable
        sock.connect(('10.255.255.255', 1))
        local_ip = sock.getsockname()[0]
    except Exception:
        local_ip = '127.0.0.1'
    finally:
        sock.close()

    return local_ip

# Define the byte array
packet = bytes([
  0x3c, 0x3f, 0x78, 0x6d, 0x20, 0x76, 0x65,
  0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31,
  0x2e, 0x30, 0x22, 0x20, 0x65, 0x6e, 0x63, 0x6f,
  0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x75, 0x74,
  0x66, 0x2d, 0x38, 0x22, 0x3f, 0x3e, 0x3c, 0x50,
  0x72, 0x6f, 0x62, 0x65, 0x3e, 0x3c, 0x55, 0x75,
  0x69, 0x64, 0x3e, 0x37, 0x34, 0x46, 0x31, 0x45,
  0x44, 0x33, 0x37, 0x2d, 0x35, 0x45, 0x38, 0x32,
  0x2d, 0x34, 0x33, 0x45, 0x38, 0x2d, 0x39, 0x41,
  0x36, 0x31, 0x2d, 0x36, 0x36, 0x46, 0x43, 0x44,
  0x33, 0x32, 0x39, 0x32, 0x36, 0x45, 0x32, 0x3c,
  0x2f, 0x55, 0x75, 0x69, 0x64, 0x3e, 0x3c, 0x54,
  0x79, 0x70, 0x65, 0x73, 0x3e, 0x69, 0x6e, 0x71,
  0x75, 0x69, 0x72, 0x79, 0x3c, 0x2f, 0x54, 0x79,
  0x70, 0x65, 0x73, 0x3e, 0x3c, 0x2f, 0x50, 0x72,
  0x6f, 0x62, 0x65, 0x3e
])

broadcast_ip = "239.255.255.250"
port = 37020
local_ip = get_local_ip()

# Send the UDP broadcast packet
send_udp_broadcast(packet, port, broadcast_ip, local_ip)

# Listen for responses
listen_for_responses(port)

@JaceKac Just change parsing to what you need, you might wanna look for IP and model only perhaps.



@alastairstevenson You can pin this or share this script for others who might need it
 
Last edited:
Thank you its working but there is one problem with the outputed xml. The messages in output are not complete - if there is a second message coming it can stop from showing the first one. Look at my example:
Received message from ('10.30.1.230', 37020):

<?xml version="1.0" encoding="UTF-8" ?>
<ProbeMatch>
<Uuid>74F1ED37-5E82-43E8-9A61-66FCD32926E2</Uuid>
<Types>inquiry</Types>
<Encrypt>true</Encrypt>
<Salt>08698ff46d2beb1e7f2b96ce724e12df5d5a4caaf859387e1049fb318b965d1f</Salt>
<DeviceType>46708</DeviceType>
<DeviceDescription>HWN-2104H</DeviceDescription>
<DeviceSN>HWN-2104H0420220308CCRRJ61598500WVU</DeviceSN>
<CommandPort>8000</CommandPort>
<HttpPort>80</HttpPort>
<MAC>24-0f-9b-39-66-cc</MAC>
<IPv4Address>10.30.1.230</IPv4Address>
<IPv4SubnetMask>255.255.255.0</IPv4SubnetMask>
<IPv4Gateway>10.30.1.1</IPv4Gateway>
<IPv6Address>fd5d:10f9:f75c:4474:260f:9bff:fe39:66cc</IPv6Address>
<IPv6Gateway>::</IPv6Gateway>
<IPv6MaskLen>64</IPv6MaskLen>
<DHCP>false</DHCP>
<AnalogChannelNum>0</AnalogChannelNum>
<DigitalChannelNum>4</DigitalChannelNum>
<SoftwareVersion>V4.32.116build 220112</SoftwareVersion>
<DSPVersion>V5.0, build 211229</DSPVersion>
<BootTime>2023-06-12 15:12:25</BootTime>
<OEMInfo>N/A</OEMInfo>
<Activated>true</Activated>
<PasswordResetAbility>true</Pass
Received message from ('10.30.1.205', 37020):

<?xml version="1.0" encoding="UTF-8"?>


so the first message is not complete + not containing the closing <ProbeMatch> tag so it can not be properly parsed any fix for that ?
 
works with fragmented packets also, safe to increase to even 2500 i just tested on work and recieved 100+ devices almost instantly, even faster than SADP tool for windows
 
ok i can share my modified version of script.
You can view simple table or full raw XML. just use "python name_of_the_script.py" to get table view or "name_of_the_script.py raw" to get full jsons.

probably you need to install prettytable package

Code:
import xml.etree.ElementTree as ET
from prettytable import PrettyTable
import socket
import time
import argparse

def send_udp_broadcast(packet, port, broadcast_ip, local_ip):
    # Create a UDP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)

    # Bind the socket to the local IP and port
    sock.bind((local_ip, port))

    # Enable broadcasting mode
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

    # Send the byte array to the broadcast address
    sock.sendto(packet, (broadcast_ip, port))

    # Close the socket
    sock.close()

def listen_for_responses(port, wait_time, display_format="table"):
    # Create a UDP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)

    # Set a timeout for the socket to prevent blocking indefinitely
    sock.settimeout(wait_time)

    # Bind the socket to listen to all interfaces on the given port
    sock.bind(("", port))

    responses = []

    try:
        for i in range(wait_time, 0, -1):
            print(f"Waiting for result...seconds to go {i:02}", end='\r')
            time.sleep(1)

        print("Processing responses...")
        while True:
            # Wait for a response
            data, addr = sock.recvfrom(1824)

            if display_format == "raw":
                # Print the whole received XML
                print(data.decode('utf-8'))
            else:
                # Parse the XML
                root = ET.fromstring(data.decode('utf-8'))

                # Find the nodes you want
                mac = root.find('MAC').text
                device_description = root.find('DeviceDescription').text
                deviceSN = root.find('DeviceSN').text
                ipv4Address = root.find('IPv4Address').text
                dhcp = root.find('DHCP').text

                # Add the extracted data to the list of responses
                responses.append([ipv4Address, mac, device_description, deviceSN, dhcp])

    except socket.timeout:
        pass

    if display_format == "table":
        # Create a table with 5 columns
        table = PrettyTable()
        table.field_names = ["IPV4", "MAC", "Description", "Serial Number", "DHCP"]

        # Add rows with the extracted data
        for response in responses:
            table.add_row(response)

        # Print the table
        print(table.get_string(sortby="IPV4"))
def get_local_ip():
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    try:
        # Doesn't even have to be reachable
        sock.connect(('10.255.255.255', 1))
        local_ip = sock.getsockname()[0]
    except Exception:
        local_ip = '127.0.0.1'
    finally:
        sock.close()

    return local_ip

# Define the byte array
packet = bytes([
  0x3c, 0x3f, 0x78, 0x6d, 0x20, 0x76, 0x65,
  0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31,
  0x2e, 0x30, 0x22, 0x20, 0x65, 0x6e, 0x63, 0x6f,
  0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x75, 0x74,
  0x66, 0x2d, 0x38, 0x22, 0x3f, 0x3e, 0x3c, 0x50,
  0x72, 0x6f, 0x62, 0x65, 0x3e, 0x3c, 0x55, 0x75,
  0x69, 0x64, 0x3e, 0x37, 0x34, 0x46, 0x31, 0x45,
  0x44, 0x33, 0x37, 0x2d, 0x35, 0x45, 0x38, 0x32,
  0x2d, 0x34, 0x33, 0x45, 0x38, 0x2d, 0x39, 0x41,
  0x36, 0x31, 0x2d, 0x36, 0x36, 0x46, 0x43, 0x44,
  0x33, 0x32, 0x39, 0x32, 0x36, 0x45, 0x32, 0x3c,
  0x2f, 0x55, 0x75, 0x69, 0x64, 0x3e, 0x3c, 0x54,
  0x79, 0x70, 0x65, 0x73, 0x3e, 0x69, 0x6e, 0x71,
  0x75, 0x69, 0x72, 0x79, 0x3c, 0x2f, 0x54, 0x79,
  0x70, 0x65, 0x73, 0x3e, 0x3c, 0x2f, 0x50, 0x72,
  0x6f, 0x62, 0x65, 0x3e
])

broadcast_ip = "239.255.255.250"
port = 37020
local_ip = get_local_ip()

# Send the UDP broadcast packet
send_udp_broadcast(packet, port, broadcast_ip, local_ip)

# Listen for responses

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Listen for responses and display in table format or raw XML.")
    parser.add_argument("display_format", choices=["table", "raw"], default="table", nargs='?', help="Display format (table or raw)")

    args = parser.parse_args()

    listen_for_responses(port, 5, args.display_format)
 
Oh BTW,
The edited edition of yours only gets a single device on network for some reason. And then locks the binding on socket and never being released upon end.

I believe it never gets to the point of:
sock.close()