Es funktioniert unter OpenBSD
Wie bereits in einem Kommentar von @eradman erwähnt, ist dies unter OpenBSD möglich.
Als root:
hzy# cat <<'EOT' >/tmp/foo; chmod 001 /tmp/foo
#! /bin/sh
: this is secret
echo done
EOT
Als regulärer Benutzer:
hzy$ cat /tmp/foo
cat: /tmp/foo: Permission denied
hzy$ /tmp/foo
done
Das funktioniert, indem man /dev/fd/3
dem Interpreter (oder was auch immer das offene fd zum Skript ist) übergibt . Dieser Trick würde unter Linux nicht funktionieren, wo /dev/fd/N
es keine Sonderzeichengeräte gibt, die dup(2)
beim Öffnen einen der fd zurückgeben, sondern "magische" Symlinks zur Originaldatei / zum Originaleintrag, die die Datei von Grund auf öffnen [1]. Es könnte in Free / NetBSD oder Solaris implementiert werden ...
Aber es ist nicht das, was es verspricht
Grundsätzlich bedeutet das Erteilen der x
(Ausführungs-) Erlaubnis auch das Erteilen der r
(Lese-) Erlaubnis für jede Datei, die einen Shebang hat:
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
ist nicht der einzige Weg; Wenn der Interpreter wie perl
oder dynamisch mit einer ausführbaren Datei verknüpft ist , kann stattdessen python
ein LD_PRELOAD
ed-Hack verwendet werden, der die read(2)
Funktion überschreibt .
Und nein, wenn Sie es setuid machen, wird ein normaler Benutzer nicht daran gehindert, seinen Inhalt zu sehen. sie könnte es einfach unterlaufen lassen ptrace(2)
, wodurch die setuid-Bits ignoriert werden:
Als root:
hzyS# cat <<'EOT' >/tmp/bar; chmod 4001 /tmp/bar
#! /bin/sh
: this is secret
id
EOT
Als regulärer Benutzer:
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
"
(Entschuldigung, wenn dies nicht der einfachste Weg ist, es zu demonstrieren)
[1] Dies könnte unter Linux mithilfe von emuliert werden binfmt_misc
, der Interpreter muss jedoch geändert oder ein Wrapper muss verwendet werden. Im letzten Teil dieser Antwort finden Sie ein Beispiel, das absichtlich lächerlich unsicher gemacht wurde.
[2] oder generell jede Datei, die nicht execve()
zur Rückkehr führt ENOEXEC
.