The bit setuid dapat diatur pada file executable sehingga ketika menjalankan, program ini akan memiliki hak-hak istimewa dari pemilik file bukan pengguna yang sebenarnya, jika mereka berbeda. Ini adalah perbedaan antara uid efektif (id pengguna) dan uid nyata .
Beberapa utilitas umum, seperti passwd
, dimiliki oleh root dan dikonfigurasi dengan cara ini karena kebutuhan ( passwd
perlu mengakses /etc/shadow
yang hanya dapat dibaca oleh root).
Strategi terbaik ketika melakukan ini adalah melakukan apa pun yang perlu Anda lakukan sebagai superuser segera kemudian menurunkan hak istimewa sehingga bug atau penyalahgunaan lebih kecil kemungkinannya terjadi saat menjalankan root. Untuk melakukan ini, Anda mengatur cairan efektif proses menjadi cairan asli. Dalam POSIX C:
#define _POSIX_C_SOURCE 200112L // Needed with glibc (e.g., linux).
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void report (uid_t real) {
printf (
"Real UID: %d Effective UID: %d\n",
real,
geteuid()
);
}
int main (void) {
uid_t real = getuid();
report(real);
seteuid(real);
report(real);
return 0;
}
Fungsi yang relevan, yang seharusnya memiliki padanan dalam sebagian besar bahasa tingkat yang lebih tinggi jika digunakan secara umum pada sistem POSIX:
getuid()
: Dapatkan nyata uid.
geteuid()
: Dapatkan uid yang efektif .
seteuid()
: Tetapkan uid yang efektif .
Anda tidak dapat melakukan apa pun dengan yang terakhir tidak sesuai dengan uid asli kecuali sejauh setuid ditetapkan pada executable . Jadi untuk mencoba ini, kompilasi gcc test.c -o testuid
. Anda kemudian perlu, dengan hak istimewa:
chown root testuid
chmod u+s testuid
Yang terakhir mengatur bit setuid. Jika sekarang Anda menjalankan ./testuid
sebagai pengguna normal, Anda akan melihat proses secara default berjalan dengan efektif 0, root.
Bagaimana dengan skrip?
Ini bervariasi dari platform ke platform , tetapi di Linux, hal-hal yang memerlukan penerjemah, termasuk bytecode, tidak dapat menggunakan bit setuid kecuali diatur pada penerjemah (yang akan sangat sangat bodoh). Berikut skrip perl sederhana yang meniru kode C di atas:
#!/usr/bin/perl
use strict;
use warnings FATAL => qw(all);
print "Real UID: $< Effective UID: $>\n";
$> = $<; # Not an ASCII art greedy face, but genuine perl...
print "Real UID: $< Effective UID: $>\n";
Sesuai dengan akar * nixynya, perl telah membangun variabel khusus untuk uid ( $>
) dan uid nyata ( $<
). Tetapi jika Anda mencoba yang sama chown
dan chmod
digunakan dengan executable yang dikompilasi (dari C, contoh sebelumnya), itu tidak akan membuat perbedaan. Script tidak bisa mendapatkan hak istimewa.
Jawabannya adalah dengan menggunakan biner setuid untuk menjalankan skrip:
#include <stdio.h>
#include <unistd.h>
int main (int argc, char *argv[]) {
if (argc < 2) {
puts("Path to perl script required.");
return 1;
}
const char *perl = "perl";
argv[0] = (char*)perl;
return execv("/usr/bin/perl", argv);
}
Kompilasi ini gcc --std=c99 whatever.c -o perlsuid
, lalu chown root perlsuid && chmod u+s perlsuid
. Anda sekarang dapat mengeksekusi skrip perl apa saja dengan uid efektif 0, terlepas dari siapa pemiliknya.
Strategi serupa akan bekerja dengan php, python, dll. Tapi ...
# Think hard, very important:
>_< # Genuine ASCII art "Oh tish!" face
TOLONG TOLONG JANGAN tinggalkan barang seperti ini . Kemungkinan besar, Anda sebenarnya ingin mengkompilasi dalam nama skrip sebagai jalur absolut , yaitu, ganti semua kode main()
dengan:
const char *args[] = { "perl", "/opt/suid_scripts/whatever.pl" }
return execv("/usr/bin/perl", (char * const*)args);
Mereka memastikan /opt/suid_scripts
dan semua yang ada di dalamnya adalah read-only untuk pengguna non-root. Kalau tidak, seseorang bisa bertukar apa pun untuk whatever.pl
.
Selain itu, berhati-hatilah karena banyak bahasa skrip memungkinkan variabel lingkungan mengubah cara mereka mengeksekusi skrip . Misalnya, variabel lingkungan dapat menyebabkan pustaka yang disediakan oleh pemanggil dimuat, yang memungkinkan pemanggil untuk mengeksekusi kode arbitrer sebagai root. Jadi, kecuali Anda tahu bahwa baik juru bahasa dan skrip itu sendiri kuat terhadap semua variabel lingkungan yang mungkin, JANGAN LAKUKAN INI .
Jadi, apa yang harus saya lakukan?
Cara yang lebih aman untuk memungkinkan pengguna non-root menjalankan skrip sebagai root adalah dengan menambahkan aturan sudo dan meminta pengguna menjalankannya sudo /path/to/script
. Sudo menghapus sebagian besar variabel lingkungan, dan juga memungkinkan administrator memilih siapa yang dapat menjalankan perintah dan dengan argumen apa. Lihat Bagaimana menjalankan program tertentu sebagai root tanpa prompt kata sandi? sebagai contoh.
-privileged
cangkang dan, jika dipanggil dari skrip yang bertanggung jawab, juga dapat dengan aman dipanggil dengansuid root
cara itu. Saya takut bahwa gagasan tentang skrip yang bertanggung jawab adalah semacam pipedream di dunia nyata. Pokoknya, mungkin perlu disebutkan betapa pentingnya untuk menghindari menulis segala macam jika mungkin sementara izin ditingkatkan ...-privileged
shell" dan "script yang bertanggung jawab". Apakah Anda ingin melakukan jawaban lain tentang cangkang? Saya tidak bisa menjanjikan Anda tanda centang;) Tidak ada banyak alasan bagus untuk melakukan ini -sudo
adalah pilihan yang jauh lebih baik jika memungkinkan - saya menulisnya sebagai jawaban umum yang berasal dari pertanyaan awal tentang otentikasi kata sandi sistem di php .sudo
- saya anggapsudo
sebagai psikotik karena berpura-pura tidak seperti ituroot
. Anda bahkan dapat menempatkan gumpalan shell disudoers
.su
menurut saya lebih baik untuk keperluan scripting, meskipunsudo
bagus untuk aplikasi live. Tapi tidak adalah sebagai eksplisit sebagai skrip dengan#!/bin/ksh -p
bangline atau apa punsuid ksh
di$PATH
adalah.Ya Anda bisa, tetapi itu mungkin ide yang sangat buruk . Biasanya, Anda tidak akan menetapkan SUID menggigit langsung di eksekusi Anda, tetapi gunakan sudo (8) atau su (1) untuk melaksanakannya (dan batas yang bisa melaksanakannya)
Namun perlu dicatat, ada banyak masalah keamanan yang memungkinkan pengguna biasa menjalankan program (dan terutama skrip!) Sebagai root. Sebagian besar dari mereka harus melakukan itu kecuali program itu ditulis secara khusus dan sangat hati-hati untuk mengatasinya, pengguna jahat dapat menggunakannya untuk mendapatkan shell root dengan mudah.
Jadi, bahkan jika Anda melakukannya, itu akan menjadi ide yang sangat baik untuk pertama-tama membersihkan SEMUA input ke program yang ingin Anda jalankan sebagai root, termasuk lingkungannya, parameter baris perintah, STDIN dan semua file yang diproses, data yang berasal dari koneksi jaringan itu terbuka, dll. Ini sangat sulit untuk dilakukan, dan bahkan lebih sulit untuk melakukannya dengan benar.
Misalnya, Anda dapat mengizinkan pengguna yang hanya mengedit beberapa file dengan editor. Tetapi editor memungkinkan eksekusi perintah dari bantuan eksternal atau penangguhan, sehingga memberikan pengguna root shell untuk melakukan apa yang mereka inginkan. Atau Anda mungkin menjalankan skrip shell yang terlihat sangat aman bagi Anda, tetapi pengguna dapat menjalankannya dengan $ IFS yang dimodifikasi atau variabel lingkungan lainnya yang benar-benar mengubah perilaku itu. Atau mungkin skrip PHP yang seharusnya mengeksekusi "ls", tetapi pengguna menjalankannya dengan $ PATH yang dimodifikasi dan dengan demikian membuatnya menjalankan sebuah shell yang ia beri nama "ls". Atau puluhan masalah keamanan lainnya.
Jika program benar-benar harus melakukan sebagian pekerjaannya sebagai root, mungkin akan lebih baik untuk memodifikasinya sehingga berjalan seperti pengguna normal, tetapi jalankan saja (setelah membersihkan sebanyak mungkin) bagian yang benar-benar membutuhkan root melalui program pembantu suid.
Perhatikan bahwa meskipun Anda benar-benar mempercayai semua pengguna lokal Anda (seperti, Anda memberi mereka kata sandi root), itu adalah ide yang buruk, karena pengawasan keamanan yang tidak disengaja oleh APAPUN dari mereka (seperti, memiliki skrip PHP online, atau kata sandi yang lemah, atau terserah) tiba-tiba memungkinkan penyerang jarak jauh untuk sepenuhnya kompromi seluruh mesin.
sumber
man sh
- dan bahkan yang gagal melakukannyacommand -p env -i ...
. Lagipula ini cukup sulit untuk dilakukan. Namun, jika dilakukan dengan benar, untuk tujuan eksplisit, bisa lebih baik bagisuid
penerjemah yang cakap daripada menggunakansu
atausudo
- karena perilaku salah satu dari mereka akan selalu berada di luar kendali naskah (meskipunsu
lebih kecil kemungkinannya untuk melempar bola lengkungan karena cenderung menjadi sedikit kurang gila) . Membundel seluruh paket adalah satu-satunya taruhan yang pasti - lebih baik pastikan itu saja.