Subject: Re: SetUID scripts
To: Peter Galbavy <peter@wonderland.org>
From: Ken Hornstein <kenh@cmf.nrl.navy.mil>
List: netbsd-help
Date: 07/03/1996 10:36:01
>On this topic, now that the problem is well known, could somebody explain
>to me in very small words what the well known security problem with set UID
>scripts is ? I never grasped it. Mea culpa.

Shell scripts are implemented by re-writing the command, so that when
you say:

#!/bin/sh

At the top of your shell script "/usr/bin/foo", the command that gets
executed is:

/bin/sh /usr/bin/foo

(This is done by the kernel)

In the case of sh, it starts up, looks at it's command line, and says, "Hey,
I'm supposed to open up /usr/bin/foo, let me go do that".  Simple enough :-)

(This is also why you have to say "#!/usr/bin/awk -f", since awk expected
the filename after the "-f" option).

So, let's say you have a setuid script.  The effective userid will be set
to root (or whoever), and it will run the command "/bin/sh /usr/bin/foo".
_This_ isn't a problem (modulo the other nasty security holes in sh, like
IFS, etc).

The problem is any user can create a symlink to this script.  For example,
I can create a symlink to /usr/bin/foo in my home directory.  (For the
sake of argument, let's call this simlink /home/kenh/bar).

So, what happens when I run /home/kenh/bar, is this:

1) Kernel reads /home/kenh/bar, sees the "#!/bin/sh", and also notes the 
   setuid bit is set (because /usr/bin/foo is setuid), so it sets the
   setuid bit in the new process and exec's "/bin/sh /usr/bin/foo".

2) /bin/sh starts up, sees that it's supposed to open /usr/bin/foo, it
   opens it, and goes along it's merry way.

Now, the hole is you can _change_ the symlink between steps 1 and 2 (since
it takes some finite amount of time for /bin/sh to get around to opening
the file) and point the symlink at whatever program you want to run.  Thus,
you can have root run any program you wish.

Note that this particular vulnerability is not limited to /bin/sh; _any_
script that uses #! can be subverted.

Perl gets around this hole by having "suidperl" stat the file that gets opened
and making sure that there are actually setuid bits on that file and that it
is owned by root.

The SUIDSCRIPTS option for the kernel opens the file before it checks the
mode bits as fd 0, and then runs "/bin/sh /dev/fd/0" (or whatever interpreter
you specify), thus not giving anyone a chance to change what file is being
run.

(If I'm wrong in any of the above, please let me know).

--Ken