A short tutorial on setuid/setgid file permissions http://neworder.box.sk/newsread.php?newsid=2380 I was writing a scanner to catalog setuid/setgid binaries and when I ran into trouble, I found a lack of information about set(u/g)id bits around. I think most *nix newbies will find the same lack of information, even in most file permission texts. This is a fairly important topic, because some distros are filled with negative permissions that you will need to fix. Hopefully after you read this you'll fully understand the positives and negatives of setuid. Setuid and setgid permissions are useful on binary files. They allow the program to with the file owner's permissions. This ordinary file for instance: [root@localhost setuid]# ls -l nmap -rwxrwxr-x 1 root root 223036 Jan 2 15:30 nmap [root@localhost setuid]# file nmap nmap: ELF 32-bit LSB executable, Intel 80386, version 1, dynamically linked (uses shared libs), stripped Most linux users should be famlliar with nmap. A standard user can't use most of the advanced options, as they require nmap to have root privlidges. So we don't screw up any old permissions make a copy of the nmap binary. Issue these commands as root: cp /usr/bin/nmap ~/uidnmap chmod 4776 ~/uidnmap The chmod set the setuid bit on the file. Now the permissions should look something like this: # ls -l nmap -rwsrwxr-x 1 root root 223036 Jan 2 15:30 nmap # file nmap nmap: setuid ELF 32-bit LSB executable, Intel 80386, version 1, dynamically linked (uses shared libs), stripped Notice the s in executable permission slot now. This copy of nmap will allow normal users to perform the 90% of nmap functions that require root. If there is a buffer overflow in nmap, it will also allow ordinary users to be able to execute whatever code they can imagine, as root. Which is why I recommend you DON'T set the setuid bit for convenience. But try it out, know what it does. Here is a full list of the permissions that can be set. ---s--s--t 7000 setuid, setgid, sticky ---s--s--- 6000 setuid, setgid ---s-----t 5000 setuid, sticky ---s------ 4000 setuid ------s--t 3000 setgid, sticky ---s------ 2000 setgid ---------t 1000 sticky ---------- 0000 none So to set a file as setuid, setgid and readable, writable and executable by all, you would type: chmod 6777 file The sticky bit is of no concern to this text but I'll include this explanation since it might have piqued your curiosity: { The ISVTX (the sticky bit) indicates to the system which executable files are shareable (the default) and the system maintains the program text of the files in the swap area. The sticky bit may only be set by the super user on shareable executable files. If the sticky bit is set on a directory means no other user can is set on a directory, an unprivileged user may not delete or rename files of other users in that directory. The sticky bit may be set by any user on a directory which the user owns or has appropriate permissions. } - From the NetBSD manpage. Back to the topic: Let's say G1bs0nH4c| shell with the webserver's permissions. Your don't run your webserver as root hopefully, so you're okay there. But he has access to the system, if only with a normal user's permissions. You're a lazy bum and don't like to type ./executable so you put . in your path. G1bs0nH4c| puts a bash script called 'ls' in some directory that makes a copy of bash, chmod 4777s it, then deletes itself. You think ls intermittently fudged up, and think nothing of it. Now he has root access to your system. Sure, you probably don't have a vulnerable cgi, or . in your path. But that's only one example. Root accounts look very suspicious in the /etc/password so a smart attacker won't rely on one to gain access each time. Much more reliable to make a user account and use a setuid shell to gain root privs. You can find all the setuid and setgid files on your system by issuing the command: /usr/bin/find / -user root -perm -4000 -o -perm -2000 Setuid programs have a wide range of consequences and powers. A world-readable, root-owned setuid /usr/bin/less would allow any user to read any file, not a good thing. If chown was set as setuid, anyone can do anything. That one file would allow what amounts to root access. Try to stay away from setting files as setuid, there are almost always better ways to accomplish your task. One bad use of setuid I've seen is in the RedHat distro and possibly others. The gnome games are setuid. Possibly so the games can write to the root-owned high score files, but normal users can't. A bad security breach to protect a high score file, ignorant. Some notes on setuid shells: bash -- must be run with the -p or --posix argument to accept it's own setuid permissions, otherwise it drops euid root. tcsh -- Will not run if it's setuid. ash -- Normal. pdksh-- Normal. sash -- Normal. If your changing permission on system files, you should make backups or notes so you don't forget the good permissions. Don't forget to delete or unset anything you've set as setuid to test it. Leaving setuid shells around is not a good practice. Following is a shell script I wrote to catalog setuid/setgid files and compare it with that catalog on future scans. It's fairly complete, only a few things need fixing. The part which mails differences in the catalog and current setuid programs is not there. Also, it uses diff to figure out what has been added removed. I can't figure out a decently easy way to remove the hexcodes diff uses to show where in the file the differences are. The log file could use a facelift as well. If you fix any of those things email me the fixes at volatile@phreaker.net. Feel free to email me to ask questions about anything in this document. Have Fun. ------------------------------------------------------------------------------------ #!/bin/bash #Written by volatile(volatile@phreaker.net) #Catalogs setgid/setuid programs and catalogs them for comparison in future scans. #Copyright (C) 2002 Patrick Jordan #This program is free software; you can redistribute it and/or modify #it under the terms of the GNU General Public License as published by #the Free Software Foundation; either version 2 of the License, or #(at your option) any later version. #This program is distributed in the hope that it will be useful, #but WITHOUT ANY WARRANTY; without even the implied warranty of #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #GNU General Public License for more details. #You should have received a copy of the GNU General Public License #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #Run Options: #Run with no options- On the first run it will make a new catalog # of setuid/setgid programs on your system, subsequent runs will # compare current setuid/setgid programs with the catalog. #Run with 'scan' option to repress any catalogging or comparisons. #Run with 'makecatalog' option to force it to make a new catalog. #Config: #Set directories for catalogs/system logs/temporary files here. #Directory for log. logdir="/var/log" #catalogue directory. siddir="/etc" #Temporary file directory. tmpdir="/var/tmp" if [ "$1" = "scan" ]; then echo -e "\\033[1;32mScanning for setuid/setgid programs and exiting.\\033[0;39m" /usr/bin/find / \( -perm -4000 -o -perm -2000 \) exit fi if [ "$1" = "makecatalog" ]; then echo -e "\\033[1;32mWriting a new setuid/setgid program catalog.\\033[0;39m" /usr/bin/find / \( -perm -4000 -o -perm -2000 \) > $siddir/sids exit fi if [ -f $siddir/sids ]; then echo -e "\\033[1;32mScanning for added/removed setuid programs.\\033[0;39m" /usr/bin/find / \( -perm -4000 -o -perm -2000 \) > $tmpdir/sidsnow.temp sidsbefore="$siddir/sids" sidsnow="$tmpdir/sidsnow.temp" if diff $sidsnow $sidsbefore >> $tmpdir/sidsnew.temp; then echo -e "\\033[1;32mNo new setuid program(s) found.\\033[0;39m" rm $tmpdir/sidsnow.temp exit else #Write Changes to log: echo -e "\\033[1;31mAlert: new setuid program(s) found.\\033[0;39m" date=$(date) echo "" >> $logdir/sids.log echo "" >> $logidr/sids.log echo $date >> $logdir/sids.log echo "Setuid program changes found." >> $logdir/sids.log echo "" >> $logdir/sids.log sed 's/ $tmpdir/sidsformat.temp sed 's/> /Removed: /' $tmpdir/sidsformat.temp > $tmpdir/sidsnew.temp sidsnew=`cat $tmpdir/sidsnew.temp` echo "$sidsnew" >> $logdir/sids.log #Write changes to stdout: echo "$sidsnew" echo "" echo "If this is okay add/remove the entry to $siddir/sids, or delete $siddir/sids and rerun sidscan." echo "" #Mail changes to root: #FIXME -- #Delete temp files: rm -f $/sidsnow.temp rm -f $tmpdir/sidsnew.temp rm -f $tmpdir/sidsformat.temp exit fi else echo -e "\\033[1;31mNotice: /etc/sids not found writing new one.\\033[0;39m" /usr/bin/find / \( -perm -4000 -o -perm -2000 \) > $siddir/sids chmod 660 $siddir/sids touch $logdir/sids.log chmod 660 $logdir/sids.log echo -e "\\033[1;32mCatalog written to $siddir/sids.\\033[0;39m" exit fi exit