hikvision sdap tool linux command line

JaceKac

n3wb
Joined
May 15, 2023
Messages
10
Reaction score
1
Location
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?
 

trempa92

Pulling my weight
Joined
Mar 26, 2020
Messages
745
Reaction score
231
Location
Croatia,Zagreb
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.
 

trempa92

Pulling my weight
Joined
Mar 26, 2020
Messages
745
Reaction score
231
Location
Croatia,Zagreb
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()))
 

JaceKac

n3wb
Joined
May 15, 2023
Messages
10
Reaction score
1
Location
Poland
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
 

trempa92

Pulling my weight
Joined
Mar 26, 2020
Messages
745
Reaction score
231
Location
Croatia,Zagreb
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
 

JaceKac

n3wb
Joined
May 15, 2023
Messages
10
Reaction score
1
Location
Poland
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
 

trempa92

Pulling my weight
Joined
Mar 26, 2020
Messages
745
Reaction score
231
Location
Croatia,Zagreb
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

JaceKac

n3wb
Joined
May 15, 2023
Messages
10
Reaction score
1
Location
Poland
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
 

trempa92

Pulling my weight
Joined
Mar 26, 2020
Messages
745
Reaction score
231
Location
Croatia,Zagreb
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.
 

JaceKac

n3wb
Joined
May 15, 2023
Messages
10
Reaction score
1
Location
Poland
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()))
 

trempa92

Pulling my weight
Joined
Mar 26, 2020
Messages
745
Reaction score
231
Location
Croatia,Zagreb
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:

JaceKac

n3wb
Joined
May 15, 2023
Messages
10
Reaction score
1
Location
Poland
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 ?
 

trempa92

Pulling my weight
Joined
Mar 26, 2020
Messages
745
Reaction score
231
Location
Croatia,Zagreb
Increase packet byte that you recieve from 1024 to lets say MTU limit size to avoid fragmentation of UDP packets.

1686729378908.png
 

trempa92

Pulling my weight
Joined
Mar 26, 2020
Messages
745
Reaction score
231
Location
Croatia,Zagreb
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
 

JaceKac

n3wb
Joined
May 15, 2023
Messages
10
Reaction score
1
Location
Poland
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)
 

trempa92

Pulling my weight
Joined
Mar 26, 2020
Messages
745
Reaction score
231
Location
Croatia,Zagreb
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()
 
Top