This document is a report written by Team.ENVY (Chan-in Kim, Myung-hoon Park, Myeong-jin Shin, Kang-min Yang, Yu-kyung Lee), who carried out the KITRI BoB 12th NVR Vulnerability Analysis project, on the construction of the Dahua analysis environment.
1.1. Necessity
In order to analyze Dahua's vulnerabilities, debugging the binary that activates the service is essential. Therefore, this document describes how to debug by bypassing watchdog and Dahua's shell access restrictions.
2. Analysis
In the case of Dahua, after Challenge, the binary responsible for the service, is executed, the shell cannot be used, and a prompt where only a few commands can be executed is executed.
You can perform functions such as checking device status and changing settings at this prompt, but escaping was essential because gdb must be run through a shell to build an analysis environment.
Administrators can activate ssh using the web interface and GUI, but Dahua's self-produced dsh is executed, and the shell is very limited to 4 usable commands.
Therefore, it was necessary to make some modifications to the booting process through UART communication.
First, the commands that Dahua's U-Boot can use are limited compared to regular U-Boot.
Afterwards, I changed the init variable in bootargs to /bin/sh, but I didn't get a shell.
Also, “Starting Kernel…” After confirming that the kernel boot log was not output, it was determined that the problem was related to standard output.
We confirmed that the dh_keyboard environment variable is a variable that changes the kernel output mode, and changed the variable's value as follows.
MStar # setenv -f dh_keyboard 0
Afterwards, I was able to check the kernel output.
Before executing the init script, I tried to run ash by modifying the contents of /etc/passwd, but modification was not possible because all directories except /var, /root, and /dev were read-only.
Therefore, an attempt was made to modify /etc/passwd through bind mount, but the integrity of the read-only file system was verified during initialization of the challenge binary, and if the verification failed, it was rebooted.
cp /etc/passwd /var/passwd
mount --bind /var/passwd /etc/passwd
Through the script written in /etc/init.d, all services up to just before the challenge binary was executed were activated to enable all functions in the shell, and then the nfs was mounted to enable the analysis binary.
mount -t nfs -o vers=3,nolock 192.168.0.103:/volume3/nfs /nfs
I ran the challenge in the background and redirected the output so that the shell is still available after the challenge runs.
dvrhelper /var/Challenge > /dev/null &
After executing the challenge, the bind mount command could not be executed as if it were prohibited.
Therefore, all of the above restrictions were bypassed through the following steps.
Clone /etc/passwd to a writable location using the cp command.
Perform bind mount immediately before running the challenge (however, the file contents must not be changed)
After the initialization process has been completed in the Challenge binary and the service is running normally, change /etc/passwd contents (dsh → ash)
Perform nfs server mount
3. Analysis environment construction boot script
Modify the contents of rcS and run all init scripts except S99Dahua.
ROOTMNT=/mnt
mount -t devtmpfs none /dev
mount -t proc proc /proc
insmod /lib/modules/4.9.37/kernel/crypto.ko
insmod /lib/modules/4.9.37/kernel/fwcrypto.ko
mount -rw /dev/mtdblock3 /mnt
mount -t squashfs /dev/gpfwdecrypt_dev /root/
exec switch_root /root /bin/sh
/bin/mount -a
mount -t devtmpfs none /dev
/etc/init.d/S00devs
/etc/init.d/S01udev
/etc/init.d/S80network
Modify the contents of S99Dahua to background the Challenge binary and redirect output.
cat << 'EOF' > /var/S99Dahua
#!/bin/sh
source /etc/profile
mount -t squashfs /dev/mtdblock8 /mnt/ext_usr
mount -t squashfs /dev/mtdblock5 /mnt/web
mount -t squashfs /dev/mtdblock4 /mnt/custom
mount -t cramfs /dev/mtdblock6 /mnt/logo
mount -t ramfs /dev/mem /var
CONFIG_NUM=`cat /proc/mtd |grep -w "config"|awk -F':' '{print $1}' | grep -Eo '[0-9]+'`
ubiattach /dev/ubi_ctrl -b 4 -m $CONFIG_NUM -d 0
if [ $? -ne 0 ] ; then
echo "Partition Config doesn't format"
ubiformat /dev/mtd$CONFIG_NUM -y
ubiattach /dev/ubi_ctrl -b 4 -m $CONFIG_NUM -d 0
else
echo "ubiattch /dev/mtdblock$CONFIG_NUM OK"
fi
volnum=`ubinfo -a /dev/ubi0 | grep "Volumes count"|awk -F':' '{printf $2}'`
if [ $volnum -ne 0 ]; then
echo "Partition Config already has vol"
mount -t ubifs /dev/ubi0_0 /mnt/mtd/
else
echo "Parition Config hasn't vol"
ubimkvol /dev/ubi1 -m -N Config
mount -t ubifs /dev/ubi0_0 /mnt/mtd/
fi
if [ $? -ne 0 ] ; then
ubidetach -m $CONFIG_NUM
ubiformat /dev/mtd$CONFIG_NUM -y
ubiattach /dev/ubi_ctrl -b 4 -m $CONFIG_NUM -d 0
ubimkvol /dev/ubi0 -m -N Config
mount -t ubifs /dev/ubi0_0 /mnt/mtd
mkdir -p /mnt/mtd/Config
touch /mnt/mtd/Config/eracfg-finish
fi
mkdir -p /mnt/mtd/Config /mnt/mtd/Log /var/tmp
touch /var/udhcpd.leases
rm /mnt/mtd/Config/udhcpd.leases
ln -s /var/udhcpd.leases /mnt/mtd/Config/udhcpd.leases
if [ ! -f /mnt/mtd/Config/reboot_cnt.txt ]; then
echo sys_reboot_cnt=0 > /mnt/mtd/Config/reboot_cnt.txt
fi
val=`cat /mnt/mtd/Config/reboot_cnt.txt|busybox sed 's/[^0-9]//g'`
let val=0
busybox sed -i 's/sys_reboot_cnt=.*/sys_reboot_cnt='$val'/g' /mnt/mtd/Config/reboot_cnt.txt
echo 5 > /proc/sys/vm/dirty_ratio
echo 8192 > /proc/sys/vm/min_free_kbytes
echo 200 > /proc/sys/vm/vfs_cache_pressure
echo f > /sys/class/net/eth0/queues/rx-0/rps_cpus
echo 4096 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt
echo 4096 > /proc/sys/net/core/rps_sock_flow_entries
echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter
echo 307200 > /proc/sys/net/core/rmem_max
echo 0 > /proc/sys/net/ipv4/tcp_window_scaling
#echo 2000 > /proc/sys/net/core/netdev_max_backlog
echo 1 > /proc/sys/vm/overcommit_memory
p7zip x /usr/lib/lib.7z /var/
cat /proc/dahua/loadmodules | (read key value; if [ "$value" != "0" ];then
/usr/etc/load_modules.sh
fi)
ifconfig lo up
ifconfig eth0 up
netinit
#busybox telnetd -l /bin/sh &
udhcpd -f&
net3g &
#rm /var/lib/* -rf
p7zip x /usr/bin/Challenge.7z /var
p7zip x /usr/bin/Aol.7z /var
chmod 777 /var/Challenge
chmod 777 /var/Aol
chmod -R 777 /var/*
sendboot 192.168.254.254 8899
echo 1 > /proc/sys/vm/drop_caches
mkdir -p /var/empty/sshd
chown root:root /var/empty/sshd
chmod 755 /var/empty/sshd
appauto= cat /proc/cmdline | busybox sed "s/ /\n/g" | grep "appauto" | busybox sed "s/[^0-9]//g"
if [ "$appauto" == "1" ]
then
/var/Aol &
fi
ulimit -Sc unlimited
dvrhelper /var/Challenge > /dev/null &
#ulimit -Sc unlimited;cd /home;dvrhelper /var/Challenge
EOF
To mount a writable directory, run part of the contents of S99Dahua first.
source /etc/profile
mount -t squashfs /dev/mtdblock8 /mnt/ext_usr
mount -t squashfs /dev/mtdblock5 /mnt/web
mount -t squashfs /dev/mtdblock4 /mnt/custom
mount -t cramfs /dev/mtdblock6 /mnt/logo
mount -t ramfs /dev/mem /var
Copy the contents of the read-only directory to a writable location and perform bind mount.
cp /etc/passwd /var/passwd
mount --bind /var/passwd /etc/passwd
cp -r /bin /var/bin
mount --bind /var/bin /bin
cp -r /lib /var/lib
mount --bind /var/lib /lib
Run the modified S99Dahua.
chmod +x /var/S99Dahua
/var/S99Dahua
Afterwards, change the nfs server mount and /etc/passwd.