Memungkinkan setuid pada shell script

The setuid izin sedikit menceritakan Linux untuk menjalankan program dengan user id dari pemilik, bukan 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; shell script 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 yang mengabaikan setuid atribut ketika diterapkan untuk eksekusi skrip shell.

Asumsi saya'm. bersedia untuk menerima risiko tersebut, apakah ada cara untuk memberitahu Linux untuk mengobati setuid bit yang sama pada shell script seperti halnya pada executable?

Jika tidak, apakah ada solusi umum untuk masalah ini? Solusi saya saat ini adalah untuk menambahkan sudoers entri untuk memungkinkan SEMUA untuk menjalankan suatu script sebagai pengguna saya ingin jalankan sebagai, dengan NOPASSWD untuk menghindari prompt password. Utama kelemahan itu adalah kebutuhan untuk sudoers entry setiap kali saya ingin melakukan hal ini, dan kebutuhan untuk penelepon untuk sudo beberapa-script bukan hanya beberapa script

Linux mengabaikan setuid¹ bit pada semua ditafsirkan executable (yaitu executable dimulai dengan #! line). The comp.unix.pertanyaan FAQ menjelaskan masalah keamanan dengan setuid shell script. Masalah-masalah ini ada dua macam: peristiwa-terkait dan shell-terkait; aku pergi ke rincian lebih lanjut di bawah ini. Jika anda don't peduli tentang keamanan dan ingin memungkinkan setuid script, di bawah Linux, anda'll perlu patch kernel. Sebagai 3.x kernel, saya pikir anda perlu untuk menambahkan panggilan ke install_exec_creds di load_script fungsi, sebelum panggilan untuk open_exec, tapi saya belum't diuji.

Setuid shebang

Ada kondisi balapan yang melekat dengan cara shebang (#!) biasanya dilaksanakan:

  1. Kernel membuka executable, dan menemukan bahwa itu dimulai dengan #!.
  2. Kernel menutup eksekusi dan membuka penerjemah sebaliknya.
  3. Kernel memasukkan path ke script untuk daftar argumen (sebagai argv[1]), dan mengeksekusi interpreter. Jika setuid script diperbolehkan dengan implementasi ini, penyerang dapat memanggil sewenang-wenang script dengan menciptakan link simbolik yang ada setuid script, mengeksekusi, dan mengatur untuk mengubah link setelah kernel telah melakukan langkah 1 dan sebelum penerjemah mendapat sekitar untuk membuka argumen pertama. Untuk alasan ini, sebagian besar jenis unix mengabaikan bit setuid ketika mereka mendeteksi shebang. Salah satu cara untuk mengamankan pelaksanaan ini akan untuk kernel untuk mengunci file script sampai penerjemah telah dibuka (perhatikan bahwa ini harus mencegah tidak hanya membatalkan tautan atau timpa file, tetapi juga bisa mengganti nama direktori di jalan). Tapi sistem unix cenderung menghindar dari wajib kunci, dan tautan simbolis akan membuat kunci yang benar fitur yang sangat sulit dan invasif. Saya don't pikir siapa pun yang melakukannya dengan cara ini. Beberapa sistem unix (terutama OpenBSD, NetBSD dan Mac OS X, yang memerlukan pengaturan kernel harus diaktifkan) menerapkan aman setuid shebang menggunakan fitur tambahan: jalan /dev/fd/N mengacu pada file yang sudah dibuka pada file descriptor N (jadi opening /dev/fd/N kira-kira setara dengan dup(N)). Banyak sistem unix (termasuk Linux) memiliki /dev/fd tapi tidak setuid script.
  4. Kernel membuka executable, dan menemukan bahwa itu dimulai dengan #!. Let's mengatakan file descriptor untuk eksekusi adalah 3.
  5. Kernel membuka penerjemah.
  6. Kernel sisipan /dev/fd/3 daftar argumen (sebagai argv[1]), dan mengeksekusi interpreter. Sven Mascheck's shebang halaman memiliki banyak informasi tentang peristiwa di seluruh jenis unix, termasuk setuid dukungan.

    Setuid interpreter

    Let's asumsikan anda've berhasil membuat program anda jalankan sebagai root, entah karena OS anda mendukung setuid shebang atau karena anda've digunakan asli biner wrapper (seperti sudo). Pernahkah anda membuka sebuah lubang keamanan? Mungkin. Masalah di sini adalah tidak tentang ditafsirkan vs disusun program-program. Masalahnya adalah apakah anda runtime sistem berperilaku aman jika dijalankan dengan hak istimewa.

  • Setiap dinamis terkait native executable biner adalah dengan cara ditafsirkan oleh dynamic loader (misalnya /lib/ld.jadi), yang memuat dynamic library yang diperlukan oleh program. Pada banyak jenis unix, anda dapat mengkonfigurasi jalur pencarian untuk perpustakaan dinamis melalui lingkungan (LD_LIBRARY_PATH adalah nama umum untuk variabel lingkungan), dan bahkan beban tambahan ke perpustakaan semua dieksekusi binari (LD_PRELOAD). The invoker program yang dapat mengeksekusi kode sewenang-wenang dalam program itu's konteks dengan menempatkan secara khusus dibuat libc.begitu dalam $LD_LIBRARY_PATH (antara lain taktik). Semua waras sistem mengabaikan LD_* variabel dalam setuid executable.
  • Di kerang seperti sh, csh dan turunannya, variabel lingkungan secara otomatis menjadi shell parameter. Melalui parameter-parameter seperti JALAN, JIKA, dan banyak lagi, invoker script memiliki banyak peluang untuk mengeksekusi kode sewenang-wenang dalam skrip shell's konteks. Beberapa kerang set variabel-variabel tersebut ke default waras jika mereka mendeteksi bahwa script telah dipanggil dengan hak-hak istimewa, tapi aku don't tahu bahwa ada implementasi tertentu bahwa saya akan percaya.
  • Paling runtime lingkungan (apakah asli, bytecode atau ditafsirkan) memiliki fitur serupa. Beberapa mengambil tindakan pencegahan khusus dalam setuid executable, meskipun orang-orang yang menjalankan kode asli sering don't melakukan apa-apa lebih bagus dari dynamic linking (yang tidak mengambil tindakan pencegahan).
  • Perl adalah sebuah pengecualian. Itu secara eksplisit mendukung setuid script dengan cara yang aman. Pada kenyataannya, anda dapat menjalankan script setuid bahkan jika OS anda mengabaikan bit setuid pada script. Hal ini karena perl kapal dengan setuid root pembantu yang melakukan pemeriksaan yang diperlukan dan reinvokes penerjemah yang diinginkan script dengan yang diinginkan hak-hak istimewa. Hal ini dijelaskan dalam perlsec manual. Ini digunakan untuk menjadi bahwa setuid script-script perl yang dibutuhkan #!/usr/bin/suidperl -wT, bukan #!/usr/bin/perl -wT, tapi pada banyak sistem modern, #!/usr/bin/perl -wT sudah cukup. Perhatikan bahwa menggunakan biner asli wrapper tidak apa-apa dalam dirinya sendiri untuk mencegah masalah ini. Pada kenyataannya, itu dapat membuat situasi buruk, karena itu dapat mencegah anda runtime environment mendeteksi bahwa itu dipanggil dengan hak dan melewati runtime nya konfigurabilitas. Asli biner pembungkus dapat membuat sebuah shell script aman jika wrapper sanitizes lingkungan. Naskah harus berhati-hati untuk tidak membuat terlalu banyak asumsi (misalnya tentang direktori saat ini) tapi ini berjalan. Anda dapat menggunakan sudo untuk ini asalkan itu's set up untuk membersihkan lingkungan. Daftar hitam variabel rawan kesalahan, jadi selalu putih. Dengan sudo, pastikan bahwa env_reset pilihan diaktifkan, bahwa setenv mati, dan bahwa env_file dan env_keep hanya mengandung berbahaya variabel.

    TL DR:

  • Setuid peristiwa ini tidak aman tapi biasanya diabaikan.
  • Jika anda menjalankan program dengan hak akses (baik melalui sudo atau setuid), menulis kode asli atau perl, atau memulai program dengan pembungkus yang sanitizes lingkungan (seperti sudo dengan env_reset pilihan). ¹ diskusi Ini berlaku sama jika anda mengganti "setgid" untuk "setuid"; mereka berdua diabaikan oleh kernel Linux pada script
Komentar (15)

Salah satu cara untuk memecahkan masalah ini adalah untuk memanggil shell script dari sebuah program yang dapat menggunakan setuid sedikit. sesuatu seperti sudo. Sebagai contoh, di sini adalah bagaimana anda akan mencapai hal ini dalam sebuah program C:

#include 
#include 
#include 
#include 

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. kompilasi Sekarang lakukan setuid pada program ini biner:

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

Sekarang, anda harus mampu menjalankan hal itu, dan anda'll melihat script yang dieksekusi dengan tidak ada izin. Tapi di sini juga anda harus hardcode script path atau lulus sebagai baris perintah arg di atas exe.

Komentar (12)

Aku awalan beberapa script yang ada di perahu ini demikian:

#!/bin/sh
[ "root" != "$USER" ] && exec sudo $0 "$@"

Catatan bahwa ini tidak menggunakan setuid tetapi hanya mengeksekusi file saat ini dengan sudo.

Komentar (1)

Jika anda ingin menghindari panggilan sudo some_script anda hanya dapat melakukan:

  #!/ust/bin/env sh

  sudo /usr/local/scripts/your_script

SETUID program perlu dirancang dengan sangat hati-hati karena mereka berjalan dengan hak akses root dan pengguna memiliki kontrol yang besar atas mereka. Mereka perlu untuk kewarasan-cek semuanya. Anda tidak bisa melakukannya dengan script karena:

  • Kerang besar potongan-potongan perangkat lunak yang berinteraksi dengan berat pengguna. Hal ini hampir mustahil untuk kewarasan memeriksa segala sesuatu — terutama karena sebagian besar dari kode ini tidak dimaksudkan untuk menjalankan dalam mode.
  • Script ini adalah sebagian besar cepat'n'kotor solusi dan biasanya tidak disiapkan dengan hati-hati seperti yang mereka akan memungkinkan setuid. Mereka memiliki banyak berpotensi berbahaya fitur.
  • Mereka sangat bergantung pada program lain. Hal ini tidak cukup bahwa shell diperiksa. sed, awk, dll. akan perlu diperiksa juga

Harap dicatat bahwa sudo menyediakan beberapa kewarasan memeriksa tetapi tidak't cukup — memeriksa setiap baris dalam kode anda sendiri.

Sebagai catatan terakhir: pertimbangkan untuk menggunakan kemampuan. Mereka memungkinkan anda untuk memberikan proses yang berjalan sebagai pengguna hak-hak istimewa yang biasanya akan memerlukan hak akses root. Namun untuk contoh, sementara ping kebutuhan untuk memanipulasi jaringan, tidak perlu untuk memiliki akses ke file. I'm tidak yakin namun jika mereka diwariskan.

Komentar (1)

Anda dapat membuat sebuah alias untuk sudo + nama script. Tentu saja, yang bahkan lebih banyak pekerjaan yang harus diatur, karena anda kemudian harus men-setup sebuah alias, juga, tapi itu menghemat anda dari keharusan untuk mengetik sudo.

Tapi jika anda don't pikiran mengerikan risiko keamanan, menggunakan setuid shell sebagai penerjemah untuk shell script. Don't tahu apakah itu'll bekerja untuk anda, tapi saya kira itu mungkin.

Biarkan saya menyatakan bahwa saya menyarankan agar benar-benar melakukan ini, meskipun. I'm hanya menyebutkan hal itu untuk tujuan pendidikan ;-)

Komentar (2)

super [ -r reqpath] perintah [ argumen ]

Super memungkinkan ditentukan pengguna untuk menjalankan script (atau perintah-perintah) seolah-olah mereka adalah akar; atau dapat mengatur uid, gid, dan/atau pelengkap kelompok pada per-perintah dasar sebelum melaksanakan perintah. Hal ini dimaksudkan untuk menjadi alternatif yang aman untuk membuat script setuid root. Super juga memungkinkan pengguna biasa untuk menyediakan perintah untuk eksekusi oleh orang lain; ini mengeksekusi dengan uid, gid, dan kelompok pengguna dengan perintah.

Super berkonsultasi `super.tab'' file untuk melihat apakah pengguna diijinkan untuk mengeksekusi perintah yang diminta. Jika izin diberikan, super akan exec pgm [ argumen ], di mana pgm adalah program yang berhubungan dengan perintah ini. (Akar diperbolehkan eksekusi secara default, tetapi masih bisa membantah jika aturan tidak termasuk akar. Pengguna biasa yang dianulir eksekusi secara default.)

Jika perintah merupakan sebuah symbolic link (atau hard link, juga) super program kemudian mengetik % perintah args setara dengan mengetikkan % super perintah arg (perintah tidak harus super atau super tidak akan mengakui bahwa itu's yang dipanggil melalui sebuah link.)

http://www.ucolick.org/~akan/RUE/super/README

http://manpages.ubuntu.com/manpages/utopic/en/man1/super.1.html

Komentar (2)

Jika untuk beberapa alasan sudo tidak tersedia, anda dapat menulis tipis wrapper script di C:

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

Dan setelah anda compile mengaturnya sebagai setuid dengan chmod 4511 wrapper_script.

Ini adalah sama dengan yang lain diposting menjawab, tapi menjalankan script dengan lingkungan yang bersih dan secara eksplisit menggunakan /bin/bash bukan shell yang disebut dengan sistem (), dan menutup beberapa potensi lubang keamanan.

Catatan bahwa ini membuang lingkungan sepenuhnya. Jika anda ingin menggunakan beberapa variabel lingkungan tanpa membuka kerentanan, anda benar-benar hanya perlu menggunakan sudo.

Jelas, anda ingin memastikan naskah itu sendiri hanya dapat ditulis oleh root.

Komentar (0)

Pertama kali saya menemukan pertanyaan ini, yakin dengan semua jawaban, di sini adalah jauh lebih baik, yang juga memungkinkan anda untuk benar-benar obfuscate anda bash script, jika anda begitu ingin!

Itu harus jelas.

#include 
#include 

template 
T &replace (
          T &str, 
    const U &from, 
    const U &to)
{
    size_t pos;
    size_t offset = 0;
    const size_t increment = to.size();

    while ((pos = str.find(from, offset)) != T::npos)
    {
        str.replace(pos, from.size(), to);
        offset = pos + increment;
    }

    return str;
}

int main(int argc, char* argv[])
{
    // Set UUID to root
    setuid(0);

    std::string script = 
R"(#!/bin/bash
whoami
echo $1
)";

    // Escape single quotes.
    replace(script, std::string("'"), std::string("'\"'\"'"));

    std::string command;
    command = command + "bash -c '" + script + "'"; 

    // Append the command line arguments.
    for (int a = 0; a < argc; ++a)
    {
        command = command + " " + argv[a];
    }

    return system(command.c_str());
}

Kemudian anda menjalankan

g++ embedded.cpp -o embedded
sudo chown root embedded
sudo chmod u+s embedded
Komentar (2)