Еще одна стажировка, или сказ про реверс IP-камеры

9fc55e90776b5d151fc272781b2c43d9.jpg

Вступление

Итак, меня взяли на стажировку. Стажировка рассчитана на 2–3 месяца неспешной работы по 20 часов в неделю.

Что обещали научить делать (забегая вперед — обещание выполнили):

  • анализ открытых источников;

  • анализ аппаратных интерфейсов устройства;

  • схемотехнический анализ устройства;

  • работу с программаторами;

  • пайку;

  • анализ технологических интерфейсов микроконтроллеров;

  • анализ программного обеспечения (как статический, так и динамический);

  • поиск недекларированных возможностей;

  • разработку консольного приложения.

С отдельными пунктами я уже был знаком: кое-что было на занятиях в вузе, что-то попадалось на CTF, про другие я только слышал (например, пайка и прочие «железячные» штуки).

Теперь о задании. Объектом исследования была типичная IP-камера, которая умеет записывать видео на MicroSD и стримить через Интернет на мобильное приложение (настраивается тоже через приложение). Еще камера может обнаруживать движение в кадре и отправлять владельцу фотографию происходящего. Целью исследования было проведение анализа защищенности модифицированной камеры и разработка PoC, позволяющего отключить функционал обнаружения движения в кадре, находясь в одной локальной сети с устройством.

Стоит отметить, что функционал камеры, благодаря которому в результате удалось разработать PoC, изначально в ней отсутствовал и был добавлен в прошивку специально, чтобы было, что искать (возможно, какие-нибудь уязвимости можно было бы найти и в оригинальной прошивке, но сколько времени это заняло бы у неопытного исследователя?). Но протокол, на основе которого данный функционал реализован, реально существовал.

Этап 1

Этот этап скорее обзорный, нужно было:

  • узнать возможности камеры;

  • найти внешние аппаратные интерфейсы камеры и определить протоколы, которые используются камерой на данных интерфейсах;

  • попробовать найти в открытых источниках прошивки для камеры или какую-либо информацию о них.

Интерфейсы у камеры следующие:

  • слот для MicroSD. Карточка должна быть отформатирована в FAT32, иначе это с ней сделают принудительно при первой попытке использования. Записывается видео в своеобразном формате, подробнее чуть ниже под спойлером;

  • Wi-Fi-модуль;

  • MicroUSB-порт. Изначально возникли сомнения в том, что он способен передавать данные, в дальнейшем они подтвердились: от разъема к плате идут два провода — только питание.

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

При запуске камера шлет информацию о себе широковещательно (сначала четыре пакета подряд, потом еще шесть с интервалом 5 секунд) на 6666-й UDP-порт. Структура пакета:

  • 00 00 55 AA;

  • 16 байт нулей;

  • {«ip»:»192.168.0.102», «gwId»: «bf2a13eff2a4a35f67bo4w», «active»:2, «ablilty»:0, «encrypt»: true, «productKey»: «endfc4sm1iaczb4l», «version»:»3.2»};

  • CRC32 от всех пунктов, приведенных выше;

  • 00 00 AA 55.

Бесполезный бонус: как сохраняется видео на microSD

После записи видео на флешке появляются такие файлы:

image-loader.svg
  1. Для воспроизведения .avs можно использовать специальный плеер с официального сайта производителя.

  2. session.log — в начале короткий заголовок из ASCII-символов, потом много нулей (ровно 16 Мбайт).

  3. С photo.bin то же самое, только еще есть несколько неведомых байтов. Эти файлы фактически пустые, и у них нет времени создания и изменения. По ходу работы камеры они не меняются.

  4. index00.bin, index01.bin:

  • размер точно по 8 Мбайт (01 — предыдущая версия файла 00, при каждом запуске старый 01 заменяется);

  • первые 112(=16×7) байт заголовок, дальше блоки данных, описывающие avs-файлы:

image-loader.svg
  • байт 0B на скрине — скорее всего что-то вроде указателя на следующий файл для записи;

  • размер блока 452 байта. Судя по размеру, всего возможно 18 558 видеофайлов до конца этого индекса. Блоки данных состоят из 32 байт, разделяемых промежутками по 420 нулей:

image-loader.svgimage-loader.svg

− желтое — порядковый номер блока и часть имени avs-файла;
− фиолетовое — было одинаковым в нескольких блоках;
− красное и синее — unixtime начала и конца записи;
− зеленое — размер файла.

