The 'Security Digest' Archives (TM)

Archive: About | Browse | Search | Contributions | Feedback
Site: Help | Index | Search | Contact | Notices | Changes

ARCHIVE: Unix 'Security Mailing List' - Archives (1984 - 1987)
DOCUMENT: Unix 'Security Mailing List' #11 1985-03-25 (1 file, 7705 bytes)
NOTICE: recognises the rights of all third-party works.


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.


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



			      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.

	* 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

	* 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

	* 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)

	  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"'),    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

	* 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.