I would like to use the Dahua Home Assistant Integration to pull the intercom in an apartment into the home automation. Unfortunately, the credentials in the intercom UI are starred out.

Attempt 1 - MicroSD card

Inside the unit is a microsd card. Unfortunately, there is nothing on it, presumably it is for storing image snapshots. There does not seem to be a way in the UI to back up the settings to the SD card Either.


Attempt 2 - UART

Hoping to find a root console, I connected to the UART header. It's a 3.3V header, and the 2 data pins are closest to the CPU, the closest one to the CPU is RX for the device, and the next one is TX. The bootloader can't be interrupted, and the kernel stops interacting with the console when it starts.

Here are the boot messages, in case it is of any use.

HELLO! BOOT0 is starting! Mar 12 2019 03:15:40 
boot0 version : 4.0.0
boot0 commit : 8 
i2c gpio config 22777722
axp209 read error
axp152 read error
DRAM Type = 3 (2:DDR2,3:DDR3,6:LPDDR2,7:LPDDR3)
DRAM CLK = 672 MHz
DRAM zq value: 000039bb
DRAM size = 128 MB
Reg 0x01c20848: 0x00003333
0x01c20028 0x90041811
0x01c200a0 0x8100000f
SpiNand_read_id 00000000 000000ef 000000aa
Succeed in opening spi nand flash.
Succeed in reading Boot1 file head.
current block is 2.
current block is 3.
current block is 4.
current block is 5.
current block is 6.
current block is 7.
The file stored in block 2 to block 6 is perfect.
----------storage_type = 5  in boot0-------------------------
Ready to disable icache.
Jump to secend Boot.
[      0.489]

U-Boot 2011.09-rc1-svn3935 (May 13 2019 - 12:50:19) Allwinner Technology 

[      0.498]version: 1.1.0
[      0.502]uboot commit : 8 
[      0.508]pmbus:   ready
not set main pmu id
axp read error
probe axp20x failed
axp152 read error
probe axp15 failed
axp_probe error
set power on vol to default
dcdc2_vol = 1100
axp set dcdc2_vol to 1100 failed
dcdc3_vol = 3300
axp set dcdc3_vol to 3300 failed
aldo2_vol = 2500
axp set aldo2_vol to 2500 failed
aldo3_vol = 3000
axp set aldo3_vol to 3000 failed
ldo1_vol = 3300
axp set ldo1_vol to 3300 failed
ldo2_vol = 3000
axp set ldo2_vol to 3000 failed
ldo3_vol = 3000
axp set ldo3_vol to 3000 failed
ldo4_vol = 1800
axp set ldo4_vol to 1800 failed
find power_sply to end
vbus exist
no battery, limit to dc
[      0.779]DRAM:  save config for small mem_size 
workmode = 0
storage type = 5
[      0.837]SPINAND: x5 spinand is initing...OK
spinand id is 0xaaef 
spi_nand_scan_id_table chip->pages_per_blk 64 
spi_nand_scan_id_table chip->page_size 2048 
spi_nand_scan_id_table chip->page_spare_size 64 
spi_nand_scan_id_table chip->blks_per_chip 1024 
ret 0 status b0 18
ret 0 status b0 18
ret 0 status c0 0
ret 0 status a0 0
find Bbt0
find 1tbB 
good block is 1024
[      0.872]sunxi flash init ok
can't find corresponding entry
partition file version 2
success to parse partinfo from patition file.
----------------- partinfo ------------------
fs_tpye :0 NO 1 CRAMFS 2 SQUASHFS 3 UBI 4 JFFS2 5 EXT4 6 VFAT 
fs_flags:1 Read 2 Write 
-name-        -offset-      -size-       -fs_flags-   -fs_type-    -backup_off-
boot0       : 0             40000         0             0             ffffffff    
boot        : 40000         240000        0             0             ffffffff    
mbr         : 280000        20000         0             0             ffffffff    
env         : 2a0000        20000         0             0             42a0000     
updateflag  : 2c0000        100000        0             0             ffffffff    
partition   : 3c0000        100000        1             1             43c0000     
kernel      : 4c0000        500000        0             0             44c0000     
romfs       : 9c0000        500000        1             1             49c0000     
logo        : ec0000        20000         1             0             4ec0000     
web         : ee0000        500000        1             1             4ee0000     
data        : 13e0000       500000        1             1             53e0000     
usr         : 18e0000       f00000        1             1             58e0000     
pd          : 27e0000       20000         1             1             67e0000     
rootfstype cramfs root /dev/mtdblock7


