Tuesday, May 28, 2013

Ambiguities in the wait_timeout parameter in MySQL

The wait_timeout parameter in MySQL defines the duration of inactive connections to remain open. However, when doing SHOW VARIABLES at a MySQL shell, you may be fooled into thinking that the setting is set to 28800 for all new connections:

mysql> show variables like '%wait_timeout%';
| Variable_name            | Value    |
| wait_timeout             | 28800    |
You have to keep in mind though that the setting is derived from either interactive_timeout or wait_timeout, depending on how you initiated the connection from MySQL. If you're using the MySQL client, chances are it's using the interactive_timeout.  This article helps provide some good explanation of the behavior: http://blog.mozilla.org/it/2012/04/24/when-is-qwait_timeout-not-wait_timeout/

Therefore, it's important to use the GLOBAL modifier to determine what the default settings are currently set: http://dev.mysql.com/doc/refman/5.1/en/show-variables.html
With the GLOBAL modifier, SHOW VARIABLES displays the values that are used for new connections to MySQL. If a variable has no global value, the session value is displayed. With SESSION, SHOW VARIABLES displays the values that are in effect forthe current connection. If no modifier is present, the default is SESSION. LOCAL is a synonym for SESSION.

Tuesday, May 7, 2013

Continued Reverse Engineering of the SDE-5001

After posting my previous writeup, I was sort of puzzled by the intricate nature of the authentication protocol for the Samsung SDE-5001.  There are third-party apps such as IP Cam Viewer that appear to login and authenticate correctly (assuming we designate the device as a Night Owl RTSP camera).  Were they simply implementing this proprietary Samsung protocol?

To better understand this issue, I decided to find a way to capture the network traces from a smartphone or a tablet.  To do so, I put my laptop's wireless card into hotspot mode and plugged the laptop into a wired Ethernet connection.  It turns out that Android (including Jelly Bean) devices can't connect to wireless networks placed in this mode, but at least Apple devices can do so.  I use an IPad to establish a WiFi connection to the laptop, allowing me to capture the network traces from the wireless Ethernet card.

By examining the Wireshark traces, it turns out that even though you specify RTSP port 4520, the IP Camera apps connects to port 4524 (+4 offset), which appears to accept authentication requests.

Capturing the network trace you see the following:
OPTIONS rtsp://myipcamera.example.com:4524/1 RTSP/1.0
CSeq: 1
User-Agent: IPCamViewer

When this request is given, the Samsung DVR responds with a 401 Unauthorized, a realm=, and a nonce= value:

RTSP/1.0 401 Unauthorized
CSeq: 1
Date: Wed May  8 06:39:55 2013 GMT
WWW-Authenticate: Digest realm="NET-i", nonce="0000000000000000000000002E923766"
The next sequence includes the Authorization: Digest header.  The realm value and nonce are replayed, and a response= hash is calculated.
OPTIONS rtsp://myipcamera.example.com:4524/1 RTSP/1.0
CSeq: 2
User-Agent: IPCamViewer
Authorization: Digest username="johnsmith", realm="NET-i", nonce="0000000000000000000000007B719AE4", uri="rtsp://myipcamera.example.com:4524/1", response="758b43dd292609c5b6e80084aa688ac5"

How is the response= value calculated?  Aparently it appears to follow the RFC2069 spec:

The documentation at the bottom of http://tools.ietf.org/html/rfc2617 shows how this digest can be calculated in the C language.  The Python equivalent is shown below.  Note that the OPTIONS: is used  since the previous network packet uses it instead of the more typical GET/POST verb requests.
import hashlib
username = "johnsmith"

ha1 =  hashlib.md5("%s:%s:%s" % (username, realm, password)).hexdigest()
ha2 = hashlib.md5("OPTIONS:%s" % uri).hexdigest()

response = hashlib.md5("%s:%s:%s" % (ha1, nonce, ha2)).hexdigest()
print response
I was able to confirm the hash value matched the one the Samsung device transmitted with this Python code. Therefore, it seems as if the Samsung device has both a proprietary way in its ActiveX control to authenticate and a more standards based to do so.

Monday, May 6, 2013

Reverse Engineering the Samsung SDE-5001's authentication protocol...

One of the major limitations in many of Samsung's IP cameras including the SDE-5001, is that they depend on Internet Explorer and ActiveX plugins to view video streams over the web. You can use the dedicated mobile apps from the
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 4520

DESCRIBE rtsp:// RTSP/1.0
Authorization: Basic [base64-encoded username]:[base64-decoded pw])

OPTIONS rtsp:// RTSP/1.0
CSeq: 1

DESCRIBE rtsp:// 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("", 4521)
data = open('authenticate_packet', 'r').read()
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".

Understanding how the ID and PASSWORD strings required some extra reverse engineering with the Samsung web interface and the ActiveX modules that get dynamically loaded in the browser. One thing to notice in the JavaScript
of the Samsung web interface that it embeds an <IFRAME> tag and attempts to log the user in with two functions. The data_parser() JavaScript code appears to encode data into a base64, while the second function hex_func_five() appears
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:
<script language="javascript">
writeObjCtrl(720, 576, 'obj', 'GTileContainerCtlDetroit', 'CLSID:26E1BEAF-C1A1-482b-8714-08844F1BCF7F', '../webviewer.cab#version=1,0,0,276');

This CAB file can actually be downloaded from the system and extracted using the cabextract utility in Ubuntu:


$ 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.

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.

In the next section of the code, we observe that a memory address location 0x069A9880 is referenced.     We notice that this address location is stored in the EDI register and the byte is XOR'd with the username. Essentially we have found the key used to perform the rest of the XOR encryption.

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 val

We 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!

GitHub's web hooks

Recently GitHub has made changes to their web hooks...

1. Your Webhooks need to be URL-encoded now.  In the past, you could get away with it and GitHub would handle the url-encoding themselves.   No longer.

2. All webhooks are now by default monitoring/tracking only push events.  If you have other events, you need to use the GitHub hooks API.

The best way to make these changes?  Use Chrome's Dev HTTP client: https://chrome.google.com/webstore/detail/dev-http-client/aejoelaoggembcahagimdiliamlcdmfm?hl=en

a. Add a Header with Authorization: token <token>where <token> represents your OAuth token for GitHub.

b. Change to use https://

c. Set to api.github.com/repos/<your GitHub owner>/<repo name>/hooks

d. Grab the webhook ID in the JSON response.

c. Set the JSON payload to be add_events and push like the following: