I've recently been given the scary but interesting task to let someone (who I know is malicious) have access to a system, to run computational jobs on it. My job is to make sure that this someone, lets call him Danny, can't wreck havoc on the system.
I've also been given a number of conditions, like, "you can't minimize the system" and "you have to provide Danny with shell access" which makes things more complicated.
I pondered a while how on earth I should get around the problem with zero day exploits. I will never be able to patch the system fast enough, so there will always be a window of opportunity to exploit the system while it is unpatched.
My solution is to strip
privileges(5)
out of the user's limit set. This means that no matter what, Danny can never get those privileges back.
I started out by using the limitpriv attribute in
user_attr(4)
to restrict the limit set:
danny::::limitpriv=basic,!proc_info
I want Danny's processes to never be able to get anything beyond the basic privileges, and I even take away proc_info because I don't want him to see what else is running on the system.
It turns out that this fails horribly. My first test was just a simple
su(1M),
which gave the following, slightly confusing, result:
# su - danny su: Invalid GID
This baffled me at first, but checking the
source
I quickly found that the call to
setgid(2)
failed in su.c.
It turns out that there are three "unsafe" privileges (proc_setid, sys_resource and proc_audit), which shouldn't be removed. They are documented in the
privileges(5)
man page, but I failed to notice that.
The problem is that the
pam_unix_cred(5)
module drops the privileges before
su has called setgid(2).
If I retained the proc_setid privilege I could run su - danny, but this wasn't what I wanted. With the proc_setid privilege there is a remote possibility that he could exploit a program and switch user, and I really don't want Danny to have the slightest chance of doing that. I don't trust him :)
I had a chat with some people in Engineering, and this is being worked on, but I can't wait for it to be fixed,
so had to do some more thinking. I recalled having used
ppriv(1)
to do privilege testing when I worked on fixing bug 4344159 (*w* /usr/bin/w has excessive privilege for the job it performs), so I created a small wrapper script to launch a shell with privileges stripped:
#!/bin/sh # Copyright 2005 Sun Microsystems Inc. All rights reserved. # Use is subject to license terms. # # Invoke a shell which has very limited privileges exec /usr/bin/ppriv -s L=basic,!proc_info,proc_audit -e /bin/bash
Then I set this as the shell for Danny, and I got the result I wanted. It bypasses the problems with limitpriv as it is run after the catch-22 section I ran into,
and runs as Danny instead of root.
Once logged in he has the following sets of privileges available:
$ ppriv $$ 622: /bin/bash flags =E: basic,!proc_info I: basic,!proc_info P: basic,!proc_info L: basic,proc_audit,!proc_info
With this in place I feel more at ease letting Danny on to the system.
If you decide to try this, please note that it will break things and that the error messages aren't always clear. A couple of examples follow:
$ passwd passwd: Changing password for danny Enter existing login password: Unexpected failure. Password file/table unchanged.
$ crontab -e crontab: can't create your crontab file in the crontab directory.
$ ping www.sun.com ping: socket Permission denied
If you try this out and run into problems, please let me know as I am interested in knowing more about what this breaks!
[Technorati Tags: OpenSolaris Solaris Security]





