Linux mengabaikan bit setuid¹ pada semua executable yang ditafsirkan (yaitu executable yang dimulai dengan sebuah #!
baris). The comp.unix.questions FAQ menjelaskan masalah keamanan dengan script shell setuid. Masalah-masalah ini ada dua jenis: terkait shebang dan terkait shell; Saya masuk ke detail lebih lanjut di bawah ini.
Jika Anda tidak peduli dengan keamanan dan ingin mengizinkan skrip setuid, di Linux, Anda harus menambal kernel. Pada kernel 3.x, saya pikir Anda perlu menambahkan panggilan ke install_exec_creds
dalam load_script
fungsi, sebelum panggilan ke open_exec
, tapi saya belum menguji.
Setuid shebang
Ada kondisi ras yang melekat pada cara shebang ( #!
) biasanya diterapkan:
- Kernel membuka executable, dan menemukan bahwa itu dimulai dengan
#!
.
- Kernel menutup executable dan membuka interpreter sebagai gantinya.
- Kernel menyisipkan path ke skrip ke daftar argumen (as
argv[1]
), dan mengeksekusi interpreter.
Jika skrip setuid diizinkan dengan implementasi ini, penyerang dapat memanggil skrip arbitrer dengan membuat tautan simbolis ke skrip setuid yang ada, menjalankannya, dan mengatur untuk mengubah tautan setelah kernel melakukan langkah 1 dan sebelum penerjemah berkeliling untuk membuka argumen pertamanya. Untuk alasan ini, sebagian besar unices mengabaikan bit setuid ketika mereka mendeteksi shebang.
Salah satu cara untuk mengamankan implementasi ini adalah bagi kernel untuk mengunci file skrip sampai interpreter membukanya (perhatikan bahwa ini harus mencegah tidak hanya memutus tautan atau menimpa file, tetapi juga mengganti nama direktori di path). Tetapi sistem unix cenderung menghindar dari kunci wajib, dan tautan simbolik akan membuat fitur kunci yang benar terutama sulit dan invasif. Saya tidak berpikir ada yang melakukannya dengan cara ini.
Beberapa sistem unix (terutama OpenBSD, NetBSD dan Mac OS X, yang semuanya memerlukan pengaturan kernel untuk diaktifkan) mengimplementasikan setuid shebang aman menggunakan fitur tambahan: path merujuk ke file yang sudah dibuka pada deskriptor file N (jadi pembukaannya adalah kira-kira setara dengan ). Banyak sistem unix (termasuk Linux) memiliki tetapi tidak memiliki skrip setuid./dev/fd/N
/dev/fd/N
dup(N)
/dev/fd
- Kernel membuka executable, dan menemukan bahwa itu dimulai dengan
#!
. Katakanlah file descriptor untuk executable adalah 3.
- Kernel membuka interpreter.
- Kernel memasukkan
/dev/fd/3
daftar argumen (as argv[1]
), dan mengeksekusi penerjemah.
Halaman shebang Sven Mascheck memiliki banyak informasi tentang shebang di seluruh unit, termasuk dukungan setuid .
Penerjemah setuid
Mari kita asumsikan 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 bukan tentang program yang ditafsirkan vs dikompilasi. Masalahnya adalah apakah sistem runtime Anda berperilaku aman jika dijalankan dengan hak istimewa.
Setiap biner yang dapat dieksekusi secara dinamis terhubung dengan cara diinterpretasikan oleh loader dinamis (misalnya /lib/ld.so
), yang memuat pustaka dinamis yang diperlukan oleh program. Pada banyak unices, 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 dijalankan ( LD_PRELOAD
). Penyerang program dapat mengeksekusi kode arbitrer dalam konteks program tersebut dengan menempatkan keahlian khusus ( libc.so
di $LD_LIBRARY_PATH
antara taktik lain). Semua sistem waras mengabaikan LD_*
variabel dalam executable setuid.
Dalam shell seperti sh, csh dan turunannya, variabel lingkungan secara otomatis menjadi parameter shell. Melalui parameter seperti PATH
, IFS
, dan banyak lagi, Invoker script memiliki banyak kesempatan untuk mengeksekusi kode arbitrary dalam konteks skrip shell. Beberapa shell mengatur variabel-variabel ini ke default waras jika mereka mendeteksi bahwa script telah dipanggil dengan hak istimewa, tapi saya tidak tahu bahwa ada implementasi tertentu yang akan saya percayai.
Sebagian besar lingkungan runtime (apakah asli, bytecode atau ditafsirkan) memiliki fitur serupa. Beberapa mengambil tindakan pencegahan khusus dalam executable setuid, meskipun yang menjalankan kode asli sering tidak melakukan hal yang lebih baik daripada menghubungkan dinamis (yang memang mengambil tindakan pencegahan).
Perl adalah pengecualian penting. Ini secara eksplisit mendukung skrip setuid dengan cara yang aman. Bahkan, skrip Anda dapat menjalankan setuid bahkan jika OS Anda mengabaikan bit setuid pada skrip. Ini karena perl mengirim dengan setuid root helper yang melakukan pemeriksaan yang diperlukan dan menginstal ulang juru bahasa pada skrip yang diinginkan dengan hak istimewa yang diinginkan. Ini dijelaskan dalam manual perlsec . Dulu skrip perl setuid diperlukan #!/usr/bin/suidperl -wT
alih-alih #!/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 . Bahkan, ini dapat membuat situasi menjadi lebih buruk , karena dapat mencegah lingkungan runtime Anda mendeteksi bahwa ia dipanggil dengan hak istimewa dan memintas konfigurasi runtime-nya.
Pembungkus biner asli dapat membuat skrip shell aman jika pembungkus membersihkan lingkungan . Script harus berhati-hati untuk tidak membuat terlalu banyak asumsi (misalnya tentang direktori saat ini) tetapi ini berjalan. Anda dapat menggunakan sudo untuk ini asalkan sudah diatur untuk membersihkan lingkungan. Variabel daftar hitam rentan kesalahan, jadi selalu daftar putih. Dengan sudo, pastikan env_reset
opsi dihidupkan, setenv
dimatikan, dan itu env_file
dan env_keep
hanya berisi variabel tidak berbahaya.
TL, DR:
- Setuid shebang tidak aman tetapi biasanya diabaikan.
- Jika Anda menjalankan program dengan hak istimewa (baik melalui sudo atau setuid), tulis kode asli atau perl, atau mulai program dengan pembungkus yang membersihkan lingkungan (seperti sudo dengan
env_reset
opsi).
¹ Diskusi ini berlaku sama jika Anda mengganti "setgid" dengan "setuid"; keduanya diabaikan oleh kernel Linux pada skrip
suidperl
barang - barang itu telah ditinggalkan dan ditandai untuk dihapus selama bertahun-tahun (tetapi tetap tidak-kurang)suidperl
telah dihapus pada perl 5.11 (5.12 stable): perl5110delta:> "suidperl" telah dihapus. Ini digunakan untuk menyediakan mekanisme untuk meniru bit setuid permisi pada sistem yang tidak mendukungnya dengan benar. perl5120delta:> "suidperl" tidak lagi menjadi bagian dari Perl. Ini digunakan untuk menyediakan mekanisme untuk meniru bit setuid permisi pada sistem yang tidak mendukungnya dengan benar.Salah satu cara untuk memecahkan masalah ini adalah dengan memanggil skrip shell dari program yang dapat menggunakan bit setuid.
sesuatu seperti sudo. Sebagai contoh, berikut adalah bagaimana Anda akan mencapai ini dalam program C:
Simpan sebagai setuid-test2.c.
kompilasi
Sekarang lakukan setuid pada biner program ini:
Sekarang, Anda harus dapat menjalankannya, dan Anda akan melihat skrip Anda dieksekusi tanpa izin siapa pun.
Tapi di sini Anda juga perlu membuat hardcode pada jalur skrip atau meneruskannya sebagai baris perintah arg ke exe di atas.
sumber
PATH
danLD_LIBRARY_PATH
merupakan vektor yang jelas. Beberapa kerang mengeksekusi$ENV
atau$BASHENV
atau~/.zshenv
bahkan sebelum mereka mulai mengeksekusi script yang tepat, sehingga Anda tidak dapat melindungi dari ini sama sekali dari dalam script. Satu-satunya cara aman untuk menjalankan skrip shell dengan hak istimewa adalah dengan membersihkan lingkungan . Sudo tahu bagaimana melakukannya dengan aman. Jadi jangan menulis bungkus sendiri, gunakan sudo .LD_LIBRARY_PATH
antara hal-hal lain ketika bertemu bit setuid.system
, Anda mungkin merasa lebih mudah (dan lebih efisien) untuk menggunakan salah satuexec
keluarga - kemungkinan besarexecve
. Dengan begitu, Anda tidak membuat proses baru atau memulai shell, dan Anda dapat meneruskan argumen (dengan asumsi bahwa skrip istimewa Anda dapat menangani argumen dengan aman).Saya awali beberapa skrip yang ada di kapal ini sebagai berikut:
Perhatikan bahwa ini tidak menggunakan
setuid
tetapi hanya menjalankan file saat ini dengansudo
.sumber
sudo
prompt. (Bagi saya, seluruh titik setuid memungkinkan hal-hal berjalan sebagai root tanpa perlu sudo.)Jika Anda ingin menghindari panggilan,
sudo some_script
Anda bisa melakukan:Program SETUID perlu dirancang dengan sangat hati-hati karena dijalankan dengan hak akses root dan pengguna memiliki kontrol besar terhadapnya. Mereka perlu memeriksa semuanya. Anda tidak dapat melakukannya dengan skrip karena:
sed
,,awk
dll. perlu diperiksa jugaHarap dicatat bahwa
sudo
menyediakan beberapa pemeriksaan kewarasan tetapi tidak cukup - periksa setiap baris dalam kode Anda sendiri.Sebagai catatan terakhir: pertimbangkan untuk menggunakan kemampuan. Mereka memungkinkan Anda untuk memberikan proses yang berjalan sebagai hak istimewa khusus pengguna yang biasanya membutuhkan hak akses root. Namun misalnya, ketika
ping
perlu memanipulasi jaringan, ia tidak perlu memiliki akses ke file. Namun saya tidak yakin apakah itu diwariskan.sumber
/ust/bin/env
seharusnya/usr/bin/env
.Anda dapat membuat alias untuk sudo + nama skrip. Tentu saja, itu lebih sulit untuk diatur, karena Anda kemudian harus mengatur alias juga, tetapi itu menyelamatkan Anda dari keharusan mengetikkan sudo.
Tetapi jika Anda tidak keberatan dengan risiko keamanan yang mengerikan, gunakan setuid shell sebagai penerjemah untuk skrip shell. Tidak tahu apakah itu akan berhasil untuk Anda, tapi saya kira itu mungkin.
Biarkan saya menyatakan bahwa saya menyarankan agar tidak melakukan ini. Saya hanya menyebutkannya untuk tujuan pendidikan ;-)
sumber
rm -rf /
(dan perintah lain dari seri JANGAN LAKUKAN DI RUMAH ).perintah super [-r reqpath] [args]
Super memungkinkan pengguna tertentu untuk mengeksekusi skrip (atau perintah lain) seolah-olah mereka root; atau dapat mengatur grup uid, gid, dan / atau tambahan berdasarkan per-perintah sebelum menjalankan perintah. Ini dimaksudkan sebagai alternatif yang aman untuk membuat skrip setuid root. Super juga memungkinkan pengguna biasa untuk memasok perintah untuk dieksekusi oleh orang lain; ini dijalankan dengan uid, gid, dan grup pengguna yang menawarkan perintah.
Super berkonsultasi file `` super.tab '' untuk melihat apakah pengguna diizinkan untuk menjalankan perintah yang diminta. Jika izin diberikan, super akan exec pgm [args], di mana pgm adalah program yang dikaitkan dengan perintah ini. (Root diizinkan untuk dieksekusi secara default, tetapi masih dapat ditolak jika aturan mengecualikan root. Pengguna biasa tidak diizinkan untuk mengeksekusi.)
Jika perintah adalah tautan simbolik (atau tautan keras juga) ke program super, maka mengetik% perintah args sama dengan mengetik% super command args (Perintah tidak boleh super, atau super tidak akan mengenali bahwa itu dipanggil melalui tautan.)
http://www.ucolick.org/~will/RUE/super/README
http://manpages.ubuntu.com/manpages/utopic/en/man1/super.1.html
sumber
Jika karena alasan tertentu
sudo
tidak tersedia, Anda dapat menulis skrip pembungkus tipis di C:Dan sekali Anda compile mengaturnya sebagai
setuid
denganchmod 4511 wrapper_script
.Ini mirip dengan jawaban lain yang diposting, tetapi menjalankan skrip dengan lingkungan yang bersih dan secara eksplisit menggunakan
/bin/bash
alih-alih shell yang dipanggil olehsystem()
, dan karenanya menutup beberapa lubang keamanan potensial.Perhatikan bahwa ini sepenuhnya membuang lingkungan. Jika Anda ingin menggunakan beberapa variabel lingkungan tanpa membuka celah, Anda benar-benar hanya perlu menggunakannya
sudo
.Jelas, Anda ingin memastikan skrip itu sendiri hanya dapat ditulis oleh root.
sumber
Saya pertama kali menemukan pertanyaan ini, tidak yakin dengan semua jawaban, di sini ada yang jauh lebih baik, yang juga memungkinkan Anda untuk sepenuhnya mengaburkan skrip bash Anda, jika Anda memang cenderung!
Itu harus jelas.
Lalu kamu lari
sumber