Китайские камеры Jovision и их OEM клоны. Мистификация безопасности

Так получилось, что для одного из проектов понадобилась управляемая система пространственного позиционирования целеуказателя. Сервоприводы различных производителей оказались довольно дорогими и было решено купить управляемую камеру и использовать встроенный сервопривод камеры для позиционирования. С PTZ камерами я дела никогда не имел, поэтому на пробу была приобретена камера J2000IP-CmPTZ-111v2.0, якобы российского производителя »3С-Групп».


Внимание! Публикация не является обзором камеры и скорее всего описывает разбор механизмов управления камерой предлагаемый производителем оборудования.


Итак камера J2000IP-CmPTZ-111v2.0, она же Jovision JVS-H411. Ничем не выдающаяся камера домашнего сегмента. Как и большинство камер построена на чипе HiSilicon 3518E.


image
Так как чип довольно распространён и к нему есть SDK, то производители поверх собранного ядра начинают «наворачивать» сверху свои специфические сервисы. Прошивки устройств обычно отличаются драйверами wifi модуля. Wifi модуль можно определить из названия прошивки взятой с адреса http://www.jovecloud.com/ipc/3518es/:


jvs3518es-7601.bin — Ralink RT7601
jvs3518es-8188.bin — Realtek RTL8188
jvs3518es-9271.bin — Atheros AR9271


Прошивка в моём устройстве jvs3518es-7601.bin и валидна она для следующего списка устройств фирмы Jovision:


H411
J2000IP-CmPTZ-111-V2.0
H411V1_1
H411S-H1
H411V2
HC420S-H2
HC520D-H1
HC420-H2
H411-H1
H411KEDA
AT-15H2
SW-H411V3
HZD-600DM
AJL-H40610-S1
AJL-H40610-S2
JD-H40810

Итак. С моделью определились. Никакая это не российская разработка, как позиционирует её компания »3С-Групп», а просто OEM клон камеры большого китайского производителя.


Но если это клон и прошивка китайская, то значит и сервисы в ней зашиты китайские. В принципе так и есть. Камера подразумевает регистрацию в облаке Jovision, подключения типа P2P, позволяет видеть изображение на своём телефоне и управлять камерой удалённо. Как любой сисадмин не доверяющий сторонним сервисам безопасности, тем более китайским, тем более видео, первое что я бы рекомендовал сделать — это поставить в камере шлюзом по умолчанию саму себя и использовать другие методы управления.


Для удалённого управления камерой производитель предоставляет OCX оснастку для IE (для контроля из локальной сети) и Android приложение (для контроля через сеть интернет). Так как камеру планировалось использовать из-под Unix систем, то варианты с IE и Android отпали, как не подходящие под условия использования.


Никакого более менее доступного API в сети найдено не было, поэтому начали реверсить то, что имели в наличии. OCX оснастка как оказалась использует 2 варианта управления:


  1. управление через закрытый ipc протокол.
  2. управление через встроенный thttpd сервер.

Первый вариант сначала исключили (потом вернулись к нему ради интереса), т.к. реверс проприетарного протокола мог бы затянуться надолго и начали копать второй вариант. Оказалось, что все запросы к камере идут на один единственный URL


http:///cgi-bin/jvsweb.cgi

Естественно как наверное и положено в различных устройствах безопасности — доступ к устройству должен закрываться логином и паролем, примерно так.


http:///cgi-bin/jvsweb.cgi?username=admin&password=password

И после этого должна следовать команда управления. Но после того, как я добрался до внутренностей прошивки, я был сильно удивлён содержимому файла jvsweb.cgi


#!/bin/sh
eval `./proccgi`
echo Content-type: application/json
#echo
#echo $FORM_cmd
#echo $FORM_action
#echo $FORM_param
#echo $FORM_username
#echo $FORM_password
#echo
./wagent $FORM_cmd $FORM_action "$FORM_param" $FORM_username $FORM_password

Маленькая программка proccgi парсит web запрос к серверу и конвертит его в переменные, которые далее «скармливаются» программе агенту, передающему эти данные в управляющую программу.


Как показало исследование, поля username и password не влияют ни на что от слова СОВСЕМ. Важны только первые три параметра.


