respective iPhone and Android app stores, but what if you wanted to use other browsers or clients? Since the documentation mentions the use of the Real Time Streaming Protocol (RTSP), couldn't any compatible client work?
This question prompted me to verify whether the camera could actually followed the RTP/RTSP specification (http://www.ietf.org/rfc/rfc2326.txt). According to the RFC documents, RTSP normally uses a similar type of authentication flow as Basic HTTP authentication requests. An Authorization: line is added with the username and password base64-encoded in the request header.
Sifting through documents of different Samsung DVR models publicly available, I tried many different variations of the RTSP protocol to try to elicit a response from the Samsung device:
telnet 192.168.0.25 4520 DESCRIBE rtsp://192.168.0.25/profile3/media.smp RTSP/1.0 Authorization: Basic [base64-encoded username]:[base64-decoded pw]) CSeq:1 OPTIONS rtsp://192.168.0.25/profile3/media.smp RTSP/1.0 CSeq: 1 DESCRIBE rtsp://10.240.56.200/mpeg4/media.smp RTSP/1.0 CSeq: 1 Accept: application/sdp Bandwidth: 384000 Accept-Language: de-DE User-Agent: QuickTime/7.4.5 (qtver=7.4.5;os=Windows NT 5.1Service Pack 3)
None of these commands would cause the server to reply. This prompted me to check to see if the Samsung device was also using a proprietary protocol to authenticate. Using Wireshark to capture the network traces while attempting to
login successfully to the DVR through Internet Explorer, I found one packet of interest:
The initial network frames exchanged in particular interested me because you can see the plaintext 'AUTHENTICATE' in the initial data payload. The packet also contains the ID: and PW: (not shown) and then traces of AUTHENTICATE_OK in the subsequent packet responses. This protocol is consistent with an online Samsung document called
"DVR Protocol Specification for NET-i (and WebViewer)" -- there are Part I and Part II specs. Part I deals with the authentication aspect. The packet structure is shown below:
The response packet according to the documentation matches the payload being sent for the SDE-5001 devices. I could see that S & V were the first two characters and AUTHENTICATE being in the middle of the packet. To help confirm that this packet would elicit a reply, I saved the data payload from Wireshark to a file called "authenticate_packet" and wrote this small Python script to see whether I could replay the authentication sequence:
import telnetlib tn = telnetlib.Telnet("192.168.0.25", 4521) data = open('authenticate_packet', 'r').read() tn.write(data) sess_op = tn.read_some() print sess_op
Instead of no response from the Samsung device, the response from the Samsung device
all of a sudden yielded:
00000000 53 56 36 41 55 54 48 45 4e 54 49 43 41 54 45 5f |SV6AUTHENTICATE_|
00000010 4f 4b 01 54 45 58 54 53 55 43 43 45 53 0a |OK.TEXTSUCCES.|
This experiment helped confirm that the Samsung SDE-5001 follows the same protocol as the Samsung DVR spec. However, the documentation also seemed to suggest that the username and password (ID/PASSWORD) were sent as cleartext. Decoding the authentication packet, however, yielded a bunch of encoded text. For instance, for the username "joesmith" and password "123456", the corresponding data was "GtxTGa3KAcI=" and "7c4a8d09ca3762af61e59520943dc26494f8941b".
to be the MD5 hash of the password.
document.login_page_submit.data1.value = data_parser(document.login_page.data1.value); document.login_page_submit.data2.value = hex_func_five(document.login_page.data2.value);
The data_parser() function appears to base64-encode the username, but the string doesn't match
the username string "GtxTGa3KAcI=" sent in the Wireshark network packet. Therefore, it appeared that the Samsung RTSP port was using some additional type of encoding that could only be studied by examining the ActiveX code.
When watching a successful authentication to occur, I noticed that Samsung's web
server renders a page that injects <object> tag into the DOM. This <object> tag is the ActiveX module.
The name of the file is webviewer.cab:
This CAB file can actually be downloaded from the system and extracted using the cabextract utility in Ubuntu:
wget http://184.108.40.206/webviewer.cab $ cabextract webviewer.cab webviewer.cab: WARNING; possible 7208 extra bytes at end of file. Extracting cabinet: webviewer.cab extracting H264GTileContainer.ocx extracting H264GCalendarCtrl.ocx extracting H264GTimeLineCtrl.ocx extracting H264GSetupBrowser.ocx extracting H264GMediaPlayer.ocx extracting H264GMediaSource.ax extracting H264GVideoDecoder.ax extracting H264GAudioDecoder.ax extracting H264GAudioDecoderADPCM.ax extracting H264GVideoRenderer.ax extracting XNS_h264.dll extracting H264MediaMan.dll extracting XRegistry.ocx extracting device_shr_h264.dll extracting h264decoder.dll extracting lib_VoiceEngine_dll.dll extracting webviewer.inf
The files that were extracted include OCX and DLL files, which are all Portable Executable (PE) files that can be loaded and run in Microsoft Windows. The ActiveX modules that are loaded by Internet Explorer to provide the GUI and controls for the Samsung SmartViewer software. The additional H.264-related modules appear to perform the audio/video decoding too.
Which of the modules is responsible for handling the initial authentication? Doing a search of the string exports with PEBrowser in the modules or simply a grep for the string for "AUTHENTICATE_OK" reveals that this code is actually contained in the file, device_shr_h264.dll.
grep AUTHENTICATE_OK * Binary file device_shr_h264.dll matches
The interactive debuggers Olly Dbg or IDA Pro (32-bit mode) can be used to try to understand what's happening. We can attach a process to Internet Explorer, login to the Samsung interface with a known username and password, and view the device_shr_h264.dll loaded in memory (listed as device~1.dll). We view the exported strings in the file and trace where the strings are used inside the code:
We can search for "AUTHENTICATE" and find the matching strings:
We can trace into this function and notice that the sprintf() command for the username and password is being generated:
A breakpoint can be added further upstream until you notice that the username and password are being passed into registers. OllyDbg will show these values in the registers window, so it's easy enough to see when they are referenced.
The exact location in which the user and password can reloading the web page and setting breakpoints until the appropriate sections can be isolated. I noticed that the username started to show up as a register location where the use of the ASCII string "VSS_SVP2.0" gets referenced.
In the following section of the assembly code, the byte referencing the address location DS:[ESI+10027BDC] is moved into the EDI register, XOR'd with the previous character (the EDL register is cleared to 0x00 earlier), and repeated until the end of the string is reached. This latter operation is done by using the SCAS opcode is used to increment the ESI register until what is stored in the AL register, 0x00, which is essentially implementing the strlen() function).
The equivalent code for the above assembly code in Python would essentially be:
constant = "VSS_SVP2.0" init_val = 0x00 for c in constant: init_val ^= ord(c)
There is additional code that attempts to XOR this value with other bytes referenced by 0x69A7BE8, but inspecting the memory contents using OllyDbg's Follow In Dump -> Immediate constant reveals that all the data is 0x00, leaving the result of the previous code to be unchanged. This section therefore seems to be a placeholder for more XOR mixing, but seems to be unused.
The key at address 0x69A9880 appears to start with the data 0x52, 0x50, 0x70, etc.. The maximum amount of space allocated to the username and password appears to be 32-bytes each, so the XOR operation seems to be limited to a 32-byte operation.
The above section of the assembly code is equivalent to the following Python code. Since many of the assembly instructions are performing byte-level operations, we often need to take the results of the AND/XOR operation and mask
the bits with the 0xFF byte. Assuming the secret key is 64-bytes, the XOR algorithm is therefore listed as follows:
def samsung_xor_encode(username, init_val): secret_key = [0x52, 0x50, 0x7, 0x15, 0x23, 0x33, 0x41, 0x49, 0x50, 0x53, 0x61, 0x00, 0x08, 0x16, 0x24, 0x26, 0x34, 0x42, 0x10, 0x28, 0x36, 0x44, 0x63, 0x56, 0x03, 0x11, 0x19, 0x29, 0x37, 0x45, 0x33, 0x56, 0x57, 0x04, 0x12, 0x20, 0x30, 0x38, 0x46, 0x58, 0x05, 0x13, 0x21, 0x31, 0x39, 0x47, 0x62, 0x06, 0x14, 0x22, 0x32, 0x40, 0x48, 0x08, 0x37, 0x18, 0x34, 0x26, 0x12, 0x38, 0x26, 0x58, 0x45, 0x08] val = "" for n, u in enumerate(username): result = (init_val ^ ord(u)) val += chr(result) cl = (~init_val & 0xFF) cl = cl >> 7 init_val = init_val << 1 cl = (cl + init_val) & 0xFF init_val = cl ^ secret_key[n] return valWe can then use this function to implement the XOR encryption:
init_val = 0x00 for c in constant: init_val ^= ord(c) encoded = samsung_xor_encode("johnsmith", init_val) decoded = samsung_xor_encode(encoded, init_val) print "Encoded username: %s" % (encoded.encode('base64')) print "Decoded username: %s" % (decoded)
The XOR algorithm can be verified by using known plaintext usernames and observing the authentication packets between the ActiveX module and the Samsung DVR. Since the XOR algorithm is used for both decryption and encryption, we can verify both by encoding the plaintext username as well as decoding the encrypted username. Fortunately, the password doesn't require this extensive reverse-engineering, since it only computes a standard MD5 hash against the password for authentication.
One important point that should be noted is that this information in this article details an encryption algorithm only used for authentication and not used for any type of copy protection. The intention of this writeup is to document my understanding of the authentication protocols for these DVR systems and to enable more browser-friendly plug-ins beyond Internet Explorer to work with these systems, especially since Samsung uses custom but publicly disclosed RTP/RTSP protocols to request video/audio streams once the authentication sequence is completed. If you're interested in doing so, please let me know!