Using a Raspberry Pi Pico to Hack an IP Camera
Having too much cheer during the holidays? In this month’s article, Colin offers a diversion from the jolly season by urging developers to retreat to the basement to brush up on hardware hacking skills. He shows how a low-cost Raspberry Pi Pico and a TP-Link Tapo C200 smart IP camera could become the next automated bird deterrent or a home automation server.
The holidays are a great time to pick up some low-cost IoT hardware for practicing or developing your hardware-hacking skills. In this article, I’ll go over some work on the TP-Link Tapo C200 smart Internet Protocol (IP) camera. I use this camera as the basis for several labs in my undergraduate course on cybersecurity at Dalhousie University. It’s also a heavily attacked device. You’ll find several nice websites and repositories that have similar work. In particular, I first used the work by DrmnSamoLiu on GitHub [1], but several other resources are also available [2]. Despite all the attacks, there is still lots of analysis left!
One alluring feature of this camera is its very low cost—it often appears in sales, reducing the cost further. And it features some interesting hardware, including a camera with pan-tilt capability, a microphone, and a speaker. It also runs Linux with Wi-Fi connectivity, so if you could run your own software on this device, you could turn it into anything from an automated bird deterrent to a local, miniature, home automation server.
To make this as accessible as possible, I’ll use the Raspberry Pi Pico as the actual hardware-hacking tool. Onto this board we’ll load several different firmware images to give us the various interfaces we need to work with the Tapo C200.
FIRST LOOKS
When looking at a device to analyze, one cheat is to use the FCC-ID that any wireless device is required to have. Looking up the FCC-ID of this device (2AXJ4C200V2) [3] will give you internal photos of the main board. I often use this to check if the device appears to have some internal headers that might make attacking it easier, before even buying it.
In this case, I already knew the device had lots of prior attacks, but if you are checking out a holiday deal on another IoT device, check the internal photos in the FCC filings to get an idea of what hardware is present. A photo I took of the main board is given in Figure 1. Of particular interest is the main System on Chip (SoC), which is an Ingenic T31. Once you find the datasheet for this device, it will tell you that the device is a MIPS32 architecture, highly integrated device, with DDR memory on-board and both video and image signal processors. On the other side of the board (not shown) is the SPI flash chip (XMC 25QH65C), which appears to be the only non-volatile memory on this device. The normal first order of business would be to see if we can dump this flash memory chip, which we’ll do using the classic “clip on reader,” before showing you how to do this over the serial port using U-Boot.
SPI FLASH DUMPING, ROUND 1
The normal way of dumping SPI flash would be to use a hardware interface with the flashrom tool. The first thing I did was program the Raspberry Pi Pico with the pico-serprog firmware made by hardware hacker Thomas Roth (“stacksmashing”) [4]; specifically, I used a slightly extended version of it, from my companion repository for this article [5].
To use this tool, we simply attach the Raspberry Pi Pico, using either a SOIC-8 IC test clip or by connecting each of the SPI wires, as shown in Figure 2. The one caveat here is that we need to hold the main SoC in reset, to prevent it from attempting to access the SPI flash chip. In this case, we can find from the datasheet that SoC pin 7 is the reset pin. Looking carefully at the PCB, you’ll find an open spot where a resistor or capacitor could be mounted on the trace connected to Pin 7 on the PCB. You can either use the pad to hold the reset line low with a wire, or just solder a blob onto the pins to hold the pin in reset.
Either way, once this is done, using flashrom should work to dump the binary. See the companion repository [5] for the full description of the commands. With a binary in hand, we can do an initial analysis.
BINWALKING
The tool of choice for analyzing such firmware images is called binwalk. This open-source tool can automatically find interesting bits of data, and will automatically extract them if we run the simple command binwalk -e spi.bin, where spi.bin was the file we read out using flashrom.
Running the command will result in a number of interesting-sounding results from it. In particular, it has extracted the root filesystem to a new folder, “squashfs-root”.
Looking at this filesystem, we can find two of the most interesting files for our IoT exploration, /etc/passwd and /etc/shadow. They contain a list of the users along with their hashed passwords. Copies of these files are given in Listing 1 and Listing 2, respectively. The hashed passwords mean we’d need to run a password cracker. But we can compare multiple copies of the devices to confirm that the same password is used across all devices.
Listing 1
The “passwd” file has the hashed root password, but in this case the shadow file (Listing 2) has this disabled.
root:$1$ORLLCgGG$/0YVH02yJhoAVshA3pdU40:0:0:root:/root:/bin/ashnobody:*:65534:65534:nobody:/var:/bin/falseadmin:*:500:500:admin:/var:/bin/falseguest:*:500:500:guest:/var:/bin/falseftp:*:55:55:ftp:/home/ftp:/bin/false
Listing 2
Modern devices used the shadow file, which won’t be readable during normal operation. The root user is disabled because there is no valid hash present.
root:x:0:0:99999:7:::daemon:*:0:0:99999:7:::ftp:*:0:0:99999:7:::network:*:0:0:99999:7:::nobody:*:0:0:99999:7:::
What is interesting on this device is that the shadow file in Listing 2 has an “x” in place of the hashed password. This prevents the login, since Linux is expecting a hashed password here. In fact, the hashed password probably should not have been left in /etc/passwd, but this bit of leftover information gave us a default password that was used at one point. Because the actual shadow file (which Linux is using) has this disabled, we know that we won’t be able to log in directly, anyway.
But enough looking through files. Let’s start talking to our device while it’s operating.
SERIAL LINK ONLINE
Looking at the main board from Figure 1, the bottom right area of the board has some silkscreen markings reading TX/RX/GND/VCC, which suggest a serial port is present. I’ve separated out this section of the photo so you can get a closer look in Figure 3. In earlier versions of the hardware, you can solder header pins onto those pads and get a serial port. On the later hardware revisions, you need one more step. The zoomed-in view in Figure 3 shows a few 0402-size pads with no components mounted. These are labelled R1027 and R1028. The manufacturer has added some-do-not-mount (DNM) resistors to make your life a little harder.

You’ll need to either mount R1027 and R1028, or just short those pads with solder to activate the serial port.
You’ll need to jumper those pads first, and then you’ll find a serial port at 115200 baud rate. If you don’t have a USB-Serial adapter, you can re-use the Raspberry Pi Pico and reflash it with a USB-CDC firmware (see companion repository [5]). This firmware is the pico-uart-bridge project by Álvaro Fernández Rojas (“Noltari”) [6]. As I promised this entire article uses the low-cost Raspberry Pi Pico for everything!
Once the system eventually boots, you get a login prompt, but if you enter the root user, you can get a response that the user is invalid (since it’s been disabled). So we need to go a little further to get access to this system.
DAS U-BOOT, ROUND 1
The most common embedded Linux bootloader is called Das U-Boot (or just “U-Boot” for short). This bootloader has a powerful prompt that lets you access memory along with changing the Linux boot command line. One common attack is to modify the Linux command line to add an “init” argument that opens a shell and skips the login process entirely.
One of the first orders of business on an embedded Linux system will be to access the U-Boot console. During the boot process you can see the typical message that says “Autobooting in 1 seconds.” (This is also shown in Listing 3.) In the old days of unsecured IoT devices, you could press Enter during this message to enter the boot console; but these days, manufacturers try to disable this attack.
Often, however, we can force the bootloader entry by shorting the SPI flash pins as the correct time, as shown in Figure 4. This type of attack is called PIN2PWN. The timing here is critical—we need to leave the SPI flash working while the U-Boot bootloader loads, but then short the pins when it tries to load the Linux kernel. If we’re successful, we’ll see a message like Listing 3, which is the U-Boot console. You might have to experiment with the timing to get this working, or just jump ahead to the second method.