Главное, что из этого я хочу донести до всех читателей: КАМЕРА НЕБЕЗОПАСНА! и управлять ей может кто угодно находясь с ней в одной сети. Продолжаем исследования. Подключение к камере по telnet (адрес по умолчанию 192.8.8.8) осуществляется по фиксированному логину и паролю root/jvbzd, который нельзя поменять обычными методами!!!


Опять же подключиться может кто угодно. Именно по данной причине я первым делом убрал доступ камеры в облако. Если базовые политики безопасности сразу являются скомпрометированы, то нет смысла доверять чему-то более высокоуровневому.


Попробуем залезть еще поглубже. Процесс загрузки камеры состоит из загрузки ядра, чтения базовых настроек системы, запуску проверялки-перехватчика портов и запуска самой программы управления. Если с первыми двумя пунктами всё понятно, то с третьим пунктом возникает вопрос.
Перехватчик портов основываясь на списке жёстко зарезервированных под сервисы портов, проверяет из занятость и резервирует за собой. Программа управления представляет собой статически скомпилёный бинарник весом в 5 мегабайт, в котором «зашита» вся логика управления камерой.


Ядро камеры имеет встроенный watchdog и если от программы управления в нужный момент не пришёл alive сигнал, то камера автоматически перезагружается.


Для того чтобы запустить камеру в отладочном режиме необходимо сделать 3 шага:


  1. Перезагрузить камеру и в течении 5 секунд после начала перезагрузки зайти на камеру телнетом
  2. Запустить ps w и через kill «пристрелить» процессы startup.sh и /tmp/sctrl. startup.sh необходимо «стрелять первым», т.к. в строке следующей за запуском /tmp/sctrl стоит команда reboot
  3. Запустить /tmp/sctrl с ключами:
    • cmd=0/1 — включение командного интерфейса системы контроля
    • debug=0/1 — включение расширенного дебага

Все указанные действия необходимо выполнить в 10–15 секундный срок, до отработки watchdog. После запуска программы управления вы увидите лог работы, а также лог обработки входящих команд.
Программа управления делится на несколько частей:


  1. модуль управления по ipc
  2. модуль управления по http
  3. модуль подключения к облаку
  4. модуль обнаружения совместимых сетевых устройств
  5. модуль управления по интерфейсу onvif

Модуль управления по ipc работает постоянно и ожидает команд на порту 9101
Модуль управления по http реализован на свободном сервере thttpd, работает постоянно и ожидает команд на порту 80
Модуль подключения к облаку проверяет соединение каждые 10 секунд.
Модуль обнаружения сетевых устройств пытается найти рекордер
Модуль управления по интерфейсу onvif работает совместно с thttpd и предоставляет очень кривую и бедную поддержку управления.


Да! забыл написать. Камера предоставляет шифрование трафика между клиентом и камерой, но!!! ключ шифрования един на все прошивки и лежит в файле /tmp/encrypt!!!


Отбросим грустные вопросы и попробуем вернуться к управлению камерой. Все данные поступающие через веб интерфейс прозрачно транслируются в модуль управления. Модуль управления состоит из десятка подпрограмм отвечающих за обработку той или иной команды. К сожалению разработчики видимо решили, что код управляющей программы никогда не будет никому интересен и положили в одну корзину с подпрограммами управления состоянием камеры, подпрограммы управления памятью, вызовами процедур и состоянием самой системы управления.


Список подпрограмм управления можно получить через запрос


http:///cgi-bin/jvsweb.cgi?cmd=webhelp

Вот список всех блоков управления камерой


cmd list and help information

  mptz
        mptz zoom [X] [Y] [ZOOM]
  timer
        display all timer list
  stream
        for stream test
  account
        account operation cmd
  webalarm
        alarm operation command
  webmdetect
        motion detect operation command
  webprivacy
        privacy operation command
  webrecord
        record operation command
  webstorage
        storage operation command
  webstream
        stream operation command
  webifconfig
        ifconfig operation command
  webwifi
        wifi operation command
  webosd
        osd operation command
  websnapshot
        Have a snapshot of the channel
  webhelp
        Display help info
  webipcinfo
        ipcinfo operation command
  webdevinfo
        webdevinfo operation command
  webimage
        image operation command
  yst
        yst operation command
  system
        websystem operation command
  multimedia
        multimedia operation command
  ptz
        ptz operation command
  webaudio
        webaudio operation command
  redirect
        redirect stdout stderror
  webled
        led control command
  webad
        audio detect
  wdtoff
        Manual close watchdog

