Кот-призрак. Как эксплуатировать новую RCE-уязвимость в веб-сервере Apache Tomcat - «Новости» » Самоучитель CSS
Меню
Наши новости
Учебник CSS

Невозможно отучить людей изучать самые ненужные предметы.

Введение в CSS
Преимущества стилей
Добавления стилей
Типы носителей
Базовый синтаксис
Значения стилевых свойств
Селекторы тегов
Классы
CSS3

Надо знать обо всем понемножку, но все о немногом.

Идентификаторы
Контекстные селекторы
Соседние селекторы
Дочерние селекторы
Селекторы атрибутов
Универсальный селектор
Псевдоклассы
Псевдоэлементы

Кто умеет, тот делает. Кто не умеет, тот учит. Кто не умеет учить - становится деканом. (Т. Мартин)

Группирование
Наследование
Каскадирование
Валидация
Идентификаторы и классы
Написание эффективного кода

Самоучитель CSS

Вёрстка
Изображения
Текст
Цвет
Линии и рамки
Углы
Списки
Ссылки
Дизайны сайтов
Формы
Таблицы
CSS3
HTML5

Новости

Блог для вебмастеров
Новости мира Интернет
Сайтостроение
Ремонт и советы
Все новости

Справочник CSS

Справочник от А до Я
HTML, CSS, JavaScript

Афоризмы

Афоризмы о учёбе
Статьи об афоризмах
Все Афоризмы

Видео Уроки


Наш опрос



Наши новости

       
2-04-2020, 16:20
Кот-призрак. Как эксплуатировать новую RCE-уязвимость в веб-сервере Apache Tomcat - «Новости»
Рейтинг:
Категория: Новости

Сегодня я рассмотрю уязвимость в Apache Tomcat, которая позволяет читать файлы на сервере и при определенных условиях выполнять произвольный код. Проблема скрывается в особенностях реализации протокола AJP, по которому происходит взаимодействие с сервером Tomcat. Для эксплуатации злоумышленнику не требуется каких-либо прав в целевой системе.

Tomcat — это контейнер сервлетов с открытым исходным кодом. Он написан на языке Java и реализует такие спецификации, как JavaServer Pages (JSP) и JavaServer Faces (JSF). Это один из наиболее популярных веб-серверов, особенно часто он используется в корпоративной среде. Его ставят как самостоятельное решение или в качестве контейнера сервлетов в различных серверах приложений, например GlassFish или JBoss.


Баг нашел исследователь из Chaitin Tech в начале этого года. Уязвимость получила статус критической. Как сейчас стало модно, она обзавелась собственным названием — Ghostcat — и логотипом в виде кота-призрака.


Уязвимость позволяет злоумышленнику читать произвольные файлы на целевой системе внутри директории appBase. Реализация протокола AJP (Apache JServ Protocol) позволяет контролировать атрибуты, которые отвечают Р·Р° формирование пути РґРѕ запрашиваемых файлов. Специально сформированный запрос РЅР° сервер позволяет прочитать содержимое файлов, доступ Рє которым невозможен РІ РґСЂСѓРіРёС… условиях. Если можно загрузить файл РЅР° сервер, существует СЂРёСЃРє использования уязвимости для выполнения произвольного РєРѕРґР°.


INFO


Уязвимости присвоен идентификатор CVE-2020-1938. Ошибка присутствует в актуальных ветках дистрибутива и затрагивает все версии Apache Tomcat ниже 9.0.31, 8.5.51 и 7.0.100.




 

Тестовый стенд


Начнем со стенда для тестирования уязвимости. Для этого достаточно запустить контейнер Docker из официального репозитория Tomcat.


docker run -it --rm -p 8080:8080 -p 8009:8009 tomcat:9.0.30

Очень важно расшарить порт 8009, это AJP-протокол, в котором и была найдена уязвимость.


Если хочется вместе со мной возиться с отладкой приложения, то нужно действовать немного по-другому. Для дебага я буду использовать IntelliJ IDEA. Сначала скачаем уязвимую версию Apache Tomcat. Я взял 9.0.30. Распакуем и откроем проект в IDEA. Теперь создадим новую конфигурацию отладки с шаблоном Remote.


