I got couple of Hikvision cameras that needed to have their passwords reset.
Instead of reset-to-factory default button these cameras have very elaborate password reset process.
Officially one must download SADP tool, get the serial number off the camera, fetch it to the Hikvision support, then they generate you a reset code that you plug in into the camera.
The unreliable Hikvision support can be bypassed with this tool (more details here).
I feel very dirty because I had to install the SADP in a Windows virtual machine (it does not work under Linux).
Interesting that the tool is build around QT and libpcap so technically it should not be too difficult to port it to Linux.
Looking at traffic captures the tool discovers the camera via multicast (239.255.255.250, udp port 37020) with this payload:
<?xml version="1.0" encoding="utf-8"?><Probe><Uuid>13A888A9-F1B1-4020-AE9F-05607682D23B</Uuid><Types>inquiry</Types></Probe>
The camera responds to with this:
<?xml version="1.0" encoding="UTF-8"?>
<ProbeMatch><Uuid>FC25924E-AFE2-49E6-ACC9-F84A6859054D</Uuid>
<Types>inquiry</Types>
<DeviceType>38930</DeviceType>
<DeviceDescription>DS-2CD2432F-IW</DeviceDescription>
<DeviceSN>DS-2CD2432F-IW20150126CCCH502126167</DeviceSN>
<CommandPort>8000</CommandPort>
<HttpPort>80</HttpPort>
<MAC>c0-56-e3-fe-42-92</MAC>
<IPv4Address>10.1.1.251</IPv4Address>
<IPv4SubnetMask>255.255.255.0</IPv4SubnetMask>
<IPv4Gateway>10.1.1.1</IPv4Gateway>
<IPv6Address>::</IPv6Address>
<IPv6Gateway>::</IPv6Gateway>
<IPv6MaskLen>64</IPv6MaskLen>
<DHCP>false</DHCP>
<AnalogChannelNum>0</AnalogChannelNum>
<DigitalChannelNum>1</DigitalChannelNum>
<SoftwareVersion>V5.2.5build 141201</SoftwareVersion>
<DSPVersion>V5.0, build 140714</DSPVersion>
<BootTime>2016-03-06 09:18:17</BootTime>
</ProbeMatch>
This is all nice and easy to replicate, except when discovering that when resetting the password the tool talks to camera directly via ethernet frames:
Reset packet:
12:14:16.063953 52:54:00:db:ae:e4 > XX:XX:XX:XX:XX:XX, ethertype Unknown (0x8033), length 80:
0x0000: 2102 0142 0000 173a 0604 0a00 ba54 5254 !..B...:.....TRT
0x0010: 00db aee4 0a01 0102 XXXX XXXX XXXX 0a01 ........XXXXXX..
0x0020: 01fb ffff ff00 5252 5364 5264 6572 6439 ......RRSdRderd9
0x0030: 0000 a100 0000 0000 0000 0000 0000 0000 ................
0x0040: 0000 ..
Response packet:
12:14:16.094857 XX:XX:XX:XX:XX:XX > 52:54:00:db:ae:e4, ethertype Unknown (0x8033), length 260:
0x0000: 2101 01f6 0000 173a 0604 0b01 8a3b XXXX !......:.....;XX
0x0010: XXXX XXXX 0a01 01fb ffff ffff ffff 0000 XXXX............
0x0020: 0000 ffff ff00 4453 2d32 4344 3234 3332 ......DS-2CD2432
0x0030: 462d 4957 3230 3135 3031 3236 4343 4348 F-IW20150126CCCH
0x0040: XXXX XXXX XXXX XXXX XX00 0000 0000 0000 XXXXXXXXX.......
0x0050: 0000 0000 0000 0000 9812 0000 1f40 0000 .............@..
0x0060: 0001 0000 0000 5635 2e32 2e35 6275 696c ......V5.2.5buil
0x0070: 6420 3134 3132 3031 0000 0000 0000 0000 d.141201........
0x0080: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0090: 0000 0000 0000 5635 2e30 2c20 6275 696c ......V5.0,.buil
0x00a0: 6420 3134 3037 3134 0000 0000 0000 0000 d.140714........
0x00b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x00c0: 0000 0000 0000 3230 3136 2d30 332d 3036 ......2016-03-06
0x00d0: 2030 393a 3138 3a31 3700 0000 0000 0000 .09:18:17.......
0x00e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x00f0: 0000 0000 0000 ......
Now looking further it appears that discovery as well as expected UDP communication there is also ethernet frame type of communication going on in parallel:
Broadcast:
12:13:29.539493 52:54:00:db:ae:e4 > ff:ff:ff:ff:ff:ff, ethertype Unknown (0x8033), length 80:
0x0000: 2102 0142 0000 1739 0604 0300 80b6 5254 !..B...9......RT
0x0010: 00db aee4 0a01 0102 ffff ffff ffff 0000 ................
0x0020: 0000 0000 0000 fe80 0000 0000 0000 889f ................
0x0030: 720d 7c8f 8429 0000 0000 0000 0000 0000 r.|..)..........
0x0040: 0000 ..
Response:
12:13:29.555356 XX:XX:XX:XX:XX:XX > 52:54:00:db:ae:e4, ethertype Unknown (0x8033), length 416:
0x0000: 2101 01f6 0000 1739 0604 0400 8c42 XXXX !......9.....BXX
0x0010: XXXX XXXX 0a01 01fb ffff ffff ffff 0000 XXXX............
0x0020: 0000 ffff ff00 4453 2d32 4344 3234 3332 ......DS-2CD2432
0x0030: 462d 4957 3230 3135 3031 3236 4343 4348 F-IW20150126CCCH
0x0040: XXXX XXXX XXXX XXXX XX00 0000 0000 0000 XXXXXXXXX.......
0x0050: 0000 0000 0000 0000 9812 0000 1f40 0000 .............@..
0x0060: 0001 0000 0000 5635 2e32 2e35 6275 696c ......V5.2.5buil
0x0070: 6420 3134 3132 3031 0000 0000 0000 0000 d.141201........
0x0080: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0090: 0000 0000 0000 5635 2e30 2c20 6275 696c ......V5.0,.buil
0x00a0: 6420 3134 3037 3134 0000 0000 0000 0000 d.140714........
0x00b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x00c0: 0000 0000 0000 3230 3136 2d30 332d 3036 ......2016-03-06
0x00d0: 2030 393a 3138 3a31 3700 0000 0000 0000 .09:18:17.......
0x00e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x00f0: 0000 0000 0000 029c 5648 0a01 0101 0000 ........VH......
0x0100: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0110: 0000 0000 0000 0000 0000 0000 0000 0007 ................
0x0120: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0130: 0000 0000 0000 0000 0000 0000 0000 0050 ...............P
0x0140: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0150: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0160: 0000 4453 2d32 4344 3234 3332 462d 4957 ..DS-2CD2432F-IW
0x0170: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0180: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0190: 0000
So theoretically it is possible to create a tool based on the reset password code generator to completely cut out middle man.
This is the way I see it working:
1) Discover camera and get serial number and camera ip
2) Get camera date/time via simple GET to port 80.
3) Generate reset code with camera serial number and date/time
4) send magic packet to reset camera.
I found some examples of the traffic that does not contain fe80 0000…XXXX…0000 bit at the end (looks like previous version of SADP Tool didn’t append that crap). I successfully replayed that packet.
I have noticed that the checksum does not include the source (header) of the packet, so as long as the MAC address matches in the body the header can be spoofed.
I have changed the mac address on VM where SADP Tool was running and looks like4 bytes between Source MAC and Destination MAC in the body changes. As well as 2x 2 bytes surrounding 06040300.
If I increment any number by one and decrement @ 0x0018 the packet gets response. This implies that the check sum is only 2 bytes long.
So far I figured out the check sum for older type of discovery packet (without crap at the end of the packet).
the check sum is located here:
0x0010: 00db aee4 0a01 0102 ffff ffff ffff 0000
In this example it is 0102.
Actually the check sum is 0201 (reversed order).
The check sum algorithm is 16-bit one’s complement.
The trick (which was given away by comparing sequential packets) is to ignore the header, and to reverse order in these two bytes:
0x0000: 2102 0142 0000 1739 0604 0300 80b6 5254
in example above they are check-summed as b680.
Next step is to see if I can apply the same method to the password reset packet….
At this stage I solved the following: discovery via frames, discovery via UDP, generate reset code and reset the camera via frame.
There is a potential problem to get camera time reliably (in case it is not configured in same subnet).
After poking around Sadp.dll I found these interesting XML strings:
<?xml version="1.0" encoding="utf-8"?><Probe><Uuid>%s</Uuid><Types>inquiry</Types></Probe>
<?xml version="1.0" encoding="utf-8"?><Probe><Uuid>%s</Uuid><Types>update</Types><MAC>%s</MAC><Password>%s</Password><IPv4Address>%s</IPv4Address><CommandPort>%d</CommandPort><HttpPort>%d</HttpPort><IPv4SubnetMask>%s</IPv4SubnetMask><IPv4Gateway>%s</IPv4Gateway><IPv6Address>%s</IPv6Address><IPv6Gateway>%s</IPv6Gateway><IPv6MaskLen>%d</IPv6MaskLen><DHCP>%s</DHCP></Probe>
<?xml version="1.0" encoding="utf-8"?><Probe><Uuid>%s</Uuid><MAC>%s</MAC><Types>reset</Types><Code>%s</Code></Probe>
<?xml version="1.0" encoding="utf-8"?><Probe><Uuid>%s</Uuid><MAC>%s</MAC><Types>reset</Types><Code>%s</Code><Password>%s</Password></Probe>
<?xml version="1.0" encoding="utf-8"?><Probe><Uuid>%s</Uuid><MAC>%s</MAC><Types>reset</Types><SyncIPCPassword>true</SyncIPCPassword ><Code>%s</Code><Password>%s</Password></Probe>
<?xml version="1.0" encoding="utf-8"?><Probe><Uuid>%s</Uuid><MAC>%s</MAC><Types>getcode</Types></Probe>
<?xml version="1.0" encoding="utf-8"?><Probe><Uuid>%s</Uuid><MAC>%s</MAC><Types>exchangecode</Types><Code>%s</Code></Probe>
<?xml version="1.0" encoding="utf-8"?><Probe><Uuid>%s</Uuid><MAC>%s</MAC><Types>activate</Types><Password>%s</Password></Probe>
<?xml version="1.0" encoding="utf-8"?><Probe><Uuid>%s</Uuid><MAC>%s</MAC><Types>getencryptstring</Types></Probe>
None of that proved to be useful of extracting local time (except inquiry).
See this post for actual script.