Ini bekerja pada OpenBSD
Seperti yang telah disebutkan dalam komentar oleh @eradman, ini dimungkinkan pada OpenBSD.
Sebagai root:
hzy# cat <<'EOT' >/tmp/foo; chmod 001 /tmp/foo
#! /bin/sh
: this is secret
echo done
EOT
Sebagai pengguna biasa:
hzy$ cat /tmp/foo
cat: /tmp/foo: Permission denied
hzy$ /tmp/foo
done
Itu bekerja dengan mengirimkan /dev/fd/3
(atau apa pun fd terbuka ke skrip) ke penerjemah. Trik itu tidak akan berfungsi di Linux, di mana /dev/fd/N
bukan perangkat karakter khusus yang mengembalikan a dup(2)
fd ketika dibuka, tetapi "sulap" symlinks ke file asli / gigi, yang membuka file dari awal [1]. Ini dapat diimplementasikan dalam Free / NetBSD atau Solaris ...
Tapi itu bukan apa yang harus terjadi
Pada dasarnya memberikan x
izin (mengeksekusi) berarti juga memberikan r
izin (baca) pada file apa pun yang memiliki shebang [2]:
hzy$ cat /tmp/foo
cat: /tmp/foo: Permission denied
hzy$ ktrace -ti /tmp/foo
done
hzy$ kdump | tail -n8
70154 sh GIO fd 10 read 38 bytes
"#! /bin/sh
: this is secret
echo done
"
70154 sh GIO fd 1 wrote 5 bytes
"done
ktrace
bukan satu-satunya cara; jika interpreter terkait secara dinamis dapat dieksekusi seperti perl
atau python
, LD_PRELOAD
hack ed yang menimpa read(2)
fungsi dapat digunakan sebagai gantinya.
Dan tidak, menjadikannya setuid tidak akan mencegah pengguna biasa melihat kontennya; dia bisa menjalankannya di bawah ptrace(2)
, yang akan menyebabkan bit setuid diabaikan:
Sebagai root:
hzyS# cat <<'EOT' >/tmp/bar; chmod 4001 /tmp/bar
#! /bin/sh
: this is secret
id
EOT
Sebagai pengguna biasa:
hzyS$ ktrace -ti /tmp/bar
uid=1001(duns) euid=0(root) gid=1001(duns) groups=1001(duns)
hzyS$ kdump
... nothing, the kernel disabled the ktrace ...
hzyS$ cc -Wall -xc - -o pt <<'EOT'
#include <unistd.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <signal.h>
int main(int ac, char **av){
int s; pid_t pid;
if((pid = fork()) == 0){
ptrace(PT_TRACE_ME, 0, 0, 0);
execvp(av[1], av + 1);
}
while(wait(&s) > 0 && WIFSTOPPED(s)){
s = WSTOPSIG(s);
ptrace(PT_CONTINUE, pid, (caddr_t)1, s == SIGTRAP ? 0 : s);
}
}
EOT
hzyS$ ./pt ktrace -ti /tmp/bar
uid=1001(duns) gid=1001(duns) groups=1001(duns)
hzyS$ kdump | tail -5
29543 sh GIO fd 10 read 31 bytes
"#! /bin/sh
: this is secret
id
"
(maaf jika ini bukan cara yang paling sulit untuk menunjukkannya)
[1] ini dapat ditiru di Linux dengan menggunakan binfmt_misc
, tetapi penerjemah harus dimodifikasi, atau pembungkus harus digunakan; lihat bagian terakhir dari jawaban ini untuk contoh yang sengaja dibuat tidak aman.
[2] atau secara umum, file apa pun yang tidak akan menyebabkannya execve()
kembali ENOEXEC
.