4 poin oleh GN⁺ 2024-06-24 | 1 komentar | Bagikan ke WhatsApp
  • sudo dan doas bergantung pada binary setuid dan eskalasi hak akses, sehingga ini adalah eksperimen yang menyerahkan eksekusi perintah root kepada sshd lokal yang diikat ke soket domain Unix
  • Tujuannya adalah agar hanya pengguna yang diizinkan yang dapat menjalankan perintah root sambil tidak meninggalkan kemampuan eskalasi hak akses pada seluruh sesi pengguna
  • Implementasinya terdiri dari file kunci SSH khusus root, /run/sshd/sshd.sock dengan akses terbatas, serta instans sshd terpisah dengan opsi AuthorizedKeysFile dan PermitRootLogin=yes
  • Karena ssh tidak memiliki opsi untuk langsung meneruskan soket yang sudah ada, awalnya digunakan ProxyCommand dan socat, lalu beralih ke ProxyUseFdpass dan skrip Python singkat untuk meneruskan file descriptor soket
  • Pendekatan ini berfungsi, dan penanganan keamanannya terutama bergantung pada OpenSSH, tetapi untuk penggunaan sehari-hari lebih cocok jika passfd.py dijadikan executable kecil dan seluruh perintah ssh dibungkus dengan wrapper

Keterbatasan struktural sudo dan doas

  • sudo dan doas bergantung pada binary setuid dan eskalasi hak akses untuk menjalankan perintah sebagai root
  • Desain ini memiliki beberapa keterbatasan
    • Seluruh sesi pengguna harus tetap memiliki kemampuan untuk melakukan eskalasi hak akses
    • Tidak berfungsi saat seluruh sesi pengguna dijalankan di dalam namespace pengguna yang dibatasi
    • Binary setuid menimbulkan pembatasan pada konfigurasi keamanan sistem secara keseluruhan
  • s6-sudod adalah alternatif yang memisahkan program menjadi server berhak akses dan klien tanpa hak akses

Tujuan eksperimen

  • Menggunakan ssh secara lokal untuk menjalankan peran seperti sudo, tetapi instans sshd tersebut tidak diekspos ke jaringan
  • Ada dua syarat utama
    • Hanya pengguna yang diizinkan yang dapat menjalankan perintah sebagai root
    • Tidak menggunakan eskalasi hak akses

Konfigurasi sshd untuk login root lokal

  • Membuat kunci SSH khusus yang hanya dipakai untuk autentikasi root, lalu menyimpannya di /root/.ssh/local_keys alih-alih authorized_keys biasa
  • Mengikat instans sshd terpisah ke soket domain Unix, dan membatasi izin /run/sshd/ agar pengguna yang tidak diizinkan tidak bisa mengakses soket tersebut
  • Contoh eksekusinya menggunakan s6-ipcserver untuk membuat /run/sshd/sshd.sock dan meneruskan opsi berikut ke sshd
    • AuthorizedKeysFile=/root/.ssh/local_keys
    • PermitRootLogin=yes
  • /etc/ssh/sshd_config tidak diubah
    • Karena login root tidak ingin diizinkan pada sshd yang ada dan terikat ke jaringan
    • Pada konfigurasi yang ada, PermitRootLogin no tetap dipertahankan

Penguncian akun root dan penanganan login kata sandi

  • Akun root dikunci agar tidak bisa login dengan cara apa pun, dan ini dilakukan dengan menambahkan ! di depan hash kata sandi
  • sshd menafsirkan awalan ! ini sebagai penguncian akun sehingga login root tidak diizinkan
  • Nilai kata sandi root di /etc/passwd diubah dengan mengganti ! menjadi *
    • sshd tidak menafsirkan * sebagai nilai penguncian khusus
    • * tidak akan cocok dengan hash kata sandi mana pun, sehingga login dengan kata sandi secara efektif tetap dinonaktifkan
  • Selain itu, PasswordAuthentication no dikonfigurasi di sshd_config, dan menonaktifkan autentikasi berbasis kata sandi di sshd adalah konfigurasi yang aman

