File System Analysis Report
1. Overview
This document is a report described by Team.ENVY (Kim Chan-in, Park Myung-hoon, Shin Myung-jin, Yang Gang-min, Lee Yu-kyeong) who carried out the BoB 12th NVR Vulnability Analysis project.
1.1. Necessity
File system analysis is essential to perform embedded vulnerability analysis. It is an essential step to identify and deactivate a watchdog for debugging, which activates a service for performing vulnerability analysis. Therefore, this document describes the contents of file system analysis to perform vulnerability analysis.
1.2. /etc/inittab
The contents of "/etc/initab" are as follows. First of all, when the NVR is booted, the "/etc/init.d/rcS" file will be executed first. In addition, it can be seen that the "/etc/scripts/SsShutdown.sh " file is executed when the NVR is terminated.
::sysinit:/etc/init.d/rcS
# Example of how to put a getty on a serial line (for a terminal)
::respawn:/sbin/getty -L ttyS0 115200 vt100
# Stuff to do when restarting the init process
::restart:/sbin/init
# Stuff to do before rebooting
::ctrlaltdel:/sbin/reboot
::shutdown:/etc/scripts/SsShutdown.sh
2. Analyzing Boot Scripts
2.1. init script
2.1.1. /etc/init.d/rcS
With the "/bin/mount -a" command, mount the device based on the content in "/etc/mtab", set the environment variable and run all scripts in the "/etc/init.d" directory.
2.1.2. /etc/init.d/S00hostname
Use the hostname command to set the hostname.
2.1.3. /etc/init.d/S01devs
If there is no directory used for the NVR service, create and mount it.
2.1.4. /etc/init.d/S02udevd
Run the udevd command to activate the udev service.
2.1.5. /etc/init.d/S03syslogd
Run the /sbin/syslogd command to activate the syslog service.
2.1.6. /etc/init.d/S04klogd
Run the /sbin/klogd command to record the kernel log.
2.1.7. /etc/init.d/S05sysctl
Run the sysctl command based on the contents of the /etc/sysctl.conf configuration file.
2.1.8. /etc/init.d/S06network
Configure the local network interface using the ifconfig, route command.
2.1.9. /etc/init.d/S82mount
The mount command is used to mount the flash memory, which is an mtdblock device, and the flash memory that is mounted in the app directory is only read-only.
2.1.10. /etc/init.d/S83dvr_main
Run the startup.sh script.
2.1.11. /root/startup.sh
After going through processes such as loading the driver module, initializing storage, and initializing the network related to the NVR service, /bin/scheduler, /root/daemon binary is executed.
2.2. Activation service analysis
2.2.1. daemon
This binary is the last binary to run in init script. When the binary is reversed, the dvr_main binary is executed through the fork function, and when the child process ends, the state is imported using a waitpid system call and different tasks are performed based on the state.
DAT_000250e4 = fork();
if (DAT_000250e4 == 0) {
memset(dvr_main_path,0,0x80);
snprintf(dvr_main_path,0x80,"%s/dvr_main","/root",uVar16,pcVar3,iVar4,pcVar1);
memset(acStack_52c,0,0x80);
snprintf(acStack_52c,0x80,"%s",&DAT_000138b8);
memset(acStack_4ac,0,0x80);
snprintf(acStack_4ac,0x80,"%d",DAT_000250e0);
memset(acStack_22c,0,0x200);
snprintf(acStack_22c,0x200,"[DAEMON] %s:%d %s %s %s\n","dvr_main_thread_body",0x331,
dvr_main_path,acStack_52c,acStack_4ac);
iVar4 = 5;
FUN_0001162c(acStack_22c);
do {
iVar13 = execl(dvr_main_path,dvr_main_path,acStack_52c,acStack_4ac,&DAT_000138e8,"console.log",0);
...
2.2.2. dvr_main
Analysis using the lsof command yields the following results.
dvr_main 865 1024 root 105u unix 0x9ed9b9c0 0t0 8785 /tmp/ARBSocket_Main type=STREAM
dvr_main 865 1024 root 106u unix 0xaca1f9c0 0t0 10202 /tmp/upgrade_sock type=STREAM
dvr_main 865 1024 root 107u unix 0x99824000 0t0 11267 /tmp/SunapiSocket type=STREAM
dvr_main 865 1024 root 109u unix 0xa027cdc0 0t0 10302 /tmp/OnvifSocket type=STREAM
dvr_main 865 1024 root 110u unix 0xa027cb00 0t0 10300 /tmp/rtsp_socket type=STREAM
Since onvif and rtsp sockets are used and SunapiSocket sockets are also used, it can be determined that the binary activates the service.
2.2.3. Web Service
Finally, we analyzed the process running through the ps command.
2669 2668 2668 ? 00:00:00 lighttpd
2670 2670 2670 ? 00:00:00 php-cgi
2731 2670 2670 ? 00:00:00 php-cgi
2671 2671 2671 ? 00:00:00 php-cgi
2730 2671 2671 ? 00:00:00 php-cgi
2672 2672 2672 ? 00:00:00 php-cgi
2733 2672 2672 ? 00:00:00 php-cgi
2673 2673 2673 ? 00:00:00 php-cgi
2732 2673 2673 ? 00:00:00 php-cgi
2675 2668 2668 ? 00:00:00 attributes.cgi
2679 2668 2668 ? 00:00:00 eventstatus.cgi
2707 2668 2668 ? 00:00:00 system.cgi
2710 2668 2668 ? 00:00:00 network.cgi
2729 2668 2668 ? 00:00:00 media.cgi
2754 2668 2668 ? 00:00:00 security.cgi
2767 2668 2668 ? 00:00:00 video.cgi
2784 2668 2668 ? 00:00:00 transfer.cgi
2799 2668 2668 ? 00:00:00 image.cgi
2823 2668 2668 ? 00:00:00 eventactions.cg
2843 2668 2668 ? 00:00:00 eventsources.cg
2848 2668 2668 ? 00:00:00 io.cgi
2866 2668 2668 ? 00:00:00 recording.cgi
2880 2668 2668 ? 00:00:00 ptzcontrol.cgi
2900 2668 2668 ? 00:00:00 ptzconfig.cgi
2915 2668 2668 ? 00:00:00 bypass.cgi
2929 2668 2668 ? 00:00:00 display.cgi
2952 2668 2668 ? 00:00:00 pw_init.cgi
2960 2668 2668 ? 00:00:00 eventrules.cgi
2961 2668 2668 ? 00:00:00 ai.cgi
2975 2668 2668 ? 00:00:00 factory.cgi
2998 2668 2668 ? 00:00:00 debug.cgi
Through the lighttpd binary, it can be seen that the web service is operating as a cgi binary.
sh-4.3# lsof -p 2848
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
io.cgi 2848 root cwd DIR 31,12 0 680 /app/root/webviewer/stw-cgi
io.cgi 2848 root rtd DIR 0,1 0 1 /
io.cgi 2848 root txt REG 31,12 87976 2762 /app/root/webviewer/stw-cgi/io.cgi
...
io.cgi 2848 root 0u unix 0xa027f700 0t0 10487 /tmp/io-fastcgi.socket-0 type=STREAM
io.cgi 2848 root 3u unix 0x99826940 0t0 11428 /tmp/io-fastcgi.socket-0 type=STREAM
Additionally, as a result of executing the lsof command on the operating cgi, it may be confirmed that the cgi binary also refers to the socket file.
2.3. Check mount
After the boot is complete, the following results can be obtained by executing the mount command.
sh-4.3# mount
rootfs on / type rootfs (rw)
proc on /proc type proc (rw,relatime)
sysfs on /sys type sysfs (rw,relatime)
tmpfs on /dev type tmpfs (rw,relatime,size=74752k)
tmpfs on /tmp type tmpfs (rw,relatime)
tmpfs on /pam type tmpfs (rw,relatime,size=163840k)
tmpfs on /media type tmpfs (rw,relatime,size=32768k)
tmpfs on /debug type tmpfs (rw,relatime,size=5120k)
devpts on /dev/pts type devpts (rw,relatime,mode=600,ptmxmode=000)
none on /dev/shm type tmpfs (rw,relatime,size=10240k)
/dev/mtdblock9 on /system type jffs2 (rw,relatime)
/dev/mtdblock12 on /app type jffs2 (ro,relatime)
/dev/sda1 on /mnt/sda1 type xfs (rw,relatime,attr2,inode64,noquota)
/dev/sda2 on /mnt/sda2 type xfs (rw,relatime,attr2,inode64,noquota)
/dev/sda3 on /mnt/sda3 type xfs (rw,relatime,attr2,inode64,noquota)
/dev/sda4 on /mnt/sda4 type xfs (rw,relatime,attr2,inode64,noquota)
As confirmed in the init script, the /app directory was counted as read-only, and web service-related files existed in the folder. In addition, it was confirmed that the sda device loaded with xfs was a hard disk.
It was confirmed that log-related data were present in the /mnt/sda1 directory as follows.
sh-4.3# pwd
/mnt/sda1/MetaData/log
sh-4.3# ls
HDDStatus.log console_20231026014525.log
access.log console_20231027050004.log
backup_log_vss.db2 console_20231027210411.log
console.log console_20231029070032.log
console.log_NetworkError console_20231031180103.log
console_20230917145053.log cslog.log
console_20230918011457.log easy_server-fri.log
console_20230918070311.log easy_server-fri.log.bak
console_20230918080536.log easy_server-mon.log
console_20230918130141.log easy_server-mon.log.bak
console_20230919062706.log easy_server-sat.log
console_20230925115326.log easy_server-sat.log.bak
console_20230926094533.log easy_server-sun.log
console_20230930105047.log easy_server-sun.log.bak
console_20231003084051.log easy_server-thr.log
console_20231005212057.log easy_server-thr.log.bak
console_20231008220122.log easy_server-tue.log
console_20231012064649.log easy_server-tue.log.bak
console_20231013002935.log easy_server-wed.log
console_20231013180020.log error.log
console_20231015064517.log event_log.sql
console_20231015115634.log event_log.sql-shm
console_20231016043407.log event_log.sql-wal
console_20231017143458.log event_log.txt
console_20231019071853.log hddman.log
console_20231019073859.log system_log.txt
console_20231020090143.log upgrade.log_backup
console_20231022230605.log upgrade_std_str.log
console_20231024032436.log
2.4. Watchdog Analysis
The /dev/watchdog device is referred to by the daemon binary and the dvr_main binary. Therefore, a reboot may be prevented through feeding.
sh-4.3# lsof /dev/watchdog
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
CamThread 848 root 28r FIFO 0,8 0t0 7019 pipe
CamThread 848 root 29w FIFO 0,8 0t0 7019 pipe
CamThread 848 root 31r FIFO 0,8 0t0 7031 pipe
CamThread 848 root 32w FIFO 0,8 0t0 7031 pipe
CamThread 848 root 34r FIFO 0,8 0t0 7710 pipe
CamThread 848 root 35w FIFO 0,8 0t0 7710 pipe
CamThread 848 root 37r FIFO 0,8 0t0 7069 pipe
CamThread 848 root 38w FIFO 0,8 0t0 7069 pipe
CamThread 848 root 72w CHR 10,130 0t0 1879 /dev/watchdog
ssui 1210 root 3r FIFO 0,8 0t0 6910 pipe
ssui 1210 root 4w FIFO 0,8 0t0 6910 pipe
ssui 1210 root 5r FIFO 0,8 0t0 6913 pipe
ssui 1210 root 6w FIFO 0,8 0t0 6913 pipe
ssui 1210 root 13r FIFO 0,8 0t0 6944 pipe
ssui 1210 root 14w FIFO 0,8 0t0 6944 pipe
lwproxy 1362 root 1w FIFO 0,8 0t0 7860 pipe
lwproxy 1362 root 4r FIFO 0,8 0t0 7853 pipe
dhcpd 2357 root 5r FIFO 0,8 0t0 7860 pipe
ntpd 2383 root 28w FIFO 0,8 0t0 9772 pipe
tutkd 2522 root 5r FIFO 0,8 0t0 7860 pipe
lighttpd 2576 root 4r FIFO 0,8 0t0 8971 pipe
lighttpd 2576 root 5r FIFO 0,8 0t0 7860 pipe
dropbear 4191 root 4r FIFO 0,8 0t0 15766 pipe
dropbear 4191 root 6w FIFO 0,8 0t0 15766 pipe
sh 4228 root 6w FIFO 0,8 0t0 15766 pipe
dropbear 6941 root 4r FIFO 0,8 0t0 79055 pipe
dropbear 6941 root 6w FIFO 0,8 0t0 79055 pipe
sh 6988 root 6w FIFO 0,8 0t0 79055 pipe
lsof 12667 root 4w FIFO 0,8 0t0 99111 pipe
lsof 12667 root 5r FIFO 0,8 0t0 99112 pipe
lsof 12668 root 3r FIFO 0,8 0t0 99111 pipe
lsof 12668 root 6w FIFO 0,8 0t0 99112 pipe
However, if an error occurs in the dvr_main binary, the daemon binary catches it and reboots the device, so I will explain that part. Reversing daemon is as follows.
do {
if (*(uint *)((int)&status_arr+ ptr1) == uVar3) {
memset(log1,0,0x200);
uVar3 = (&error_code)[result * 3];
snprintf(log1,0x200,"[DAEMON] %s:%d %s\n","handle_dvrmain_exitcode",0x2d0,uVar3);
log_write(log1);
local_15d0 = (&DAT_00013460)[result * 3];
goto LAB_00012108;
}
result = result + 1;
ptr1 = ptr1 + 0xc;
} while (result != 0xf);
local_15d0 = 1;
memset(log1,0,0x200);
snprintf(log1,0x200,"[DAEMON] %s:%d exit reason is [%d]\n","handle_dvrmain_exitcode",0x2d9,uVar 3);
...
snprintf(log1,0x200,"[DAEMON] %s:%d System Restart Count (%d), ExitCode (%d)\n",
"dvr_main_thread_body",0x370,addr,local_15d0);
log_write(log1);
switch(local_15d0) {
case 0:
file system unmount
reboot
case 1:
continue
case 2:
reboot
case 3:
Format after unmount if file system type is xfs or ext type
reboot
case 4:
running swupgrader process background
default:
Forced reboot after unmounting the file system
Since the daemon binary creates a child process through the fork function and executes the dvr_main binary through the execl function, it has a structure that reboots the system through the case statement after checking the error code of dvr_main.
Last updated