Entire Product Categories at Risk
According to D-Link 39 models across Connected Home Products, including wifi cameras, camera recorders and storage, are affected by this single vulnerability. What does that mean in terms of exposure to consumers? In a collaboration with Shodan we discovered 400,000 devices publicly accessible that could be affected by this 0day. The DCS-930L camera alone made up 55,000 of the search results. Consumers are encouraged to update their devices with the latest firmware.
39 models across several D-Link Connected Home Product families are affected by this flaw, including WiFi Cameras, Camera Recorders, and Cloud Storage devices
How We Did It
We started out by examining the camera for physical access that might assist with later software-focused vulnerability analysis. We removed the casing and decided to target the TSOP Flash memory for data extraction and the pads at JP-2 for a possible interface. After some analysis using proprietary Senrio software and popular logic analyzer tools, we were able to determine that block JP-2 contained pins that transmitted data during boot. We were able to determine that this was a UART connection and reverse engineered the correct pinouts. We then proceeded with making these connections more accessible by soldering leads onto the JP-2 pads.
Soon, we had reliable physical access to the unprotected UART. We calculated the baud rates manually using the period of the pulses. This is calculated by measuring signals from the wires that we connected. We examine the duration or width of the smallest "pulse" (in this case 17.25μs). Since 17.25μs is 17.25 millionths of a second, we can calculate the baud rate by doing this math: (1/17.25)*1000000 = 57971
The calculated baud rate is thus 57971, which is close to the standard: 57600 (8 None 1). With this data we are able to decode the data transmitted by the device within the logic analyzer software and see that it was, in fact, a boot log. This data could also be trivially exported from the logic analyzer and parsed.
The first vulnerability we found was a technique to trivially exfiltrate files from the system. We discovered that we could download files via the web interface started by the system during boot. We used the UART interface to move files to the web server’s api directory, “/etc_ro/web/api/“, renamed them to a “.jar” file extension (so the browser would not try to render them), and then logged into the web interface, browsed to the files, and downloaded them over HTTP. While D-Link posts firmware publicly on their support site, and we easily extracted the filesystem with binwalk, this technique was incredibly valuable when we needed to extract files generated during runtime, like core dumps, from the system.
We began our analysis of dcp in IDA Pro. dcp is an ELF file running on Linux installed on a MIPS core. If you’ve worked with ARM before, MIPS is an easy transition. The registers and instructions are similar and MIPS is also a RISC architecture. The biggest catch to a novice MIPS reverser is delay slots. On MIPS the instruction following a transition of execution, like a branch or a call, is executed without being affected by the previous instruction. You can think of it as the following instruction being executed first. So when looking at the static disassembly, you will see an instruction loading the first argument into $a0 for a function call immediately after that function call, as at address 0x403a0c in the screenshot below
We expanded our script to bombard the dcp process with invalid requests to find out how the parser would perform and whether any of the strcpy()s would result in a stack buffer overflow. Over UART, we turned on core dumps with ‘ulimit -c unlimited’ and then sent the custom dcp commands over the network with 0x200 bytes of data in each value. Sure enough, dcp crashed and produced a core dump, which we downloaded over HTTP using the web server technique we had previously discovered.
Exploiting the overflow was straightforward once we realized that the command arguments were all written to an executable, hard-coded, address in process memory! IDA claimed the section was only configured to allow read/write access, but when we double checked and examined process memory over UART with ‘cat /proc/<pid>/maps’ we saw it was actually executable. This meant we could simply place shellcode in one of the command’s arguments, point the overwritten return address ($ra) to our shellcode, and not bother with a ROP chain.
For a Proof of Concept, we decided to change the device password. We wrote up a few lines of MIPS assembly code to call tdb_set_device_passwd() with a new password of our choosing (we chose ‘senrio’). The only tricky part was that we couldn’t use any nulls (as the overwrite is caused by an unbounded string copy that stops copying when it encounters a null) and the executable was based at 0x00400000. This was not a problem for overwriting the stored $ra with the address of our shell code because the system is little endian and 0x00 was the last byte we needed to write, but we did need the address for tdb_set_device_passwd() and a pointer to the string containing our new password.
We set the stored value of $s1 to the address of tdb_set_device_passwd() + 0x43434343 (“CCCC”) and the stored value of $s2 to the pointer to our new password + 0x43434343, and the stored value of $s0 to 0x43434343. We wrote shell code to subtract $s0 from $s1 and $s2 to get the correct addresses.
We crafted a new command message, assigning each key=value pair to hold a different part of the exploit, consisting of the shellcode, the password, and the overflow values. We only used 4 of the 5 keys, there is a key the command uses which we could have included but had no use for. Its absence prevented the function from actually trying to add a volume, lessening the footprint we left on the device.
After successfully exploiting the camera, we gathered information on how many users this would affect. We went to D-Link’s support site and downloaded old firmware releases for the 930L to find out when the bug was introduced. We extracted dcp from each release using binwalk and found that the class 6 parser was vulnerable when it was first introduced in version 1.12, released over a year ago on 03/16/2015.
To find out how many publicly available 930Ls the bug affected, we turned to Shodan for the camera’s unique web server response, “DCS-930L” and came up with 55,559 results. We assumed that not all the devices on Shodan were running the most recent version, so we looked for any updates to the web server response that could help identify firmware versions. According to their release notes, D-Link also introduced support for TLS in v1.12.
Affected Products: DCS-2132L, DCS-2136L, DCS-2210L, DCS-2230L, DCS-2310L, DCS-2330L, DCS-2332L, DCS-2630L, DCS-5009L, DCS-5010L, DCS-5020L, DCS-5029L, DCS-5030L, DCS-5222L, DCS-6004L, DCS-6010L, DCS-6212L, DCS-700L, DCS-7010L, DCS-800L, DCS-820L, DCS-825L, DCS-850L, DCS-855L, DCS-930L, DCS-931L, DCS-932L, DCS-933L, DCS-934L, DCS-935L, DCS-936L, DCS-942L, DCS-960L, DNR-202L, DNR-312L, DNR-322L, DNS-320L, DNS-327L, DNS-340L
Code Reuse Also Means Vulnerability Reuse
"Low-hanging" simple-to-exploit stack overflows have largely disappeared from traditional endpoints (computers and servers) thanks to better protections like stack cookies, ASLR, smarter compilers and other advanced mitigations. However, bugs like this are still alive and well in the embedded devices, ICS, and IoT that we use every day in our infrastructure, hospitals, and businesses. While our exploit code only changes the password, "remote code execution" means complete control of the device. It only takes a little more work to modify our proof-of-concept to do something different like install a backdoor, allowing an attacker persistent access to high value networks.
Stack overflow bugs like this are still alive and well in the embedded devices, ICS, and IoT that we use every day in our infrastructure, hospitals, and businesses.