#!/bin/bash #Copyright 2001, William Stearns #Copyleft: # detectlib provides the back-end functions for removing worms and viruses. # Copyright (C) 2001 William Stearns # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # The author can also be reached at: # William Stearns #email: wstearns@pobox.com (preferred) #web: http://www.pobox.com/~wstearns #snail: 544 Winchester Place # Colchester VT, 05446, USA DetectLibVer="024" False=1 #As far as bash is concerned. True=0 #Please leave Need_Utils before the rest, please. This gets called at #the beginning of each function that needs a system tool. Need_Utils () { for OneUtil in "$@" ; do if ! type -path "$OneUtil" >/dev/null 2>/dev/null ; then echo Missing support tool \"$OneUtil\" in path \"$PATH\" echo Exiting. exit $False fi done } debug () { : #echo '++++ (debugging information)' $* >/dev/stderr } #------------------------------------------------------------------------- # askYN function, returns true or false depending on user input. #------------------------------------------------------------------------- askYN () { #SUDO checked TESTYN="" while [ "$TESTYN" != 'Y' ] && [ "$TESTYN" != 'N' ] ; do echo -n '?' >/dev/stderr read TESTYN || : case $TESTYN in T*|t*|Y*|y*) TESTYN='Y' ;; F*|f*|N*|n*) TESTYN='N' ;; esac done if [ "$TESTYN" = 'Y' ]; then return 0 #True else return 1 #False fi } #End of askYN #No required utils outside of bash builtins AttackName () { #Params: A descriptive name for this worm. if [ -n "$@" ]; then NameOfAttack="$@" else debug Null attack name in AttackName. fi } #No required utils outside of bash builtins AttackMarker () { #Params: One or more files or directories whose presence (of any of them, not all of them) #essentially guarantees the attack is on the system. #DO NOT ASSUME ANY EXTERNAL UTILITY CAN BE TRUSTED AT THIS POINT. AttackPresent=$False if [ -z "$NameOfAttack" ]; then debug Null attack name in AttackMarker. fi for OneFile in "$@" ; do if [ -e "$OneFile" ]; then debug Found "$OneFile" AttackPresent=$True fi done if [ "$AttackPresent" = "$True" ]; then echo $NameOfAttack detected. else echo $NameOfAttack DOES NOT appear to be present on this system, good. fi return $AttackPresent } Need_Utils rm AttackFiles () { for OneObj in "$@" ; do if [ -d "$OneObj" ] || [ -f "$OneObj" ] || [ -b "$OneObj" ] || \ [ -c "$OneObj" ] || [ -p "$OneObj" ] || [ -S "$OneObj" ]; then ObjectsFound=$True fi done OneObj="" if [ "$ObjectsFound" = "$True" ]; then echo Do you wish to delete the following objects: echo $@ echo If so, enter \"Y\" without the quotes. if askYN ; then #Delete non-directories first for OneObj in "$@" ; do if [ -f "$OneObj" ] || [ -b "$OneObj" ] || \ [ -c "$OneObj" ] || [ -p "$OneObj" ] || \ [ -S "$OneObj" ] ; then rm -f "$OneObj" fi done OneObj="" #Now get the dirs for OneObj in "$@" ; do if [ -d "$OneObj" ]; then rm -ri "$OneObj" fi done OneObj="" else echo NOT removing the above listed files and directories. fi return $True else echo None of the following files and directories were detected: echo $@ return $False fi } Need_Utils mv ReplacedFile () { #Params: Suspect utility name, Where the good copy was moved if replaced. if [ -f "$2" ]; then echo \"$2\" found, so we assume \"$1\" is a trojan version and echo will restore the original version. if [ ! -f "$1" ]; then debug \"$1\" does not exist in WrappedUtil. fi echo Would you like to restore "$1" from "${2}" if askYN ; then mv -f "$2" "$1" else echo NOT restoring "$1" from "$2" . fi fi } NukedFiles () { #Params: Files which may have been removed from the system, have been truncated to 0 bytes, #or have been stripped of incriminating lines. if [ -n "$@" ]; then echo The following files may have been removed from the system, echo been truncated, or may have had lines removed from them. echo You should inspect them to see if they need to be echo restored from backup. Any log files in the following echo should not be trusted to be complete. echo $@ else debug Null filelist in NukedFiles fi } Need_Utils killall PathToRunningApps () { #Params: full path to apps that may be running as part of the attack echo Would you like to kill all running processes run from the echo following executables? If so, enter \"Y\" without quotes. echo "$@" if askYN ; then for OneApp in "$@" ; do killall -9 "$OneApp" killall -9 "${OneApp##*/}" done else echo NOT killing the above listed applications. fi } Need_Utils cat $SUDO grep mktemp dd rm || exit 1 #printf wc AddedLine () { #Params: file which may have had a line added, line that was added (or at least enough of a regexp to match). if [ "$#" != "2" ]; then echo Incorrect number of arguments to AddedLine! >/dev/stderr else #case "$1" in #/*) # echo Filename is not relative in AddedLine! >/dev/stderr # ;; #*) if [ ! -f "$1" ]; then echo "$1" doesn\'t exist, can\'t remove \"$2\". >/dev/stderr #FIXME - does this allow a partial line? elif $SUDO cat "$1" | grep -q "$2" ; then OLDUMASK=`umask` umask 177 TMPFILE=`mktemp -q /tmp/delline.XXXXXX` if [ $? -ne 0 ]; then echo "$0: Can't create temp file, exiting..." exit 1 fi $SUDO cat "$1" >"$TMPFILE" cat "$TMPFILE" | grep -v "$2" | $SUDO dd of="$1" 2>/dev/null #printf "%1s%-2s%-40s%-50s\n" '-' "$[ `$SUDO cat "$TMPFILE" | wc -l` - `$SUDO cat "$1" | wc -l` ]" "$1" "$2" echo "Removing \"$2\" from $1" #Was: echo -n "Removing \"$2\" from $1; " ; echo $[ `$SUDO cat "$TMPFILE" | wc -l` - `$SUDO cat "$1" | wc -l` ] lines removed. $SUDO rm -f "$TMPFILE" umask $OLDUMASK else echo \"$2\" is not in "$1" - not removing. >/dev/stderr fi # ;; #esac fi } #------------------------------------------------------------------------- # ReplacedLine procedure, replaces $2 with $3 in the given file $1 #------------------------------------------------------------------------- Need_Utils $SUDO touch cat grep printf umask mktemp sed dd rm || exit 1 ReplacedLine () { #Params: $1 File that needs the line changed, $2 string to look for, $3 string with which it should be replaced. #Example: #substline somefile "\(^[^#].*\)" "#\1" #Translation: add a # in front of all lines that don't have one. if [ "$#" != "3" ]; then echo Incorrect number of arguments to ReplacedLine! >/dev/stderr else #case "$1" in #/*) # echo Filename is not relative in ReplacedLine! >/dev/stderr # ;; #*) if [ ! -f "$1" ]; then $SUDO touch "$1" fi if $SUDO cat "$1" | grep -q "$2" ; then printf "%-3s%-40s%-50s\n" '-/+' "$1" "$2 -> $3" #Was: echo Replacing \"$2\" with \"$3\" in $1 OLDUMASK=`umask` umask 177 TMPFILE=`mktemp -q /tmp/substline.XXXXXX` if [ $? -ne 0 ]; then echo "$0: Can't create temp file, exiting..." exit 1 fi $SUDO cat "$1" >"$TMPFILE" cat "$TMPFILE" | sed -e "s@$2@$3@g" | $SUDO dd of="$1" 2>/dev/null $SUDO rm -f "$TMPFILE" umask $OLDUMASK fi # ;; #esac fi } #End of ReplacedLine ServicesStopped () { #Params: names of SysVinit scripts that may need to be restarted. for OneService in "$@" ; do echo Would you like to stop and start service \"$OneService\"? echo If so, enter \"Y\" without quotes. if askYN ; then if [ -f "/etc/rc.d/init.d/$OneService" ]; then "/etc/rc.d/init.d/$OneService" stop "/etc/rc.d/init.d/$OneService" start elif [ -f "/etc/init.d/$OneService" ]; then "/etc/init.d/$OneService" stop "/etc/init.d/$OneService" start else echo Can\'t find the script that stops and starts the "$OneService" service. echo Please restart it by hand. fi else echo NOT restarting the above listed service. fi done } SuspectUtils="" PackagesMangled () { #Params: pairs of files overwritten, the name(s) of package(s) that should not be trusted anymore #FIXME - both this and Need_Utils need to compare to each other at each invocation; #overlap should cause very loud warnings! echo The following packages \(rpms, debs, tars, etc.\) may have been echo modified beyond my ability to fix them. If any of the following echo are installed on your system, please pull down fresh copies from echo a trusted source. Please check for packages that have been echo updated since your distribution was released and get those if they echo exist. echo -e "Modified File\tPossible Package Name" while [ -n "$1" ]; do echo -e "$1\t$2" if [ -z "$2" ]; then debug One parameter short in PackagesMangled after \"$1\" shift 1 else shift 2 fi done } #Need_Utils mkdir #Last function, please InitDetectLib () { if [ ! "$DetectLibInitialized" = "$True" ]; then #set PATH=/knowngood DetectLibInitialized=$True fi }