Все числа в little endian.

Запись в файл производится маленькими порциями с одновременным обновлением index файла. Файлы режутся по ~20 минут, скорее всего отсечка по размеру (по времени слишком «некрасивые» числа выходят).

При сканировании были найдены открытые TCP-порты:

NetBIOS имя камеры — dgiot, что является отсылкой к китайскому производителю облачных сервисов для IoT-устройств (сайт, гитхаб). При попытке подключиться по telnet становится известным имя хоста — anyka, что является названием SoC для IP-камер, на базе которого, как потом выяснилось, устройство и сделано.

На загадочном турецком сайте была найдена прошивка — образ SquashFS (это внушало надежду, что в дальнейшем можно будет увидеть не просто прошивку, но какую-то Unix-систему). Анализировать не стал, т.к. в дальнейшем предполагалось извлечь прошивку из самого устройства.

Этап 2

На данном этапе я наконец-то вскрываю корпус и заглядываю внутрь устройства, чтобы на плате поискать ключевые компоненты, определить их взаимосвязи, найти те, что отвечают за обработку внешних интерфейсов (тех самых, что на предыдущем этапе искали). Еще я искал отладочные интерфейсы (UART, JTAG) и должен был найти компонент, содержащий основную прошивку.

На фотографиях ниже цифрами обозначены элементы, которые мне показались потенциально полезными.

Сторона А

3ca5b05d354f129b42129698a9562fb8.jpg

Сторона Б

2ec63c6f8a7d2f8caf20290e541b5778.jpg

Реально полезными оказались два:

Зеленым обведен потенциальный отладочный интерфейс (характерные подписи контактов, см. спойлер «Сторона А»).

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

К слову, найти документацию на конкретно этот SoC так и не удалось, но это не сильно помешало.

На этом этапе я задавал кучу вопросов из разряда «а что это за точки?», на которые руководитель стажировки терпеливо отвечал.

Те самые точки

08d08ba421dc782695473d96abf9614b.jpg

Взаимодействие всех внешних интерфейсов происходит через ANYKA. Для понимания взаимосвязей компонентов бывает полезно изобразить их на функциональной схеме:

image-loader.svg

Тут я предположил, что прошивка находится во флеш-памяти.

Этап 3

На этом этапе нужно было попробовать добыть прошивку: прочитать программатором из флеш-памяти или разобраться с отладочными контактами и прочитать прошивку через них (в образовательных целях я попробовал оба варианта).

Этот этап выполнялся в лаборатории. С использованием программатора ChipProg-48 были успешно считаны все 8192 Кбайт памяти. Тут же я впервые взял в руки паяльник и попытался подпаяться к контактам UART. Что-то даже получилось.

32cea619a224c88c371c5cf3e848debd.jpg

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

Кстати, для новичков с дрожащими руками: закон Мерфи работает. Капля припоя, сорвавшаяся с жала, не могла найти другого места для падения, кроме как сразу на три ножки драйвера мотора, напрочь лишив камеру возможности поворачиваться по одной из осей. Так что будьте внимательнее с тем, где держите паяльник.

При подключении к UART возникает вопрос выбора скорости передачи данных (baudrate). Говорят, ее можно определить с помощью логического анализатора, но быстрее оказалось найти нужное значение методом перебора — 115200.

Об автоматизации перебора

Появлялась мысль автоматизировать процесс программного подбора скорости: простенький скрипт, который пытается получить и вывести в консоль пару сотен символов с serial-порта для всех возможных значений скорости, чтобы потом глазами найти адекватные строки. Для этого устройства идея, в принципе, рабочая, но с другими могут быть проблемы: нет никаких гарантий, что с serial будут прочитаны именно ASCII-строки и что глазами можно будет отличить их от мусора.

Подключившись по UART к уже включенной камере, получили в терминал кучу строк, похожих на логи приложения. Если сначала подключиться к интерфейсу, а потом уже включать устройство, то можно увидеть интересную строку: Hit any key to stop autoboot: и таймер на 3 секунды. Нажатие любой клавиши действительно прерывает автозагрузку, и в результате был получен доступ к оболочке U-Boot.

