Turning a Webcam Into a Backdoor

Posted by Chris Morales on Jan 12, 2016 5:00:00 AM

Find me on:

Why do this?

Reports of successful hacks against Internet of Things (IoT) devices have been on the rise. Most of these efforts have involved demonstrating how to gain access to such a device or to break through its security barrier. Most of these attacks are considered relatively inconsequential because the devices themselves contain no real data of value (such as credit card numbers or PII). The devices in question generally don't provide much value to a botnet owner as they tend to have access to lots bandwidth, but have very little in terms of CPU and RAM.

However these devices get more interesting to sophisticated attackers when they can be used to establish a persistent point of access in a network. Putting a callback backdoor into a webcam, for example, gives a hacker full-time access to the network without having to rely on infecting a laptop, workstation or a server, all of which are usually under high scrutiny and may often be patched.  On a tiny device, there is no anti-virus and no endpoint protection. In fact, no one thinks of the device as having software on it at all. This makes these devices potentially inviting for persistent attackers who rely on stealthy channels of command-and-control to manage their attacks.

The downside for the attacker is that this class of devices doesn't usually have any persistent storage that is really usable. Instead, they use nvram to store configuration and the flash ROM to store the running code.  So the attacker's hope for real persistence rests on being able to control what will be in the flash ROM. In this blog, we will explore how difficult it is to create a new flash image that could contain all the tools we need to have a real persistent backdoor to the network on which the device is installed. Once we have such a flash image, putting it in place could involve "updating" an already deployed device or installing the backdoor onto the device somewhere in the delivery chain - i.e. before it is received and installed by the end customer. For this experiment to be meaningful, it is imperative that the device continue to perform its normal function otherwise it would immediately raise suspicion or cause the customer to replace the device with a working version.

Getting started

In this scenario, the Vectra Threat Labs team purchased a consumer-grade D-Link WiFi web camera for roughly $30 USD*. Cracking open that little wonderful plastic case was an amazing experience with a kind reminder that a Leatherman is not the right tool for every job ...


A quick look at the circuit board shows:

  • WiFi antenna
  • Ralink RT5350F
  • SDram M12L2561616a-6t
  • Flash Rom MX25L3205

Dumping the flash memory

Given the presence of the flash memory chip on the PCB, we surmise that this is where the data/code is likely kept for persistence. So the first thing to do is to dump the content of that chip to see what is stored on it.

After hooking up a Bus Pirate to the board, we can use flashrom to dump the content.


#flashrom -p buspirate_spi:dev=/dev/ttyUSB0,spispeed=1M
flashrom v0.9.7-r1782 on Linux 4.0.0-kali1-amd64 (x86_64)
flashrom is free software, get the source code at

Calibrating delay loop... OK.
Found Macronix flash chip "MX25L3205(A)" (4096 kB, SPI) on buspirate_spi.
Found Macronix flash chip "MX25L3205D/MX25L3208D" (4096 kB, SPI) on buspirate_spi.
Found Macronix flash chip "MX25L3206E" (4096 kB, SPI) on buspirate_spi.
Multiple flash chip definitions match the detected chip(s): "MX25L3205(A)", "MX25L3205D/MX25L3208D", "MX25L3206E"
Please specify which chip definition to use with the -c <chipname> option.

Now we can dump the content of the flash chips for further analysis.

#flashrom -p buspirate_spi:dev=/dev/ttyUSB0,spispeed=1M -c 'MX25L3205(A)' -r MX25L3205-A

Analyzing the flash dump

Once we have a nice dump of the flash we can use binwalk to determine what is inside of it.

#binwalk -Me MX25L3205-A 
0             0x0             uImage header, header size: 64 bytes, header CRC: 0x11BEF629, created: Tue Feb  3 11:07:53 2015, image size: 111116 bytes, Data Address: 0x80200000, Entry Point: 0x80200000, data CRC: 0xCD95F789, OS: Linux, CPU: MIPS, image type: Standalone Program, compression type: none, image name: "SPI Flash Image"
91040         0x163A0         U-Boot version string, "U-Boot 1.1.3"
105424        0x19BD0         HTML document header
105777        0x19D31         HTML document footer
105780        0x19D34         HTML document header
105979        0x19DFB         HTML document footer
106140        0x19E9C         HTML document header
106840        0x1A158         HTML document footer
210495        0x3363F         PEM certificate
211671        0x33AD7         PEM RSA private key
327680        0x50000         uImage header, header size: 64 bytes, header CRC: 0xABF213A9, created: Tue Feb  3 11:07:48 2015, image size: 3730981 bytes, Data Address: 0x80000000, Entry Point: 0x8038B000, data CRC: 0x2829F3C1, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: "Linux Kernel Image"
327744        0x50040         LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 6394309 bytes327744        0x50040         LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 6394309 bytes

