1 poin oleh GN⁺ 4 jam lalu | 1 komentar | Bagikan ke WhatsApp
  • ssh-init-vm menyuntikkan kunci privat host SSH sementara melalui cloud-init pada koneksi SSH pertama ke VM baru untuk mencegah serangan man-in-the-middle, dan mempercayainya hanya selama pembuatan atau pengambilan kunci host jangka panjang
  • Berfungsi juga pada VPS atau cloud tanpa fitur perlindungan akses khusus seperti Hetzner Cloud, dan yang dibutuhkan hanya cloud-init yang didukung luas
  • Pada Trust On First Use yang umum, jika pengguna mengetik yes pada pertanyaan ssh “The authenticity of host [...] can't be established”, penyerang dapat memproksikan trafik atau menyediakan mesin yang tampak seperti VM milik pengguna
  • Jika kunci privat host SSH jangka panjang dimasukkan langsung ke cloud-init userdata, itu membantu autentikasi koneksi pertama, tetapi materi kunci sensitif dapat terekspos melalui layanan metadata, SSRF, sistem penyedia cloud, atau workstation administrator
  • ssh-init-vm menaruh kunci sementara di direktori sementara dan tidak memasukkannya ke ~/.ssh/known_hosts, tidak menyimpan output VM mentah begitu saja, dan mengandalkan rotasi kunci host OpenSSH untuk mencatat kunci jangka panjang

Masalah kebocoran cloud-init userdata

  • Dengan menyuntikkan kunci privat host SSH jangka panjang lewat cloud-init, kunci publik dapat dimasukkan ke ~/.ssh/known_hosts untuk mengautentikasi koneksi pertama, tetapi kunci privat dapat bocor lewat beberapa jalur
  • Proses sewenang-wenang di dalam VM biasanya dapat memperoleh userdata dari layanan metadata yang umumnya dapat dibaca, dan pada VM Hetzner isi cloud-init dapat terlihat di http://169.254.169.254/hetzner/v1/userdata
  • Penyerang dapat membuat proses membocorkan metadata melalui SSRF, dan pemblokiran semacam ini tidak selalu diterapkan bahkan di lingkungan yang memiliki fitur perlindungan khusus
  • Pada sistem lain milik penyedia cloud, userdata juga dapat terekspos; dalam dokumentasi API pembuatan server, Hetzner secara eksplisit menyatakan agar tidak menyimpan “passwords or other sensitive information”
  • Workstation administrator juga bisa menjadi tempat cloud-init userdata tersisa atau lewat, sehingga pendekatan memasukkan kunci privat jangka panjang menciptakan risiko paparan selama kunci itu masih berlaku

Analisis keamanan dan model ancaman

  • Asumsinya adalah protokol dan implementasi OpenSSH tepercaya, dan tidak bergantung pada kemampuan administrator untuk mendeteksi serangan
  • Perlindungan terhadap penyerang jaringan

    • Yang dilindungi adalah integritas workstation administrator dan VM
    • Penyerang adalah man-in-the-middle yang sepenuhnya mengendalikan jaringan, dan dapat mengetahui cloud-init userdata pada suatu saat setelah skrip berhasil atau gagal lalu berhenti
    • Perlindungan berlaku karena penyerang tidak mengetahui materi kunci ketika nilainya masih tersisa
    • Skrip menyimpan kunci host SSH sementara di direktori sementara agar tidak terpakai secara tidak sengaja, dan tidak memasukkan kunci host SSH sementara ke ~/.ssh/known_hosts
  • Jika workstation administrator dikompromikan

    • Yang dilindungi terbatas pada VM dan kunci privat host SSH jangka panjang milik VM
    • Penyerang sepenuhnya mengendalikan jaringan dan workstation administrator, tetapi diasumsikan tidak mengakses VM yang sebenarnya
    • Kunci privat host SSH jangka panjang tidak pernah berada di workstation administrator, dan karena penyerang tidak mengakses VM yang sebenarnya, ia tidak memperoleh kunci host jangka panjang VM
    • Jika penyerang mengakses VM yang sebenarnya, kemungkinan besar ia dapat mengetahui kunci host SSH dengan cara seperti ssh root@<VM> cat /etc/ssh/ssh_host_*
  • Jika VM atau penyedia dikompromikan

    • Yang dilindungi terbatas pada integritas workstation administrator
    • Penyerang sepenuhnya mengendalikan jaringan dan juga dapat sepenuhnya mengendalikan VM atau penyedia
    • Bahkan dalam kasus ini, asumsi bahwa OpenSSH aman tetap melindungi integritas workstation administrator
    • Sebagai pertahanan tambahan, skrip tidak menulis output VM mentah langsung ke ~/.ssh/known_hosts, tetapi mengandalkan rotasi kunci host SSH jangka panjang dari OpenSSH
    • Pendekatan ini mencegah host yang telah dikompromikan menyuapi parser known_hosts dengan data berbahaya, dan memastikan hanya kunci yang benar-benar dikendalikan oleh VM yang dicatat ke ~/.ssh/known_hosts
    • Opsi OpenSSH seperti HashKnownHosts dan opsi terkait di masa depan juga dapat ditangani dengan benar