Как подсказали help и гугл, в оболочке U-Boot есть команда md — memory display, выводящая содержимое ОЗУ. Ее аргументами являются адрес и количество объектов (по умолчанию объект — это dword). Я попробовал найти место, чтобы туда загрузить 8 Мбайт из флеш-памяти, но получал постоянно один и тот же набор байтов при попытках прочитать что-либо:

ac25b87ed094c8643beb0779ac7dadc6.jpg

Это меня отпугнуло, и я не стал дальше копать в данном направлении.

Наличие U-Boot и его переменные среды окончательно подтвердили теорию, что в устройстве есть ОС Linux (характерные параметры загрузки ядра — четвертая строка в выводе ниже).

Вывод env print (еще одна команда U-Boot)

backuppage=ffffffff
baudrate=115200
boot_normal=readcfg; run read_kernel; bootm ${loadaddr}
bootargs=console=ttySAK0,115200n8 root=/dev/mtdblock4 rootfstype=squashfs init=/sbin/init mem=64M flash=SF device_id=00000000000 ethaddr=00:55:7b:b5:7d:f7 devinfo=jcoxxx memsize=64M
bootcmd=run boot_normal
bootdelay=3
console=ttySAK0,115200n8
erase_env=sf probe 0:0 ${sf_hz} 0; sf erase 0x20000 0x2000
ethact=AKEthernet-0
ethaddr=00:55:7b:b5:7d:f7
fs_addr=0x230000
init=/sbin/init
ipaddr=192.168.1.99
kernel_addr=31000
kernel_size=154590
loadaddr=81808000
memsize=64M
mtd_root=/dev/mtdblock4
netmask=255.255.255.0
read_kernel=sf probe 0:0 ${sf_hz} 0; sf read ${loadaddr} ${kernel_addr} ${kernel_size}
rootfstype=squashfs
serverip=192.168.1.1
setcmd=setenv bootargs console=${console} root=${mtd_root} rootfstype=${rootfstype} init=${init} mem=${memsize}
sf_hz=20000000
stderr=serial
stdin=serial
stdout=serial
ver=U-Boot 2013.10.0-AK_V2.0.03 (Sep 21 2017 - 17:00:25)
vram=12M

Путем модификации параметров загрузки ОС Linux возможно изменить стандартный порядок загрузки (запуск /sbin/init на запуск /bin/sh), что дает шелл в запущенной Linux-системе (основной функционал камеры в этот момент еще не начал работать). Последовательность команд в оболочке U-Boot, позволяющая сделать это:

setenv init /bin/sh # задать новое значение переменной
run setcmd # собрать заново переменную bootargs с уже внесенными изменениями
run boot_normal # запустить ОС

В результате ОС запустилась и дала возможность выполнять любые Linux-команды. Путем чтения устройства /dev/mtd0 можно считать содержимое флеш-памяти. Самый простой способ — записать с помощью dd содержимое флеш-памяти на microSD-карточку — почему-то в голову не пришел. Я пытался выводить содержимое ПЗУ в консоль и потом вырезать его из логов PuTTY, который использовал для подключения к serial-порту. Но в этом клиенте есть такая настройка, как Answerback to ^E, содержащая строку, которая будет автоматически отправляться серверу в случае получения от него ^E (что может произойти при выводе бинарного файла в консоль). И ладно бы проблема была только в этом — можно просто задать пустой answerback — еще PuTTY заменяет \n на \r\n, а \r\n оставляет без изменений. В итоге нереально понять, что нужно заменять обратно, а что нет. (Ну или по еще каким-то неведомым причинам размер дампа увеличивался на несколько байт.)

В итоге я использовал магию вида dd if=/dev/mtd0 2>/dev/null | base64, а потом локально декодировал вывод, достав его из логов.

В конце концов полученный через UART дамп совпал с тем, что был вытащен с использованием программатора.

Этап 4

На этом этапе нужно было:

  • разобраться со структурой полученного ранее дампа и привести его к виду, доступному для анализа;

  • узнать, что именно запускается в прошивке и в какой последовательности.

Среди логов, выводящихся во время загрузки ОС, попался такой фрагмент:

Разделы

mtd_part[0]:
name = KERNEL
size = 0x200000
offset = 0x31000
mask_flags = 0x1

mtd_part[1]:
name = MAC
size = 0x1000
offset = 0x231000
mask_flags = 0x1

mtd_part[2]:
name = ENV
size = 0x1000
offset = 0x232000
mask_flags = 0x1

mtd_part[3]:
name = A
size = 0x100000
offset = 0x233000
mask_flags = 0x1

mtd_part[4]:
name = B
size = 0x400000
offset = 0x333000
mask_flags = 0x1

mtd_part[5]:
name = C
size = 0xaf000
offset = 0x733000
mask_flags = 0x1

Creating 6 MTD partitions on "spi0.0":
0x000000031000-0x000000231000 : "KERNEL"
0x000000231000-0x000000232000 : "MAC"
0x000000232000-0x000000233000 : "ENV"
0x000000233000-0x000000333000 : "A"
0x000000333000-0x000000733000 : "B"
0x000000733000-0x0000007e2000 : "C"

Собственно, на прошлом этапе можно было извлекать дамп целиком из /dev/mtd0, а можно уже разбитым на разделы из /dev/mtd[1–6]. Оставалось только разобраться, что это за разделы с говорящими и не очень названиями (binwalk с этим отлично справился):

  1. KERNEL — заголовок U-Boot и zImage ядро Linux.

  2. MAC — помимо MAC-адреса в ASCII со странным значением (FF: FF: FF:00:00:00), тут были только 00 и FF в большом количестве.

  3. ENV — переменные окружения для U-Boot.

  4. A — образ SquashFS с более-менее стандартным линуксовым набором директорий и файлов.

  5. B — образ SquashFS, содержащий творчество разработчиков устройства: приложения, библиотеки, модули ядра.

  6. C — образ JFFS2, содержащий в основном конфиги: сетевые настройки (в т.ч. данные для подключения к Wi-Fi-сети), файл passwd.

О файле passwd

В этом файле содержался хеш пароля для пользователя root. Но, увы, гугл о нем не знал, брут по каким-то словарям для IoT с гитхаба не помог, а полный перебор занял бы на моем процессоре около года, так что пришлось отказаться от идеи подключаться к камере по telnet и творить все, что вздумается.

Порядок запуска внутри ОС описан в файле /etc/init.d/rc.local:

Содержимое

#!/bin/sh

#print kernel error default
echo 4 > /proc/sys/kernel/printk

# mount usr file-system.
/bin/mount -t squashfs /dev/mtdblock5 /usr
# mount jffs2 file-system.
/bin/mount -t jffs2 /dev/mtdblock6 /etc/jffs2
# note: can't recommend running other app before `mount` command.

#start ftp server, dir=root r/w, -t 600s(timeout)
/usr/bin/tcpsvd 0 21 ftpd -w / -t 600 &

#start syslogd & klogd, log rotated 3 files(200KB) to /var/log/messages
syslogd -D -n -O /var/log/messages -s 200 -b 3 & # -l prio
klogd -n & # -c prio

#create ramdisk
dd if=/dev/zero of=/tmp/zero bs=512 count=200
losetup /dev/loop0 /tmp/zero
mkfs.vfat /dev/loop0
mkdir /tmp/ramdisk
mount /dev/loop0 /tmp/ramdisk

ifconfig lo 127.0.0.1

#load camera module
/usr/sbin/camera.sh setup

dmesg > /tmp/start_message
#start system service
#/usr/sbin/service.sh start &

## set min free reserve bytes
echo 2048 > /proc/sys/vm/min_free_kbytes

#install usb wifi driver(default)
insmod /usr/modules/sdio_wifi.ko
sleep 1 #### 等待电源稳定后再加载其他驱动
insmod /usr/modules/otg-hs.ko
sleep 2 #### 等待otg 向usb host 核心层完成一些注册工作后再加在驱动
insmod /usr/modules/rtl8188fu.ko

#ifconfig eth0 up

#检查是否有恢复usr分区的升级包
echo "start revocer_app..."
/bin/revocer_app

#start ipc
read -t 1 -n 1 char
if [ "$char" == "n" ];then
	echo "stop"
else
	echo "start dgiot..."
	/usr/dgiot/bin/dgiot &
	echo "start ota_upgrade..."
	/bin/ota_upgrade &
fi

echo "start telnet......"
telnetd &

Вот схема запуска:

image-loader.svg

Основная жизнедеятельность камеры реализована в приложении dgiot, дальше предстоит работать именно с ним. Это обычный ELF-файл для ARM, никаких проблем с его загрузкой в IDA Pro, как у предыдущего стажера, не возникло.

Этап 5

