it-swarm-id.com

Izinkan setuid pada skrip Shell

Bit izin setuid memberi tahu Linux untuk menjalankan program dengan id pengguna pemilik yang efektif alih-alih pelaksana:

> cat setuid-test.c

#include <stdio.h>
#include <unistd.h>

int main(int argc, char** argv) {
    printf("%d", geteuid());
    return 0;
}

> gcc -o setuid-test setuid-test.c
> ./setuid-test

1000

> Sudo chown nobody ./setuid-test; Sudo chmod +s ./setuid-test
> ./setuid-test

65534

Namun, ini hanya berlaku untuk executable; Script shell mengabaikan bit setuid:

> cat setuid-test2

#!/bin/bash
id -u

> ./setuid-test2

1000

> Sudo chown nobody ./setuid-test2; Sudo chmod +s ./setuid-test2
> ./setuid-test2

1000

Wikipedia kata :

Karena meningkatnya kemungkinan kelemahan keamanan, banyak sistem operasi mengabaikan atribut setuid ketika diterapkan pada skrip Shell yang dapat dieksekusi.

Dengan asumsi saya bersedia menerima risiko itu, apakah ada cara untuk memberitahu Linux untuk memperlakukan setuid sedikit sama pada skrip Shell seperti halnya pada executable?

Jika tidak, apakah ada solusi umum untuk masalah ini? Solusi saya saat ini adalah menambahkan entri sudoers untuk memungkinkan ALL untuk menjalankan skrip yang diberikan sebagai pengguna yang saya inginkan dijalankan dengan, dengan NOPASSWD untuk menghindari Prompt kata sandi. Kerugian utama untuk itu adalah kebutuhan untuk entri sudoers setiap kali saya ingin melakukan ini, dan kebutuhan untuk penelepon ke Sudo some-script bukan hanya some-script

195
Michael Mrozek

Linux mengabaikan bit setuid¹ pada semua executable yang ditafsirkan (mis. Executable yang dimulai dengan baris #!). FAQ comp.unix.questions menjelaskan masalah keamanan dengan skrip setuid Shell. 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 fungsi load_script , sebelum panggilan ke open_exec, Tapi saya belum menguji.


Setuid Shebang

Ada kondisi ras yang melekat pada cara Shebang (#!) Biasanya diterapkan:

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

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 unites 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 membutuhkan pengaturan kernel untuk diaktifkan) mengimplementasikan seteb Shank aman menggunakan tambahan fitur: path /dev/fd/N mengacu pada file yang sudah dibuka pada deskriptor file [~ # ~] n [~ # ~] (jadi membuka /dev/fd/N kira-kira setara dengan dup(N)). Banyak sistem unix (termasuk Linux) memiliki /dev/fd Tetapi tidak memiliki skrip setuid.

  1. Kernel membuka executable, dan menemukan bahwa itu dimulai dengan #!. Katakanlah deskriptor file untuk executable adalah 3.
  2. Kernel membuka interpreter.
  3. Kernel memasukkan /dev/fd/3 Daftar argumen (sebagai argv[1]), Dan mengeksekusi interpreter.

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 adalah tidak tentang program yang ditafsirkan vs dikompilasi. Masalahnya adalah apakah sistem runtime Anda berperilaku aman jika dijalankan dengan hak istimewa.

  • Setiap executable biner asli yang terhubung secara dinamis dengan cara ditafsirkan oleh loader dinamis (mis. /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 libc.so Yang dibuat khusus di $LD_LIBRARY_PATH (Di antara taktik lain). Semua sistem waras mengabaikan variabel LD_* Di setuid executable.

  • Dalam shells seperti sh, csh dan turunannya, variabel lingkungan secara otomatis menjadi parameter Shell. Melalui parameter seperti PATH, IFS, dan banyak lagi, penyerang skrip memiliki banyak peluang untuk mengeksekusi kode arbitrer dalam konteks skrip Shell. Beberapa shell mengatur variabel-variabel ini ke default waras jika mereka mendeteksi bahwa skrip telah dipanggil dengan hak istimewa, tetapi 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 bagus daripada tautan dinamis (yang memang mengambil tindakan pencegahan).

  • Perl adalah pengecualian. 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 dikirimkan dengan pembantu root setuid 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 setuid Perl diperlukan #!/usr/bin/suidperl -wT Bukan #!/usr/bin/Perl -wT, Tetapi pada kebanyakan sistem modern, #!/usr/bin/Perl -wT Sudah cukup.

Perhatikan bahwa menggunakan pembungkus biner asli tidak melakukan apa-apa untuk mencegah masalah ini . Bahkan, itu dapat membuat situasi lebih buruk, karena itu dapat mencegah lingkungan runtime Anda mendeteksi bahwa ia dipanggil dengan hak istimewa dan melewati konfigurabilitas runtime-nya.

Pembungkus biner asli dapat membuat skrip Shell aman jika pembungkus membersihkan lingkungan . Skrip harus berhati-hati agar tidak membuat terlalu banyak asumsi (mis. 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 bahwa opsi env_reset Dihidupkan, bahwa setenv tidak aktif, dan 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 opsi env_reset).

¹ Diskusi ini berlaku sama jika Anda mengganti "setgid" dengan "setuid"; keduanya diabaikan oleh kernel Linux pada skrip

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:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    setuid( 0 );   // you can set it at run time also
    system( "/home/pubuntu/setuid-test2.sh" );
    return 0;
 }

Simpan sebagai setuid-test2.c.
menyusun
Sekarang lakukan setuid pada program biner ini:

su - nobody   
[enter password]  
chown nobody:nobody a.out  
chmod 4755 a.out  

Sekarang, Anda harus dapat menjalankannya, dan Anda akan melihat skrip Anda dieksekusi tanpa izin siapa pun.
Tapi di sini Anda juga perlu membuat hardcode path skrip atau meneruskannya sebagai command line arg ke exe di atas.

57
Hemant

Saya awali beberapa skrip yang ada di kapal ini sebagai berikut:

#!/bin/sh
[ "root" != "$USER" ] && exec Sudo $0 "[email protected]"

Perhatikan bahwa ini tidak menggunakan setuid tetapi hanya menjalankan file saat ini dengan Sudo.

24
rcrowley

Jika Anda ingin menghindari panggilan Sudo some_script Anda bisa melakukan:

  #!/ust/bin/env sh

  Sudo /usr/local/scripts/your_script

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:

  • Shell adalah perangkat lunak berukuran besar yang sangat berinteraksi dengan pengguna. Hampir tidak mungkin untuk memeriksa semua kewarasan - terutama karena sebagian besar kode tidak dimaksudkan untuk berjalan dalam mode seperti itu.
  • Script sebagian besar merupakan solusi cepat dan biasanya tidak disiapkan dengan hati-hati sehingga mereka memungkinkan setuid. Mereka memiliki banyak fitur yang berpotensi berbahaya.
  • Mereka sangat bergantung pada program lain. Tidak cukup bahwa Shell sudah diperiksa. sed, awk, dll. perlu diperiksa juga

Harap perhatikan bahwa Sudo menyediakan beberapa pemeriksaan kewarasan tetapi tidak mencukupi - 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, sementara ping perlu memanipulasi jaringan, ia tidak perlu memiliki akses ke file. Namun saya tidak yakin apakah itu diwariskan.

12
Maciej Piechotka

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 perintah 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

5
Nizam Mohamed

Anda dapat membuat alias untuk Sudo + nama skrip. Tentu saja, itu lebih sulit untuk diatur, karena Anda kemudian harus mengatur alias juga, tetapi itu menghemat Anda dari keharusan mengetik 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 benar-benar melakukan ini. Saya hanya menyebutkannya untuk tujuan pendidikan ;-)

4
wzzrd

Jika karena alasan tertentu Sudo tidak tersedia, Anda dapat menulis skrip pembungkus tipis di C:

#include <unistd.h>
int main() {
    setuid(0);
    execle("/bin/bash","bash","/full/path/to/script",(char*) NULL,(char*) NULL);
}

Dan begitu Anda mengompilasinya, setel sebagai setuid dengan chmod 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 dipanggil oleh system(), dan karenanya menutup beberapa lubang keamanan potensial.

Perhatikan bahwa ini sepenuhnya membuang lingkungan. Jika Anda ingin menggunakan beberapa variabel lingkungan tanpa membuka kerentanan, Anda benar-benar hanya perlu menggunakan Sudo.

Jelas, Anda ingin memastikan skrip itu sendiri hanya dapat ditulis oleh root.

2
Chris