Так получилось, что для одного из проектов понадобилась управляемая система пространственного позиционирования целеуказателя. Сервоприводы различных производителей оказались довольно дорогими и было решено купить управляемую камеру и использовать встроенный сервопривод камеры для позиционирования. С PTZ камерами я дела никогда не имел, поэтому на пробу была приобретена камера J2000IP-CmPTZ-111v2.0, якобы российского производителя "3С-Групп".
Внимание! Публикация не является обзором камеры и скорее всего описывает разбор механизмов управления камерой предлагаемый производителем оборудования, а также оценку безопасности её использования.
Итак камера J2000IP-CmPTZ-111v2.0, она же Jovision JVS-H411. Ничем не выдающаяся камера домашнего сегмента. Как и большинство камер построена на чипе HiSilicon 3518E.
Так как чип довольно распространён и к нему есть 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 варианта управления:
- управление через закрытый ipc протокол.
- управление через встроенный thttpd сервер.
Первый вариант сначала исключили(потом вернулись к нему ради интереса), т.к. реверс проприетарного протокола мог бы затянуться надолго и начали копать второй вариант. Оказалось, что все запросы к камере идут на один единственный URL
http://<camip>/cgi-bin/jvsweb.cgi
Естественно как наверное и положено в различных устройствах безопасности — доступ к устройству должен закрываться логином и паролем, примерно так.
http://<camip>/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 шага:
- Перезагрузить камеру и в течении 5 секунд после начала перезагрузки зайти на камеру телнетом
- Запустить ps w и через kill "пристрелить" процессы startup.sh и /tmp/sctrl. startup.sh необходимо "стрелять первым", т.к. в строке следующей за запуском /tmp/sctrl стоит команда reboot
- Запустить /tmp/sctrl с ключами:
- cmd=0/1 — включение командного интерфейса системы контроля
- debug=0/1 — включение расширенного дебага
Все указанные действия необходимо выполнить в 10-15 секундный срок, до отработки watchdog. После запуска программы управления вы увидите лог работы, а также лог обработки входящих команд.
Программа управления делится на несколько частей:
- модуль управления по ipc
- модуль управления по http
- модуль подключения к облаку
- модуль обнаружения совместимых сетевых устройств
- модуль управления по интерфейсу onvif
Модуль управления по ipc работает постоянно и ожидает команд на порту 9101
Модуль управления по http реализован на свободном сервере thttpd, работает постоянно и ожидает команд на порту 80
Модуль подключения к облаку проверяет соединение каждые 10 секунд.
Модуль обнаружения сетевых устройств пытается найти рекордер
Модуль управления по интерфейсу onvif работает совместно с thttpd и предоставляет очень кривую и бедную поддержку управления.
Да! забыл написать. Камера предоставляет шифрование трафика между клиентом и камерой, но!!! ключ шифрования един на все прошивки и лежит в файле /tmp/encrypt!!!
Отбросим грустные вопросы и попробуем вернуться к управлению камерой. Все данные поступающие через веб интерфейс прозрачно транслируются в модуль управления. Модуль управления состоит из десятка подпрограмм отвечающих за обработку той или иной команды. К сожалению разработчики видимо решили, что код управляющей программы никогда не будет никому интересен и положили в одну корзину с подпрограммами управления состоянием камеры, подпрограммы управления памятью, вызовами процедур и состоянием самой системы управления.
Список подпрограмм управления можно получить через запрос
http://<camip>/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://<camip>/cgi-bin/jvsweb.cgi?cmd=<cmd>&action=<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://<camip>/cgi-bin/jvsweb.cgi?cmd=account&action=list
а добавление пользователя
http://<camip>/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
Определение движения
<ch> list # List motion detects
# cmd=webmdetect&action=1 list
# cmd=webmdetect 1&action=list
<ch> 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
Определение приватной зоны на изображении, которую не нужно транслировать
<ch> list # List privacy zones
# cmd=webprivacy&action=1 list
# cmd=webprivacy 1&action=list
<ch> 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
<ch> list # List settings
<ch> 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<chid> <streamid>&action=ability
# cmd=webstream -c1 1&action=ability
<ch> list # List streams
<ch> 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}
<ch> resolution # Get stream possible resolution
<ch> 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":"u0004u0002"}
changemode:
????
Обратите внимание, что при помощи команд webwifi и webifconfig можно спокойно просканировать рядом находящиеся WIFI сети и подключиться к ним. Таким образом подконтрольная камера может спокойно шпионить за окружающей обстановкой
- webosd
Управление идентификатором камеры на видео
<ch> list # Get channel info
<ch> 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 <datetime>
system <reboot/reset/softreset>
Функция позволяет ребутить или сбрасывать устройство
http://<camip>/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 <datetime> settime 2012-06-07 13:58:00 system <reboot/reset/softreset>
- 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://<camip>/cgi-bin/jvsweb.cgi?cmd=yst&action=get_port
http://<camip>/cgi-bin/jvsweb.cgi?cmd=yst&action=get_video
Первая покажет порт управления системой и параметры порта. Вторая покажет текущие видеопотоки имеющиеся в системе. Вывод второй команды обычно такой.
rtsp://<camip>/live0.264
rtsp://<camip>/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://<camip>/cgi-bin/jvsweb.cgi?cmd=ptz&action=move¶m=["chnid":1,"x":0,"y":-0.5]
http://<camip>/cgi-bin/jvsweb.cgi?cmd=mptz&action=down
Обе команды дают камере команду повернуться вниз. В первом случае мы указываем скорость с которой будет опускаться камера. Скорость рассчитывается как 255 умноженное на значение скорости. Таким образом при значении скорости равной 0.01 камера будет опускаться вниз со скоростью 2 точки на 1 тик. Во втором случае камера будет опускаться со скоростью 100 точек на 1 тик. Значение тика я пока не выяснил. Нужно замерить.
Камера будет опускаться до тех пор пока не достигнет нулевой точки, либо пока не будет получена следующая команда.
http://<camip>/cgi-bin/jvsweb.cgi?cmd=ptz&action=move¶m=["chnid":1,"x":0,"y":0]
http://<camip>/cgi-bin/jvsweb.cgi?cmd=mptz&action=stop
preset и locatePreset служат для быстрого добавления и вызова точек позиционирования
http://<camip>/cgi-bin/jvsweb.cgi?cmd=mptz&action=preset 1
http://<camip>/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