suFirewall: Creating a Controlled Setuid Environment
Chris Cox
People who are new to UNIX but are familiar with different
operating
systems (e.g., VMS, MVS, etc.) typically find UNIX more
"open,"
but inherently non-secure. Their opinion is often based
upon their
understanding of how controlled (or more likely, restricted)
their
previous OS was in comparison to UNIX. I suggest that
UNIX should
not be seen as a non-secure environment, but rather
a highly tailorable
environment that allows system administrators to construct
their own
security mechanisms, protocols, and methodologies. What
I have detailed
here is a very flexible tool to aid in defining security
within your
UNIX environment.
The key to UNIX's "openness" and/or "closedness"
lies
within its files. To control UNIX you need to control
files. Arguably
the most influential file type within UNIX is the directory
(this
differs from other OSs, which usually give equal if
not higher precedence
to the files within a directory). In UNIX, if I have
read (r) and
search (x) permissions for a directory, I will be able
to read all
readable files, copy them -- at the very least obtain
a directory
listing of the file names therein. However, if I have
write (w) permission
via user, group, or other, then I can change file ownerships
and do
file removals -- even if neither the directory nor the
file belongs
to me. Ultimately, if you do not want people to manipulate
or even
look at the contents of a directory you own, you should
remove all
permissions for group and other within the directory
mode (e.g., 700
or rwx------). But this would seem to be going from
one extreme,
very "open", to another, very "closed";
typically,
a UNIX security policy falls between the two extremes.
setuid programs allow certain operations to be performed
as
a different user within the controlled environment of
the program.
In the "good old days" of UNIX, even scripts
were allowed
to be setuid. But since the PATH environment variable
is usually dynamic, setuid programs create a potential
security
loophole: they can be used to exploit and/or violate
the privileges
of the effective user ID if PATH is reset so that executables
within the script would point to executables on the
overriding PATH.
The now ancient solution to this problem was to fully
qualify the
executable path names within the setuid script. This
was an
ugly solution in that it depended upon the discipline
of the programmer
to assure that directly and indirectly called executables
had fully
qualified path names. Most UNIX systems do not allow
setuid
scripts anymore (DGUX 4.x was the last one I knew of).
However, since
UNIX shell script is an excellent rapid prototyping
language, this
has made it more difficult to build powerful setuid
applications
in a short period of time.
A helpful UNIX utility would be a sort of "firewall"
for setuid
program execution -- including scripts. One example
of an application
where this suFirewall could be used is with source code
control.
By using setuid front ends to the source code control
commands
in SCCS, you could hide the actual s-files from the
user.
Other examples may include giving restricted access
to root level
commands or the setting up of a secured login environment
for restricted
user accounts.
What I describe here is a secure process for creating
setuid
programs -- scripts or binary executables. This process
should
work for any SVR4 UNIX as well as most UNIX derivatives
which support
symbolic links.
Making Directory and File Structures
Two directories (at least) are necessary to the secured
execution
environment. The first directory, the Secured Directory,
contains
the executable files where only the effective user has
access. The
second directory, the Public Directory, contains the
suFirewall
program as well as the interface stubs which determine
what Secured
Directory commands may be executed.
Create the Secured Directory with the owner set to the
effective user
id you wish to exploit (e.g., suser). Set the permissions
on the directory
to 700, so that only the owner can examine or make changes
to files contained there. Within this directory, place
all of the
executables that need to execute as the effective user
as well as
any other files referenced by the executables (e.g.,
configuration
files). Do not set the setuid bit on the executables:
suFirewall
will do this.
To force even the owner of the Secured Directory to
use the suFirewall
access interface, you may want to optionally prefix
or suffix the
executables with a string of your own choosing. This
will prevent
accidental bypassing of the suFirewall interface (for
instance,
when dot (.) has precedence in your PATH). The suFirewall
access interface will use the name of the stub file
found within the
Public Directory and will create the name of the actual
secured executable
by prefixing or suffixing your special character string.
You can use
non-printable characters for your prefix or suffix;
I prefer this,
since it makes it even more difficult to accidentally
invoke the Secured
executable name.
The Public Directory (e.g., /usr/local/bin) will have
permissions
such that all users of the suFirewall interface can
execute
the "stub" files located there. Each "stub"
file is
a symbolic link to the suFirewall program. The "stub"
file name is the name of the Secured Directory executable
without
the optional suffix or prefix. The suFirewall program
can
reside here, but if users have write permission to the
Public Directory
(thus the ability to delete/replace the suFirewall),
you might
prefer to place it in a directory that doesn't allow
general write
access. In addition, suFirewall itself may only have
execute
permission for members of a particular UNIX group. Figure
1 shows
how the resulting directory structure might look.
Making the suFirewall Program
As mentioned earlier, all the "stub" files
are symbolic links
to the suFirewall. The actual suFirewall executable
uses the basename of argv[0] plus any optional prefix
or suffix characters (known only to suFirewall) to determine
which program in the Secured Directory to execute.
All of the executable programs and scripts are funneled
through this
setuid executable (suFirewall will do an execvp,
among other things). Listing 1 shows full source for
this suFirewall
program. Below are the general steps to follow in coding
the program:
1. Reset the PATH to the standard path for the platform.
2. Prepend to this PATH the path(s) where your secured
programs
and scripts will reside. Use putenv to modify PATH
in the environment.
3. Take the basename of argv[0] as the name of the
secured program desired. Optionally, prefix or suffix
printable/non-printable
characters to the newly formed Secured Directory program
name. I'll
refer to the resulting program name as secured_name.
4. Use putenv to place anything else you want into the
environment.
5. Perform an execvp(secured_name, argv).
6. Compile the program and turn on the setuid bit for
the
effective user.
7. Place the program in a directory area which is searchable
by and
is on the PATH of the users of the Secured programs.
Drawing "Effective" Conclusions
Since the suFirewall actually controls the user's environment,
the user cannot simply alter his/her PATH to circumvent
security.
Also, the user is completely isolated from the source
and executables
used by the suFirewall, to the extent that he/she does
not
know if a binary or a script is really being executed.
Doing a ps while a secured shell script program is running
will show the shell being invoked with the secured_name
as
its first argument. If you find this too revealing,
then you could
execvp a shell directly with argv[0] set to whatever
name you want in order to better hide the fact that
you are using
a shell script. This strategy, however, incurs the undue
overhead
of invoking a shell to execute binary files.
You could also put an executable in the Secured Directory
which maps
to the name of the suFirewall program itself. This program
could be used to perform real work.
Getting Realuid
Sometimes within a setuid program, you will need to
revert
back to your real user id. For example, your own file
permissions
may be such that you cannot access the files under another
user id
(this is especially true for AIX users, see the sidebar
"AIXceptions").
Within a C program, reverting to the real user id is
a trivial call
to setuid. Doing the same from a script, however, requires
using a separate program. Call the program realdo from
inside
your secured scripts to execute commands as the real
user instead
of as the effective user. Listing 2 shows realdo.c.
Applying suFirewall
As I mentioned earlier, source code control is an excellent
proving
ground for suFirewall. Normally in SCCS, the s-files
(delta files) are read accessible (mode 444) and found
in a searchable
directory (mode 755). This means that only the SCCS
toolset can manipluate
the s-files and only the owner of the s-files can
use administrative commands. However, if you have customized
the way
files are manipulated by writing scripts around the
standard SCCS
commands, might not want people to access the s-files
via
the normal SCCS commands.
One solution is to make the directory for the s-files
accessible
only by the effective user (e.g., suser) of suFirewall.
This way, only the suFirewall command set can manipulate
the
files. The effective user can still do the SCCS commands
(since he/she
owns the s-files), but this is generally acceptable.
I also mentioned earlier the possibility of using configuration
files
within the suFirewall commands. You could for instance,
source
in a file of local/environment variables that could
be used within
the suFirewall scripts to locate the s-file area,
perform extra security measures, or define commonly
used functions
across all suFirewall scripts.
Listing 3 contains the source for a script which will
do a get
-e (check out) of a file. Listing 4 sets some variables
to enable
you to locate where the s-files reside, what release
trunks
are locked down, and some shell functions.
Afterthoughts
UNIX can be a very secure operating environment as long
as you know
the secrets of security. Avoiding setuid scripts is
too limiting
a solution to setuid "backdoors." I hope that
suFirewall
will help you to perform rapid prototyping, if not full-scale
development,
using UNIX scripts.
About the Author
Chris Cox is a Computer Science graduate of Texas A&M
University
with an Electrical Engineering minor. He has been working
with UNIX
since System III, and over the past ten years has been
a software
developer, configuration manager, porting engineer,
and system administrator
for heterogeneous UNIX environments. Chris is currently
employed as
a configuration manager by CARE Systems Corporation,
Dallas, TX. He
can be reached via email at Chris_Cox@ps.net.
|