Nó hoạt động trên OpenBSD
Như đã được đề cập trong một bình luận của @eradman, điều này là có thể trên OpenBSD.
Là gốc:
hzy# cat <<'EOT' >/tmp/foo; chmod 001 /tmp/foo
#! /bin/sh
: this is secret
echo done
EOT
Là người dùng thông thường:
hzy$ cat /tmp/foo
cat: /tmp/foo: Permission denied
hzy$ /tmp/foo
done
Điều đó hoạt động bằng cách chuyển /dev/fd/3
(hoặc bất cứ fd mở nào cho tập lệnh) cho trình thông dịch. Thủ thuật đó sẽ không hoạt động trên Linux, nơi /dev/fd/N
không phải là thiết bị ký tự đặc biệt trả về một dup(2)
fd khi được mở, nhưng các liên kết tượng trưng "ma thuật" cho tệp / nha khoa gốc, mở tệp từ đầu [1]. Nó có thể được triển khai trong Free / NetBSD hoặc Solaris ...
Nhưng nó không phải là những gì nó bị phá vỡ để được
Về cơ bản, cho phép x
(thực thi) có nghĩa là cũng cho phép r
(đọc) trên bất kỳ tệp nào có 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
không phải là cách duy nhất; nếu trình thông dịch được liên kết động có thể thực thi như perl
hoặc python
, một LD_PRELOAD
hack ed ghi đè read(2)
chức năng có thể được sử dụng thay thế.
Và không, làm cho nó được thiết lập sẽ không ngăn người dùng thông thường nhìn thấy nội dung của nó; cô ấy chỉ đơn giản có thể chạy nó bên dưới ptrace(2)
, điều này sẽ khiến các bit setuid bị bỏ qua:
Là gốc:
hzyS# cat <<'EOT' >/tmp/bar; chmod 4001 /tmp/bar
#! /bin/sh
: this is secret
id
EOT
Là người dùng thông thường:
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
"
(xin lỗi nếu đây không phải là cách thẳng thắn nhất để chứng minh điều đó)
[1] điều này có thể được mô phỏng trên Linux bằng cách sử dụng binfmt_misc
, nhưng trình thông dịch sẽ phải được sửa đổi, hoặc một trình bao bọc sẽ phải được sử dụng; xem phần cuối của câu trả lời này để biết ví dụ cố tình làm cho không an toàn một cách lố bịch.
[2] hoặc nói chung, bất kỳ tệp nào sẽ không execve()
trở lại ENOEXEC
.