Attempt 3 - flash dump

I royally screwed up here, after successfully desoldering the chip, I installed it backwards into a programmer and fried it - there was a red dot on the opposite side of the chip, and I took that to be pin 1!

Fortunately, I have another apartment in the same complex, and was able to recover the flash chip from there.

It uses a Winbond W25N01GVZEIG, a 128MB SPI flash chip. I mounted onto a test board and hooked it up to a CH341 programmer, but it was not supported by Flashrom. I started adding support, but it has a few idiosyncrasies that made it non-trivial. I next hooked it up to a Raspberry pi, with the following pinout:

DescriptionFlash PinPi Pin
Write Protect (3.3V)317
Hold (3.3V)717

I  found this script  which handles the weirdness of it, but at 25MHz, would give different sizes of output files (within a few KB, so maybe some race condition?).

Since the chip is supported by the MTD driver, I worked out how to set up the device tree for Ubuntu on the  Raspberry Pi 4 to access the flash as an MTD device, and this worked reliably at 25MHz. I was able to read out the full contents a few times, and compare the results to ensure everything read correctly.  The partition table from the boot log allowed me to set up the partitions correctly. The device tree files are in spinand.tbz attached to this article.

The problem I now face is that most of the filesystems are encrypted. U-boot is not, and it seems this is a custom build with Dahua's proprietary encryption, so de-compiling U-boot, or bringing it up in an emulator might be a good start.

Attempt 4

Attacking the encryption seems to be an exercise in yak shaving, so the next thing to try is snooping the ethernet traffic and capturing the password that way.

I didn't try snooping the comms between the VTO & VTH, as the VTO is in the apartment complex and I'm doing this at home, but I did have a play at home. Without the server on the other side, there isn't a lot transmitted that is particularly useful.

I did, however, find the remote configuration tool for the unit, and that was a lot more promising. It has a backup function, but the output file was encrypted. I snooped the traffic during the backup, and while some of the info was transmitted in the clear, the useful parts for this exercise were also encrypted.

The config tool could also edit parameters on the device remotely, however, the passwords were starred out. They did have the right number of stars though, so it was likely that the tool knew what the password was. Loading the tool in Ghidra and decompiling it, I could see that it used QT, which is a well documented windowing toolkit. I came across this StackOverflow question, which led me to the documentation for setEchoMode. Searching through the executable for calls to this showed only a couple of instances where the mode was set to 2 (Password), so I changed it to 0 (Normal) in the binary and queried the device, and success! I had the password in the clear, and can now set up the Home Assistant plugin.

I've attached the binary patch for the executable, in case anyone else needs to extract the password from their unit. After extracting it, you can apply the patch as follows (make sure you have the correct version of ConfigTool):

bspatch ConfigTool.exe.orig ConfigToolPatched.exe ConfigTool.exe.V5.001.0000002.0.R.20230223.showpw.bsdiff

Recovering the failed unit

Since one of the intercoms was non-functional, I had to replace the flash memory. A simple copy of the firmware from the other device brought it up, but it did ask for a new password on boot, and wiped it's configuration. Not a big problem, since I can backup and restore from the other unit.

The bigger problem was that it came up with the MAC address and serial number of the other unit. This would cause a problem, since they are both connected to the same network, and MAC addresses are supposed to be unique.

Digging around the flash dump showed that both the MAC address and serial number were in the unencrypted env partition, and editing this got it going again. The first 4 bytes of the env partition are a CRC32 of bytes 0x0004-0xFFFF of the env partition. I've included some scripts in firmware_scripts.tbz to extract the env partition and reinsert it into the firmware image.

Additional Notes

The firmware update files for the units can be grabbed from the Dahua Wiki.

The firmware files are a zip file with a modified magic number, 7Zip can extract them.

The firmware zips contain a number of uImages for the relevant partitions.

The Dahua Firmware Mod Kit can somewhat extract the images, but since most are encrypted, further work is needed. I've attached the config I've created, is case anyone finds it useful.