Обход аутентификации на маршрутизаторах с помощью CVE-2021–20090

Обход аутентификации на маршрутизаторах

Уязвимость CVE-2021-20090 позволяет получить доступ к любому скрипту веб-интерфейса без прохождения аутентификации. Суть уязвимости заключается в том, что в веб-интерфейсе некоторые каталоги, через которые отправляются изображения, файлы CSS и сценарии JavaScript, доступны без аутентификации. В этом случае проверка каталогов, к которым разрешен доступ без аутентификации, выполняется с использованием начальной маски. Указание символов «../» в путях к родительскому каталогу блокируется прошивкой, но использование комбинации «../» игнорируется. Таким образом, можно открывать защищенные страницы при отправке таких запросов, как «http://192.168.1.1/images/../index.htm». В этой статье рассмотрим как осуществляется обход аутентификации на маршрутизаторах с помощью CVE-2021–20090.

Корневые оболочки на UART

Довольно часто  маршрутизаторы, предлагают оболочку через последовательное соединение, известное как универсальный асинхронный приемник / передатчик (UART) на печатной плате. Производители часто оставляют контрольные точки или незанятые площадки на печатной плате для доступа к UART. Они часто используются для отладки или тестирования устройства во время производства. В данном случае нам очень повезло, что после некоторой плохой пайки и тестирования WSR-2533DHPL2 предложил оболочку BusyBox в качестве root вместо UART.

Если это для кого-то ново, давайте быстро рассмотрим этот процесс (в Интернете есть много статей с более подробным описанием взлома оборудования и оболочек UART).

Первый шаг для нас — открыть корпус маршрутизатора и попытаться определить, есть ли способ доступа к UART.

Обход аутентификации на маршрутизаторах

Интерфейс UART на WSR-2533DHP3

Мы видим заголовок J4, который может быть тем, что мы ищем. Следующим шагом является проверка контактов с помощью мультиметра, чтобы определить мощность (СCV), землю (GND) и наши потенциальные контакты передачи / приема (TX / RX). После того, как мы их определили, мы можем припаять некоторые контакты и подключить их к такому инструменту, как JTAGulator, чтобы определить, по каким контактам мы будем связываться и с какой скоростью передачи.

Обход аутентификации на маршрутизаторах

Мы могли бы определить это другими способами, но JTAGulator значительно упрощает это. После установки напряжения, которое мы используем (3,3 В, найденного ранее с помощью мультиметра), мы можем запустить сканирование UART, которое попытается отправить возврат каретки (или некоторые другие указанные байты) и получить на каждом контакте с разными битами, что помогает  определить, какая их комбинация позволит нам общаться с устройством.

Обход аутентификации на маршрутизаторах

Запуск сканирования UART на JTAGulator

Сканирование UART показывает, что отправка возврата каретки через контакт 0 в качестве TX, с контактом 2 в качестве RX и скоростью передачи 57600 дает вывод BusyBox v1, который выглядит так, как будто у нас есть наша оболочка.

Обход аутентификации на маршрутизаторах

Сканирование UART в поисках нужных нам настроек
 
Разумеется, после установки JTAGulator в режим UART Passthrough (который позволяет нам связываться с портом UART) с использованием настроек, которые мы нашли при сканировании UART, мы попадаем в корневую оболочку на устройстве.
 
Обход аутентификации на маршрутизаторах
 
Теперь мы можем использовать эту оболочку для исследования устройства и переноса любых интересных двоичных файлов на другую машину для анализа. В этом случае мы взяли двоичный файл httpd, который обслуживал веб-интерфейс устройства.

Httpd и аутентификация через веб-интерфейс

Доступ к двоичному файлу httpd значительно упрощает поиск уязвимостей в веб-интерфейсе, поскольку мы можем добавить его в Ghidra и идентифицировать любые интересные фрагменты кода. Одна из первых вещей, на которую я обычно обращаю внимание при анализе любого веб-приложения или интерфейса, — это то, как оно обрабатывает аутентификацию.

Изучая веб-интерфейс, я заметил, что даже после входа в систему файлы cookie сеанса не устанавливаются и токены не хранятся в локальном / сеансовом хранилище, так как же отслеживалось, кто прошел проверку подлинности? Открывая httpd в Ghidra, мы находим функцию с именем Assessment_access (), которая приводит нас к следующему фрагменту:

