มันทำงานบน 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
ไม่ใช่อุปกรณ์ตัวอักษรพิเศษที่คืนdup(2)
ค่า fd เมื่อเปิด แต่ symlink "magic" กลับไปยังไฟล์ต้นฉบับ / Dentry ซึ่งเปิดไฟล์จากศูนย์ [1] มันสามารถนำมาใช้ในฟรี / NetBSD หรือ Solaris ...
แต่มันไม่ใช่สิ่งที่แตกสลายไป
การให้x
สิทธิ์โดยทั่วไป(ดำเนินการ) หมายถึงการอนุญาตr
(อ่าน) ไฟล์ใด ๆ ที่มี 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
ไม่ใช่วิธีเดียว; ถ้าล่ามที่มีการเชื่อมโยงแบบไดนามิกปฏิบัติการเหมือนperl
หรือpython
การLD_PRELOAD
สับเอ็ดซึ่งแทนที่read(2)
ฟังก์ชั่นสามารถนำมาใช้แทน
และไม่ทำให้ setuid ไม่ทำให้ผู้ใช้ทั่วไปเห็นเนื้อหา เธอสามารถเรียกใช้ภายใต้ptrace(2)
ซึ่งจะทำให้บิต setuid ถูกละเว้น:
ในฐานะที่เป็นราก:
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
แต่ล่ามจะต้องมีการแก้ไขหรือจะต้องใช้ wrapper ดูส่วนสุดท้ายของคำตอบนี้สำหรับตัวอย่างที่ทำโดยเจตนาไม่ปลอดภัยอย่างน่าขัน
[2] หรือโดยทั่วไปไฟล์ใด ๆ ซึ่งจะไม่ทำให้เกิดการที่จะกลับมาexecve()
ENOEXEC