Kondisi agar serangan man-in-the-middle benar-benar berhasil

  • Keberhasilan serangan man-in-the-middle bergantung pada apakah pengguna benar-benar menyadari bahwa semua koneksi sejak awal mengarah ke mesin yang salah, menolak memasukkan kata sandi, serta apakah ssh mengatur penerusan agent atau X11
  • Dalam kondisi yang disederhanakan menurut ssh-mitm, peluang keberhasilan tinggi jika penyerang dapat menipu pengguna dengan memberikan akses ke mesin yang dikendalikan penyerang alih-alih host target yang sebenarnya
  • Serangan juga berhasil jika penyerang menipu pengguna agar memberikan informasi yang memungkinkan login ke host yang sebenarnya
    • Jika pengguna login ke mesin penyerang dengan kata sandi, penyerang bisa berhasil
    • Jika pengguna login dengan metode autentikasi apa pun lalu memasukkan kata sandi di prompt, penyerang bisa berhasil
    • Jika pengguna login dengan metode autentikasi apa pun dan meneruskan koneksi ssh-agent, penyerang bisa berhasil
  • Jika kondisi di atas tidak ada, penyerang memerlukan akses ke host yang sebenarnya untuk menipu pengguna, tetapi kemungkinan gagal karena tidak bisa login ke host yang sebenarnya hanya dengan input dari pengguna
  • Jika pengguna meneruskan koneksi X11, penyerang juga dapat berhasil menyerang workstation administrator terlepas dari metode autentikasinya

