COMMAND

    Angel and Autobuse

SYSTEMS AFFECTED

    Those using vulnerable versions

PROBLEM

    John  Daniele  decided  to  play  around  with a couple of network
    management  tools  on   securityfocus.com;  Angel  and   Autobuse.
    Unfortunately, upon review of the source, he noticed a bad  trend.
    Both  tools   handle  temporary   files  insecurely.   The l0pht's
    tempwatch tool is useful in rooting out such problems:

        http://www.l0pht.com/advisories/watch.txt

    (or /usr/ports/security/tempwatch on OpenBSD)...

    For example, in Autobuse's main perl script, line 96:

        if(!$test_run) {
                open OUT, ">/tmp/autobuse_report.$$"
                        or die "can't open /tmp/autobuse_report.$$";
                select OUT;
        }

    Simple symlink attack: make a link from a file that is writable to
    the user running the script to /tmp/autobuse_report.$$ (just brute
    force the .$$ part) to overwrite the linked file.  Since a lot  of
    users  will  be  putting  network  managements  scripts  in root's
    crontab, this poses a significant risk to security.

    Variation of the same story in Angel.pl, line 504:

	 sub timeexec
        {
                ...
                my($tempfile) = "/tmp/timeexec.$$";
                $myproc = Proc::Simple->new();
                $myproc->start("$cmd >$tempfile 2>&1");
                ...
                open (CDTEMP, "$tempfile") || return (-1, ());
                ...

    The  subroutine  timeexec()  is  called  by Angel's Check_ping.pl,
    Check_load.pl and Check_disk.pl plugin scripts like this:

        ($ret, @output) = timeexec($Default_tries, $Default_timeout, $rcmdline);

    John  looked   around  for   some  more   perl/shell  scripts   on
    securityfocus  that   exhibited  the   same  problem   and   found
    confcollect:

        #!/bin/sh
        VERSION=0.1d
        COPYRIGHT='1999 Eddie Olsson <ewt@skagelund.com>'
        PATH=$PATH:/sbin
        # Ls instllningar i filen /etc/confcollect.conf
        [ -f /etc/confcollect.conf ] || exit 1
        . /etc/confcollect.conf
        CFILENAME=`hostname`.`date +"%Y%m%d"`.confcollect.tar.gz
        ...
        tar zcf /tmp/$CFILENAME /etc 2>/dev/null

    John also noticed  a vulnerable example  script on my  slack 7 box
    at  /usr/lib/m4-examples/stackovf.sh  (yeah,  yeah,  who  is silly
    enough to run this stuff as r00t?)

        #!/bin/sh
        ...
        tmpfile=/tmp/t.$$
        trap `rm -f $tmpfile; exit 1' 1 2 3 15
        ...
        $M4 -L999999999 > $tmpfile 2>&1

    OH! OH! and a really cool program that a number of ppl run  called
    root-portal contains  a number  of scripts  afflicted by  the same
    bug:

        #!/bin/sh
        cd /tmp
        ...
        if test "${more_recent}" = "${half_hour_ago}"
        then
                mv -f recentnews.txt recentnews.txt.old > /dev/null
                wget -q http://freshmeat.net/backend/recentnews.txt
                if test ! -f /tmp/recentnews.txt
                then
                        mv -f recentnews.txt.old recentnews.txt > /dev/null
                fi
                chmod a+rw recentnews.txt
                date '+%Y%j%H%M' > /tmp/freshmeat_read.timestamp
                chmod a+rw freshmeat_read.timestamp
        fi

    Heh, forgot to  mv freshmeat_read.timestamp too  eh?  Nice  way to
    make certain files world writable!

SOLUTION

    Rule of thumb:

    - Create a more secure storage directory for your temporary files.
      mkdir /home/blah; chmod 600 /home/blah
    - Allow the user to easily customize this directory:

        $SECUREDIR = /home/blah

    - Check  for the  existence of  your temporary  file before you do
      anything with it:

        $SECUREDIR=/home/blah
        $tmpfile=$SECUREDIR/t.$$
        if [ -e $tmpfile ]; then
                echo -e "ERROR! : temporary file exists, erasing!\r\n"; rm -rf
        $tmpfile
        fi

    -  you still have an  exploitable race here.  A better  way around
       this  (esp.  for  program  with  many  tmp  files)  is to use a
       temporary  directory  instead,  as  in  OpenBSD's /etc/security
       script:

        umask 077
        DIR=/tmp/_secure$$
        TMP1=$DIR/_secure2
        TMP2=$DIR/_secure3

        if ! mkdir $DIR ; then
                printf "tmp directory %s already exists, looks like:\n" $DIR
                ls -alF $DIR
                exit 1
        fi

        trap 'rm -rf $DIR; exit 1' 0 1 2 3 13 15

    or if  you're using  OpenBSD, use  the mktemp(1)  program in  your
    scripts:

        http://www.openbsd.org/cgi-bin/man.cgi?query=mktemp

    - If necessary, ensure that the file is not a symlink:

        if( -l $tmpfile ); then ...

    Autobuse is fixed, partly, in autobuse version snap949125599,  and
    more so in today's snap949380617, which uses this mktemp function:

        sub get_tmpfile {
            my $file;
            do {
            open RAN, "/dev/random" || die;
            read(RAN,$foo,16);
            close RAN;
            $file = '/tmp/autobuse' . unpack('H16',$foo);
            } while (-e $file || -l $file);
        
            return $file;
        }

    This method  is Linux-specific,  but that's  all ppl  need mostly.
    The fixed autobuse is available at

        http://www.picante.com/~gtaylor/autobuse/