Він працює на OpenBSD
Як уже згадувалося в коментарі @eradman, це можливо на OpenBSD.
Як корінь:
hzy# cat <<'EOT' >/tmp/foo; chmod 001 /tmp/foo
#! /bin/sh
: this is secret
echo done
EOT
Як постійний користувач:
hzy$ cat /tmp/foo
cat: /tmp/foo: Permission denied
hzy$ /tmp/foo
done
Це працює, передаючи /dev/fd/3
інтерпретатору (або будь-якому відкритому fd сценарію). Цей трюк не буде працювати в Linux, де /dev/fd/N
не спеціальні пристрої символів, які повертають a dup(2)
fd при відкритті, але "магія" посилається на оригінальний файл / зубний ряд, який відкриває файл з нуля [1]. Він може бути реалізований у Free / NetBSD або Solaris ...
Але це не те, що це тріщини
В основному, надання x
дозволу на виконання (виконання) означає також надання r
дозволу на (читання) будь-якому файлу, у якому є шебанг [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
не єдиний спосіб; якщо інтерпретатор є динамічно пов'язаним виконуваним файлом, наприклад, perl
або python
, LD_PRELOAD
замість нього read(2)
може бути використаний ed-хак, який замінює функцію.
І ні, якщо налаштувати його не завадить звичайному користувачеві бачити його вміст; вона може просто запустити його під ptrace(2)
, що призведе до ігнорування встановлених бітів:
Як корінь:
hzyS# cat <<'EOT' >/tmp/bar; chmod 4001 /tmp/bar
#! /bin/sh
: this is secret
id
EOT
Як постійний користувач:
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
"
(вибачте, якщо це не найпростіший спосіб продемонструвати це)
[1] це може бути емульовано в Linux за допомогою binfmt_misc
, але інтерпретатор повинен бути модифікований або використовувати оболонку; див. останню частину цієї відповіді за прикладом, навмисно зробленим смішно небезпечним.
[2] або взагалі будь-який файл, який не призведе execve()
до повернення ENOEXEC
.