#!/bin/sh #====================================================================== # Copyright: (c) 1999 Paul Wilson # Name: SetUp.sh # Date: 17 November 1999 # Author: Paul Wilson # Parameters: # 1 setup [ optional ] # Description: # This is an integrity checker intended for UNIX/Linux systems. With minor # mods, it could become a light-weight tripwire replacement. It produces # lists of files which match specific criteria : # # suid files # sgid files # files with no recognisd user or group # world writable files and directories # writable executables # md5 checksums for a list of files # # The truely paranoid can run this from a CD which would have protected # versions of any files which 'must not' be changed. If you choose this # approach, remember to include not just this script, but the shell, md5sum # and copies of all the utilities that get called. Eventually I'll get round # to doing a proper README for a CD version. # # It runs in one of two modes, setup or check : # # SetUp setup # Give the script a parameter and it creates the lists which will later # be used to check against. # # SetUp # Without parameters the script produces a new set of files which then # get compared against the original lists. Differences are logged. # Maintenance: # 0.2 19991117 hooker First release #====================================================================== Version=0.2 export PATH=/bin:/usr/bin:/usr/local/bin LOGDIR=/var/log/local BaseDir=/production/.Security CheckDir=${BaseDir}/.Check DataDir=${BaseDir}/.Data ReportDir=${BaseDir}/.Reports Error=0 Warning=0 tmpfile1=/tmp/tmp.s.1 tmpfile2=/tmp/tmp.s.2 if [ $# = "0" ];then Mode=Check cd ${CheckDir} md5File=${CheckDir}/md5.list rm -f * 2>/dev/null else Mode=SetUp cd ${DataDir} md5File=${DataDir}/md5.list fi #---------------------------------------------------------------------- # Compare $File $Type $SeverityLevel: # Given a sngle file name, compare the master copy against the copy # just produced, and itemise any differences. # # SeverityLevel = 0 => Ignore # SeverityLevel = 1 => Warning # SeverityLevel = 2 => Error # Compare () { File=$1 Msg=$2 SeverityLevel=$3 diff ${DataDir}/${File} ${CheckDir}/${File} > ${tmpfile1} rc=$? if [ "${rc}" = "0" ];then echo " ${Msg} list OK" >> ${ReportFile} else echo " ${Msg} list changed :" >> ${ReportFile} echo " Missing .." >> ${ReportFile} grep "^< " ${tmpfile1} | awk '{ print " " $2 }' >> ${ReportFile} echo " New .." >> ${ReportFile} grep "^> " ${tmpfile1} | awk '{ print " " $2 }' >> ${ReportFile} case "${SeverityLevel}" in "1") $((Warning = Warning + 1)) 2>/dev/null ;; "2") $((Error = Error + 1)) 2>/dev/null ;; "*") ;; esac fi } #---------------------------------------------------------------------- # Specifically check the MD5 list (differences are always critical) # CompareMD5 ( ) { OList=${DataDir}/md5.list NList=${CheckDir}/md5.list diff ${OList} ${NList} > ${tmpfile1} rc=$? if [ "${rc}" = "0" ];then echo " MD5 finger prints OK" >> ${ReportFile} else echo " MD5 finger prints list changed :" >> ${ReportFile} $((Error = Error + 1)) 2>/dev/null ChangeList='' DeleteList='' NewList='' grep "^[<>]" ${tmpfile1} | awk '{ print $3 }' | sort -u > ${tmpfile2} name=zz cat ${tmpfile2} | while [ -n "${name}" ];do read name if [ -n "${name}" ];then Orec=`grep ${name} ${OList}` Nrec=`grep ${name} ${NList}` if [ -n "${Orec}" -a -n "${Nrec}" ];then ChangeList=${ChangeList}:${name} else if [ -n "${Orec}" ];then DeleteList=${DeleteList}:${name} else NewList=${NewList}:${name} fi fi fi done ShowChanges "${ChangeList}" "Changes to the fingerprint" ShowChanges "${DeleteList}" "No longer in list" ShowChanges "${NewList}" "New files" fi } #---------------------------------------------------------------------- # LOGMSG # Write a message with a standard prefix to a known file. # LOGMSG () { Msg='' while [ "$#" != "0" ];do Msg="${Msg} $1" shift done if [ -n "${Msg}" ];then LogFile=${LOGDIR}`date +%Y%m` dt=`date +%Y%m%d.%H%M%S` echo "${dt} ${Msg}" >> ${LogFile} fi } #---------------------------------------------------------------------- # ShowChanges $List $Msg # List contents of one of the MD5 changes lists # ShowChanges () { List=$1: Msg=$2 if [ -n "${List}" ];then echo " ${Msg} :" >> ${ReportFile} Item=zz echo ${List} | sed -e 's/:/ /g' | while [ -n "${Item}" ];do read Item if [ -n "${Item}" ];then echo " ${Item}" >> ${ReportFile} fi done else echo " ${Msg} unchanged" >> ${ReportFile} fi } #====================================================================== #\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ #====================================================================== # Start the checks .. # # SUID list find / -perm -4000 -print >suid.list 2>/dev/null # SGID list find / -perm -2000 -print >sgid.list 2>/dev/null # no recognised user or group find / -nouser -o -nogroup -print >no.user.group 2>/dev/null # World writable files and directories find / -perm -002 -a \( -type f -o -type d \) -print >ww.fd 2>/dev/null # Writable executables (owner, group & world) find / -perm +111 -a -perm -200 -a -type f -print >wxo.f 2>/dev/null find / -perm +111 -a -perm -20 -a -type f -print >wxg.f 2>/dev/null find / -perm +111 -a -perm -2 -a -type f -print >wxw.f 2>/dev/null # # Now create the MD5 fingerprints .. # # add anything you like to this list, but note that the contents # of the suid and sgid lists get added later on as the check starts # # ps, top, rm and ls are in the list because many rootkits will replace # these binaries with versions which won't show the trojans that have been # placed in the system ! # # /usr/local/sbin/firewall holds the server's firewall rules # echo "/usr/bin/perl" > ${tmpfile1} echo "/bin/sh" >> ${tmpfile1} echo "/bin/bash" >> ${tmpfile1} echo "/bin/ps" >> ${tmpfile1} echo "/usr/bin/top" >> ${tmpfile1} echo "/bin/rm" >> ${tmpfile1} echo "/bin/ls" >> ${tmpfile1} echo "/bin/login" >> ${tmpfile1} echo "/etc/inetd.conf" >> ${tmpfile1} echo "/etc/group" >> ${tmpfile1} echo "/etc/passwd" >> ${tmpfile1} echo "/etc/inittab" >> ${tmpfile1} echo "/sbin/ipchains" >> ${tmpfile1} echo "/usr/local/sbin/SetUp.sh" >> ${tmpfile1} echo "/usr/local/sbin/firewall" >> ${tmpfile1} name="zz" > ${md5File} cat s?id.list ${tmpfile1} | sort -u | while [ -n "${name}" ];do read name if [ -f "${name}" ];then MD5=`cat ${name} | /usr/bin/md5sum | awk '{ print $1 }'` echo "${MD5} ${name}" >> ${md5File} fi done #---------------------------------------------------------------------- # Check/Setup complete # chown root:root * chmod 400 * if [ "${Mode}" = "SetUp" ];then exit fi #---------------------------------------------------------------------- # Check done, so compare results against the original setup # ReportFile=${ReportDir}/`date +%Y%m%d.%H%M` echo "Integrity Check `date`" >> ${ReportFile} # SUID list .. Compare suid.list SUID 2 # SGID list .. Compare sgid.list SGID 2 # Files without recognised user or group Compare no.user.group "No user or group" 1 # World writable files and directories Compare ww.fd "World writable" # Writable executables (owner, group & world) Compare wxo.f "Executables writable by owner" 0 Compare wxg.f "Executables writable by group" 1 Compare wxw.f "Executables writable by world" 2 # MD5 fingerprint file -- this has to be treated a little differently CompareMD5 echo "==================================================" >>${ReportFile} echo >>${ReportFile} if [ ${Error} = 0 && ${Warning} = 0 ];then LOGMSG "IC (Version ${Version})" "Check OK" else LOGMSG "IC (Version ${Version})" "Complete: ${Error}/${Warning}" fi rm -f ${tmpfile1}