1 komentar

 
GN⁺ 4 jam lalu
Komentar Lobste.rs
  • Keren karena bisa diotomatisasi. Untuk cara manual, saya biasanya memverifikasi sidik jari SSH server lewat kanal terpisah di konsol penyedia cloud
    Saya tidak mengelola terlalu banyak instance cloud, jadi tidak masalah kalau ada beberapa langkah manual saat provisioning

    • Cara itu juga berhasil. Hanya saja, penyedia yang saya pakai saat itu belum menghubungkan bagian itu, dan pada saat yang sama saya sedang membuat skrip otomatisasi konfigurasi
  • Kalau zona DNS sudah diotomatisasi, pendekatan lain juga memungkinkan: buat token sekali pakai dengan cakupan yang sangat sempit, misalnya hanya mengizinkan pembuatan satu record untuk my-server-hostname.example.net
    Kirim token itu ke server lewat cloud-init, lalu biarkan server mengunggah kunci SSH publiknya sebagai record SSHFP di DNS. Setelah itu, klien SSH bisa dibuat untuk memverifikasi record SSHFP secara otomatis, dan zona DNS tersebut harus ditandatangani DNSSEC
    Alur ini memungkinkan server tetap menyimpan kunci host SSH privat sekaligus menghindari rotasi kunci. Sebagian besar penyedia DNS tidak mendukung token akses sekali pakai sedetail ini, tetapi Anda bisa menaruh layanan web internal sederhana yang memverifikasi token itu lalu melakukan panggilan API memakai token permanen dengan cakupan tak terbatas. Server SSH tidak akan bisa mengakses token permanen tersebut

    • Cara yang kreatif, dan token sekali pakai untuk layanan kustom sepertinya cukup fleksibel sehingga bisa bekerja dengan baik
      Meski begitu, saya rasa saya akan lebih memilih membuat sertifikat SSH daripada menulis ke domain DNSSEC, dan mulai dari titik itu jadinya soal solusi mana yang paling cocok untuk lingkungan tertentu
      Saya penasaran apakah Anda tahu software atau penyedia yang bisa membuat token sefleksibel ini, atau memang perlu membangun sendiri sampai tingkat tertentu
  • Cukup rapi. Tapi sepertinya bulan dan hari tertukar pada tanggal di tulisan itu

    • Senang seperti biasa bisa mengutak-atik OpenSSH, dan format bulan/hari sudah saya perbaiki
  • Dulu saya pernah membuat layanan eksperimental untuk menjajaki masalah ayam-dan-telur SSH yang sama
    Layanan itu membuat record DNS SSHFP saat diminta; kalau tertarik, lihat https://github.com/tedb/sshfp

  • Senang melihat ada pembahasan tentang layanan metadata 169.254.169.254 yang agak konsisten di berbagai penyedia VM. Itu bisa dilihat dari berbagai entri cloudinit/source/DataSource*.py di source cloud-init
    Secara pribadi saya makin lelah dengan desain dan keterbatasan cloud-init. Saya tertarik menyatukan konfigurasi sistem di VM QEMU lokal, mesin remote, container, dan perangkat keras fisik
    proyek arch-boxes menunjukkan bagaimana image ArchLinux cloud-init dibuat, dan itu hanyalah sekumpulan skrip shell yang sangat sederhana. Jika pendekatan ini diterapkan dengan guestfish atau µvm, Anda bisa memakai skrip yang benar-benar sama untuk image kompatibel OCI, image disk untuk QEMU atau penyedia cloud, dan provisioning mesin fisik baru
    Dengan beberapa flag QEMU, pendekatan yang sama bisa direplikasi tanpa bergantung pada cloud-init. Sepanjang yang saya tahu, systemd.system-credentials tidak bisa dipakai untuk mengirim kunci host sementara; yang ada hanya kredensial untuk ~/.ssh/authorized_keys seperti ssh.authorized_keys.root
    Sebagai gantinya, Anda bisa membuat file unit yang dijalankan pada tahap initrd atau bersama systemd-firstboot.service. File unit ini bisa dimasukkan lebih dulu ke dalam image atau disuntikkan sementara dengan kredensial systemd.extra-unit.*, lalu diaktifkan lewat opsi baris perintah kernel systemd.wants=…. Di QEMU, keberadaan layanan metadata bisa ditiru dengan entri -netdev user,id=metadata,net=169.254.0.0/16,dhcpstart=169.254.0.15,guestfwd=tcp:169.254.169.254:80-cmd:…. Namun, kemungkinan besar antarmuka yang dibuat perlu diaktifkan, dan itu juga mungkin lebih baik ditangani dengan file unit sementara
    Dengan cara ini, saat melakukan konfigurasi sistem yang konsisten di berbagai jenis “mesin”, Anda mendapatkan fleksibilitas yang cukup besar dengan kompleksitas yang relatif rendah. Sebenarnya untuk tugas ini saja, pendekatan terbaik tampaknya adalah alat pembuat image menghasilkan image mesin dengan kunci host tetap, lalu memasang skrip rotasi kunci host kustom sebagai layanan SystemD yang dijalankan saat reboot pertama atau saat shutdown

    • Di ArchLinux, jika Anda mengaktifkan HOOK systemd di /etc/mkinitcpio.conf, Anda bisa—dan pada praktiknya memang harus—menulis file unit SystemD untuk pekerjaan yang dilakukan di initrd
      Saat benar-benar dipakai, ini hanya sedikit lebih merepotkan dibanding menulis {/etc,/usr/lib}/initcpio/hooks
      Namun karena cukup mudah mengaktifkan systemd-networking dan systemd-resolved di initrd, initrd bisa mengambil tanggung jawab memulai sistem dan menjadwalkan pekerjaan sebelum beralih ke root filesystem
      Tentu saja ini mungkin kurang cocok untuk perangkat keras fisik seperti laptop, karena koneksi Wi‑Fi bisa memerlukan sesuatu seperti NetworkManager, tetapi sangat cocok untuk VM QEMU dan VM hosting, dan banyak pekerjaan startup sistem yang secara alami pas di ruang ini
      Tujuannya adalah mendapatkan konsistensi lintas mesin fisik, container, VM lokal, dan VM hosting tanpa bergantung pada cloud-init, tanpa terikat pada satu penyedia cloud tertentu, dan dengan dependensi yang pada dasarnya dipersempit menjadi SystemD
    • Untuk alat yang sangat kecil dan tinggal diperluas hanya dengan fungsi yang Anda butuhkan, mungkin sesuatu seperti https://github.com/the-maldridge/shinit/ juga bisa