Кот-призрак. Как эксплуатировать новую RCE-уязвимость в веб-сервере Apache Tomcat - «Новости»
Создание шаблона Remote в IDEA

Здесь в поле Command lines arguments строка СЃ параметрами, которые нужно указать РїСЂРё запуске сервера. Рекомендую выбрать версию JDK 1.4.x.


Конфигурация отладки. Аргументы для запуска Tomcat в режиме удаленной отладки
Конфигурация отладки. Аргументы для запуска Tomcat в режиме удаленной отладки

Сами параметры можно передать РІ Docker СЃ помощью ключа -e или --env. Переменная окружения, используемая для этих целей, называется JAVA_OPTS. Обрати внимание на опцию suspend: если РѕРЅР° включена (suspend=y), Java будет приостанавливать загрузку виртуальной машины и ждать подключения отладчика и только после успешного коннекта продолжит запуск. У меня получилась такая строка.


-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=*:5005

Запускаем контейнер. Не забывай пробрасывать порт, который указал для удаленной отладки.


docker run -it --rm -p 8080:8080 -p 8009:8009 -p 5005:5005 --name=tomcatrce --hostname=tomcatrce -e "JAVA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=*:5005" tomcat:9.0.30

Запущенный сервер Tomcat 9.0.30

Открываем браузер, переходим на запущенный сервер (не забывай, что порт — 8080) и наблюдаем страницу 404. Дело в том, что в последних версиях официального докер-контейнера Tomcat папка webapps СЃРѕ стандартными приложениями была переименована РІ webapps.dist. Достаточно удалить папку и создать симлинк на оригинальную версию директории.


docker exec tomcatrce rm -rf /usr/local/tomcat/webapps
docker exec tomcatrce ln -s /usr/local/tomcat/webapps.dist /usr/local/tomcat/webapps

После этого обновляем страницу и видим приветствие сервера Tomcat.


Приветственная страница стенда Tomcat

Tomcat работает, теперь дело за фронтендом, который поможет нам в исследовании AJP. Я создам еще один контейнер на основе Debian.


docker run -it --rm -p 80:80 --name=apache --hostname=apache --link=tomcatrce debian /bin/bash

Понятно из названия, какой веб-сервер я буду использовать в качестве фронта, — Apache. Устанавливаем.


apt update && apt install -y nano apache2

Я выбрал его, так как он проще в настройке прокси до Tomcat. Ты можешь использовать любой другой веб-сервер по желанию.


Включаем модуль для работы прокси с протоколом AJP.


a2enmod proxy_ajp

Теперь редактируем стандартный конфиг виртуального хоста (/etc/apache2/sites-enabled/000-default.conf) Рё указываем адрес Tomcat.


ProxyPass / ajp://tomcatrce:8009/

И перезагружаем Apache.


service apache2 restart

Проксируем трафик через Apache к Tomcat по протоколу AJP

Помимо веб-сервера, нам также понадобится какой-нибудь сниффер. Я буду использовать Wireshark. На этом стенд готов. Кстати, если ты не любишь Docker, то есть вариант скачать с сайта разработчика версию с готовыми бинарниками. Все версии можно найти в разделе с архивами.


Теперь можно переходить к разбору уязвимости.


Детали уязвимости. Чтение произвольных файлов на сервере


Apache JServ Protocol (AJP) — это бинарный протокол, созданный ради избавления от избыточности HTTP. AJP гораздо более эффективен, обладает высокой производительностью благодаря значительной оптимизации и отлично масштабируется.


AJP обычно используется для балансировки нагрузки, когда один или несколько внешних веб-серверов (front-end) отправляют запросы на сервер (или серверы) приложений. Сессии направляются к нужному благодаря механизмам роута, где каждый сервер приложений получает свое имя.


В современных Tomcat используется AJP 1.3 (AJP13). Поскольку это двоичный протокол, браузер напрямую не может отправлять запросы AJP13. Поэтому в качестве фронтенда выступает любой популярный веб-сервер — nginx, Apache, IIS.


