Subject: Security Mailing List, # 11 Date: 25 Mar 85 21:41:50 MST (Mon) Date: 20 Mar 85 00:15:48 CST (Wed) From: ihnp4!ucla-cs!lcc!jbrown Subject: SUID shell scripts There has been some discussion of the bugs in SUID shell scripts lately, and a bug fix has been suggested. Unfortunately, this fix addresses only one of the bugs. There are quite a number of "interesting" behaviors related to files whose names begin with a dash. I will attempt to list them and their effects and causes. I list possible cures for these problems, but am almost convinced that suid shell scripts can never be proven secure because of the incredible number of possible holes. Cases and effects: (tested under 4.1 and 4.2) execl call first line args to sh action(s) following assume a shell script called "-" "-","-",0 #! /bin/sh - - executes ./.profile goes interactive. "-","-",0 #! /bin/sh - - - - executes ./.profile executes ./- "-","/bin/sh",0 #! /bin/sh /bin/sh - goes interactive. "-","/bin/sh",0 #! /bin/sh - /bin/sh - - executes ./.profile executes ./- "-","-",0 #! /bin/csh - - executes $HOME/.cshrc executes $HOME/.login goes interactive. executes $HOME/.logout "-","-",0 #! /bin/csh -f - -f - goes interactive. executes $HOME/.logout "-","/bin/csh",0 #! /bin/csh /bin/csh - executes $HOME/.cshrc goes interactive "-","/bin/csh",0 #! /bin/csh -f /bin/csh -f - goes interactive following assume a shell script called "x" "x","-",0 #! /bin/sh - x executes ./x "x","-",0 #! /bin/sh - - - x executes ./x "x","/bin/sh",0 #! /bin/sh /bin/sh x executes ./x "x","/bin/sh",0 #! /bin/sh - /bin/sh - x executes ./x "x","-",0 #! /bin/csh - x executes $HOME/.cshrc executes $HOME/.login executes ./x executes $HOME/.logout "x","-",0 #! /bin/csh -f - -f x executes ./x executes $HOME/.logout "x","/bin/csh",0 #! /bin/csh /bin/csh x executes $HOME/.cshrc executes ./x "x","/bin/csh",0 #! /bin/csh -f /bin/csh -f x executes ./x OK, (whew) that's the possibilities I know of, and their effects. Now to explain their causes: 1) In sh, if the first argument after throwing away options begins with a dash, it executes ./.profile. If, after throwing away options, there are no arguments left, argv[0] will be examined. 2) In both shells, '-' is a perfectly good OPTION, and will get thrown away. However, in sh only argv[1] can be options, and so further dashes are file names. In csh, all arguments beginning with dash are OPTIONS. 3) In both shells, if they are left with no arguments after discarding options, they run interactive. 4) In csh, if there is no -f then $HOME/.cshrc is executed. 5) In csh, if argv[0] begins with a dash and there is no -f then $HOME/.login is executed. 6) In csh, if argv[0] begins with a dash then after all other actions $HOME/.logout is executed. Possible cures (but see conclusions): 1) don't execute *any* of the special files (.profile, .cshrc, .login, .logout) if uid!=euid or gid!=egid. 2) don't allow input from stdin if uid!=euid or gid!=egid. Conclusion: At first, I thought that a few simple fixes to the kernel and the shells would fix these problems. However, I believe I have realized the error of my ways. The incredible number of holes I've found just examining this set of behaviors plus the other holes people have mentioned (IFS, PATH, etc) make me believe that the existing shells are simply insecure. I would suggest that somebody write a simple, stupid, SECURE shell for use in suid shell scripts. Of course, it would still be tough to write TRULY secure scripts, much as it is difficult to write secure suid programs in general. ---------------------------------------------------------------------------- Date: 25 Mar 85 10:53:19 CST (Mon) From: ihnp4!hpfcla!ajs Subject: known security holes KNOWN SECURITY HOLES ON UNIX SYSTEMS HP CONFIDENTIAL! LAST UPDATED 850312 List collected by Alan Silverstein. All security problems listed are correctable on site unless noted with "S" (sensitive) in the left margin. (In "sanitized" versions of this list, all such lines are removed.) If this list is incomplete, please send me additions or corrections. This is a "sanitized" list, also generalized from HPUX to generic UNIX. BASIC PRINCIPLES OF GOOD SECURITY: * Physical control of equipment. * Management committment to security. * Employee education on what is expected of them. * Administrative procedures designed to increase security. * Concealment alone is not security. * Better to know you are not secure, than falsely think you are. * HARDWARE: Anyone who can connect the root disc to another system and mount it can break security. Anyone who can mount a personal volume on the local system can do the same. If init state 1 starts any shells without going through login, anyone who reboots the system can be super-user. Solution: Physical security, no removable mass storage volumes (or protected mount(1) command), and an init state 1 which requires login. * FILE SYSTEM: Sloppy ownerships/permissions are a common problem, particularly on special files. Solutions: Be sure the filesystem is generally secure. Special files like /dev/mem, /dev/kmem, and /dev/rhd should not even be readable except by super-user. Use a default umask of 022 (see sh(1)) so new files are not writable except by the owner. * ROOT DIRECTORY: It must be 555 (unwritable), owned by root. If unprotected, any user can move /etc and create their own /etc/passwd file (and so on). Solution: Protect root directory. Comment: Pre-4.0 versions of sdfinit(8) (Series 500 only) left new volumes set to 777. It's necessary to do "ls -ld /" to check this. * PUBLIC DIRECTORIES: In general, most of them must be owned by root, other, and set to be unwritable. In particular /etc, /usr, /usr/lib, and the super-user's login directory are sensitive due to system config and .profile files there. Solution: Deny write access to public directories except where the need exists (such as /tmp). * CONFIGURATION FILES: Certain files must be owned by root (or package owners, like news or lp) and unwritable by the public, including /etc/inittab, /etc/rc, /etc/passwd, /etc/group, /etc/profile, /usr/lib/crontab, and the super-user's .profile. Solution: Deny access to sensitive files except where the need exists. * COMMAND PATHS: Shell scripts, and programs which use exec(2), may be violated by Trojan horses when run by the super-user or other users. In particular, a user might call a setuid program with a bogus PATH variable exported. Solution: All shell scripts and certain programs should set their own PATH before running any commands, or use explicit (absolute) paths, and/or require that they themselves are invoked using absolute paths (like /bin/su). * PRIVILEGED-USER PATHS: If the super-user's (or any user's) PATH variable includes "." or a null field (for "current directory"), and the user changes to a non-secure directory, he might unknowingly run a Trojan horse program named the same as a standard command. This program might create a setuid/setgid shell and then remove itself. Solutions: Avoid "current directory" in $PATH. Some commands should require that they be in invoked with absolute paths. Keep the file system sufficiently secure that non-privileged users cannot plant Trojan horses in libraries or commands. Comment: One possibility is to have the shell check the ownership of files before running them. If a command is found in a directory in PATH which does not start with "/", and if it is not owned by the user who is trying to run it, give an error (forcing the user to type "./" to run it). * SETUID (SUID) COMMANDS: Programs owned by root (or a privileged group) and set to run as super-user (or other users or groups) can lead to trouble by allowing shell escape to privileged shells, appending to protected files, dumping writable, setuid core files, etc. In particular, mount(1) is dangerous to set to 4555 if the system has a removable mass storage device, as users can mount volumes containing super-user shells. Solution: Minimize use of setuid/setgid. Deny access to setuid/setgid programs except where the need exists and the program has been checked for holes. Be sure all setuid/setgid commands are not writable. Be able to account for all setuid/setgid programs on the system (and/or check for them periodically). Programs must do setuid(getuid()) and setgid(getgid()) before doing a shell escape. Chown(2) must turn off set bits when ownership is changed. * SETUID (SUID) SCRIPTS: Files which begin with "#! command", for direct execution of command by exec(2), and which are setuid or setgid, may be tricked through unforeseen side effects of running "command". For example, if the script is a readable shell script ("#! /bin/sh"), it can be linked by anyone to a file named "-sh", or merely exec'd with an arg1 of "-sh". The shell runs setuid, but the leading "-" in the name causes it to read /etc/profile, and (worse) the user's .profile, when starting up. (On BSD4.2, if the name is "-", you get an interactive prompt.) Solutions: Disallow setuid/setgid script execution by exec(2), or disallow linking to such files (is this sufficient?), or modify all potentially scripted commands to avoid this problem. (Note: Only commands which understand "#"-style comments are even candidates for scripting.) * TERMINAL ACCESS: An unattended, logged-in terminal is asking for trouble. A terminal whose special file is readable by other users is subject to having data stolen. Solutions: Log out or lock (using internal command lock(1)) any terminal not in use. Do not make your terminal's special file readable by the public. * "PARKED" TROJAN HORSES: In addition to libraries or commands left in a file system where a privileged user/group might accidentally use them, pirates can leave programs running on "idle" terminals which simulate login, su, or other commands. Solution: Don't trust an idle terminal. Especially, don't fall for an obvious swindle, such as "Login incorrect" or "}ls: not found" when you think you did not mistype. Be sure the login command in particular is not generally executable, so login emulators must "fail login". * DIAL-IN ACCESS: Dial-in lines are potential holes. Solutions: Keep phone numbers as private as possible. Set getty to hang up in a short time. Add "external security" passwords to getty (rewrite it). Limit logins on external lines by using /etc/securetty. Use new logging features of login(1). * ALL USERS HAVE PASSWORDS: Any user without a password is subject to having another user login or su to their identity. Solution: Insure that all users have passwords, even pseudo-users like "who" and "sync", just in case su -c allows dangerous actions. If necessary, put "*" in the password field in /etc/passwd to make it impossible to login or su to that user. Or, deny access to the su command. * ALL GROUPS ARE SECURE: The newgrp command allows changing group identity in a manner similar to su, except that if a group has no password, only users in the group's list can newgrp to it. Solution: Insure that all groups have correct user lists, and/or all groups have dummy ("*") or real passwords, and/or disable the newgrp command. (Putting a real password on a group opens it up to anyone, which can actually reduce security.) * GOOD PASSWORDS USED: Bad passwords can lead to easy violation of security. Solutions: Don't use permutations of username, nor people's real names, nor easy-to-guess personal data. Use long passwords not in any dictionary; mix in uppercase, digits, and other characters. Don't re-use old passwords. Change passwords periodically. Educate system users. Also, do not disable accounts after N bad login attempts; this just makes it easier for pirates to lock out system administrators. Comments: System V.2 passwd(1) improves the situation. Do NOT use the password timeout facility (see passwd(1)) because (1) it leads to fast selection of bad passwords, (2) it leaves users unable to change again fast, (3) users still only need to have two different passwords, and (4) pirates can easily find abandoned accounts. * HIDE PASSWORDS: Pirates are at an advantage if they can copy your password file and it contains valid (encrypted) passwords. Solutions: Make it impossible to copy it with uucp. Keep real passwords in a different file and put fake ones in /etc/passwd (but this requires changes to many system libraries and commands, so probably should not be attempted on-site; it should be standardized). * RSH: Restricted shells are impossible to do completely right. Solution: Use them as a deterrent on accounts where needed but do not depend on them alone to guarantee security. * CHROOT: The chroot(1) command and chroot(2) system call are normally executable by super-user only. If an ordinary user could chroot to a sub-file-system, they could create a small directory structure with a dummy /etc/passwd, make a copy of /bin/su and /bin/sh therein, chroot, su, then make the copy of sh setuid to super-user for later use. Solution: Restrict access to the chroot command. Make all setuid/setgid programs, such as su, unreadable (which does not, unfortunately, prevent linking to them). * CRONTAB: The path to /usr/lib/crontab must be secure, and the file itself, plus all parts of the paths to all files it invokes, including the files themselves, plus all files they in turn invoke. All such files (scripts or programs) are run by cron as super-user, so they must not be replaceable by Trojan horses. Solutions: Check crontab very carefully on occasion. Keep it unreadable by the public. Use su -c (and/or newgrp) in crontab before running commands (e.g. 'exec su news -c "exec notedemon.day"'), so as to minimize processes run automatically as root, or do not run cron at all (unlikely). Comment: A shell script (cronck) exists which helps do a limited check on crontab. * AT(1) COMMAND: The at command is easy to violate by doing chmod to super-user on a spooled shell script. The atrun demon then runs the script as its owner. Solution: It's possible to protect /usr/spool/at to be unwritable, and setuid the at and atrun commands, but this may not be sufficient. Or, don't run atrun from crontab, e.g. disable the at(1) facility. Comment: System V.2 at(1) corrects this. * MAILERS: Mailers, and other programs which can save files, might let users modify /etc/passwd by appending to it, especially if they run setuid/setgid. Also, some mailers have a bad habit of prepending a "From" line containing the name of the process owner, who is an innocent bystander, to mail passing through the system, thus revealing the name of at least one user on the system. Also, some mailers use LOGNAME as the name of the sender. Solutions: Such programs must not modify non-owned files. Avoid running such programs setuid/setgid if possible. Keep sensitive files protected. Don't reveal random usernames in mailer programs, and don't use LOGNAME. * CRYPT COMMAND/LIBRARY: The encryption used is not as hard to break as once thought (see the Bell System Technical Journal, Volume 63, Number 8, Part 2). Solutions: Do not leave any cleartext around; it helps break the key if found. Don't use same the key as your password. Simple double-crypting or pre-ORing with patterns don't help; packing or otherwise re-distributing the data does. * UUCP CONFIGURATION: Most files in /usr/spool/uucp are publicly readable by default. If uucp owns certain other files, such as demons, and the uucp password is well known, users can use su -c to mess with the demons. The COMMANDS and USERFILE files must be properly constructed. The L.sys file contains private information like phone numbers. DIALLOG contains phone numbers. Solutions: Hide (protect) /usr/spool/uucp if necessary, to keep mail and other transactions secret and avoid changes to them. Have all uucp logins be for users other than uucp (such as remote system names) so people knowing those passwords can't dork with uucp-owned files, and keep the uucp password itself a secret. Insure that COMMANDS and USERFILE are protected (including the path to them), and that they are conservative (limit access except as required). Insure that L.sys is owned by uucp and not generally readable. By default DIALLOG is protected; no action is necessary. * BTMP AND SULOG FILES: If these files exist, login(1) and su(1), respectively, use them to log failed login attempts and all su attempts. Only usernames are logged in btmp, not passwords, but on occasion a user might type their password in to the login prompt. Also, sulog can help a pirate found out who system administrators are. Solution: Be sure /usr/adm/btmp and /usr/adm/sulog are only readable/writable by the super-user, and the path to them is secure. Long-term, perhaps login(1) and su(1) should chmod the file if necessary. (Note that smart pirates will never use su themselves, anyway.) * DATA NOT ENCRYPTED: Sensitive data lives on a disc shared with other files and other people. File system problems can (in the worst case) make such data public. Solution: Encrypt sensitive data, or keep it on private media. * USE QUOTED HERE DOCUMENTS: Unquoted shell "here" documents (see sh(1)) can cause trouble. For example, if the line "rm -r $x/dir" appears, but $x is not set until the script is executed, the file system could be injured. Solution: Quote all here documents, especially those which are shell scripts or at(1) input, unless there is a good reason not to so do.