So the format of this firmware consists of a u-boot and a Linux kernel and image.

We could have used dd, lzma or cpio to extract the content of the firmware or we can let binwalk do this work. We still need to extract the last step of the cpio image to see the content of the image.

#cpio -ivd --no-absolute-filenames -F. 0.cpio 

Once this last step is done, we can access the Linux image filesystem.

One interesting binary in the filesystem is the /bin/upgradefw,  this seems to be the executable used to performed verification and update of the firmware.

#file ./bin/upgradefw
./bin/upgradefw: ELF 32-bit LSB executable, MIPS, MIPS-II version 1 (SYSV), dynamically linked, interpreter /lib/, stripped

Analyzing the upgradefw binary

For this section we are going to rely on IDA Pro as the tool of choice to reverse-engineer the upgrade binary.

IDA is able to take a very good first pass at the binary which makes it way easier to analyze. Following the code path from the main function brings us pretty rapidly to a function named "check" that does most of the work of verifying if the flash image is valid before sending it to mtd_write.

The validation done by the upgradefw binary seems to include a few crc32 checks, memmem/strstr checks and some loop that computes a value and compares it to a fixed value or two.

The logic flow of the check function between the entry point and a success return looks roughly like this:

  1. Check if file opened correctly
  2. Check size of the file
  3. Load file and check that read worked
  4. Check the "Signature: "

  5. Check the "Release: "

  6. Compare the Release to the current Release

  7. Uboot/uimage check routine

    switching to x86 here for the 55AA55AA checksum.

Adding a backdoor

At this point, adding a backdoor roughly devolves to adding a service inside a Linux system - in our case, all we want is a simple connect-back Socks proxy. This can either be accomplished with a srelay and netcat in the startup script or more optimized C code, or one could go with a simple callback backdoor with a shell using netcat and busybox which are already present on the system. 

It's always a good idea to be as lightweight as possible on the features added - after all, we don't have a full laptop to work with here, but rather a tiny webcam with 4MB of ROM.  So adding too much functionality is just going to break the software. While we are making the modification, we can also remove the capacity to reflash the device in the future. This would prevent an administrator-initiated firmware update which would remove our backdoor. 


After spending some time building a repackaging script, we found a nice script on the Ralink website that ended up being pretty useful.

use it with:

make -f Makefile.4M

After that, all that is needed is a fix to the checksum in the file.  This can either be achieved with a RaLink utility name addchecksum or by manually fixing the checksum. The offset/range the checksum use can be discovered in both the upgradefw or addchecksum binary.  And as usual...  check your endianness. 

Testing a connect back

Using the telnetd / busybox / netcat we can bring back a telnet socket to an outside host to have remote persistence to the webcam. With the webcam acting as a proxy, the attacker can now send control traffic into the network to advance his attack, and likewise use the webcam to siphon out stolen data. 

Escape character is '^]'.
(none) login: admin
BusyBox v1.12.1 (2015-11-11 05:41:04 UTC) built-in shell (ash)
Enter 'help' for a list of built-in commands.

# ls /bin
iwpriv          pcmcmd          nvram_daemon    ntpclient       sounddb         ipush           touch           pwd             ls              cp
ov7740          switch          mii_mgr         mtd_write       notifystream    schedule        sync            ps              login           chmod
uvc_stream      gpio            ated            msmtp           mydlinkevent    lanconfig       sleep           ping            kill            cat
mail            nvram_set       reg             mDNSResponder   imagetp         iperf           sh              mount           grep            ash
i2c             nvram_get       pppoecd         lld2d           upgradefw       inadyn          sed             mknod           echo            busybox
swing           ralink_init     openssl         disablebonjour  audiopush       umount          rm              mkdir           date            alphapd



So does all this mean that D-Link's web camera has a major security issue? Not necessarily - we get what we pay for, and asking a vendor who sells a webcam on Amazon for $30 to provide safe firmware update features which would require a TPM or a specialized chip to verify the content and signature of a software update is not very realistic. Rather the point of this demonstration is to highlight the real impact that IoT devices pose to the attack surface of a network. As we've shown, the barriers to hacking these devices are relatively low, and even the most basic devices can provide the plumbing for a persistent command-and-control channel. While these devices are low-value in terms of hard costs, they still matter to the security of the network, and teams need to keep an eye on them to reveal any signs of malicious behavior. 

*Vectra disclosed the issue to D-LInk in early December 2015. As of January 7, 2016, the company has not provided a fix.

Topics: IoT, Internet of Things, APT, Monitoring

Subscribe to the Vectra Blog

Recent Posts

Posts by Topic

Follow us