PIN2PWN causes an invalid SPI data response that causes the bootloader to drop to a recovery prompt, requiring just something to short two of the SPI data pins.
Listing 3
Watching the boot process shows you where to interrupt the boot to drop to the U-Boot console, interrupting it either using PIN2PWN or the serial password.
Now running in RAM - U-Boot at: 83fd0000MMC: msc: 0the manufacturer 20SF: Detected XM25QH64CIn: serialOut: serialErr: serialGPIO : 67894000 -> 67894000the manufacturer 20SF: Detected XM25QH64C--->probe spend 4 msSF: 8388608 bytes @ 0x0 Read: OK--->read spend 2687 ms------Firmware check pass!-----Autobooting in 1 secondsisvp_t31#
As a special hint: this device actually has two U-Boot consoles. If you watch the normal boot process, you’ll notice two sequences that say “Autobooting in 1 seconds,” and we actually want to target the second U-Boot console.
DAS U-BOOT, ROUND 2
Besides using PIN2PWN, how does the manufacturer enter U-Boot during development? It turns out there is actually a password for the bootloader. This was listed on the prior work webpage, and was discovered as part of analyzing the open-source code released for GPL compliance.
This means you can also enter the U-Boot console by simply typing slp over the serial port during the autoboot phase. Again, you ideally want to enter the second U-Boot instance. If this works, you’ll get the same console that is the final line of Listing 3.
SPI FLASH DUMPING, ROUND 2
If you didn’t have an SOIC-8 clip, we can use the U-Boot console to access the SPI flash. The commands in Listing 4 first detect the flash (sf probe), followed by copying a section of it to internal memory (sf read). The final command dumps 256 bytes of the internal memory. We can transfer off this internal memory copy using a simple script. The addresses of the flash memory and the internal memory were printed during the boot process, or you could look at the commands run on boot normally to understand the address space.
Listing 4
Using the U-Boot console allows you to dump the SPI flash contents directly.
isvp_t31# sf probethe manufacturer 20SF: Detected XM25QH64Cisvp_t31# sf read 0x800000 0 0x100000SF: 1048576 bytes @ 0x0 Read: OKisvp_t31# md.b 0x800000 25600800000: 06 05 04 03 02 55 aa 55 aa 0c 00 00 98 40 00 00 .....U.U.....@..00800010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...................
The companion repository [5] includes an example Python script to dump the entire flash automatically using this interface. There are more advanced U-Boot features that we can use to transfer files, but this shows that a simple console provides everything we need to read the entire filesystem out, with almost no additional hardware.
But reading the filesystem out isn’t the most interesting thing we can do. The grand finale is to log into the system “live,” so we can explore it on the hardware, itself.
LINUX PASSWORD BYPASS
If you issue the command printenv in the U-Boot console, you’ll get some environmental variables; a subset of them is shown in Listing 5. In particular bootargs is the Linux boot arguments, and bootcmd is the command run to boot the kernel. We can change bootargs by running the command in Listing 6. This will change Linux, so it boots into a basic shell, instead of running the normal initialization commands.
Listing 5
The environmental variables include the Linux boot arguments.
isvp_t31# printenvbaudrate=115200bootargs=console=ttyS1,115200n8 mem=45M@0x0 rmem=19M@0x2d00000 root=/dev/mtdblock6 rootfstype=squashfs spdev=/dev/mtdblock7 noinitrd init=/etc/preinitbootcmd=sf probe;sf read 0x80700000 0x80200 0x175000; bootm 0x80700000bootdelay=1
Listing 6
We can re-write the boot arguments to boot to a simple shell.
setenv bootargs console=ttyS1,115200n8 mem=42M@0x0 rmem=22M@0x2a00000root=/dev/mtdblock6 rootfstype=squashfs spdev=/dev/mtdblock7 noinitrdinit=/bin/sh
If your bootcmd differs from Listing 5, you might be in the wrong U-Boot instance. The other U-Boot instance seems to have an invalid boot argument.
Once you’re in this console, you can explore the system “live.” Because we interrupted the boot process (replacing the correct init call with our shell), many systems will be broken. You can improve this by first running the command /etc/preinit, which was the command we skipped. You might then want to run some of the commands in /etc/init.d for example, but you’ll likely find many things broken, since this just gave us a basic console. To get persistent access, we’d need to rewrite the root password and save it back to the SPI flash, and enable the root user. You could also turn on a more convenient network-based interface such as an SSH server. All of this will be a topic for future exploration!
FUTURE WORK
In this article, I demonstrated how you can get into hardware hacking with low-cost tools. As of this writing, the Raspberry Pi Pico is $4 from Sparkfun. You’ll spend more buying the target and even the jumper wires than you will on the Pico, itself.
The C200 IP camera is an interesting target, because a robust community of hardware hackers is looking at it, and the device itself has a lot of capabilities. With a little more effort, you can run your own applications on it. But even if you don’t plan on doing that, it is a nice project to work on during the long winter nights.
Be sure to check out my companion GitHub repository [5], where I’ve posted some of the scripts developed during this work. It also includes links to several other hardware hackers who have explored the device, including a graduate student here at Dalhousie who found how you can blink the lights on your device.
REFERENCES
[1] Tapo C200 Hacking by “drmnsamoliu”: https://drmnsamoliu.github.io/
[2] Tapo C200 Hacking by “nervous-inhuman”: https://github.com/nervous-inhuman/tplink-tapo-c200-re
[3] https://www.fcc.gov/oet/ea/fccid
[4] https://stacksmashing.net/
[5] Colin O’Flynn, Companion Repository (Circuit Cellar Embedded System Essentials): https://github.com/colinoflynn/circuitcellar-EmbeddedSystemEssentials
[6] https://github.com/Noltari/pico-uart-bridge
PUBLISHED IN CIRCUIT CELLAR MAGAZINE • JANUARY 2024 #414 – Get a PDF of the issue
Colin O’Flynn has been building and breaking electronic devices for many years. He is an assistant professor at Dalhousie University, and also CTO of NewAE Technology both based in Halifax, NS, Canada. Some of his work is posted on his website (see link above).



