GNU/Linux >> Belajar Linux >  >> Linux

Mengapa SUID dinonaktifkan untuk skrip shell tetapi tidak untuk binari?

Ada kondisi balapan yang melekat pada cara shebang (#! ) biasanya diimplementasikan:

  1. Kernel membuka executable, dan menemukan bahwa itu dimulai dengan #! .
  2. Kernel menutup executable dan sebagai gantinya membuka interpreter.
  3. Kernel menyisipkan jalur ke skrip ke daftar argumen (sebagai argv[1] ), dan mengeksekusi penafsir.

Jika skrip setuid diizinkan dengan implementasi ini, penyerang dapat memanggil skrip sewenang-wenang dengan membuat tautan simbolis ke skrip setuid yang ada, menjalankannya, dan mengatur untuk mengubah tautan setelah kernel melakukan langkah 1 dan sebelum juru bahasa melakukan membuka argumen pertamanya. Untuk alasan ini, semua unice modern mengabaikan bit setuid saat mendeteksi shebang.

Salah satu cara untuk mengamankan implementasi ini adalah agar kernel mengunci file skrip hingga penerjemah membukanya (perhatikan bahwa ini tidak hanya harus mencegah pemutusan tautan atau penimpaan file, tetapi juga mengganti nama direktori mana pun di jalur). Tetapi sistem unix cenderung menghindar dari kunci wajib, dan tautan simbolik akan membuat fitur kunci yang benar menjadi sulit dan invasif. Saya rasa tidak ada orang yang melakukannya dengan cara ini.

Beberapa sistem unix mengimplementasikan secure setuid shebang menggunakan fitur tambahan:path /dev/fd/N mengacu pada file yang sudah dibuka pada deskriptor file N (jadi buka /dev/fd/N kira-kira setara dengan dup(N) ).

  1. Kernel membuka executable, dan menemukan bahwa itu dimulai dengan #! . Misalkan deskriptor file untuk yang dapat dieksekusi adalah 3.
  2. Kernel membuka juru bahasa.
  3. Kernel menyisipkan /dev/fd/3 daftar argumen (sebagai argv[1] ), dan mengeksekusi penafsir.

Semua varian unix modern termasuk Linux mengimplementasikan /dev/fd , tetapi sebagian besar tidak mengizinkan skrip setuid. OpenBSD, NetBSD dan Mac OS X mendukungnya jika Anda mengaktifkan pengaturan kernel non-default. Di Linux, orang telah menulis tambalan untuk mengizinkannya tetapi tambalan itu tidak pernah digabungkan. Halaman shebang Sven Mascheck memiliki banyak informasi tentang shebang di seluruh uni, termasuk dukungan setuid.

Selain itu, program yang berjalan dengan hak istimewa tinggi memiliki risiko bawaan yang biasanya lebih sulit dikendalikan dalam bahasa pemrograman tingkat tinggi kecuali jika juru bahasa dirancang khusus untuk itu. Alasannya adalah kode inisialisasi runtime bahasa pemrograman dapat melakukan tindakan dengan hak istimewa yang lebih tinggi, berdasarkan data yang diwarisi dari penelepon dengan hak istimewa lebih rendah, sebelum kode program memiliki kesempatan untuk membersihkan data ini. Runtime C tidak banyak membantu pemrogram, sehingga program C memiliki kesempatan yang lebih baik untuk mengambil kendali dan membersihkan data sebelum hal buruk dapat terjadi.

Anggaplah Anda telah berhasil membuat program Anda berjalan sebagai root, baik karena OS Anda mendukung setuid shebang atau karena Anda telah menggunakan pembungkus biner asli (seperti sudo ). Sudahkah Anda membuka lubang keamanan? Mungkin. Masalahnya di sini adalah bukan tentang program yang ditafsirkan vs yang dikompilasi. Masalahnya adalah apakah sistem runtime Anda berperilaku aman jika dijalankan dengan hak istimewa.

  • Eksekusi biner asli apa pun yang terhubung secara dinamis dengan cara ditafsirkan oleh pemuat dinamis (mis. /lib/ld.so ), yang memuat pustaka dinamis yang diperlukan oleh program. Pada banyak unice, Anda dapat mengonfigurasi jalur pencarian untuk pustaka dinamis melalui lingkungan (LD_LIBRARY_PATH adalah nama umum untuk variabel lingkungan), dan bahkan memuat pustaka tambahan ke semua binari yang dieksekusi (LD_PRELOAD ). Invoker program dapat mengeksekusi kode arbitrer dalam konteks program tersebut dengan menempatkan libc.so yang dibuat khusus dalam $LD_LIBRARY_PATH (di antara taktik lainnya). Semua sistem waras mengabaikan LD_* variabel dalam setuid yang dapat dieksekusi.

  • Di shell seperti sh, csh dan turunannya, variabel lingkungan secara otomatis menjadi parameter shell. Melalui parameter seperti PATH , IFS , dan banyak lagi, pemanggil skrip memiliki banyak peluang untuk mengeksekusi kode arbitrer dalam konteks skrip shell. Beberapa shell menyetel variabel-variabel ini ke default waras jika mereka mendeteksi bahwa skrip telah dipanggil dengan hak istimewa, tetapi saya tidak tahu apakah ada implementasi tertentu yang dapat saya percayai.

  • Sebagian besar lingkungan runtime (baik asli, bytecode atau ditafsirkan) memiliki fitur serupa. Hanya sedikit yang mengambil tindakan pencegahan khusus dalam setuid executable, meskipun yang menjalankan kode asli sering kali tidak melakukan apa pun yang lebih menarik daripada penautan dinamis (yang memerlukan tindakan pencegahan).

  • Perl adalah pengecualian penting. Ini secara eksplisit mendukung skrip setuid dengan cara yang aman. Faktanya, skrip Anda dapat menjalankan setuid meskipun OS Anda mengabaikan bit setuid pada skrip. Ini karena perl dikirimkan dengan root helper setuid yang melakukan pemeriksaan yang diperlukan dan memanggil kembali juru bahasa pada skrip yang diinginkan dengan hak istimewa yang diinginkan. Ini dijelaskan dalam manual perlsec. Dulu script setuid perl membutuhkan #!/usr/bin/suidperl -wT bukannya #!/usr/bin/perl -wT , tetapi pada sebagian besar sistem modern, #!/usr/bin/perl -wT sudah cukup.

Perhatikan bahwa menggunakan pembungkus biner asli tidak melakukan apa pun untuk mencegah masalah ini. Faktanya, ini dapat memperburuk situasi, karena mungkin mencegah lingkungan waktu proses Anda mendeteksi bahwa ia dipanggil dengan hak istimewa dan mengabaikan kemampuan konfigurasi waktu prosesnya.

Pembungkus biner asli dapat membuat skrip shell aman jika pembungkus tersebut membersihkan lingkungan. Skrip harus berhati-hati untuk tidak membuat terlalu banyak asumsi (mis. Tentang direktori saat ini) tetapi ini berlaku. Anda dapat menggunakan sudo untuk ini asalkan sudah diatur untuk membersihkan lingkungan. Variabel daftar hitam rawan kesalahan, jadi selalu daftar putih. Dengan sudo, pastikan env_reset diaktifkan, yaitu setenv tidak aktif, dan env_file itu dan env_keep hanya berisi variabel yang tidak berbahaya.

Semua pertimbangan ini berlaku sama untuk peningkatan hak istimewa apa pun:setuid, setgid, setcap.

Didaur ulang dari https://unix.stackexchange.com/questions/364/allow-setuid-on-shell-scripts/2910#2910


Terutama karena

Banyak kernel mengalami race condition yang memungkinkan Anda untuk menukar skrip shell dengan executable lain pilihan Anda antara saat proses yang baru dieksekusi berjalan setuid, dan saat penerjemah perintah memulai. Jika Anda cukup gigih, secara teori Anda bisa mendapatkan kernel untuk menjalankan program apapun yang Anda inginkan.

serta alasan lain yang ditemukan di tautan itu (tetapi kondisi ras kernel yang paling merusak). Skrip, tentu saja, dimuat secara berbeda dari program biner, yang merupakan tempat munculnya kesalahan.

Anda mungkin terhibur membaca artikel Dr. Dobb tahun 2001 ini - yang melewati 6 langkah untuk menulis skrip shell SUID yang lebih aman, hanya untuk mencapai langkah 7:

Pelajaran Tujuh -- Jangan gunakan skrip shell SUID.

Bahkan setelah semua pekerjaan kami, hampir tidak mungkin membuat skrip SUIDshell yang aman. (Hal ini tidak mungkin dilakukan pada sebagian besar sistem.) Karena masalah ini, beberapa sistem (mis., Linux) tidak menerima SUID pada skrip shell.

Sejarah ini berbicara tentang varian mana yang diperbaiki untuk kondisi balapan; daftarnya lebih besar dari yang Anda kira... tetapi skrip setuid sebagian besar masih tidak disarankan karena masalah lain atau karena lebih mudah untuk mencegahnya daripada mengingat apakah Anda menjalankan varian yang aman atau tidak aman.

Ini adalah masalah yang cukup besar, pada masa itu, sehingga sangat bermanfaat untuk membaca tentang seberapa agresif pendekatan Perl untuk mengimbanginya.


Linux
  1. Apakah Ada Konvensi Penamaan Untuk Variabel Dalam Skrip Shell?

  2. Referensi Nama Edaran Dalam Fungsi Bash Shell, Tapi Tidak Di Ksh?

  3. Bagaimana Menguji Kepatuhan Posix Dari Skrip Shell?

  1. Mengapa Tomcat bekerja dengan port 8080 tetapi tidak dengan 80?

  2. Mengapa Centos masih belum menggunakan kernel terbaru

  3. `ssh <host>` adalah shell login, tetapi `ssh <host> <command>` bukan?

  1. Mengapa Tidak Menggunakan "yang"? Apa yang Harus Digunakan Lalu?

  2. Izinkan Setuid Pada Skrip Shell?

  3. Ekstensi File Untuk Skrip Unix Shell?