COMMAND

    default cron jobs (/etc/security & /etc/daily)

SYSTEM AFFECTED

    4.4BSDlite2, OpenBSD 2.0, FreeBSD 2.1.5, BSD O/S 2.0, NetBSD 1.2

PROBLEM

    The 4.4BSDlite2 version of /etc/security passes unchecked data  to
    a shell.   These bugs make  it possible for  unpriviliged users to
    obtain root access,  EVEN IF THERE  ARE NO SETUID  PROGRAMS ON THE
    SYSTEM.

    The first problem with  /etc/security is that it  passes unchecked
    data to a  shell.  If  a user creates  a file whose  name contains
    shell  metacharacters   and  makes   it  executable   and  setuid,
    /etc/security will gladly execute  commands specified in the  name
    of the file  as root.   The problem is  the big find  line used to
    search for setuid files, which in 4.4BSDlite2 reads:

(find / ! -fstype local -a -prune -o \
    \( -perm -u+s -o -perm -g+s -o ! -type d -a ! -type f -a ! -type l -a \
       ! -type s \) | \
sort | sed -e 's/^/ls -ldgT /' | sh > $LIST) 2> $OUTPUT

    The second problem with /etc/security is its poor use of temporary
    files.   In  4.4BSDLite2  /etc/security  uses  six temporary files
    unsafely.   They  are  all  named  /tmp/_secure?.$$,  where ? is a
    number in  the range  1 through  6, and  $$ is  replaced with  the
    process id of  the shell interpreting  /etc/security at run  time.
    A malicious user  needs merely to  run an at  job a minute  before
    /etc/security which creates  symlinks named /tmp/_secure?.$$,  and
    wait for the  cron job to  overwrite the file  of his choice.   In
    addition, the user has much  control over the contents of  some of
    these temporary files, allowing users to obtain root access.

    Similarly,  the  /etc/daily  script  search  for  core files to be
    deleted  can  be  induced  to  corrupt  arbitrary  files, and even
    create valid .rhosts files.  By creating files with names like:

        + + #.core

    and leaving an appropriate symbolic link in /tmp, users can obtain
    root priviliges.

SOLUTION

    The version of /etc/security in OpenBSD 2.0 appears safe, as  does
    the version of /etc/daily  in OpenBSD-current.  On  most operating
    systems,  mkdir  is  both  atomic,  and  does  not follow symbolic
    links.  Therefore it  is possible to use  mkdir in a shell  script
    to write portable and secure code.

# A viable /etc/security, which requires OpenBSD or GNU
# find and xargs.
# note that this version lacks features found in the 4.4Lite2
# /etc/security.
#------------------------- cut here -----------------------------


#!/bin/sh
#
PATH=/sbin:/bin:/usr/bin
LC_ALL=C; export LC_ALL

host=`hostname -s`
echo "Subject: $host security check output"

LOG=/var/log
umask 077
TDIR=/tmp/_secure.$$
if ! mkdir $TDIR ; then
        echo $TDIR already exists
        ls -alF $TDIR
        exit 1
fi

TMP=$TDIR/secure
trap 'rm -rf $TDIR' 0 1 2 3 4 5 6 7 8 10 11 12 13 14 15

echo "checking setuid files and devices:"

        find / -fstype local -and -type f -and \
               \( -perm 4000 -or -perm 2000 \) -print0 | sort  \
                | xargs -0 ls -lgTd > $TMP

if [ ! -f $LOG/setuid.today ] ; then
        echo "no $LOG/setuid.today"
        cp $TMP $LOG/setuid.today
fi
if cmp $LOG/setuid.today $TMP >/dev/null; then :; else
        echo "$host setuid diffs:"
        diff -b $LOG/setuid.today $TMP
        mv $LOG/setuid.today $LOG/setuid.yesterday
        mv $TMP $LOG/setuid.today
fi
rm -f $TMP


#------------------------- cut here -----------------------------
# A viable /etc/daily based around the OpenBSD one:
#------------------------- cut here -----------------------------


#!/bin/sh -
PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local
host=`hostname -s`
echo "Subject: $host daily run output"

if [ -f /etc/daily.local ];then
        echo ""
        echo "Running daily.local:"
        . /etc/daily.local
fi

UMASK=`umask`
umask 077

TDIR=/tmp/_daily.$$
if ! mkdir $TDIR ; then
  echo $TDIR already exists
  echo ls -ldgT $TDIR
  exit 1
fi
umask $UMASK

TMP=$TDIR/daily

trap 'rm -rf $TDIR' 0 1 2 3 4 5 6 7 8 10 11 12 13 14 15

echo ""
echo "NOT Removing scratch and junk files."

find / \( ! -fstype local -o -fstype rdonly -o -fstype fdesc \
     -o -fstype kernfs -o -fstype procfs \) -a -prune -o \
     -name 'lost+found' -a -prune -o \
     -name '*.core' -a -print > $TMP

if egrep -q '\.core$' $TMP; then
    echo ""
    echo "Possible core dumps:"
    egrep '\.core$' $TMP

fi

msgs -c

if [ -f /etc/news.expire ]; then
     /etc/news.expire
fi

if [ -f /var/account/acct ]; then
     echo "" ;
     echo "Purging accounting records:" ;
     mv /var/account/acct.2 /var/account/acct.3 ;
     mv /var/account/acct.1 /var/account/acct.2 ;
     mv /var/account/acct.0 /var/account/acct.1 ;
     cp /var/account/acct /var/account/acct.0 ;
     sa -sq ;
fi

echo ""
if [ -d /var/yp/binding -a ! -d /var/yp/`domainname` ]; then
     echo "Not running calendar, (yp client)."
else
     echo "Running calendar."
     calendar -a
fi

# Rotation of mail log now handled automatically by cron and 'newsyslog'

if [ -d /var/spool/uucp -a -f /etc/uuclean.daily ]; then
     echo ""
     echo "Cleaning up UUCP:"
     echo /etc/uuclean.daily | su daemon
fi

echo ""
echo "Checking subsystem status:"
echo ""
echo "disks:"
df -k
echo ""
dump W
echo ""

mailq > $TMP
if ! grep -q "^Mail queue is empty$" $TMP; then
     echo ""
     echo "mail:"
     cat $TMP
fi

if [ -d /var/spool/uucp ]; then
     uustat -a > $TMP
     if [ -s $TMP ]; then
         echo ""
         echo "uucp:"
         cat $TMP
     fi
fi

echo ""
echo "network:"
netstat -i
echo ""

t=/var/rwho/*
if [ "$t" != '/var/rwho/*' ]; then
     ruptime
fi

echo ""
echo "NOT checking filesystems."
#echo "Checking filesystems:"
#fsck -n | grep -v '^\*\* Phase'

echo ""
if [ -f /etc/Distfile ]; then
     echo "Running rdist:"
     rdist -f /etc/Distfile
fi

sh /etc/security 2>&1 | mail -s "$host daily insecurity output" root
#------------------------- cut here -----------------------------