Моей основной задачей было обеспечить чёткое позиционирование камеры, но к сожалению из-за программной реализации продукта оказалось, что сделать это невозможно. Почему ?


Интерфейс управления кинематикой PTZ работает по RS485 и не имеет каких-либо внешних датчиков и счётчиков для определения текущего положения камеры. Интерфейс передающий команды в PTZ передаёт в модуль ядра шаг на который необходимо повернуть двигатель в нужную сторону. Для определения сектора работы, при первичной инициализации, камера поворачивается в нулевое положение по обоим осям и начинает вращение в сторону увеличения координат. Определив конец сектора вращения горизонтальной координаты камера делит полученный сектор на 65536. То же самое происходит с вертикальной координатой. Таким образом получается внутренняя координатная сетка на основании которой происходит позиционирование камеры. Когда мы при помощи интерфейса управления передаём в камеру команды поворота, в камере считается и сохраняется только внутренний счётчик недоступный пользователю. Когда мы сохраняем Preset, то программа управления сохраняет текущие координаты в которых на данный момент находится камера и потом использует их для позиционирования. Чёткое точечное позиционирование пользователю недоступно.


Но не время сдаваться :) Продолжаем копать возможности камеры. За разбор входных данных в интерфейс управления отвечает библиотека cJSON, таким образом в переменной param должна быть валидная JSON структура.


Строка запроса всегда выглядит так:


http:///cgi-bin/jvsweb.cgi?cmd=&action=¶m={"key1":"value1","key2":"value2"}

На данный запрос камера обычно возвращает несколько строк в зависимости от результата


{"status":"ok","data":""}
{"status":"param error","data":""}
param error
либо результат выполнения запроса

Распишу все найденные мной команды управления и их поля/параметры. Данные указанные в фигурных скобках содержат данные, которые необходимо поместить в поле param запроса. Большинство команд поддерживают action=list для вывода текущих настроек. Начнём с команды account.


  • account

Управление пользователями веб интерфейса системы


    list    # List all account with passwords
    add:    # add account
        {"acID": "aborche","acPW": "123","acDescript":"test","Power":17}
    check:  # check password
        {"acID":"aborche","acPW":"123"}
    modify: # modify account
        {"acID":"aborche","acOldPW":"123","acNewPW":"1234"}
    del:    # delete account
        {"acID":"aborche1"}
    count   # count accounts

Таким образом запрос списка аккаунтов будет выглядеть так


http:///cgi-bin/jvsweb.cgi?cmd=account&action=list

а добавление пользователя


http:///cgi-bin/jvsweb.cgi?cmd=account&action=add¶m={"acID": "aborche","acPW": "123","acDescript":"test","Power":17}

  • webalarm

Оповещения о срабатывании детекторов движения


    list    # List all alarms
    set:    # Set alarm
        {"delay":10,"sender":"ipcmail@163.com","server":"smtp.163.com","username":"ipcmail","passwd":"ipcam71a",
        "receiver0":"lfx@jovision.com","receiver1":"(null)","receiver2":"(null)","receiver3":"(null)"}

Остановимся на минуту на этих двух командах. Все получаемые с камеры данные являются открытыми и доступ происходит без логина и пароля! Поэтому если вы не хотите лишиться доступа к своему почтовому ящику (как пример), будьте осторожны и заведите второй ящик.


  • webmdetect

Определение движения


     list   # List motion detects
            # cmd=webmdetect&action=1 list
            # cmd=webmdetect 1&action=list
     set:
        {"bEnable":0,"nSensitivity":50,"nThreshold":15,"nRectNum":0,
        "stRect":[{"x":0,"y":0","w":0,"h":0},
            {"x":0,"y":0,"w":0,"h":0},
            {"x":0,"y":0,"w":0,"h":0},
            {"x":0,"y":0,"w":0,"h":0}],
        "nDelay":10,"nStart":0,"bOutClient":0,"bOutEMail":0}

Обратите внимание, что из-за кривизны разбора входных параметров можно беспрепятственно передавать любую длину команд с любыми параметрами. Так как камера имеет несколько каналов (видеопотоков), то часть команд может идти с номером канала.


  • webprivacy

Определение приватной зоны на изображении, которую не нужно транслировать


     list   # List privacy zones
            # cmd=webprivacy&action=1 list
            # cmd=webprivacy 1&action=list
     set:   # Set privacy zone
        {"bEnable":0,"stRect":[{"x":0,"y":0,"w":0,"h":0},
        {"x":0,"y":0,"w":0,"h":0},
        {"x":0,"y":0,"w":0,"h":0},
        {"x":0,"y":0,"w":0,"h":0}]}

  • webrecord

Настройки записи


            # cmd=webrecord&action=1 list
            # cmd=webrecord 1&action=list
     list   # List settings
     set:   #
        {"bEnable":1,"file_length":600,"timing_enable":0,"discon_enable":0,
        "alarm_enable":0,"timing_start":0,"timing_stop":0,"disconnected":0,
        "detecting":0,"alarming":0,"alarm_pre_record":6,"alarm_duration":10}

  • webstorage

содержимое внешней карты памяти


    list    # List settings
    format  # Format storage

  • webstream

Настройки потоков


            # cmd=webstream&action=1%20list
            # cmd=webstream 1&action=list
            # cmd=webstream -c &action=ability
            # cmd=webstream -c1 1&action=ability
     list   # List streams
     set:   # Set stream settings
        {"bEnable":1,   "bAudioEn":1,   "viWidth":1280, "viHeight":720,
        "width":1280,   "height":720,   "framerate":20, "bitrate":1024,
        "ngop_s":4, "rcMode":1, "encLevel":1,   "quality":40,
        "minQP":24, "maxQP":46}
     resolution # Get stream possible resolution
     ability    # Get stream settings
    requestidr  # ?????

  • webifconfig

Настройки сетевого интерфейса


    list    # Get interfaces configuration
    set:    # Set interfaces configuration
        {"inet":"dhcp",
        "eth":
            {"name":"eth0","bDHCP":1,"addr":"","mask":"","gateway":"0.0.0.0",
            "mac":"02:00:01:01:01:12","dns":"8.8.8.8"},
        "pppoe":
            {"name":"ppp0","username":"x","passwd":"1"},
        "wifiap":
            {"name":"","passwd":"","quality":0,"keystat":0,"iestat":""}
        }
    scan    # ReScan wifi networks

  • webwifi

Управление wifi подключением


    list    # List wifi networks
    connect:    # Connect to network
        {"name":"ZyXEL53",  "passwd":"",    "quality":2,
        "keystat":1,    "iestat":"\u0004\u0002"}
    changemode:
        ????

Обратите внимание, что при помощи команд webwifi и webifconfig можно спокойно просканировать рядом находящиеся WIFI сети и подключиться к ним. Таким образом подконтрольная камера может спокойно шпионить за окружающей обстановкой


  • webosd

Управление идентификатором камеры на видео


     list   # Get channel info
     set:
        {"bShowOSD":1,  "timeFormat":"MM/DD/YYYY hh:mm:ss", "position":1,
        "timePos":2,    "channelName":"HD IPC", "osdbInvColEn":1,"bLargeOSD":1}

  • webipcinfo

Информация о устройстве


    list    # Get device info
    set:
        {   "type": "J2000IP-CmPTZ-111-V2.0",
            "product":  "JVS-HI3518ES-7601",
            "version":  "V2.2.4402",
            "acDevName":    "HD IPC",
            "nickName": "",
            "sn":   36430,
            "ystID":    xxxxxxxxxx,
            "nDeviceInfo":  [],
            "nLanguage":    1,
            "date": "2016-10-22 14:31:43",
            "bSntp":    1,
            "sntpInterval": 24,
            "ntpServer":    "192.168.205.1",
            "enableStreamWatchDog": 1,
            "tz":   3,
            "bDST": 0,
            "bIPSelfAdapt": 1,
            "rebootDay":    0,
            "rebootHour":   1,
            "bRestriction": 1,
            "portUsed": "8099,554,23,8127,51994,55434,6666,8732,58434,3702,9100,9104,9106,57241,4001,6072,8899,1998,17",
            "osdText":  ["", "", "", "", "", ""],
            "osdX": 0,
            "osdY": 0,
            "osdSize":  32,
            "lcmsServer":   ""}
    settime   
    system 

Функция позволяет ребутить или сбрасывать устройство


http:///cgi-bin/jvsweb.cgi?cmd=webipcinfo&action=system reboot

  • webdevinfo


    list    # get device info
    set
        {   "type": "ipc",
            "hardware": "JVS-HI3518ES-7601",
            "firmware": "V2.2.4402",
            "manufacture":  "JVS-HI3518ES-7601",
            "sn":   "XXXXXXXXXX",
            "model":    "ipc-module",
            "channelCnt":   1,
            "streamCnt":    3,
            "ystChannelNo": [1, 2, 3, ..... 0],
            "name": "HD IPC",
            "date": "2016-12-26 20:55:23",
            "bSntp":    1,
            "sntpInterval": 24,
            "ntpServer":    "ntp.fudan.edu.cn",
            "tz":   3,
            "bDST": 0
        }
    settime 
    settime 2012-06-07 13:58:00
    system 

  • webimage

Настройка параметров изображения


    list
    set:
        {"contrast":    135,
        "brightness":   135,
        "saturation":   135,
        "sharpen":  255,
        "exposureMax":  3,
        "exposureMin":  100000,
        "scene":    0,
        "daynightMode": 0,
        "dayStart": [{
            "hour": 6,
            "minute":   0
        }],
        "dayEnd":   [{
            "hour": 18,
            "minute":   0
        }],
        "bEnableAWB":   1,
        "bEnableMI":    0,
        "bEnableST":    0,
        "bEnableNoC":   0,
        "bEnableWDynamic":  0,
        "bNightOptimization":   1,
        "bAutoLowFrameEn":  0}

  • yst

Информация о потоках для удалённого управления


    list
    set:
        {"strGroup":    "B",
        "nID":  XXXXXXXXX,
        "nPort":    9101,
        "nStatus":  2,
        "bActiving":    1,
        "nYSTPeriod":   10,
        "bTransmit":    "\u0001",
        "eLANModel":    0,
        "bWebServer":   1,
        "nWebPort": 80,
        "nPictureType": 3,
        "nPictureTypeOld":  1}
    get_port    # get control port
    get_video   # get video streams

Остановимся на данной команде. Эта команда описывает настройки видеопотоков для удалённого управления через OCX или телефон. Вряд ли что-то из этих данных вам будет полезно кроме двух команд.


http:///cgi-bin/jvsweb.cgi?cmd=yst&action=get_port
http:///cgi-bin/jvsweb.cgi?cmd=yst&action=get_video

Первая покажет порт управления системой и параметры порта. Вторая покажет текущие видеопотоки имеющиеся в системе. Вывод второй команды обычно такой.


rtsp:///live0.264
rtsp:///live1.264

  • ptz

Управление камерой


    move:   # range = step(255*x(y)), sign +/- = direction
        {"chnid":0,"x":[0.01..1],"y":[0.01..1]}
        x,y - moving speed
        0 - stop move
    move_auto: # set move speed
        {"chnid":1,"s":0.5}
    preset: #preset control
        {"chnid":0,"type":n,"presetid":p,"name":name}
        type:   0="list"
            1="Save Preset"
            2="Delete Preset"
            3="Apply Preset"
        param={"chnid":1,"type":1,"presetid":1,"name":"preset 1"} - Save Preset 1 with name "preset 1"
    lens: # lens and picture control
        {"type":n,"value":v}
        type:   0="aperture"
            1="focus"
            2="magnify"
        value:  0.01..1
    patrol:
        {"status":"ok","data":[{"id":0,"presetid": 1,"name":"1111","staytime":10},{"id":1,"presetid": 2,"name":"2222","staytime":10}]}
        type:   0="list"
            1="Save Patrol"
            2="Delete Patrol"
            3="Start Patrol"
            4="Stop Patrol"

  • mptz

    left
    right
    up
    down
    stop
    preset
    locatePreset
    aux # param=auxnum/-auxnum turn aux on/off
    dropon
    dropoff
    sensor
    zoom # Not working

Команды ptz и mptz были основной причиной начала расковыривания прошивки.


http:///cgi-bin/jvsweb.cgi?cmd=ptz&action=move¶m=["chnid":1,"x":0,"y":-0.5]
http:///cgi-bin/jvsweb.cgi?cmd=mptz&action=down

Обе команды дают камере команду повернуться вниз. В первом случае мы указываем скорость с которой будет опускаться камера. Скорость рассчитывается как 255 умноженное на значение скорости. Таким образом при значении скорости равной 0.01 камера будет опускаться вниз со скоростью 2 точки на 1 тик. Во втором случае камера будет опускаться со скоростью 100 точек на 1 тик. Значение тика я пока не выяснил. Нужно замерить.


Камера будет опускаться до тех пор пока не достигнет нулевой точки, либо пока не будет получена следующая команда.


http:///cgi-bin/jvsweb.cgi?cmd=ptz&action=move¶m=["chnid":1,"x":0,"y":0]
http:///cgi-bin/jvsweb.cgi?cmd=mptz&action=stop

preset и locatePreset служат для быстрого добавления и вызова точек позиционирования


http:///cgi-bin/jvsweb.cgi?cmd=mptz&action=preset 1
http:///cgi-bin/jvsweb.cgi?cmd=mptz&action=locatePreset 1

  • stream

Управление энкодером видеопотоков


    stream CMD CHANNELID
    stream set CHANNELID TYPE VALUE
    CMD:
        start   start the stream
        stop    stop the stream
        flush   flush the stream
        restart restart the stream
        set     set param
        debug   if be 1, print the received stream package
    TYPE:
        width - resolution width
        height - resolution height
        framerate - framerate such as 30,25,20,15,10...
        nGOP - I frame between
        bitrate - bitrate with unit of Kbit Per Second

  • multimedia

Управление изображением


    imageget:
        {"chnid":1,"type":0}
        type: 
            0   contrast
            1   brightness
            2   saturation
            3   sharpness
    imageset:
        {"chnid":1,"type":0}
        type: 
            0   contrast
            1   brightness
            2   saturation
            3   sharpness

Перед началом изменения параметров, рекомендуется сделать imageget для каждой настройки, после этого сделать изменения и сделать imageset


  • webaudio

Управление звуком


    list
    set:
        {
            "sampleRate":   8000,
            "bitWidth":     1,
            "encType":      0,
            "level":        2,
            "muted":        1,
            "micGain":      69
        }

  • webad

Определение звука


    list
    set:    {
        "bEnable":      1,
        "bEnableRecord":        1,
        "nStart":       0,
        "bOutClient":   1,
        "bOutEMail":    1,
        "bOutVMS":      1,
        "bBuzzing":     1,
        "ADThreshold":  80,
        "ADTimeInterval":       60,
        "ADPercentage": 30
        }

  • webled

Управление светодиодами


    list
    set:
        0 - turn off
        1 - turn on

В принципе это почти весь набор команд обеспечивающих взаимодействие с камерой. Остальные команды описывать смысла нет, т.к. они обеспечивают вывод отладочной информации в консоль.


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


В новых прошивках для новых камер довольно сильно переписан модуль onvif, но основные проблемы в том же состоянии.


На очереди у меня стоит камера TENVIS JPT3815W, посмотрим что есть у неё. Спасибо за уделенное время на чтение статьи, надеюсь она была для вас полезной.


PS: если нужна информация о дешифровке прошивок Jovision, то могу выложить.


© Aborche 2016


Aborche

Комментарии (2)

  • 27 декабря 2016 в 18:15

    0

    Спасибо! Очень интересный материал, не могли бы выложить более подробный материал по самому реверсингу? Как копали чем распаковывали? Ну и вообще — перед вами черный ящик (в данном случае камера) каковы ваши мысли, с чего начинали, попадали ли в какой-либо тупик:)
  • 27 декабря 2016 в 18:45

    0

    Вот и примерно понятно, как Mirai добился такого успеха. Благодарить надо китайцев.

© Habrahabr.ru