Вариант взаимодействия с сервером Tomcat через связку веб-сервер — AJP

WWW

Подробнее о протоколе ты можешь прочитать в официальной документации.



По дефолту Tomcat принимает запросы AJP на порте 8009.


/tomcat9.0.30/conf/server.xml

<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

Видим, что директива address отсутствует, поэтому AJP доступен РЅР° всех IPv4-адресах локальной машины.


По дефолту Tomcat слушает AJP-порт на всех адресах IPv4
По дефолту Tomcat слушает AJP-порт на всех адресах IPv4

Такая настройка крайне небезопасна, и сейчас ты поймешь почему.

Для начала нам нужно разобраться в формате пакетов AJP. Запустим Wireshark и сгенерируем любой легитимный запрос к серверу по AJP. В этом как раз поможет фронтенд в виде веб-сервера Apache.


Снифаем трафик от Apache к Tomcat по протоколу AJP13 через Wireshark
Снифаем трафик от Apache к Tomcat по протоколу AJP13 через Wireshark

Первые РґРІР° байта РІ пакете — это Magic, который меняется в зависимости от направления отправки. Пакеты, отправленные от веб-сервера к контейнеру Tomcat, начинаются с 0x1234, Р° РѕС‚ контейнера Рє веб-серверу — 0x4142 (строка AB, если переводить в ASCII). В рамках уязвимости нас интересует только структура пакета, отправленного от клиента к контейнеру, то есть 0x1234.


Следующие два байта — это размер тела пакета. Это обычное числовое значение типа integer. Далее идет байт, который в большинстве случаев указывает на тип сообщения. С него начинается подсчет длины тела пакета.


Существуют следующие типы сообщений от веб-сервера к Tomcat.


Типы пакетов к контейнеру Tomcat
Типы пакетов к контейнеру Tomcat

Сразу привлекает внимание пакет СЃ РєРѕРґРѕРј 0x7 (Shutdown), который выключает сервер. Спешу тебя разочаровать — пакет такого плана обработается только в том случае, если он отправлен с хоста, на котором запущен Tomcat.


Нас интересует код 0С…2. РЎ таким РєРѕРґРѕРј отправляются, например, обычные сообщения типа GET/POST. Формат тела такого сообщения выглядит следующим образом.


AJP13_FORWARD_REQUEST :=
prefix_code (byte) 0x02 = JK_AJP13_FORWARD_REQUEST
method (byte)
protocol (string)
req_uri (string)
remote_addr (string)
remote_host (string)
server_name (string)
server_port (integer)
is_ssl (boolean)
num_headers (integer)
request_headers *(req_header_name req_header_value)
attributes *(attribut_name attribute_value)
request_terminator (byte) OxFF

За кодом идет метод. Список соотношения базовых методов с их байт-кодами выглядит таким образом.


OPTIONS => 1
GET => 2
HEAD => 3
POST => 4
PUT => 5
DELETE => 6
TRACE => 7

/tomcat9.0.30/java/org/apache/coyote/ajp/Constants.java

