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