I recently had a friend lose access to his Night Owl WNVR201 device. He said he lost his password, and I said I'd see what I could do. Through a long day of reverse engineering it, I found out how to reset the password on the device.
I knew that I'd need to start by getting access to the operating system on the NVR. I started off by taking the top panel off of it, and removing the hard drive in it. When I connected the hard drive to my computer, I noticed that the settings are not stored on the hard drive. It looks like the hard drive is only used to store videos.
Since I didn't see any configuration or operating system files on it, I knew that somewhere on the motherboard, there had to be a flash chip of some kind to store the data.
Looking closely at the board, I saw that it had a MX25L12835FMI-10G chip on the board. This is when I knew I'd need to get my CH341A USB Programmer out of my desk to be able to dump the firmware.
Dumping the Firmware
Dumping the firmware is a relatively easy process. To do this, put the breakout board into the programmer with the number 1 lined up with the dot on the silkscreen diagram.
Note that in the picture, the 1 on the board is lined up with the dot on the silk screen diagram.
Plug the cable into the breakout board with the red side aligned with the 1 on the board. Next clip the connector onto the
MX25L12835FMI-10G chip on the NVR board with the red cable lined up with the dot on the top of the chip. Plug the programmer into the computer, and you're ready to dump the firmware.
Now that we have the programmer connected properly, we can use flashrom to dump the firmware. Running this command was able to dump the firmware to
flashrom -p ch341a_spi -c "MX25L12835F/MX25L12845E/MX25L12865E" -r Documents/dev/nvr.bin
Analyzing the Firmware
Now that we have the firmware for this device, we need to be able to extract the filesystems in the firmware for analysis. We can do this with binwalk.
binwalk -Me nvr.bin
Once this is done, we can see new folders and files that were pulled out of the firmware.
We now have access to the filesystems on it.
I found a few interesting ones:
_nvr.rom.extracted/squashfs-root-1/contains the applications that run on the device
_nvr.rom.extracted/squashfs-root/contain the operating system for the device
I found a script that runs on startup on this device in
This script mounts flash drives attached to the system. Turns out that after mounting the drive, the script checks if a file called
restore_factory_config_is_dangerous exists on the drive. If this file exists, it checks the contents of the file.
If the file contains solely
2012, it restores the factory configuration. If the file contains
2017, it restores the factory configuration and resets the users to the default.
Next, this script checks for the file
enable_log, and if it's found, it checks if the file contains
1. If the file contains
1, then it enables logging on the device until a reboot occurs.
Next, it checks for
enable_log_forever. If this file contains
1000000001, then it enables logging permanently. If
dvr_app exists on the drive too, then it will execute that file. If
dvr_ui_arm exists on the drive, it will also execute this file.
enable_disk_log exists on the drive, it will do something (I couldn't figure it out).
Finally, this script checks for
sysztool on the drive. If this file exists and contains
a1a2a3a4a5b1b2b3b4b5c1c2c3c4c5d1d2d3d4d5a1b2c3d4, then the device will enter uboot fix mode.
To reset the password, I created a flash drive with the file
restore_factory_config_is_dangerous, and put the number
2017 in it.
When I rebooted the device, I had access to it!
The File I Found
For reference, here's the file that I found on the device that gave me this information.
#!/bin/sh #Restore machine in remote network date ifconfig lo up ifconfig eth0 192.168.1.114 netmask 255.255.255.0 up route add default gw 192.168.1.1 echo nameserver 18.104.22.168 >> /etc/resolv.conf #Mount usb disk MOUNT_DIR=/media/usb1 # check mount status if [ -r $MOUNT_DIR ];then echo "mount dir('$MOUNT_DIR') is exist now!" else echo "mount dir('$MOUNT_DIR') isn't exist now!" mkdir $MOUNT_DIR sleep 2 fi HDISK_N='x' HDISK_ID=0 sleep 1 for i in a b c d e f g h i j k l do echo "check sd$i..." if [ -e /sys/block/sd"$i" ];then echo "sd$i found..." rv=$(cat /sys/block/sd"$i"/removable) if [ "$rv" == "1" ];then echo "usb media sd$i found..." for n in 1 2 3 4 5 0 do udisk_index=$n if [ "$n" -eq "0" ];then udisk_index=""; fi if [ -b "/dev/sd$i$udisk_index" ];then echo "usb media sd$i$udisk_index found..." mount -t vfat /dev/sd"$i"$udisk_index $MOUNT_DIR break; else echo "usb media sd$i$udisk_index not found..." fi done break else if [ '$HDISK' -eq 'x' ];then HDISK_N=$i fi for n in 1 2 do if [ -b "/dev/sd$i$n" ];then echo "disk media sd$i$n found..." HDISK_ID=$n break; else echo "disk media sd$i$n not found..." fi done fi else echo "sd$i... not found" fi done #Restore factory config for machine without keypad if [ -e $MOUNT_DIR/restore_factory_config_is_dangerous ];then echo "restore flag found." rv=$(cat $MOUNT_DIR/restore_factory_config_is_dangerous) if [ "$rv" == "2012" ];then echo "restore factory config..." dd if=/dev/zero of=/dev/mtdblock3 bs=1k seek=10 count=10 mv $MOUNT_DIR/restore_factory_config_is_dangerous $MOUNT_DIR/restore_factory_config_is_dangerous_disable fi if [ "$rv" == "2017" ];then echo "restore factory config && clear user..." dd if=/dev/zero of=/dev/mtdblock3 bs=1k seek=10 count=256 mv $MOUNT_DIR/restore_factory_config_is_dangerous $MOUNT_DIR/restore_factory_config_is_dangerous_disable fi else echo "restore flag 1 not found." fi LOG_REDIRECT=0 if [ -e $MOUNT_DIR/enable_log ];then echo "enable log found." rv=$(cat $MOUNT_DIR/enable_log) if [ "$rv" == "1" ];then touch /tmp/udisk_loging echo "enable log..." LOG_REDIRECT=1 ulimit -c unlimited ulimit -a echo "$MOUNT_DIR/%e_%t.core" > /proc/sys/kernel/core_pattern mv $MOUNT_DIR/enable_log $MOUNT_DIR/disable_log fi else echo "enable log not found." fi if [ -e $MOUNT_DIR/enable_log_forever ];then echo "enable log2 found." rv=$(cat $MOUNT_DIR/enable_log_forever) if [ "$rv" == "1000000001" ];then if [ -e $MOUNT_DIR/dvr_app ];then echo "mount bind dvr_app." mount --bind $MOUNT_DIR/dvr_app /root/dvr_app/dvr_app fi if [ -e $MOUNT_DIR/dvr_ui_arm ];then echo "mount bind dvr_gui." mount --bind $MOUNT_DIR/dvr_ui_arm /root/dvr_gui/dvr_gui fi touch /tmp/udisk_loging echo "enable log2..." LOG_REDIRECT=1 ulimit -c unlimited ulimit -a echo "$MOUNT_DIR/%e_%t.core" > /proc/sys/kernel/core_pattern fi else echo "enable log2 not found." fi if [ -e $MOUNT_DIR/enable_disk_log ];then echo "enable disk log found." if [ '$HDISK_N' -neq 'x' -a "$HDISK_ID" -neq "0" ];then echo "enable disk log2..." fi else echo "enable disk log not found." fi if [ -e $MOUNT_DIR/sysztool ];then echo "sysztool found." rv=$(cat $MOUNT_DIR/sysztool) if [ "$rv" == "a1a2a3a4a5b1b2b3b4b5c1c2c3c4c5d1d2d3d4d5a1b2c3d4" ];then echo "sysztool enter uboot fix mode" rm $MOUNT_DIR/sysztool dd if=/dev/zero of=/dev/mtdblock4 bs=1024 count=32 sleep 2 reboot fi fi #ulimit -c unlimited #echo "1" > /proc/sys/kernel/core_uses_pid #echo "/root/rec/a1/%e-%t.core" > /proc/sys/kernel/core_pattern echo "rmem_default:" cat /proc/sys/net/core/rmem_default echo "rmem_max:" cat /proc/sys/net/core/rmem_max echo "min_free_kbytes:" cat /proc/sys/vm/min_free_kbytes #echo 3000000 > /proc/sys/net/core/rmem_default echo 3000000 > /proc/sys/net/core/rmem_max echo 3000 > /proc/sys/vm/min_free_kbytes # set stack size ulimit -s 4096 cd /root/module sh load -i hwclock -s echo "do you want to run app.out(y or n)?" read -t 1 -n 1 char cd /root/dvr_app;./dvr_resource if [ "$char" == "n" ];then login fi mount -t tmpfs none /root/rec cd /root/dvr_app;./dvr_reset if [ -e "/tmp/dvr_resource_dir/pre_run_app.sh" ] ; then echo "[pre_run_app] cp" cp /tmp/dvr_resource_dir/pre_run_app.sh /tmp echo "[pre_run_app] chmod" chmod +x /tmp/pre_run_app.sh echo "[pre_run_app] running..." /tmp/pre_run_app.sh echo "[pre_run_app] finish" else echo "[pre_run_app] not found" fi if [ "$?" == "0" ];then CURTIME=`date +%y%m%d_%H%M%S` LOG_FILE=gui_$CURTIME.log cd /root/dvr_gui; if [ "$LOG_REDIRECT" == "1" ];then ./dvr_gui > "$MOUNT_DIR/$LOG_FILE" 2>&1 & else ./dvr_gui & fi cd /root/dvr_app; if [ "$LOG_REDIRECT" == "1" ];then LOG_FILE=sys_$CURTIME.log /root/sysztool.hi 600 > "$MOUNT_DIR/$LOG_FILE" 2>&1 & LOG_FILE=app_$CURTIME.log ./dvr_app > "$MOUNT_DIR/$LOG_FILE" 2>&1 else ./dvr_app fi else echo "System reset!" fi