riddle@woton.UUCP (Prentiss Riddle ) (03/09/88)
There's been a recent flurry of discussion in comp.bugs.sys5 about a few specific security pitfalls to avoid in writing setuid programs. I get the feeling that this is just the tip of the iceberg. Can anyone point us to a more comprehensive guide to how to write good setuid programs? If you've got something on-line, please consider posting it; if you know of good book or journal references, please mail them to me and I will summarize. And if nothing of this sort exists, perhaps it's time to write one. Thanks. -- Prentiss Riddle ("Aprendiz de todo, maestro de nada.") -- Opinions expressed are not necessarily those of my employer. -- riddle%woton.uucp@im4u.utexas.edu {ihnp4,uunet}!ut-sally!im4u!woton!riddle
scl@virginia.acc.virginia.edu (Steve Losen) (03/12/88)
I have no guide for writing setuid programs, but here are a few ideas that come to mind: 1) There's a big difference between setuid to root and setuid to an ordinary user. This should be obvious because of the many operations that only root can do. One should always endeaver to make a program setuid to some non-root user if at all possible. If a program is setuid to a non-root user it should revert back to the real user whenever possible so that the program can access all of the user's files. We all know what a pain it is that lp(1) can't open any files that user "lp" can't access (which may include files that the real user can access.) 2) Avoid setuid if you can. I once wrote a very simple print spooler that puts files in a directory where they are picked up periodically by a daemon to be printed. I made the directory 777 instead of using setuid-to-lp fraud. Sure a malicious user can remove files in the print queue. So what? To my knowlege, no one has ever done that in the two years since I put the system up. Ask yourself, "Does this really need to be setuid?" For example, I would *never* make a program setuid just so it could write to a protected logfile. To hell with it. make the logfile 622. 3) Have the setuid program grab all necessary resources at the beginning and revert back to the real user. For example, once you open a file you can revert back to the real user before reading or writing. This little trick can be very handy for instructors who want their students to turn in assignments to the instructor's protected directory from the student's protected directory. Sound like job for root? Nope! Write a setuid-to-instructor program that creat(2)'s a file in the instructors protected directory. Now revert back to the real user (the student), open the assignment, and copy it to the fd that was creat(2)'ed earlier. As a matter of fact, I heard a horror story about another such turn-un program. The program was setuid to root and it prompted for source and destination file names. The source name was appended to the student's home directory while the destination name was appended to the instructor's "turn-in" directory and the copy was done. Unfortunately, the programmer forgot about "../../.." and students quickly learned that they could copy any file anywhere with this program. (This was taken from comp.risks, a newsgroup I highly recommend.) Another thing you can do is set up a system so that all of its sensitive files and directories are within a single subtree. Make the directory at the top of the subtree 700 to keep ordinary users out. But within the subtree loosen the permissions. Make directories where users will create files 777. Make logfiles 622. Each program that manipulates this system is setuid to the owner of the protected directory. Upon invocation, the process chdirs below the protected directory and reverts back to the real user. Now the process can access both the user's files and the sensitive system files. This sort of design would have solved the problem with lp(1). 4) Instead of making a whole program setuid, identify the portions that need special privilege and write small, very specific setuid programs to do those tasks. Fork and/or exec the small programs from the main program. We once had a program that needed to signal another process that was owned by a different user. Instead of making the first process setuid to root, we wrote a small setuid to root program to send the signal. To keep normal users from running the little program we put it in a special group with mode 4110 and made the first program setgid to the special group. 5) If you MUST write a setuid to root program be VERY careful when checking any input or arguments from a user. Realize that root can do amazing things that even an administrator would never do. Take unlink(2) in SysV, for example. Root can unlink a directory, disconnecting from the file system any files that were in the directory. Fsck is the only way to relink those files. So even if you do an access(2) and find out that "yes, the real user can remove file foo" be sure that "foo" is not a directory. Root can also unlink "." and ".." . Another example is mount(2). You have to be root to mount a floppy on a 3b2. If you write a setuid program for your users to mount floppies, you better check carefully where the user wants to mount or she could put her own "passwd" file on the floppy and mount it on /etc. In a similar vein, when running in "root" mode, realize that environment variables are easy to fake. Never use the PATH environment variable; always fully specify the pathnames of any process you exec. If you exec a process as root, you might want to clear the environment first. Use getpwent instead of $HOME. Well this is certainly a lot more than I first intended to say. -- Steve Losen scl@virginia.edu University of Virginia Academic Computing Center
blarson@skat.usc.edu (Bob Larson) (03/14/88)
In article <700@virginia.acc.virginia.edu> scl@virginia.acc.Virginia.EDU (Steve Losen) writes: >2) Avoid setuid if you can. I once wrote a very simple print spooler > that puts files in a directory where they are picked up periodically > by a daemon to be printed. I made the directory 777 instead of using > setuid-to-lp fraud. Sure a malicious user can remove files in the > print queue. So what? So what? It depends a lot on what you are printing. When someone modifies the batch of checks waiting to be printed or gives the confedintial information you were printing to a compeditor I doubt your boss wold say "So what?". -- Bob Larson Arpa: Blarson@Ecla.Usc.Edu blarson@skat.usc.edu Uucp: {sdcrdcf,cit-vax}!oberon!skat!blarson Prime mailing list: info-prime-request%fns1@ecla.usc.edu oberon!fns1!info-prime-request
jbs@fenchurch.MIT.EDU (Jeff Siegal) (03/14/88)
In article <7616@oberon.USC.EDU> blarson@skat.usc.edu (Bob Larson) writes: >In article <700@virginia.acc.virginia.edu> scl@virginia.acc.Virginia.EDU (Steve Losen) writes: >> [...]. I made the directory 777 instead of using >> setuid-to-lp fraud. Sure a malicious user can remove files in the >> print queue. So what? >So what? It depends a lot on what you are printing. When someone >modifies the batch of checks waiting to be printed or gives the >confedintial information you were printing to a compeditor I doubt >your boss wold say "So what?". Setting the directory mode to 777 by itself doesn't let anyone modify or read anything. All it allows people do is: 1. List the file names in the directory 2. Access files in the dirctory _according_to_their_modes. 3. Remove files from the directory. #1 can be prevented, if necessary by setting the directory mode to 733 rather than 777. This effectively prevents #2 and #3 if you use obscure file names. #2 can be absolutely prevented in any case by setting the mode of each file in the directory appropriately. #3 can be absolutely prevented on BSD 4.3 systems by setting the sticky bit (mode 1733) on the directory. The security risk is minimal, since all that can be done is removing the files, not reading or writing them. Even this can be effectively prevented by using the messures described above. Jeff Siegal
wesommer@athena.mit.edu (William Sommerfeld) (03/14/88)
In article <8468@eddie.MIT.EDU> jbs@eddie.MIT.EDU (Jeff Siegal) writes: >#1 [listing the directory] can be prevented, if necessary by setting the >directory mode to 733 rather than 777. This effectively prevents >#2 [reading and/or writing files in the directory] and #3 [deleteing >files] if you use obscure file names. #2 can be absolutely prevented >in any case by setting the mode of each file in the directory >appropriately. #3 can be absolutely prevented on BSD 4.3 systems by >setting the sticky bit (mode 1733) on the directory. Of course, this implies that the daemon which reads this queue runs as root, which may not be desirable either. Secure systems should be able to withstand attacks when the attackers have complete access to all design documentation, source, and object code. "Security through obscurity" is not security at all. - How do you seed the random number generator used to generate the 100-character `obscure' filename such that knowing, for example, the approximate starting time and process ID of a process which dropped something interesting in the queue doesn't make things any easier. A much better approach would be to have a pseudo-user for for whatever facility you were creating, and a _short_, _auditable_ setuid program, without shell escapes and other similar nonsense, to deposit things in the spool directory. If you need to put a fancy user-interface on it, build the user interface as a separate process and have it fire up a setuid backend process to do the `real work'. - Bill
friedl@vsi.UUCP (Stephen J. Friedl) (03/14/88)
In article <8468@eddie.MIT.EDU>, jbs@fenchurch.MIT.EDU (Jeff Siegal) writes: > Setting the directory mode to 777 by itself doesn't let anyone modify > or read anything. All it allows people do is: > > 1. List the file names in the directory > 2. Access files in the dirctory _according_to_their_modes. > 3. Remove files from the directory. You missed at least two: 4. Rename files 5. Add new files What if you see a job ready to print. You know payroll will be printing checks soon so you make up a file of your own checks. When you see it in the queue you remove theirs and insert yours. Another one: your system's laser printer has usage accounting built into the spooler. You make up your own spooler files and stick them in the directory directly. The despooler never knows the difference. The set-sticky-bit-on-directory fix will be available for SVR3.2 from AT&T soon. If this is done, you only can only unlink files if you own the file or own the directory. This largely fixes the above problems in the manner of BSD. -- Steve Friedl, KA8CMY ARPA/CSNet: friedl@vsi.uu.net *Hi Mom* uucp email : { kentvax, uunet, attmail, ihnp4!amdcad!uport }!vsi!friedl "Too bad we judge others by their actions and ourselves by our motives"
davidsen@steinmetz.steinmetz.UUCP (William E. Davidsen Jr) (03/15/88)
In article <700@virginia.acc.virginia.edu> scl@virginia.acc.Virginia.EDU (Steve Losen) writes: | | 2) Avoid setuid if you can. I once wrote a very simple print spooler | that puts files in a directory where they are picked up periodically | by a daemon to be printed. I made the directory 777 instead of using | setuid-to-lp fraud. Sure a malicious user can remove files in the | print queue. So what? To my knowlege, no one has ever done that in | the two years since I put the system up. Ask yourself, "Does this | really need to be setuid?" For example, I would *never* make a program | setuid just so it could write to a protected logfile. To hell with it. | make the logfile 622. While I agree with much of what you said, I totally disagree on this point. I can't belive that this is workable of any system available to hackers (ie. public access, campus machines, etc), and would not really provide benefits on even a machine loaded with well behaved users. While setuid leaves problems, I doubt the proper way to solve them is to let people do things with system queues without using setuid. I have spent a great deal of time setting my system so that it is secure (one of the systems is public access). Here are a few things I've done: Scan the entire filesystems with find and identify every program in the system with setuid on. Any of these which are owned by system uids are examined carefully for problems. I have all my system queues set to require access via setuid, just the opposite of your method. I have all my lp and uucp stuff locked up, accessed by a small number of trusted programs. Other programs which access the queues may be setuid, but are not executable by anyone but the user and root. When creating files setuid prevents files from having dubious ownership, such as root. If you leave a file owned by root, it can be modified. I have logins just for working on various subsystems, most commonly uumaint (uucp) and lpmaint (lp). Logins which access uucico run under another uid, not uucp. All files and queues are accessable by uucp (unless other access is needed). No program which does a "system" call or starts a shell in any way is setuid. I have accounting on, running to a write only device. This allows me to analize system behavior as needed. It has helped me spot and correct problems, and is checked by a cron script daily and by me when I get a bad feeling. I don't allow users to execute many of the uucp programs, particularly uucico. I'm not going to post the hole here, but only logins can run the program on my system. I hope that this offers another viewpoint on this area. -- bill davidsen (wedu@ge-crd.arpa) {uunet | philabs | seismo}!steinmetz!crdos1!davidsen "Stupidity, like virtue, is its own reward" -me
scl@virginia.acc.virginia.edu (Steve Losen) (03/15/88)
In article <391@vsi.UUCP> friedl@vsi.UUCP (Stephen J. Friedl) writes: >In article <8468@eddie.MIT.EDU>, jbs@fenchurch.MIT.EDU (Jeff Siegal) writes: >> Setting the directory mode to 777 by itself doesn't let anyone modify >> or read anything. All it allows people do is: >> >> 1. List the file names in the directory >> 2. Access files in the dirctory _according_to_their_modes. >> 3. Remove files from the directory. > >You missed at least two: > > 4. Rename files > 5. Add new files > >What if you see a job ready to print. You know payroll will be printing >checks soon so you make up a file of your own checks. When you see it >in the queue you remove theirs and insert yours. Sorry I started such a controversy here. I must agree that in many situations you need a secure print spooler. My intent was to simply illustrate that in some situations setuid hassles can be avoided altogether. One should always balance the risks of opening up permisssions on certain files/directories with the possibly hidden risks of poorly designed setuid software. For the record, the spooler I wrote was a shell script and we all know setuid shell scripts are either unsupported (sysV) or a security hole (BSD). This script emulates a "spool" command that runs on our Prime systems that can print to sites all over the grounds (campus). The spooler shell script puts files in a directory for a daemon to kermit (ugh!) to a Prime system for printing. The users of this system are all academic types who understand the risks, drawbacks (slowness), etc., but who nevertheless have successfully and happily printed their jobs with this Rube Goldberg monstrosity for the past two years. I admit that this system was cobbled up quite hastily, but we were expecting to get TCP/IP on the Primes real soon and well, uh, ... you know how these things go. -- Steve Losen scl@virginia.edu University of Virginia Academic Computing Center
hansen@pegasus.UUCP (Tony L. Hansen) (03/16/88)
< 3. Remove files from the directory. < < #3 can be absolutely prevented on BSD 4.3 systems by setting the sticky < bit (mode 1733) on the directory. This enhancement was also put into System V release 3.2. Also, the /tmp and /usr/tmp directories are shipped as mode 1777. This was just one of the modifications made in that release to make the UNIX System more secure. Tony Hansen ihnp4!pegasus!hansen, attmail!tony
jack@cwi.nl (Jack Jansen) (03/17/88)
Well, some things I check a set-uid program for (most of them
learned in the time I wasn't interested yet in writing secure
setuid program but in find bugs in setuid programs:-)
- Never take for granted that the user will not do this-or-that. She
will.
- Check, double-check and triple-check *each* library or system
call. Try to think of devious ways of making it do things it
shouldn't. Hints: think of IFS, links, symbolic links, running
in removed directories(!), environment variables in general,
job control, etc etc etc.
- Never take for granted that the user will not do this-or-that. He
will.
- Always be aware of the time-sharing aspect of unix. Never write
code like
if( stat(file, &sb) < 0 ) {
/* Now we're sure the file doesn't exist so it'll be owned
** by us.
*/
fd = creat(file, mode);
}
- Never take for granted that the user will not do this-or-that. She
will.
- Never think that setgid or setuid to bin is less dangerous than
setuid to root.
- Never take for granted that the user will not do this-or-that. He
will.
- Never allow interrupt routines, *not even with a signal catcher*
to clean up in a critical section. 'ulimit stacksize' can be
very useful at times..........
- The difficult one: never trust any other machine. Given control
over one machine on an ethernet, for instance, I can impersonate
*any* other machine by first crashing the original, trusted, machine
and then impersonating it.
And, of course, the general rule is not to write setuid programs
in the first place, but that has been handled by other people.
--
Jack Jansen, jack@cwi.nl (or jack@mcvax.uucp)
The shell is my oyster.
jc@heart-of-gold (John M Chambers x7780 1E342) (03/18/88)
> And, of course, the general rule is not to write setuid programs > in the first place, but that has been handled by other people. One question I have: To my knowledge, there does not actually exist a way to "write a setuid program". Yes, of course, I know how to type: chmod 6755 foo I claim that this does not constitute "writing a setuid program". What it does is take an existing non-setuid program (that is already written and compiled) and make it into a setuid program. But when the programmer wrote it, it wasn't setuid. Lest people think I am being facetious, I'd like to point out that there is an important point at work here. When writing a program, I don't know whether it will be setuid. So how can I follow the above advice? (Obviously, by not writing any programs! :-) When I write a line of code, how do I determine whether it is in a setuid program? There is one sense in which I could conceive of actually writing a setuid program. If there were a way to test at run time whether the program (well, actually the process, but you know what I mean) is setuid: if (setuid(getpid())) { <<Don't do a bunch of stuff>> } else { <<Go ahead and do them>> } Can anyone show me the source for setuid()? I suspect that you can't, but I'd like someone to explain how stupid I'm being and how easy it is. For a further argument, consider the alternative: #if SETUID <<Don't do a bunch of stuff>> #else <<Go ahead and do them>> #endif I contend that there is no way for the C preprocessor to correctly implement the above #if command. I'd be very interested in being proved incorrect.
matt@oddjob.UChicago.EDU (Schizophrenic Solipsist) (03/18/88)
jc@heart-of-gold (John M Chambers x7780 1E342) asks:
) If there were a way to test at run time whether the program (well,
) actually the process, but you know what I mean) is setuid:
)
) if (setuid(getpid())) {
) <<Don't do a bunch of stuff>>
) } else {
) <<Go ahead and do them>>
) }
)
) Can anyone show me the source for setuid()? I suspect that you can't,
) but I'd like someone to explain how stupid I'm being and how easy it is.
int
i_am_setuid()
{
return getuid() != geteuid();
}
/* I *think* it is done in SysV as it is in BSD. Amen. */
________________________________________________________
Matt University matt@oddjob.uchicago.edu
Crawford of Chicago {astrovax,ihnp4}!oddjob!matt
geoff@desint.UUCP (Geoff Kuenning) (03/18/88)
In article <8468@eddie.MIT.EDU> jbs@eddie.MIT.EDU (Jeff Siegal) writes: > Setting the directory mode to 777 by itself doesn't let anyone modify > or read anything. All it allows people do is: > > 1. List the file names in the directory > 2. Access files in the dirctory _according_to_their_modes. > 3. Remove files from the directory. You forgot one: 4. Create files in the directory. In practice, this allows modifying, though not reading, any file. Simply remove the original and replace it by your favorite Trojan horse. On System V (the system under discussion), you can even give the file away to the original owner and group. With the utime(2) call, you can even put in the original access and modification (though not i-node change) times. -- Geoff Kuenning geoff@ITcorp.com {uunet,trwrb}!desint!geoff
pdb@sei.cmu.edu (Patrick Barron) (03/19/88)
In article <127@heart-of-gold> jc@heart-of-gold (John M Chambers x7780 1E342) writes: >Lest people think I am being facetious, I'd like to point out that there >is an important point at work here. When writing a program, I don't know >whether it will be setuid. So how can I follow the above advice? (Obviously, >by not writing any programs! :-) When I write a line of code, how do I >determine whether it is in a setuid program? On the contrary, normally when one writes a program that is going to have the set-uid bit set, one knows that for a fact before starting. Taking random programs that you know little or nothing about, and making them set-uid, is an exceptionally bad idea. >Can anyone show me the source for setuid()? I suspect that you can't, No, I can't show you the source for setuid(), but only because my Ultrix license agreement prohibits it.... :-) Seriously, there really is a setuid() system call. It doesn't do what you want, though. --Pat.
gwyn@brl-smoke.ARPA (Doug Gwyn ) (03/20/88)
In article <3098@pegasus.UUCP> hansen@pegasus.UUCP (XT1554000-Tony L. Hansen;LZ 3B-315;6243) writes: >This enhancement was also put into System V release 3.2. Also, the /tmp and >/usr/tmp directories are shipped as mode 1777. This was just one of the >modifications made in that release to make the UNIX System more secure. How well does this work in practice? Due to the large number of utilities that fail to properly clean up their tmp files, often the system administrator ends up having to periodically clean out /tmp and /usr/tmp. With this new scheme, he'll have to become superuser to do this, unless a privileged operator-executable cleanup utility is provided (or the system is rebooted and does this on each reboot).
jc@minya.UUCP (John Chambers) (03/21/88)
> A much better approach would be to have a pseudo-user for for whatever > facility you were creating, and a _short_, _auditable_ setuid program, > without shell escapes and other similar nonsense, to deposit things in > the spool directory. A program that does exactly this was posted to one of the sources group a couple of years back, under the name "append.c". Perhaps it's time to post it again. Or is it archived in one or the source newsgroups? It was also a Unix implementation of a Multics security feature. It's also a good counter-example to the frequent claims that all setuid programs are Bad Things. -- John Chambers <{adelie,ima,maynard,mit-eddie}!minya!{jc,root}> (617/484-6393)
cudcv@daisy.warwick.ac.uk (Rob McMahon) (03/27/88)
In article <8468@eddie.MIT.EDU> jbs@eddie.MIT.EDU (Jeff Siegal) writes: |In article <7616@oberon.USC.EDU> blarson@skat.usc.edu (Bob Larson) writes: |>about setuid lp programs. |Setting the directory mode to 777 by itself doesn't let anyone modify |or read anything. All it allows people do is: | | 1. List the file names in the directory | 2. Access files in the dirctory _according_to_their_modes. | 3. Remove files from the directory. 4. Add files (or links) to the directory. If you're not careful Joe User can get files printed out which he has no read permission to by making links, symbolic links, into this directory. Rob -- UUCP: ...!mcvax!ukc!warwick!cudcv PHONE: +44 203 523037 JANET: cudcv@uk.ac.warwick.cu ARPA: cudcv@cu.warwick.ac.uk Rob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England