Обход аутентификации на маршрутизаторах

Фрагмент из FUN_0041fdd4 (), вызываемый оценкой_access ()

FUN_0041f9d0 () на скриншоте выше проверяет, совпадает ли IP-адрес хоста, выполняющего текущий запрос, с IP-адресом из предыдущего действительного входа в систему.

Теперь, когда мы знаем, что делает eval_access (), давайте посмотрим, сможем ли мы это обойти. Поискав, где на него ссылаются в Ghidra, мы видим, что он вызывается только из другой функции process_request (), которая обрабатывает любые входящие HTTP-запросы.

Обход аутентификации на маршрутизаторах

process_request () решает, должен ли он разрешать пользователю доступ к странице

Что сразу бросается в глаза, так это логическое ИЛИ в более крупном операторе if (строки 45–48 на скриншоте выше) и тот факт, что он проверяет значение uVar1 (установленное в строке 43) перед проверкой вывода Assessment_access (). Это означает, что если вывод bypass_check (__ dest) (где __dest — это запрашиваемый URL) возвращает что-либо, кроме 0, мы фактически пропустим необходимость аутентификации, и запрос будет передан в process_get () или process_post () .

Давайте рассмотрим bypass_check ().

Обход проверок с помощью bypass_check ()

Обход аутентификации на маршрутизаторах

bypass_list проверяется в bypass_check ()

Взглянув на bypass_check () на скриншоте выше, мы видим, что он перебирает bypass_list и сравнивает первые n байтов _dest со строкой из bypass_list, где n — длина строки, полученной из bypass_list. Если совпадений не найдено, мы возвращаем 0, и нам потребуется пройти проверки в Assessment_access (). Однако, если строки совпадают, то нас не волнует результат метода Assessment_access (), и сервер обработает наш запрос, как и ожидалось.

Взглянув на список обхода, мы видим login.html, loginerror.html и некоторые другие пути / страницы, что имеет смысл, поскольку даже неаутентифицированные пользователи должны иметь доступ к этим URL-адресам.

Возможно, вы уже заметили здесь ошибку. bypass_check () проверяет только столько байтов, сколько находится в строках bypass_list. Это означает, что если пользователь пытается получить доступ к http: //router/images/someimage.png, сравнение будет соответствовать, поскольку / images / находится в списке обхода, а URL-адрес, который мы пытаемся достичь, начинается с / images /. Функция bypass_check () не заботится о строках, которые идут после, например, someimage.png. Так что, если мы попытаемся достичь /images/../ <somepagehere>? Например, давайте попробуем /images/..%2finfo.html. URL-адрес /info.html обычно содержит всю полезную информацию о LAN / WAN при первом входе в устройство, но возвращает всех неаутентифицированных пользователей на экран входа в систему. С нашим специальным URL-адресом мы могли бы обойти требование аутентификации.
 
После небольшого сопоставления / замены для учета относительных путей мы все еще видим неутешительный дисплей. Мы успешно обошли аутентификацию с использованием обхода пути (), но мы все еще что-то упускаем ().
 
 
404s для запросов к файлам js
 
Глядя на трафик Burp, мы видим, что несколько запросов к /cgi/<various_nifty_cgi>.js возвращают 404, которые обычно возвращают всю информацию, которую мы ищем. Мы также видим, что при запросе к этим файлам передается пара параметров.
 
Один из этих параметров (_t) — это просто отметка даты и времени. Другой — это токен httoken, который действует как токен CSRF, и выяснение того, где и как они генерируются, будет обсуждаться в следующем разделе. А пока давайте сосредоточимся на том, почему именно эти запросы не выполняются.
 
Просмотр httpd в Ghidra показывает, что при возникновении ошибок печатается изрядное количество отладочных данных. Остановка процесса httpd по умолчанию и его запуск из нашей оболочки показывает, что мы можем легко увидеть этот вывод, который может помочь нам определить проблему с текущим запросом.
 
 
запросы не выполняются из-за неправильного заголовка реферера
 
Не углубляясь в url_token_pass, мы видим, что он говорит, что httoken недействителен из http://192.168.11.1/images/..%2finfo.html. Далее мы погрузимся в httokens, но токен, который у нас здесь, правильный, а это означает, что часть, вызывающая сбой, является URL-адресом «from», который соответствует заголовку Referer в запросе. Итак, если мы создадим правило быстрого сопоставления / замены в Burp Suite, чтобы исправить заголовок Referer и удалить /images/..%2f, то мы увидим информационную таблицу, подтверждающую нашу способность обойти аутентификацию.
 
 
наш контент загружен
 
Краткое изложение того, где мы находимся на данный момент:
 
  • Мы можем обойти аутентификацию и получить доступ к страницам, которые должны быть ограничены аутентифицированными пользователями.
  • Эти страницы включают доступ к токенам, которые позволяют нам делать запросы GET / POST для получения более конфиденциальной информации и предоставлять возможность вносить изменения в конфигурацию.
  • Мы знаем, что нам также нужно правильно установить заголовок Referer, чтобы httokens были приняты.

Как получит правильные токены httokens

Хотя мы знаем, что httokens захватываются в какой-то момент на страницах, к которым мы обращаемся, мы не знаем, откуда они берутся и как они генерируются. Это будет важно понять, если мы хотим продолжить эту эксплуатацию, поскольку они должны делать или получать доступ к чему-либо важному на устройстве. Отслеживание того, как веб-интерфейс производит эти токены, было похоже на событие Capture-the-Flag.

Страница info.html, к которой мы получили доступ с обходом пути, заполняла свою информационную таблицу данными из файлов .js в каталоге / cgi / и передавала два параметра. Один — это отметка даты и времени (_t), а другой — httoken, который мы пытаемся вычислить.

Мы видим, что ссылки, используемые для получения информации из / cgi /, генерируются с помощью функции URLToken (), которая устанавливает httoken (в данном случае параметр _tn) с помощью функции get_token (), но не похоже что get_token () может быть определенным где угодно в любом из скриптов, используемых на странице.

Глядя прямо выше, где определен URLToken (), мы видим, что определена эта странная строка.

Глядя на то, где он используется, мы находим следующий фрагмент. 

1.  // decode way

2.   var head = document.getElementsByTagName("head")[0] || document.documentElement;

3.   var script = document.createElement("script");

4.   script.type="text/javascript";

5.   teks="";teksasli="";

6.   enkripsi=ArcBase.decode(enkripsi);

7.   var panjang;panjang=enkripsi.length;for (i=0;i<panjang;i++){         teks+=String.fromCharCode(enkripsi.charCodeAt(i)^3) }teksasli=unescape(teks);

8.   script.text=teksasli;

9.   head.insertBefore(script,head.firstChild );

10.   head.removeChild(script);

Который при запуске добавляет на страницу следующий скрипт:
 
1.  function getToken(){
 
2.              var objs=document.getElementsByTagName("img");
 
3.                var x;
 
4.                  for(var i=0,sz=objs.length;i < sz; i++){
 
5.                                x=objs[i].src;
 
6.                                  if(x.indexOf("data:") ==0){
 
7.                                              return ArcBase.decode(x.substring(78));
 
8.                                    }
 
9.                }
 
10.              return "";
 
11.  }
 
Мы обнаружили недостающую функцию getToken (), но, похоже, она делает что-то столь же странное, как и фрагменты, которые привели нас сюда. Она захватывает другую закодированную строку из тега изображения, который, по-видимому, существует на каждой странице (с разными закодированными строками). Так что происходит?
 
 
getToken () получает данные из этого тега spacer img
 
Токены httokens берутся из этих строк spacer img src и используются для выполнения запросов к конфиденциальным ресурсам.
 
Мы можем найти функцию, в которой httoken вставляется в тег img в Ghidra.
 
 
Не вдаваясь во все подробности о настройке / получении httoken и о том, как он проверяется на запросы GET и POST, мы скажем, что:
 
  • httokens, которые необходимы для выполнения запросов GET и POST к различным частям веб-интерфейса, генерируются на стороне сервера.
  • Они хранятся в кодировке в тегах img внизу любой страницы при ее загрузке.
  • Затем они декодируются в JavaScript на стороне клиента.

Мы можем использовать токены для любых запросов, которые нам нужны, если токен и Referer, используемые в запросе, совпадают. Мы можем делать запросы к конфиденциальным страницам, используя токен, полученный из login.html, но нам по-прежнему нужен обход аутентификации для доступа к некоторым действиям (например, внесению изменений в конфигурацию).

