Hacking the Hikvision: part 1

OK, you voted to not be lazy, and thus I’ve stuck to it. Where am I at with upgrading the DS-2CD2132 hikvision cameras? Well, not super far.

We ran into a snag. The new firmware only works in the chinese region. I guess I could accept that, but it does have the english strings in it, and, if i log in and unpack them in place, its correct. So lets talk about how to get there. (the 2nd reason for wanting to have persistent access is I want to run iptables on the device to prevent it from doing more than I am expecting).

OK, we got the serial attached. If you stop the boot in U-Boot (hit ^U), you get a little shell. If we then modify the bootargs to add init=/bin/sh, we end up with a real ‘shell’ instead of the dreaded ‘psh’ they use for restricted access.


setenv console=ttyS0 initrd=0xc0a00000,0x400000 rw root=/dev/ram dbg=0 init=/bin/sh
/bin/sh: can't access tty; job control turned off

Now we want to run all but the last two lines of /etc/init.d/rcS

/bin/mount -t proc proc /proc
/bin/mount -t sysfs sysfs /sys
/bin/mount -t ramfs ramfs /home

And we are in. But, how to get more software on there?
It seems the dropbear (which we can start as dropbear -R) suffers from this issue, so we can’t ‘ssh … cat’ to get files in and out of mtdblock.

To make dropbear more useful, lets get rid of the psh shell for root (the device has a hard-coded backdoor user of ‘root’ with password ‘hiklinux’). PS, i decoded the password running mpirun and john-the-ripper.

# cat /etc/passwd                                                                                                

OK, lets fix that:

# echo root:ToCOv8qxP13qs:0:0:root:/root/:/bin/sh > /etc/passwd

(this is all in the initramfs, so don’t worry, its not permanent yet).

I was going down the path of ‘uuencode’ and paste it in. Since we have awk, we can write a tiny uudecode:

$ cat uu.awk
function x(l, p) {
        n = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_";
    return index(n, substr(l, p + 1, 1));
/^begin/ {}
/^[^be]/ {
        len = x($0, 0);
        for(i = 1; len > 0; i += 4) {
                a = x($0, i);
                b = x($0, i + 1);
                c = x($0, i + 2);
                d = x($0, i + 3);
                printf("%c", a * 4 + b / 16);
                if(len > 1) {
                        printf("%c", b * 16 + c / 4);
                        if(len > 2) {
                                printf("%c", c * 64 + d);
                len -= 3;

However, busybox awk won’t output a null:

# awk 'BEGIN {printf "%c%c", 1, 0 }' > /tmp/l
# ls -al /tmp/l
-rw-r--r--    1 root     root             1 Jan 19 00:31 /tmp/l

Making it somewhat tricky to put a new binary on there.
So, we could use echo:

# echo -n -e \\x1\\x0 > /tmp/l
# ls -l /tmp/l# echo -n -e \\x1\\x0 > /tmp/l
# ls -l /tmp/l
-rw-r--r--    1 root     root             2 Jan 19 00:32 /tmp/l

So yeah, we could write some hack that took in a binary, converted it to echo statements, and then paste that in. Let’s try.

$ cat convert-to-echo.c                                                                                                     
#include <sys/types.h>
#include <sys/stat.h>

main(int argc, char **argv)
    int fd = open(argv[1], O_RDONLY, 0);
    int i, n;
    char line[16];
    if (fd < 0) { perror("open"); } while ((n = read(fd, line, sizeof(line))) > 0)
        printf("echo -n -e ");
        for (i = 0; i < n; i++)
            printf("\\\\x%x", line[i]);

OK, that’s some good hack. And, OMG, that actually works, we can now cross-compile some new binaries to put in the initramfs (or the mount of /dav) to get us going.

We can get the ‘dav’ filesystem mounted (its ubifs) via this snippet from /etc/app:

# awk[\042=" \047=']
MTDDEV=`/bin/awk "\\$4==\"\042app_pri\042\" {print \\$1}" /proc/mtd`

# init env variables

if [ "$MTDDEV" == "mtd13:" ] ; then
    if [ "$KRN_PRT" = "pri" ] ; then
        # try app pri: /dev/mtd13
        /usr/sbin/mount_app pri
    else # KRN_PRT == sec
        # try app second partition: /dev/mtd14
        /usr/sbin/mount_app sec
    fi # end of "$KRN_PRT" == "pri"

    # process cfg partition

    # try cfg pri: /dev/mtd15
    /usr/sbin/mount_ubifs_prt.sh 15 3 /davinci
    if [ "$?" = "0" ] ; then
        /usr/sbin/check_dir /davinci
        if [ "$?" = "0" ] ; then
            /usr/sbin/umount_ubifs_prt.sh /davinci 3

    if [ "$CFG_PRT" = "no" ] ; then
        /bin/echo "format cfg pri partition and mount"
        /usr/sbin/format_ubifs_prt.sh 15 3 cfg_pri
        /bin/mount -t ubifs /dev/ubi3_0 /davinci

    #process cfg sec: /dev/mtd16
    /usr/sbin/mount_ubifs_prt.sh 16 4 /config
    if [ "$?" = "0" ] ; then
        /usr/sbin/check_dir /config
        if [ "$?" = "0" ] ; then
            /usr/sbin/umount_ubifs_prt.sh /config 4

    if [ "$CFG_PRT" != "sec" ] ; then
        /bin/echo "format cfg sec partition and mount"
        /usr/sbin/format_ubifs_prt.sh 16 4 cfg_sec
        /bin/mount -t ubifs /dev/ubi4_0 /config
        /bin/cp -a /davinci/* /config/

    if [ "$cfg_pri_need_rcy" = "1" ] ; then
        /bin/echo "recover cfg pri partition"
        /bin/cp -a /config/* /davinci/

    export APP_PRT
    export CFG_PRT

OK, that’s enough for right now, we can get stuff on there, i should be able to patch it w/o trouble now.






5 Responses to “Hacking the Hikvision: part 1”

  1. KnownAroundHere

    “OK, but you guys said I shouldn’t be lazy.”

    But if others wanted to be lazy, there is always this :

    1. db

      the issue i’m trying to solve is how to make it have an upgraded dropbear and smb libraries.
      but yes, your earlier pointer did help get me going!

  2. Piotr

    How we can read bootargs before modiufication ? What is setup default on cameras ?

  3. Piotr

    And please help me setup console=ttyS0 it is port from my PC ? If i use windows my USB TTL is connected to port example COM3.

    1. db

      ttyS0 is the name of the serial port on the camera, it won’t change.
      if you use windows, find a tool like hyperterm for serial, and have it use your com3 usb ttl.

Leave a Reply

Your email address will not be published. Required fields are marked *