// Translates integer codes to names of HTTP methods
private static final String [] methodTransArray = {
"OPTIONS",
"GET",
"HEAD",
"POST",
"PUT",
"DELETE",
"TRACE",
...

В нашем пакете используется метод GET, поэтому и значение байта — 0x2.


В пакете AJP используется метод GET
В пакете AJP используется метод GET

Далее РІСЃРµ содержимое пакета довольно привычно Рё похоже РЅР° обычный HTTP-запрос. После параметра is_ssl начинается блок заголовков запроса (request_headers). Следующие РґРІР° байта (num_headers) отвечают за общее количество заголовков в запросе. Следом за ним перечисляются сами хидеры. Каждый заголовок имеет следующий формат:


0xA0 + <тип_хидера>[1 байт] + <длина_хидера>[2 байта] + <значение_хидера>[строка_размера_длины_хидера] + <конец_хидера>[байт 0x00]

Коды для стандартных заголовков определены в коде.


Коды стандартных HTTP-заголовков в протоколе AJP

/tomcat9.0.30/java/org/apache/coyote/ajp/Constants.java

// id's for common request headers
public static final int SC_REQ_ACCEPT = 1;
public static final int SC_REQ_ACCEPT_CHARSET = 2;
public static final int SC_REQ_ACCEPT_ENCODING = 3;
public static final int SC_REQ_ACCEPT_LANGUAGE = 4;
public static final int SC_REQ_AUTHORIZATION = 5;
public static final int SC_REQ_CONNECTION = 6;
public static final int SC_REQ_CONTENT_TYPE = 7;
public static final int SC_REQ_CONTENT_LENGTH = 8;
public static final int SC_REQ_COOKIE = 9;
public static final int SC_REQ_COOKIE2 = 10;
public static final int SC_REQ_HOST = 11;
public static final int SC_REQ_PRAGMA = 12;
public static final int SC_REQ_REFERER = 13;
public static final int SC_REQ_USER_AGENT = 14;

Некоторые заголовки крайне важны, например если content-length (0xA008) ненулевой, то Tomcat будет предполагать, что запрос имеет тело (как, например, POST-запрос), Рё попытается прочитать отдельный пакет.


За блоком хидеров следует блок атрибутов, его использование опционально, но это самая важная часть для понимания уязвимости.


Существует несколько типов основных атрибутов, каждый из них имеет код, а структура идентична структуре хидеров.


<тип_атрибута>[1 байта] + <длина_атрибута>[2 байта] + <значение_атрибута>[строка_размера_длины_атрибута] + <конец_атрибута>[байт 0x00]

/tomcat9.0.30/java/org/apache/coyote/ajp/Constants.java

// Integer codes for common (optional) request attribute names
public static final byte SC_A_CONTEXT = 1; // XXX Unused
public static final byte SC_A_SERVLET_PATH = 2; // XXX Unused
public static final byte SC_A_REMOTE_USER = 3;
public static final byte SC_A_AUTH_TYPE = 4;
public static final byte SC_A_QUERY_STRING = 5;
public static final byte SC_A_JVM_ROUTE = 6;
public static final byte SC_A_SSL_CERT = 7;
public static final byte SC_A_SSL_CIPHER = 8;
public static final byte SC_A_SSL_SESSION = 9;
public static final byte SC_A_SSL_KEY_SIZE = 11;
public static final byte SC_A_SECRET = 12;
public static final byte SC_A_STORED_METHOD = 13;

Однако любое количество других атрибутов может быть передано и через тип req_attribute (0x0A). Пара РёРјСЏ:значение атрибута передается сразу же после указания этого кода. В этом случае структура примет следующий вид:


0x0a[тип req_attribute] + <длина_имени_атрибута>[2 байта] + <имя_атрибута>[строка_размера_длины_имени_атрибута] + <конец_имени_атрибута>[байт 0x00] + <длина_значения_атрибута>[2 байта] + <значение_атрибута>[строка_размера_длины_значения_атрибута] + <конец_значения_атрибута>[байт 0x00]

Например, так передаются переменные окружения. После перечисления необходимых атрибутов отправляется байт-терминатор (0xFF), который означает не только конец списка атрибутов, но и окончание всего пакета. Именно до него считается длина тела пакета.


Сегодня я рассмотрю уязвимость в Apache Tomcat, которая позволяет читать файлы на сервере и при определенных условиях выполнять произвольный код. Проблема скрывается в особенностях реализации протокола AJP, по которому происходит взаимодействие с сервером Tomcat. Для эксплуатации злоумышленнику не требуется каких-либо прав в целевой системе. Tomcat — это контейнер сервлетов с открытым исходным кодом. Он написан на языке Java и реализует такие спецификации, как JavaServer Pages (JSP) и JavaServer Faces (JSF). Это один из наиболее популярных веб-серверов, особенно часто он используется в корпоративной среде. Его ставят как самостоятельное решение или в качестве контейнера сервлетов в различных серверах приложений, например GlassFish или JBoss. Баг нашел исследователь из Chaitin Tech в начале этого года. Уязвимость получила статус критической. Как сейчас стало модно, она обзавелась собственным названием — Ghostcat — и логотипом в виде кота-призрака. Уязвимость позволяет злоумышленнику читать произвольные файлы на целевой системе внутри директории appBase. Реализация протокола AJP (Apache JServ Protocol) позволяет контролировать атрибуты, которые отвечают Р·Р° формирование пути РґРѕ запрашиваемых файлов. Специально сформированный запрос РЅР° сервер позволяет прочитать содержимое файлов, доступ Рє которым невозможен РІ РґСЂСѓРіРёС… условиях. Если можно загрузить файл РЅР° сервер, существует СЂРёСЃРє использования уязвимости для выполнения произвольного РєРѕРґР°. INFO Уязвимости присвоен идентификатор CVE-2020-1938. Ошибка присутствует РІ актуальных ветках дистрибутива Рё затрагивает РІСЃРµ версии Apache Tomcat ниже 9.0.31, 8.5.51 Рё 7.0.100. Тестовый стенд Начнем СЃРѕ стенда для тестирования уязвимости. Для этого достаточно запустить контейнер Docker РёР· официального репозитория Tomcat. Очень важно расшарить порт 8009, это AJP-протокол, в котором и была найдена уязвимость. Если хочется вместе со мной возиться с отладкой приложения, то нужно действовать немного по-другому. Для дебага я буду использовать IntelliJ IDEA. Сначала скачаем уязвимую версию Apache Tomcat. Я взял 9.0.30. Распакуем и откроем проект в IDEA. Теперь создадим новую конфигурацию отладки с шаблоном Remote. Создание шаблона Remote в IDEA Здесь в поле Command lines arguments строка СЃ параметрами, которые нужно указать РїСЂРё запуске сервера. Рекомендую выбрать версию JDK 1.4.x. Конфигурация отладки. Аргументы для запуска Tomcat РІ режиме удаленной отладки Сами параметры можно передать РІ Docker СЃ помощью ключа -e или --env. Переменная окружения, используемая для этих целей, называется JAVA_OPTS. Обрати внимание на опцию suspend: если РѕРЅР° включена (suspend=y), Java будет приостанавливать загрузку виртуальной машины и ждать подключения отладчика и только после успешного коннекта продолжит запуск. У меня получилась такая строка. Запускаем контейнер. Не забывай пробрасывать порт, который указал для удаленной отладки. Запущенный сервер Tomcat 9.0.30 Открываем браузер, переходим на запущенный сервер (не забывай, что порт — 8080) и наблюдаем страницу 404. Дело в том, что в последних версиях официального докер-контейнера Tomcat папка webapps СЃРѕ стандартными приложениями была переименована РІ webapps.dist. Достаточно удалить папку и создать симлинк на оригинальную версию директории. После этого обновляем страницу и видим приветствие сервера Tomcat. Приветственная страница стенда Tomcat Tomcat работает, теперь дело за фронтендом, который поможет нам в исследовании AJP. Я создам еще один контейнер на основе Debian. Понятно из названия, какой веб-сервер я буду использовать в качестве фронта, — Apache. Устанавливаем. Я выбрал его, так как он проще в настройке прокси до Tomcat. Ты можешь использовать любой другой веб-сервер по желанию. Включаем модуль для работы прокси с протоколом AJP. Теперь редактируем стандартный конфиг виртуального хоста (/etc/apache2/sites-enabled/000-default.conf) Рё указываем адрес Tomcat. И перезагружаем Apache. Проксируем трафик через Apache к Tomcat по протоколу AJP Помимо веб-сервера, нам также понадобится какой-нибудь сниффер. Я буду использовать Wireshark. На этом стенд готов. Кстати, если ты не любишь Docker, то есть вариант скачать с сайта разработчика версию с готовыми бинарниками. Все версии можно найти в разделе с архивами. Теперь можно переходить к разбору уязвимости. Детали уязвимости. Чтение произвольных файлов на сервере Apache JServ Protocol (AJP) — это бинарный протокол, созданный ради избавления от избыточности HTTP. AJP гораздо более эффективен, обладает высокой производительностью благодаря значительной оптимизации и отлично масштабируется. AJP обычно используется для балансировки нагрузки, когда один или несколько внешних веб-серверов (front-end) отправляют запросы на сервер (или серверы) приложений. Сессии направляются к нужному благодаря механизмам роута, где каждый сервер приложений получает свое имя. В современных Tomcat используется AJP 1.3 (AJP13). Поскольку это двоичный протокол, браузер напрямую не может отправлять запросы AJP13. Поэтому в качестве фронтенда выступает любой популярный веб-сервер — nginx, Apache, IIS. Вариант взаимодействия с сервером Tomcat через связку веб-сервер — AJP WWW Подробнее о протоколе ты можешь прочитать в официальной документации. По дефолту Tomcat принимает запросы AJP на порте 8009. /tomcat9.0.30/conf/server.xml Видим, что директива address отсутствует, поэтому AJP доступен РЅР° всех IPv4-адресах локальной машины. РџРѕ дефолту Tomcat слушает AJP-РїРѕСЂС‚ РЅР° всех адресах IPv4 Такая настройка крайне небезопасна, Рё сейчас ты поймешь почему. Для начала нам нужно разобраться РІ формате пакетов AJP. Запустим Wireshark Рё сгенерируем любой легитимный запрос Рє серверу РїРѕ AJP. Р’ этом как раз поможет фронтенд РІ РІРёРґРµ веб-сервера Apache. Снифаем трафик РѕС‚ Apache Рє Tomcat РїРѕ протоколу AJP13 через Wireshark Первые РґРІР° байта РІ пакете — это Magic, который меняется в зависимости от направления отправки. Пакеты, отправленные от веб-сервера к контейнеру Tomcat, начинаются с 0x1234, Р° РѕС‚ контейнера Рє веб-серверу — 0x4142 (строка AB, если переводить в ASCII). В рамках уязвимости нас интересует только структура пакета, отправленного от клиента к контейнеру, то есть 0x1234. Следующие РґРІР° байта — это размер тела пакета. Это обычное числовое значение типа integer. Далее идет байт, который РІ большинстве случаев указывает РЅР° тип сообщения. РЎ него начинается подсчет длины тела пакета. Существуют следующие типы сообщений РѕС‚ веб-сервера Рє Tomcat. РўРёРїС‹ пакетов Рє контейнеру Tomcat Сразу привлекает внимание пакет СЃ РєРѕРґРѕРј 0x7 (Shutdown), который выключает сервер. Спешу тебя разочаровать — пакет такого плана обработается только в том случае, если он отправлен с хоста, на котором запущен Tomcat. Нас интересует код 0С…2. РЎ таким РєРѕРґРѕРј отправляются, например, обычные сообщения типа GET/POST. Формат тела такого сообщения выглядит следующим образом. За кодом идет метод. Список соотношения базовых методов с их байт-кодами выглядит таким образом. /tomcat9.0.30/java/org/apache/coyote/ajp/Constants.java В нашем пакете используется метод GET, поэтому и значение байта — 0x2. Р’ пакете AJP используется метод GET Далее РІСЃРµ содержимое пакета довольно привычно Рё похоже РЅР° обычный HTTP-запрос. После параметра is_ssl начинается блок заголовков запроса (request_headers). Следующие РґРІР° байта (num_headers) отвечают за общее количество заголовков в запросе. Следом за ним перечисляются сами хидеры. Каждый заголовок имеет следующий формат: Коды для стандартных заголовков определены в коде. Коды стандартных HTTP-заголовков в протоколе AJP /tomcat9.0.30/java/org/apache/coyote/ajp/Constants.java Некоторые заголовки крайне важны, например если content-length (0xA008) ненулевой, то Tomcat будет предполагать, что запрос имеет тело (как, например, POST-запрос), Рё попытается прочитать отдельный пакет. Р—Р° блоком хидеров следует блок атрибутов, его использование опционально, РЅРѕ это самая важная часть для понимания уязвимости. Существует несколько типов основных атрибутов, каждый РёР· РЅРёС… имеет РєРѕРґ, Р° структура идентична структуре хидеров.

Теги: CSS

Просмотров: 469
Комментариев: 0:   2-04-2020, 16:20
Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь. Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

 
Еще новости по теме:



Другие новости по теме: