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

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

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

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

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

Категории

Все категории
Loading categories
kibana-prototype-pollusion — PoC и анализ для Kibana Prototype Pollution RCE (CVE-2019-7609). | Kitploit
Инструменты/GitHubGitHub/aleister1102/kibana-prototype-pollusion
Анализ уязвимостейАнализ КодаЭксплуатацияЭксплуатация веб-приложенийСтатьи и ИсследованияОбучение и Образование
GitHubaleister1102/kibana-prototype-pollusion

kibana-prototype-pollusion

PoC и анализ для Kibana Prototype Pollution RCE (CVE-2019-7609).

Популярное

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

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

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

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

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

CVE-2019-7609

Версии Kibana до 5.6.15 и 6.6.1 содержат уязвимость выполнения произвольного кода в визуализаторе Timelion. Злоумышленник с доступом к приложению Timelion может отправить запрос, который попытается выполнить JavaScript-код. Это может привести к выполнению произвольных команд с правами процесса Kibana на хост-системе.

CVSS:

cvss

Блог: https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/

Полезная нагрузка: https://github.com/mpgn/CVE-2019-7609

Цель

Настройка:

  • Docker: https://www.elastic.co/guide/en/kibana/8.14/docker.html
  • Docker Compose

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

  • Kibana: https://www.elastic.co/guide/en/kibana/current/development-getting-started.html
  • Timelion: https://www.elastic.co/guide/en/kibana/5.4/timelion.html

Анализ

Timelion

После парсинга sheet:

alt text

После предварительной обработки sheet, получаем объект queries:

alt text

Затем мы перебираем массив queries (который преобразуется в массив с помощью метода values) и передаем query.function и query.arguments в invoke для вызова функции.

В функции invoke сначала получаем определение функции по её имени (query.function):

alt text

Это определение функции включает три типа функций: fn, originalFn и timelionFn. Затем она перебирает args (то есть query.arguments) и разрешает аргументы:

alt text

В данном случае аргумент в args — это объект с типом 'literal', поэтому просто возвращается литеральное значение:

alt text

На самом деле значение обёрнуто в promise.

alt text

Индексированный аргумент — это аргумент с объектом byName, содержащим внутри массив q:

alt text

После этого функция invoke вызывает functionDef.fn, которая является функцией класса Timelion, со всеми индексированными аргументами:

alt text

Функция fn вызывает originalFn, которая происходит из config.fn, где config — это tlConfig. И эта функция — fn класса Datasource extends Timelion:

alt text

Как видим, она вызывает другую originalFn с именем esFn, которая возвращает объект seriesList:

alt text

Эта функция используется для «извлечения данных из экземпляра Elasticsearch» путём вызова функции callWithRequest.

seriesList выглядит так в Datasource.fn:

alt text

А так — в Timelion.fn:

alt text

После предварительной обработки sheet цепочка выглядит так:

alt text

И код вызывает resolveChainList для разрешения списка цепочек:

alt text

Каждая цепочка сопоставляется с Promise, который возвращается из функции, вызывающей invoke с 'first' в качестве fnName и самой цепочкой в качестве args.

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

alt text

На этот раз resolveArguments получает args как массив и рекурсивно вызывает resolveArguments для каждого аргумента. Но у нас есть только один аргумент с индексом 0. И этот аргумент — объект с type == chain.

Поэтому в операторе switch вызывается функция invokeChain, и в неё передаётся объект цепочки:

alt text

Внутри invokeChain выполняется shift массива chain. Функция shift возвращает удалённый элемент, поэтому link становится объектом es:

alt text

Поскольку тип es не 'chain' (он 'function'), а !result истинно, код вызывает функцию invoke с 'first' в качестве fnName и объектом es в качестве args:

На этот раз процедура такая же, как описано выше, поэтому переходим к вызову invokeChain, где link — это объект props:

alt text

Снова код вызывает функцию invoke с 'first' в качестве fnName и объектом props в качестве args:

alt text

originalFn для props теперь — firstFn, а не fn, как у es, и принимает только один аргумент:

