Following the work I did with another wifi camera (https://github.com/guino/WR301CH1KW) I decided to tackle another 'closed' camera I already had installed this year. This is a 'TUYA' camera which is known to be protective of how their devices can be accessed and used (no 'PC' apps for instance), but I still bought the device for the price, features and the fact it works with the existing wiring/chime of the house. The main goals as usual are to try to 'backup' the video contents of the device to my NAS (hopefully without using SD cards) and in this case access the camera feed from outer applications/PC.
The hardware model is listed as WFDBELL1 (website, etc) but I am pretty sure is just an OEM branding from the actual manufacturer (https://www.mearitek.com/products-bell-5s/) which I think also makes the doorbells for 'geeni' and 'merkury' (and probably others).
The first thing was to check if there was anything published on this type of camera online: turned out with some people insterested but not a lot of progress (https://github.com/AMoo-Miki/homebridge-tuya-lan/issues/4), but I already know there are a number of other cameras in the market with the same 'hisilicon' boards in them. So we start with a quick check for open ports:
nmap 10.10.10.7
Starting Nmap 7.80 ( https://nmap.org ) at 2020-11-30 16:45 EST
Nmap scan report for 060010869 (10.10.10.7)
Host is up (0.0099s latency).
Not shown: 996 closed ports
PORT STATE SERVICE
80/tcp open http
6668/tcp open irc
No ssh/telnet port open so my only option without tearing the device appart (to find a serial port) is to check for anything I can use in the web server. A quick check reveals the web server requests a user/password which some people in the thread above already had discovered (saving me the time), so lets fuzz this thing:
$ wfuzz -w common.txt --hc=404 --basic admin:056565099 http://10.10.10.7/FUZZ
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://10.10.10.7/FUZZ
Total requests: 951
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
Total time: 0
Processed Requests: 0
Filtered Requests: 0
Requests/sec.: 0
/.local/lib/python3.8/site-packages/wfuzz/wfuzz.py:77: UserWarning:Fatal exception: Pycurl error 28: Operation timed out after 90000 milliseconds with 0 bytes received
That was a waste... seems like the web server just doesn't respond when you provide a url it doesn't understand even with the valid user/password provided.
I tried a few more options/filters without much success (only found /search ), however one of the threads above had a few working URLs that they found by dumping the firmware (/devices/deviceinfo, /sys/reboot, etc), but the one that caught my attention was /proc/
Without any remote options left I decided to open the device and try the UART route... so I opened the device and found out the SoC chip is in fact hiSilicon (as suspected):
Also found/identified the flash chip (PDF is in the project):
And for the next part: found and identified the UART pins, measured the level (3.3V) and probed potential GND/RX/TX pins:
I was hoping that like many other cameras we'd have a standard uboot hopefully configured in a way I could interrupt/change settings before loading kernel but I was surprised:
hisi-sdhci: 0
PPS:Jul 22 2019 00:22:28 meari_c5 0
please input password::
That doesn't look like u-boot, but anyway I tried different passwords without success and after searching found someone also looking for a way around it (https://github.com/DanTLehman/orion_sc008ha). I did play a little bit with it and that ppsMmcTool.txt file (see https://github.com/DanTLehman/orion_sc008ha/issues/1) but figured it was time to get more serious... time to pull out the programmer (available for around $15 just about everywhere):
I had read (probably from one of the mentioned links) that the only way they were getting to read/write these chips was by removing it from the board, but gave it a try anyway without success. Since removing/soldering the chip is time consumming and kind of a pain (not to say you can damage the board) I figured I'd try disconnecting only one (or some) pins to see if I could get it to work. After a few tries, I got lucky: it was only required to lift pin 6 (CLK) in order to be able to both read/write the chip using the 'clip':
I call this good progress, now that I have a dump of the flash memory we can run it thru binwalk and see what we get:
# binwalk -e -M ../bazz.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
18304 0x4780 gzip compressed data, has original file name: "u-boot.bin", from Unix, last modified: 2020-03-19 02:07:20
393216 0x60000 uImage header, header size: 64 bytes, header CRC: 0xCAFBC6AB, created: 2020-03-21 04:08:30, image size: 3205330 bytes, Data Address: 0x40008000, Entry Point: 0x40008000, data CRC: 0x4D094A1B, OS: Linux, CPU: ARM, image type: OS Kernel Image, compression type: none, image name: "Linux-4.9.37"
393280 0x60040 Linux kernel ARM boot executable zImage (little-endian)
395744 0x609E0 device tree image (dtb)
409432 0x63F58 device tree image (dtb)
415388 0x6569C device tree image (dtb)
419604 0x66714 gzip compressed data, maximum compression, from Unix, last modified: 1970-01-01 00:00:00 (null date)
3584472 0x36B1D8 device tree image (dtb)
3604480 0x370000 CramFS filesystem, little endian, size: 3805184, version 2, sorted_dirs, CRC 0x8C6D7F38, edition 1, 929 blocks, 3 files
8060940 0x7B000C JFFS2 filesystem, little endian
8066032 0x7B13F0 JFFS2 filesystem, little endian
8066520 0x7B15D8 JFFS2 filesystem, little endian
8067980 0x7B1B8C JFFS2 filesystem, little endian
8068468 0x7B1D74 JFFS2 filesystem, little endian
8069928 0x7B2328 JFFS2 filesystem, little endian
8070416 0x7B2510 JFFS2 filesystem, little endian
8196048 0x7D0FD0 Zlib compressed data, compressed
8196232 0x7D1088 Zlib compressed data, compressed
8196868 0x7D1304 Zlib compressed data, compressed
8197048 0x7D13B8 Zlib compressed data, compressed
8197752 0x7D1678 Zlib compressed data, compressed
8198256 0x7D1870 Zlib compressed data, compressed
8198916 0x7D1B04 Zlib compressed data, compressed
8199416 0x7D1CF8 Zlib compressed data, compressed
8199920 0x7D1EF0 Zlib compressed data, compressed
8200424 0x7D20E8 Zlib compressed data, compressed
8200860 0x7D229C Zlib compressed data, compressed
8201564 0x7D255C Zlib compressed data, compressed
8202068 0x7D2754 Zlib compressed data, compressed
8202572 0x7D294C Zlib compressed data, compressed
8203080 0x7D2B48 Zlib compressed data, compressed
8203584 0x7D2D40 Zlib compressed data, compressed
8204092 0x7D2F3C Zlib compressed data, compressed
8204600 0x7D3138 Zlib compressed data, compressed
8205108 0x7D3334 Zlib compressed data, compressed
8205616 0x7D3530 Zlib compressed data, compressed
8206124 0x7D372C Zlib compressed data, compressed
8206632 0x7D3928 Zlib compressed data, compressed
8207140 0x7D3B24 Zlib compressed data, compressed
8207648 0x7D3D20 Zlib compressed data, compressed
8208156 0x7D3F1C Zlib compressed data, compressed
8208664 0x7D4118 Zlib compressed data, compressed
8209172 0x7D4314 Zlib compressed data, compressed
8209680 0x7D4510 Zlib compressed data, compressed
8210184 0x7D4708 Zlib compressed data, compressed
8210688 0x7D4900 Zlib compressed data, compressed
8211192 0x7D4AF8 Zlib compressed data, compressed
8211628 0x7D4CAC Zlib compressed data, compressed
8212332 0x7D4F6C Zlib compressed data, compressed
8212836 0x7D5164 Zlib compressed data, compressed
8213340 0x7D535C Zlib compressed data, compressed
8213844 0x7D5554 Zlib compressed data, compressed
8214348 0x7D574C Zlib compressed data, compressed
8214852 0x7D5944 Zlib compressed data, compressed
8215356 0x7D5B3C Zlib compressed data, compressed
8215860 0x7D5D34 Zlib compressed data, compressed
8216364 0x7D5F2C Zlib compressed data, compressed
8216868 0x7D6124 Zlib compressed data, compressed
8217372 0x7D631C Zlib compressed data, compressed
8217876 0x7D6514 Zlib compressed data, compressed
8218312 0x7D66C8 Zlib compressed data, compressed
8219012 0x7D6984 Zlib compressed data, compressed
8219516 0x7D6B7C Zlib compressed data, compressed
8219952 0x7D6D30 Zlib compressed data, compressed
8220656 0x7D6FF0 Zlib compressed data, compressed
8221240 0x7D7238 Zlib compressed data, compressed
8221796 0x7D7464 Zlib compressed data, compressed
8222232 0x7D7618 Zlib compressed data, compressed
8222720 0x7D7800 JFFS2 filesystem, little endian
8229020 0x7D909C Zlib compressed data, compressed
8229504 0x7D9280 Zlib compressed data, compressed
8229992 0x7D9468 Zlib compressed data, compressed
8230480 0x7D9650 Zlib compressed data, compressed
8230664 0x7D9708 Zlib compressed data, compressed
8231148 0x7D98EC Zlib compressed data, compressed
8231636 0x7D9AD4 Zlib compressed data, compressed
8232124 0x7D9CBC Zlib compressed data, compressed
8232308 0x7D9D74 Zlib compressed data, compressed
8232488 0x7D9E28 Zlib compressed data, compressed
8232672 0x7D9EE0 Zlib compressed data, compressed
8232856 0x7D9F98 Zlib compressed data, compressed
8233040 0x7DA050 Zlib compressed data, compressed
8233524 0x7DA234 Zlib compressed data, compressed
8234012 0x7DA41C Zlib compressed data, compressed
8234500 0x7DA604 Zlib compressed data, compressed
8234988 0x7DA7EC Zlib compressed data, compressed
8235472 0x7DA9D0 Zlib compressed data, compressed
8235960 0x7DABB8 Zlib compressed data, compressed
8236448 0x7DADA0 Zlib compressed data, compressed
8236936 0x7DAF88 Zlib compressed data, compressed
8237420 0x7DB16C Zlib compressed data, compressed
8237908 0x7DB354 Zlib compressed data, compressed
8238092 0x7DB40C Zlib compressed data, compressed
8238580 0x7DB5F4 Zlib compressed data, compressed
8238760 0x7DB6A8 Zlib compressed data, compressed
8238944 0x7DB760 Zlib compressed data, compressed
8239128 0x7DB818 Zlib compressed data, compressed
8239312 0x7DB8D0 Zlib compressed data, compressed
8239492 0x7DB984 Zlib compressed data, compressed
8239980 0x7DBB6C Zlib compressed data, compressed
8240164 0x7DBC24 Zlib compressed data, compressed
8240652 0x7DBE0C Zlib compressed data, compressed
8240832 0x7DBEC0 Zlib compressed data, compressed
8241320 0x7DC0A8 Zlib compressed data, compressed
8241808 0x7DC290 Zlib compressed data, compressed
8242296 0x7DC478 Zlib compressed data, compressed
8242780 0x7DC65C Zlib compressed data, compressed
8243268 0x7DC844 Zlib compressed data, compressed
8243756 0x7DCA2C Zlib compressed data, compressed
8244244 0x7DCC14 Zlib compressed data, compressed
8244728 0x7DCDF8 Zlib compressed data, compressed
8245216 0x7DCFE0 Zlib compressed data, compressed
8245704 0x7DD1C8 Zlib compressed data, compressed
8245888 0x7DD280 Zlib compressed data, compressed
8246372 0x7DD464 Zlib compressed data, compressed
8246860 0x7DD64C Zlib compressed data, compressed
8247348 0x7DD834 Zlib compressed data, compressed
8247836 0x7DDA1C JFFS2 filesystem, little endian
8248316 0x7DDBFC JFFS2 filesystem, little endian
8249140 0x7DDF34 JFFS2 filesystem, little endian
8250600 0x7DE4E8 JFFS2 filesystem, little endian
8251088 0x7DE6D0 JFFS2 filesystem, little endian
8252548 0x7DEC84 JFFS2 filesystem, little endian
8253036 0x7DEE6C JFFS2 filesystem, little endian
8254496 0x7DF420 JFFS2 filesystem, little endian
8254984 0x7DF608 JFFS2 filesystem, little endian
8256444 0x7DFBBC JFFS2 filesystem, little endian
8256932 0x7DFDA4 JFFS2 filesystem, little endian
(recursive extraction ommitted)
After a quick look around I did not find any scripts or references to running/reading anything from the mmc card, that is, in order to get it to execute a command/script and gain access. I also did not see any mention of telnetd for me to run but I was happy to see an unencrypted cramfs partition, which included a startup script and the main doorbell/camera application itself.
So the next step is to try to gain remote access, the initrun.sh script in the cramfs partition seems like the perfect place, so I modified it (see initrun.sh in github) and prepared my own firmware file, after determining the parameters for the cramfs (by reviewing the original one):
mkfs.cramfs -b 4096 -e 1 -N little -n ppsapp mycramfs-root/ my.cramfs
cp bazz.bin mybazz.bin
dd conv=notrunc if=my.cramfs of=mybazz.bin bs=1 seek=3604480
I know my script was going to cause a little overhead by running every 10s but I wanted to know I could re-run something without rebooting by simply removing/editing/inserting the script on mmc and also wanted to be sure it would run on reboot after the mmc was mounted (however long that may take). So I flashed my modified bin file, and verified the device booted normally (by just holding pin 6 down down touching the board) and verified my script executed before soldering pin 6 back in place.
With my script being called on the mmc, I wrote a small script to start passwordless telnetd (final version of custom.sh is in github), and finally had a way into the OS:
# telnet 10.10.10.7
Trying 10.10.10.7...
Connected to 10.10.10.7.
Escape character is '^]'.
BusyBox v1.26.2 (2019-11-03 17:33:40 PST) built-in shell (ash)
/ #
The objective with the process above was not to expose vulnerabilities or make it possible to 'hack' cameras, in fact the process above required me to physically access the flash chip of the camera -- the whole point is to be able to customize the device to my specific needs, specifically to store/copy the video files on my NFS share. With root access, the first thing to do is to secure any remote access to the camera so that it can't be hacked with known username/password combinations, so I went ahead and edited /etc/passwd to have a username and password (hash) only known to me. Unlike other cameras I have seen in the market this one actually uses a read-write memory mount which allows us to just modify and copy files to the built-in memory but those changes are lost on reboot (so my script has to re-apply them on every boot), no big deal. Once I verified my new telnet user/pass worked I went ahead and changed the passwordless telnet acces for a standard (password protected) telnet on my script.
Now to see if I can mount my NFS share from the camera.... checking /proc/filesystems I knew nfs kernel modules were not loaded (or even available)... bummer.
Tried copying nfs modules from another camera on same kernel version but they would not load on this kernel.. bummer again. The only way I could get NFS to work here is to make my own kernel with NFS support (and modules) but then I'd probably have to recompile all custom kernel drivers for the camera -- there's no way in hell I'm spending the time to do all that, so at this point I'm dead set with always using the mmc card. The silver lining is that I already needed the mmc card to bootstrap my script anyway, so that saves me time from researching a way to run my script over network and such.
So how can I backup the SD card videos to my NAS? The simplest solution is usually the best: run httpd (from same busybox in mmc card) with a user/password so I can browse/download the files from a script on a raspberry pi I already use for automation around the house. That's where the httpd.conf, index.html and cgi-bin/main.cgi come in (credit to https://github.com/HeGanjie/busybox-httpd-directory-listing). I have included the the cron script that downloads the files from the doorbell to my NAS/NFS share, you just have to adjust the parameters/paths to use it with your device (NFS/share/script paths, user, password, IP and serial).
Now to the hard part... get remote viewing of the doorbell/camera.
I had already started looking at ppsapp with ghidra looking for any potential exploits to enable telnet and even found a URL that runs a command to toggle telnet access (but as previously said telnetd is not in the image), so I opened it up looking at the RTSP related code used for chromecast/ecoshow and found the code that initializes the camera buffers (and named them):
From the ppsapp code it looks like the feed to outside devices may be encrypted and I didn't want to go down that route since I had a ready-source of unencrypted data in the memory of the applicatuon.
I downloaded the armv7l toolchain for uclibc and wrote a 'streamer' application which would read the video from the circular buffer in ppsapp, monitor it and stream out any new data which works for the most part. I have added the streamer code attempts I made to github, and the most current version successfully makes files (just redirect its output to a file) which can be properly played in VLC, HOWEVER: it seems that without the RTP/RTSP encapsulation the playback cuts off every few seconds (despite a file with the same exact data playing correctly). I assume this has to do with the timing of the NAL units or it may require that each frame be transmitted in the same 'chunk' of data (which I didn't do). Nevertheless see the 'final update' section at the bottom for full solution. ~~The problem with the streamer application is that I didn't want it to use a lot of memory so I made a smaller buffer to parse the data from the ppsapp buffer and monitor/stream it that way but because of the nature of the updates it seems I am always reading data while it's being updated in memory (which corrupts the stream). With that the only 'good' solution would be to read the ppsapp circular buffer in one-shot (as quick as possible) to minimize the chances of it happening while the buffer is being updated (minimizing the chances of it being corrupt). This means I'd have to copy the full buffer (1.2Mb for 1080P) which I am not sure is worth the cost. I may end up doing it and using the SD buffer (400Kb) which would be ok. If/when I do complete the streamer application I intend to post it on here.~~
For now what I have done is come up with an alternate solution: I tracked down the address in the ppsapp which stores the buffer address for the JPEG encoding of the camera feed in real time (used for screenshots/alerts and such), so I wrote a snap.cgi script (which is in github) which does the following:
The result is I am able to get a 'snapshot' URL of the camera feed under /cgi-bin/snap.cgi:
It is a low resolution snapshot but it definitely works for alerts/previews/etc (plenty for my ios app, domoticz etc which crunch down a bunch of camera images together).
Last (for now) I also put together a 'mjpeg' stream (mjpeg.cgi in github), which basically does the same as the snap.cgi but in a loop (with the proper headers) so that I can actually see a 'moving feed' of the camera from app/browser/etc.
I will likely still work on the 'streamer' application using a full buffer -- it's more of a challenge right now than a 'need'.
I hope the above helps someone in a similar situation and if by any chance you get to the point where you have access to the firmware, feel free to use the contents of this page (PLEASE READ https://github.com/guino/BazzDoorbell/issues/2#issuecomment-739464775 including the ppsapp wchich will work with the scripts provided). Feel free to look for a ppsapp patch for your version here: https://github.com/guino/ppsapp-rtsp/issues/1
I didn't want to spend more time (than I already have) coding a solution to view a high-resolution stream from the doorbell camera so I went into the ppsapp code in ghidra again to see if I could find the code that streams the video to their app, I was thinking of just disabling the encryption so I would be able to view it directly, but in that review process I noticed that the "echo show" streaming support did not seem to be encrypted and in fact it seemed like that feature was just disabled (by hard-coded setting), so without hesitation I went ahead and modified the code/file to always start the "echo show" support. I expected I would have to make a few more changes to get it to work but no: a single byte change in the file and it baiscally started up a RTSP server on port 8554 (rtsp://
With the video recordings being saved (downloaded) onto my NFS share and having the ability to to view the live feed in HD (RTSP) and in SD (MJPEG) from any standard application I call this a resounding success and don't have any more future plans for this project.
See this link for a No-Programmer, No-UART, No-Open SD card-only solution: https://github.com/guino/BazzDoorbell/issues/2