Terhubung ke soket Unix dengan ssh

  • sshd memiliki flag -i untuk menerima soket yang sudah ada, tetapi ssh tidak memiliki flag dengan fungsi yang sama
  • Awalnya digunakan socat melalui ProxyCommand untuk terhubung ke /run/sshd/sshd.sock
  • Perintah koneksi terdiri dari elemen-elemen berikut
    • ProxyCommand='socat STDIO UNIX-CONNECT:/run/sshd/sshd.sock'
    • Menentukan kunci root khusus dengan -i .ssh/root-key.pub
    • Terhubung ke root@root
    • Berpindah ke direktori saat ini lalu menjalankan shell login
  • Kunci SSH yang digunakan adalah kunci yang terikat ke perangkat keras, sehingga perlu mengetuk perangkat fisik untuk menyetujui koneksi
  • ssh-agent yang hanya memublikasikan kunci setelah persetujuan eksplisit, misalnya hissh-agent, juga bisa menjadi alternatif

Overhead socat dan ProxyUseFdpass

  • socat membaca seluruh input dari ssh lalu menulisnya ke soket, sehingga overhead koneksi pada dasarnya menjadi duplikat
  • ProxyUseFdpass memungkinkan perintah mengirim file descriptor soket ke ssh melalui stdout, lalu ssh terhubung menggunakan soket tersebut
  • Berdasarkan contoh penggunaan OpenSSH ProxyUseFdpass dari 2016, ditulis skrip Python passfd.py
    • Terhubung ke soket domain Unix /run/sshd/sshd.sock
    • Meneruskan file descriptor dengan sendmsg dan SCM_RIGHTS
  • Setelah itu, perintah koneksi berubah menjadi menetapkan passfd.py pada ProxyCommand dan menambahkan ProxyUseFdpass=yes
  • nc -FU /run/sshd/sshd.sock juga tampak memungkinkan, tetapi manual menyebutkan bahwa -F tidak dapat digunakan bersama -U

Kesimpulan dan bentuk penggunaan nyata

  • Teknik ini berfungsi, dan penanganan keamanan sensitif sebagian besar diserahkan kepada OpenSSH
  • OpenSSH memiliki rekam jejak yang baik, dan dapat menggunakan berbagai metode autentikasi termasuk kunci SSH berbasis perangkat keras
  • Proses penyiapan di host baru tidak memiliki langkah yang rumit, dan perintah ipcserver dapat dijalankan melalui service manager sistem
  • passfd.py lebih merupakan hack cepat untuk menjalankan eksperimen
  • Untuk penggunaan sehari-hari, lebih cocok membuat executable kecil dengan fungsi yang sama dan menaruhnya di /usr/local/bin, lalu membungkus seluruh perintah ssh dengan wrapper kecil