alt text

Эта оригинальная функция в конечном итоге вызовет уязвимую функцию unflatten. На самом деле сначала вызывается fn из Timelion. Затем fn вызывает originalFn для props:

alt text

firstFn для props опускает свойства inputSeries и global в объекте byName аргумента args:

alt text

Таким образом, data, передаваемая в unflatten, будет:

root@kitploit:~
{
    label.__proto__.env.AAA: "a"
}

Доказательство:

alt text

Unflatten

Используется props(label.__proto__.env.AAA="a"). data будет выглядеть так:

alt text

На первой итерации prop = '' не существует, поэтому присваивается cur[''] = {}. Это означает, что result также получит свойство с именем '' и значением пустой объект. После этого cur присваивается {}, который является возвращаемым значением предыдущего присваивания (cur и cur[prop] ссылаются на один и тот же объект):

alt text

Теперь prop станет 'label':

alt text

Как и раньше, result получает свойство 'label', а prop становится __proto__:

alt text

На третьей итерации cur становится своим прототипом, так как __proto__ всегда существует в любом объекте:

alt text

После этого prop становится env.

Затем, поскольку cur ссылается на Object.prototype, добавляется env в Object.prototype как пустой объект, и cur также ссылается на env внутри Object.prototype.env.

alt text

После этого цикл завершается, и cur[prop] = data[p] эквивалентно env[AAA] = 'a'.

alt text

Object.prototype загрязнён свойством env:

alt text

Canvas

Функция fork возвращает ChildProcess, который можно использовать для вызова spawn

Изменим порт при вызове функции fork на 9669 (другой порт), после чего можно нормально отлаживать основной процесс:

alt text

Симулируем загрязнённый Object.prototype и переходим к моменту перед циклом:

alt text

Как видим, env эквивалентно { AAA: 'a' } из-за прототипного загрязнения. Более конкретно, env присваивается options.env. А options не определяет это свойство, поэтому используется значение из его прототипа.

После цикла:

alt text

По какой-то причине, из-за недопустимых переменных окружения (AAA=a, env=[Object object]), canvas не может создать новый сокет:

alt text

Но дочерний процесс всё равно может быть создан:

alt text

При нормальном потоке создаётся новое WebSocket-соединение:

alt text

Теперь попробуем с полезной нагрузкой и перейдём в normalizeSpawnArguments:

alt text

Как видим, стек вызовов тот же.

Но env загрязнён:

alt text

Вуаля!

envPairs после цикла:

alt text

И мы получили обратный шелл:

alt text

Spawn

После вызова normalizeSpawnArguments в функции spawn:

alt text

Как видим, envPairs содержит нашу полезную нагрузку. После этого spawn вызывает функцию spawn внутри internal/child_process.js:

alt text

Переменная options передаётся в this._handle.spawn:

alt text

Где this._handle — это дескриптор процесса:

alt text

Патч

root@kitploit:~
From 3377f813a5d96ff466bdf7343ce161de24830ed4 Mon Sep 17 00:00:00 2001
From: ppisljar <[email protected]>
Date: Wed, 16 Jan 2019 06:01:20 -0800
Subject: [PATCH] fixes

---
 .../core_plugins/timelion/server/series_functions/props.js      | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/legacy/core_plugins/timelion/server/series_functions/props.js b/src/legacy/core_plugins/timelion/server/series_functions/props.js
index 81b74901d4db..80e9cafd6712 100644
--- a/src/legacy/core_plugins/timelion/server/series_functions/props.js
+++ b/src/legacy/core_plugins/timelion/server/series_functions/props.js
@@ -32,7 +32,7 @@ function unflatten(data) {
     let prop = '';
     let m;
     while (m = regex.exec(p)) {
-      cur = cur[prop] || (cur[prop] = (m[2] ? [] : {}));
+      cur = (cur.hasOwnProperty(prop) && cur[prop]) || (cur[prop] = (m[2] ? [] : {}));
       prop = m[2] || m[1];
     }
     cur[prop] = data[p];
Скачать инструмент