На этом этапе нужно было разобраться с потоками и основными циклами в приложении, но перед этим стоило попробовать облегчить себе задачу: попытаться найти какую-либо информацию об использованных библиотеках/SDK, чтобы в первую очередь смотреть именно в тот код, который написан разработчиками устройства.

Пробежавшись глазами по строкам из ELF-файла, нашел используемые компиляторы:

  • GCC: (GNU) 3.3.2 20031005 (Debian prerelease);

  • GCC: (anyka (gcc-4.8.5 + binutils-2.24 + ulcibc-0.9.33.2)(20170223)) 4.8.5;

  • GCC: (Hisilicon_v100(gcc4.4–290+uclibc_0.9.32.1+eabi+linuxpthread)) 4.4.1.

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

Используемые SDK:

  • TUYA IPC SDK v4.2.4;

  • TUTK SDK;

  • Anyka SDK (вот тут накладка. Логично, что такое должно быть, но найти в Интернете ничего подобного не удалось).

Чтобы сопоставить найденные библиотеки и имеющееся приложение, мне посоветовали плагин Diaphora для IDA Pro. Из его функционала мне приглянулась возможность найти одинаковые функции в SDK (собранном с отладочными символами) и приложении, после чего автоматически перенести имена функций.

Мне не удалось точно угадать версию TUTK SDK, поэтому здесь Diaphora был очень кстати: ему не нужно полное совпадение функций, он по ряду собственных метрик показывает, насколько функции похожи. А для TUYA IPC SDK удобнее оказалось использовать FLAIR из состава IDA Pro. В этой статье подробно описано, как такое сделать.

И еще один способ получить исходные имена функций. Разработчиками используются функции для вывода в логи сообщений об ошибках с использованием макросов __LINE__, __FUNCTION__, __FILE__ (чтобы проще было понять, что произошло):

image-loader.svgimage-loader.svg

Я нашел две разные функции такого вида, но идея одна и та же: n-й аргумент этой функции будет именем внешней функции (той, где вызывается вывод в лог). Переименовав вручную по этому принципу несколько десятков функций, я понял, что надо это как-то автоматизировать — наконец-то настало время попробовать IDAPython. Но мне не первому в голову пришла такая идея, даже есть статья, в разделе 0×04 которой подобный скрипт описан.

После всего вышеописанного разбираться с логикой приложения гораздо комфортнее. Среди всех запускаемых потоков можно выделить следующие:

1. Поток обнаружения движения (md_judge_thread @0×123890):

image-loader.svg

2. Поток обработки данных, получаемых по сети (lpc_task_cb@0×1E9B4C). Здесь, если пакет валидный, данные передаются в lan_protocol_process@0×2290E8:

image-loader.svg

Этап 6

На заключительном этапе нужно было выяснить:

  • какие порты слушает устройство;

  • каким образом обрабатывает поступающие данные;

  • какие команды выполняет.

Параллельно с этим понять, как отправляются уведомления владельцу (те самые, которые нужно отключить в соответствии с целью исследования). И, наконец, разработать PoC, который будет выполнять эту задачу.

В приложении вызывается функция listen для сокетов на следующих портах:

Были надежды, что последние две буквы в названии второго протокола означали procedure call, так что он выглядел более многообещающим, и изучать в первую очередь я стал именно его.

Данные, поступающие на порт 6668, обрабатываются в ранее упомянутой функции lan_protocol_process@0×2290E8. Структура пакета:

 0x00 00 00 55 AA 	header
 0x04 xx xx xx xx	  session id
 0x08 00 00 00 xx 	command type
 0x0C xx xx xx xx 	length (all packet)
 0x10 xx xx xx xx 	data (e.g. json)
 ...
-0x08 xx xx xx xx	  crc32 (no check)
-0x04 00 00 AA 55 	footer

Интересно, что контрольная сумма поступающих в приложение пакетов вычисляется, но нигде не проверяется. Хотя в пакетах, получаемых от камеры в ответ, контрольная сумма присутствует и посчитана нормально.

О Kaitai Struct

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

meta:
  id: lpc_send
  endian: be
seq:
  - id: header
    contents: [0x0, 0x0, 0x55, 0xaa]
  - id: session_id
    type: u4
  - id: command
    type: u4
    enum: command_types
  - id: lenght
    type: u4
  - id: data
    size: lenght-8
  - id: crc32
    type: u4
  - id: footer
    contents: [0x0, 0x0, 0xaa, 0x55]
enums:
  command_types:
    7: type1
    13: type1_
    8: write
    11: read
    10: type2
    16: type2_
    12: token
    14: typetime
    15: wifi

На этом месте я завис, пытаясь разобраться, казалось бы, с небольшим набором команд. Полезной оказалась одна команда — 8 (должна быть в пакете по смещению 0×08) — позволяет записать произвольные 4 байта («v») по произвольному адресу («a»):

image-loader.svg

А теперь вернемся к функции md_judge_thread @0×123890 (листинг был на скрине на этапе 5). При обнаружении движения в логи пишется строка »…>>>movtion detect!» (sic!), даже если реально уведомления никуда не отправляются (т.е. выключены пользователем). Цикл, в котором это происходит, выполняется, пока переменная по адресу 0×004975F8 равна нулю, т.е. для остановки цикла и выхода из потока необходимо записать любое отличное от нуля значение по этому адресу. А как записывать что-то в память уже известно.

Для остановки потока обнаружения движения был написан скрипт на python, отправляющий правильный пакет:

command = COMMAND_WRITE # 8
data = b'{"a":4814328, "v":1}'
b = bytes([0, 0, 0x55, 0xaa])           # header
b += bytes([1, 2, 3, 4])                # session id
b += struct.pack('>L', command)         # command
b += struct.pack('>L', len(data)+8)     # length
b += data                               # data
b += bytes([0, 0, 0, 0])                # crc32, not checked
b += bytes([0, 0, 0xaa, 0x55])          # footer

После отправки этого набора байтов на порт 6668 камера переставала отправлять владельцу уведомления о появлении движения в кадре.

Отыскать в локальной сети камеру можно с помощью nmap. Необходимо найти устройства с открытым требуемым портом и именем dgiot.

Заключение

На этом стажировку можно было считать оконченной.

Так, в конечном счете должна выглядеть последовательность действий для отключения функционала обнаружения движения:

  1. Подключиться к локальной сети, в которой находится камера.

  2. С помощью nmap просканировать сеть на наличие камеры, получив ее IP-адрес.

  3. Отправить на найденный адрес сформированный пакет, что остановит поток обнаружения движения, и, как следствие, владельцу не будут приходить уведомления о движении в кадре.

Для автоматизации этих действий я использовал скрипты на bash и python.

Помимо описанного во вступлении, также я выполнил ряд пунктов из своего собственного чек-листа «когда-нибудь попробовать»:

  • исследование многопоточного приложения;

  • поковырять какой-то самописный протокол;

  • использовать Kaitai Struct;

  • попробовать написать скрипт на IDAPython.

Еще я убедился, что хочу в дальнейшем связать свою профессиональную деятельность именно с этим направлением ИБ.

Что показалось наиболее сложным:

  • работа с паяльником (с ним я все еще на «вы»);

  • понимание, когда нужно копать глубже, а когда — взглянуть на ситуацию шире.

Следует заметить, что ряд шагов, предпринятых в исследовании, можно было бы и не совершать. Но в ходе стажировки было важно не просто достигнуть цели («слегка» надуманной), а провести полноценное исследование, «потренироваться на кошках». Примененный здесь подход с успехом может быть использован и для более реальных задач.

По окончании стажировки мне вручили сертификат об успешном ее прохождении. Но, внезапно, не из бумаги/картона, а из текстолита размера А5. Изготовлен, видимо, так же, как печатные платы. Интересный формат, люди подошли с фантазией, казалось бы, к тривиальной вещи.

Фото сертификата

image-loader.svg

И после двух с лишним месяцев приключений в мире исследователей защищенности хотелось бы сказать спасибо НТЦ «Вулкан» в целом за предоставленную возможность получить опыт реверс-инжиниринга IoT-устройства и руководителю стажировки в частности, который в любое время дня и ночи приходил на помощь и своими ценными советами направлял меня в этом нелегком деле.

image-loader.svg

Raccoon Security — специальная команда экспертов НТЦ «Вулкан» в области практической информационной безопасности, криптографии, схемотехники, обратной разработки и создания низкоуровневого программного обеспечения.

Мы постоянно проводим такие индивидуальные стажировки и будем благодарны, если вы поделитесь ссылкой на эту статью с теми, кому это может быть интересно.

Оставить заявку на прохождение стажировки можно тут.

© Habrahabr.ru