1 komentar

 
GN⁺ 2024-06-24
Pendapat Hacker News
  • Alasan terbesar untuk menolak pendekatan ini adalah bertambahnya kompleksitas. Alih-alih satu binary suid yang membaca file konfigurasi lalu memanggil exec(), ada satu binary yang berjalan sebagai root dan mendengarkan UNIX socket, serta satu binary lain yang berbicara ke socket itu, dan keduanya juga harus menangani kriptografi asimetris
    Jika argumen utama terhadap sudo/doas adalah “ada binary suid yang bisa diakses semua pengguna, dan jika ada bug bisa dieksploitasi untuk eskalasi hak akses”, maka cukup lakukan seperti berikut
    chgrp wheel /usr/bin/sudo
    chmod o-rwx /usr/bin/sudo
    Jika pengguna sudo dimasukkan ke grup wheel, hanya pengguna yang bisa sudo yang dapat membaca byte file dari disk dan juga mengeksekusinya. Dari sisi kontrol akses, keamanannya hampir sama dengan pendekatan sshd yang membuat UNIX socket hanya dapat diakses pengguna wheel, tetapi kompleksitasnya jauh lebih rendah
    Selain itu, pendekatan sshd tidak bisa membatasi akses root ke perintah tertentu seperti sudo, jadi meskipun ada bug yang bisa melewati pembatasan perintah sudo, itu tetap tidak memberi hak akses lebih besar daripada pendekatan sshd
    Jika khawatir package manager merusak permission /usr/bin/sudo, bisa diperbaiki secara berkala dengan cron, atau sudo dihapus sepenuhnya lalu dipasang manual dari source di lokasi lain. Tentu saja, kalau begitu maintenance dan upgrade juga harus dilakukan sendiri

    • Secara pribadi, saya melacak semua perubahan di /etc dengan etckeeper. Perubahan dari instalasi/upgrade software maupun perubahan oleh manusia tercatat, dan saat upgrade ke rilis baru, kita bisa membuat patch dari perubahan lokal, menerapkannya ke instalasi bersih, lalu memeriksa konflik dengan 3-way merge; ini berguna
      https://etckeeper.branchable.com/
    • Memasukkan pengguna sudo ke grup wheel agar hanya pengguna yang bisa sudo yang dapat membaca dan mengeksekusi file terasa cukup masuk akal. Saya penasaran kenapa ini bukan konfigurasi default di mana-mana
    • Mohon maklum atas ketidaktahuan saya. Saya ingin dijelaskan apa itu grup wheel dan apa fungsinya. Saya tahu ini bisa membuka perdebatan yang rumit
    • Bukankah mungkin juga membuat /usr/bin/sudo menjadi immutable? Sepertinya itu bisa membantu mencegah package manager menyentuhnya
    • Untuk bagian bahwa akses root tidak bisa dibatasi ke perintah tertentu, ada infrastruktur ForcedCommand
  • Bukankah ini yang sekarang dilakukan systemd run0? systemd punya tool baru bernama run0, yang sebenarnya bukan tool yang sepenuhnya baru, melainkan cara memanggil systemd-run yang sudah lama ada melalui symbolic link bernama run0 sehingga berperilaku seperti pengganti sudo
    Perbedaan utamanya adalah ini sebenarnya bukan SUID. Ia meminta service manager menjalankan perintah atau shell dengan UID pengguna target, mengalokasikan PTY baru, lalu meneruskan data antara TTY asli dan PTY ini
    Dengan kata lain, perintah target tidak mewarisi konteks klien, melainkan berjalan dalam konteks eksekusi terisolasi yang baru di-fork dari PID 1. $TERM diteruskan, tetapi itu pengecualian eksplisit; lebih mirip allowlist daripada blocklist
    Dalam banyak hal, run0 bisa dianggap lebih mirip perilaku ssh daripada sudo
    https://mastodon.social/@pid_eins/112353324518585654

    • Kenapa systemd harus membuat ulang semuanya?
  • Apakah ada yang saya lewatkan? Saya tidak paham bagaimana login SSH sebagai root bisa lebih aman daripada memakai sudo. Saya selalu diajari untuk tidak mengizinkannya, jadi saya juga tidak benar-benar tahu seberapa berbahayanya
    Sepertinya di sini ada pertimbangan untuk memblokir pengguna remote, jadi saya tidak sedang membahas aspek keamanan itu
    Mungkin ini terkait dengan batasan sudo nomor 3, tetapi setidaknya dibandingkan nomor 1, saya tidak melihat keunggulannya
    Saya paham ini eksperimen, tetapi rasanya bukan lebih sedikit rentan daripada sudo, melainkan lebih rentan. Proxy socket terbuka tampak rentan terhadap serangan man-in-the-middle
    Meski begitu, saya belajar beberapa teknik yang bisa dilakukan dengan tool lama, dan saya suka karena ini menunjukkan hal baru

    • Binary sudo adalah suid root dan merupakan binary berprivilege yang terekspos langsung ke pengguna yang tidak tepercaya. Jika ada yang salah di dalam sudo, seluruh environment pengguna menjadi attack surface dan bisa dieksploitasi
      Pendekatan ssh tidak mengekspos binary suid, melainkan menggunakan lapisan jaringan ssh. Jadi ini tidak kurang aman dibanding mengakses ssh melalui jaringan, yang dianggap cukup aman
    • Salah satu keunggulan besar sudo adalah, alih-alih menjalankan sesuatu seperti sudo bash, kita bisa menjalankan perintah individual dengan sudo sehingga auditability meningkat
    • Login SSH sebagai root dalam tulisan itu berarti server SSH tambahan yang mendengarkan Unix socket. Threat model umum saat mengekspos login root ke internet mungkin tidak berlaku di sini
    • Pendekatan ini membandingkan kesalahan konfigurasi teoretis atau kerentanan yang mungkin ada atau mungkin tidak ada, dengan attack surface baru berupa menjalankan daemon baru
      Daemon itu juga bisa memiliki kesalahan konfigurasi atau kerentanan, dan mengurangi beberapa lapisan otorisasi berbasis pengguna menjadi satu level root
      Namun tampaknya ini tetap dianggap lebih aman. Dari sudut pandang keamanan yang rasional, ini tidak bisa dianggap lebih aman; hanya cara yang berbeda
    • Saya skeptis terhadap pendekatan pada artikel yang ditautkan, tetapi pernyataan “login langsung SSH jarak jauh sebagai root itu berbahaya” ada unsur termakan ketakutan, ketidakpastian, dan keraguan
      Pada kenyataannya, dibanding login sebagai pengguna lewat SSH jarak jauh lalu memakai sudo, login SSH langsung sebagai root secara ketat lebih aman
      Jika user@home melakukan ssh ke root@server, maka root@server hanya terdampak jika user@home dibobol
      Sebaliknya, jika user@home melakukan ssh ke user@server lalu menjadi root@server lewat sudo, maka root akan terdampak jika salah satu dari user@home atau user@server dibobol. Terutama di user@server, software lain seperti daemon atau cron job sering berjalan
      Jangan memberi orang yang berhasil menginfeksi lewat jalur semacam itu eskalasi hak akses root gratis, apalagi lateral movement yang sering terjadi karena penggunaan ulang password
      Tentu ini tidak berlaku jika sudo digunakan dalam mode khusus perintah allowlist, dan tidak menerima password atau credential yang sepenuhnya dapat diakses dari host remote
  • Apa yang terjadi jika ssh tidak berjalan saat boot? Dalam konfigurasi umum, seingat saya ia dimulai dengan bergantung pada jaringan. Kalau begitu, bahkan di konsol failsafe pun tidak bisa login
    Saya tidak tahu apa yang sebenarnya didapat dibandingkan sudo atau su. Alih-alih menghindari binary setuid, kita malah menjalankan layanan jaringan sebagai root, meski hanya terhubung ke socket

    • Sebagai orang yang memakai konfigurasi serupa, saya melakukan ini di desktop utama saya. Kalau skenario terburuk dari yang terburuk terjadi, semuanya ada backup, jadi saya instal ulang sistemnya
      Bagaimana kalau SSD mati? Saat itu pun tidak bisa login ke konsol failsafe
      Selama 30 tahun memakai Linux, hard disk mati jauh lebih sering daripada daemon sshd gagal start, dan kalau dihitung rasionya seperti membagi dengan nol
      Jika daemon sshd sistem operasi secara acak tidak mau start, saya akan menganggap itu sinyal bahwa sudah waktunya pindah ke sistem operasi yang lebih stabil
      Yang didapat dibandingkan sudo atau su adalah eksploit eskalasi hak lokal menjadi jauh lebih sulit
    • Konsol Linux, yaitu tty yang muncul di display lokal atau KVM jarak jauh, serta perangkat ttyS* dari port serial dan IPMI SoL, tidak memakai sudo atau su
      Konsol seperti ini memakai program seperti getty atau window manager, dan itu adalah program non-suid yang dimulai sebagai root
      Password root untuk login konsol memang sebaiknya disetel
    • Dalam kasus saya, saya memakai setuid/sudo karena log audit. Sekarang saya hampir tidak lagi mengoperasikan box multi-user/multi-service, dan yang multitenant kebanyakan adalah k8s, jadi cukup memakai endpoint kubectl alih-alih ssh
      Jika seseorang bisa login, saya membiarkan mereka bisa setuid ke root. Kalau itu box k8s, itu urusan tim infrastruktur platform, dan akses ke layanan di atasnya melalui penyedia otorisasi k8s
      Dari sudut pandang tim infrastruktur platform, jika yang dibutuhkan hanya metrik dan log, semuanya sudah berada di luar box; jika perlu memicu suatu task atau workflow, bisa memakai pipeline
      Namun kalau tetap ada orang yang login dan melakukan pekerjaan sebagai root, saya ingin meninggalkan log audit
      Saya tidak terpikir ada box milik saya di mana orang yang punya hak login tidak memiliki hak root penuh
      Tentu saya paham kasus ketika service melakukan setuid, tetapi untuk service biasanya systemd melakukan setuid bukan untuk menaikkan hak, melainkan untuk menurunkannya
    • Jika bisa mengakses bootloader, masih bisa menyetel systems.unit=emergency.target, init=/bin/bash, rd.break=pre-pivot, atau boot ke lingkungan live CD. Semua opsi pemulihan darurat yang umum tetap berfungsi
      Untuk keadaan darurat yang tidak terlalu fatal, saya juga tidak melihat alasan mengapa instance sshd ini harus terikat ke jaringan
  • Agak disayangkan pendekatan ini tidak mencakup semua kelemahannya. sudo bisa mengontrol grup mana yang boleh menjalankan perintah apa, argumen apa yang boleh diterima perintah itu, apakah pembuatan subshell diizinkan, dan sebagainya
    Cara ini kehilangan banyak kontrol granular seperti itu, dan bergantung pada key tepercaya yang lebih sulit dikelola daripada mengedit file sudoers
    Saya sangat merekomendasikan buku Sudo Mastery untuk melihat kemampuan mengejutkan yang bisa dilakukan sudo

    • SSH juga bisa melakukan sebagian dari itu dengan ForceCommand, tetapi saya setuju bahwa ia tidak sefleksibel atau sepresisi itu
  • Ini gagasan yang mirip dengan run0 milik Systemd: https://news.itsfoss.com/systemd-run0/

    • Dan run0 bukan solusi sementara buatan sendiri. Ia sudah diaudit, dan mungkin lebih baik daripada sesuatu yang dibuat sendiri
  • Salah satu masalah ssh adalah pembuatan proses bukan bagian dari protokol. Dan karena ini protokol jarak jauh, resource lokal tidak bisa diteruskan ke child process
    Jadi kita tidak bisa meneruskan array argumen yang dipisahkan null, meneruskan file descriptor tambahan, atau menentukan executable
    Sebagai gantinya, kita meneruskan satu string ke shell yang dikonfigurasi di server. Lalu diperlukan shell escaping, dan kita juga harus tahu shell apa yang berjalan di sisi server
    Agar SSH bisa dipakai sebagai pengganti sudo yang layak, diperlukan ekstensi dengan kemampuan yang mendekati posix_spawn

  • Sepenuhnya setuju. Saya juga melakukan hal serupa, dan dulu pernah menjelaskannya di komentar HN
    Cara saya sedikit berbeda. Saya memakai mesin khusus sebagai konsol SSH fisik, dan mesin ini berada di LAN privat yang terpisah dari mesin-mesin lain di rumah. Switch-nya bukan managed switch, melainkan switch biasa, memakai kabel Ethernet, dan tidak ada trunk
    Login hanya bisa lewat SSH, dan saya memasang Yubikey di sana
    PC desktop punya firewall sendiri, dan hanya mengizinkan traffic SSH dari alamat IP/MAC konsol SSH ini. Itu hanya berlaku di LAN privat yang dipakai bersama oleh keduanya; di LAN fisik lain, desktop tetap bisa mengakses internet
    Daemon sshd hanya mengizinkan login public key/private key dan memblokir login password
    Kalau membutuhkan root, saya menyalakan “konsol SSH”. Karena mesinnya hampir kosong, boot-nya sangat cepat. Saya login, menekan panah atas untuk memanggil kembali baris ssh root@..., lalu Enter dan menekan Yubikey
    Konsol SSH dan keyboard itu ada di atas meja, selalu dalam jangkauan
    Apakah iptables/nftables + sshd di LAN privat, apalagi yang terpisah secara fisik dari LAN privat lain, lebih aman atau kurang aman daripada binary sudo atau su, silakan masing-masing menilai
    Kalau ditanya “kenapa”, saya akan menjawab “karena bisa”. Saya sudah menyetelnya terlalu lama sampai tidak ingat kapan tepatnya. Mungkin sekitar 2 tahun lalu saya mulai bermain-main dengan ide ini, dan sejak itu terus saya pakai. Tidak pernah ada masalah sama sekali

    • Konfigurasi yang Anda punya tidak sepenuhnya sama, tetapi tampaknya mirip dengan konsep bastion host
  • Ini solusi yang elegan untuk masalah ini. Tidak perlu memperlakukan pengguna seperti anak kecil, tetapi pada saat yang sama kita harus menghindari potensi kesalahan dengan default yang masuk akal
    Jika membutuhkan root, cukup login sebagai root lewat konsol, jadi menurut saya bahkan su pun tidak diperlukan. Cara ini sedekat mungkin dengan login sebagai root di tty konsol

    • Cara yang mengatakan login saja sebagai root lewat konsol jika butuh root punya dua masalah
      Pertama, tidak seperti sudo, semua pengguna harus tahu password root
      Kedua, jika semua orang login begitu saja sebagai root, tidak ada cara untuk mengaudit siapa sebenarnya yang login dan melakukan apa
  • Saya pernah mencoba hal serupa 10 tahun lalu. Tidak ada bagian soket UNIX; saya menjalankan sshd terpisah yang hanya mendengarkan di localhost, dan tidak perlu menangani SCM_RIGHTS
    Tidak ada hasil yang bisa dibilang baik atau buruk; saya hanya kehilangan minat, jadi tidak memindahkan konfigurasi itu ke mesin berikutnya