Примечательно, что на маршрутизаторе WSR-2533DHPL2 простое использование этих токенов означает, что мы можем получить доступ к паролю администратора для устройства, уязвимость, которая, по-видимому, уже исправлена ​​на WSR-2533DHP3 (несмотря на то, что обе версии прошивки были выпущены примерно в одно и то же время).

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

Внедрение параметров конфигурации и включение telnetd

Одно из первых мест, где я проверяю любой веб-интерфейс / приложение, в котором есть такие утилиты, как функция ping, — это посмотреть, как эти утилиты реализованы, потому что даже быстрый Google обнаруживает ряд исторических примеров того, как утилиты ping маршрутизатора склонны к команде. инъекционными уязвимостями.

Хотя в команде ping не было легко достижимой инъекции команды, рассмотрение того, как она реализована, привело к другой уязвимости. Когда команда ping запускается из веб-интерфейса, она принимает входные данные хоста для проверки связи.
 
После успешного выполнения запроса ARC_ping_ipaddress сохраняется в глобальном файле конфигурации. Заметив это, первое, что я попробовал, — это ввести символ новой строки / возврата каретки (% 0A при кодировке url), за которым следует некоторый текст, чтобы увидеть, можем ли мы ввести параметры конфигурации. Разумеется, при проверке файла конфигурации текст, введенный после% 0A, появляется в новой строке файла конфигурации.
 
 
Имея это в виду, мы можем взглянуть на любые интересные настройки конфигурации, которые мы видим, и надеяться, что мы сможем их перезаписать, введя параметр ARC_ping_ipaddress. В файле конфигурации есть несколько опций, но одна из них, которая привлекла мое внимание, — это ARC_SYS_TelnetdEnable = 0. Включение telnetd казалось хорошим кандидатом для получения удаленной оболочки на устройстве.
 
Было неясно, будет ли работать простая инъекция файла конфигурации с ARC_SYS_TelnetdEnable = 1, поскольку за этим последует конфликтующий параметр позже в файле (поскольку ARC_SYS_TelnetdEnable = 0 отображается ниже в файле конфигурации, чем ARC_ping_ipdaddress). Однако после отправки следующего запроса в Burp Suite и отправки запроса на перезагрузку (что необходимо для вступления в силу определенных изменений конфигурации).
 
 
 
После завершения перезагрузки мы можем подключиться к устройству через порт 23, на котором прослушивает telnetd, и встретимся с корневой оболочкой BusyBox, как и через UART.
 

Все и сразу

 
Вот элементы, которые нам нужно собрать в скрипт Python, если мы хотим упростить эксплуатацию этого объекта:
 
  • Получите правильные httokens из тегов img на странице.
  • Используйте эти httokens в сочетании с обходом пути, чтобы сделать действительный запрос на apply_abstract.cgi
  • В этом действительном запросе на apply_abstract.cgi вставьте параметр конфигурации ARC_SYS_TelnetdEnable = 1
  • Отправьте еще один действительный запрос на перезагрузку устройства.

Быстрый запуск PoC против WSR-2533DHPL2
 

Больше затронутых устройств

21 апреля 2021 г. Tenable сообщила о CVE-2021–20090 четырем дополнительным поставщикам (Hughesnet, O2, Verizon, Vodafone), а 22 апреля сообщила о проблемах Arcadyan. Со временем стало ясно, что это затронуло еще много поставщиков, и связаться с ними и отследить их станет очень сложно, поэтому 18 мая Tenable сообщила о проблемах в Координационный центр CERT, чтобы получить помощь в этом процессе. Список затронутых устройств можно найти в собственных рекомендациях Tenable, а дополнительную информацию можно найти на странице CERT, отслеживающей проблему.

Предстоит гораздо более обширный разговор о том, как эта уязвимость в прошивке Arcadyan’s существует уже не менее 10 лет и, следовательно, нашла свое отражение в цепочке поставок по крайней мере в 20 моделях от 17 различных поставщиков, и это затрагивает технический документ выпущеный Tenable.

Выводы

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

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

 
 

 

 
 
 

 

 

 

 

 

 

 

 

 

 
 
 
 

 

Click to rate this post!
[Total: 0 Average: 0]

Leave a reply:

Your email address will not be published.