Skip to content

Commit

Permalink
[Change] scan.tpl reporting template handles column spacing on filena…
Browse files Browse the repository at this point in the history
…mes with spaces better

[Change] CLI usage semantics of --include-regex and --exclude-regex now consistently passing to 'find' command
[Change] moved all internal field separator line break modifications to lbreakifs()
[Fix] replaced usage of 'awk' on file name sensitive variables with 'cut' and/or better scoped field separator for awk
[Fix] double quote wrapped file name variables properly on restore*() functions
[Fix] quarantine .info files were not properly recording source file atime,mtime,ctime values manual quarantine calls
[Change] quarantine .info file is now field separated with colon symbol (:)
[Change] quarantine .info file value ordering has been modified
         # owner:group:mode:size(b):md5:atime(epoch):mtime(epoch):ctime(epoch):file(path)
[Change] record_hits() now writes file mode and file times (a|m|c) into hits history file
[Change] 'eval' is now used as a prefix on the 'find' command to better handle the complex set of options passed to 'find'
         and avoid globbing, splitting and other bash'esque semantic issues
[Fix] user supplied paths to CLI are now better handled if they contain special characters
[Fix] multiple user supplied paths to CLI would generate an error if the first path contained a space and subsequent paths did not
[Fix] commit c8a1279 introduced bug where clamav could be fed zero sized signature files resulting in fatal exit
  • Loading branch information
rfxn committed Dec 22, 2016
1 parent c8a1279 commit d17700f
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 86 deletions.
186 changes: 103 additions & 83 deletions files/internals/functions
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@
##
#

lbreakifs() {
if [ "$1" == "set" ]; then
IFS=$(echo -en "\n\b")
else
unset IFS
fi
}

prerun() {
if [ ! "$(whoami)" == "root" ]; then
if [ -z "$scan_user_access" ] || [ "$scan_user_access" == "0" ]; then
Expand Down Expand Up @@ -404,8 +412,8 @@ clean() {
v="$3"
sh_hitname=`echo $hitname | sed -e 's/{HEX}//' -e 's/{MD5}//' | tr '.' ' ' | awk '{print$1"."$2"."$3}'`
if [ -d "$cldir" ] && [ "$quarantine_clean" == "1" ] && [ "$quarantine_hits" == "1" ] && [ -f "$file" ]; then
if [ -f "$cldir/$sh_hitname" ] || [ -f "$cldir/custom.$sh_hitname" ] && [ -f "$file.info" ]; then
file_path=`cat $file.info | egrep -v '#' | awk '{print$6}'`
if [ -f "$cldir/$sh_hitname" ] || [ -f "$cldir/custom.$sh_hitname" ] && [ -f "${file}.info" ]; then
file_path=`egrep -v '\#' ${file}.info | cut -d':' -f9`
eout "{clean} restoring $file for cleaning attempt" $v
restore "$file" >> /dev/null 2>&1
if [ -f "$cldir/$sh_hitname" ]; then
Expand Down Expand Up @@ -461,54 +469,55 @@ clean() {
}

restore() {
file="$1"
fname=`basename $file`
if [ -f "$quardir/$file" ] && [ -f "$quardir/$file.info" ]; then
file_owner=`cat $quardir/$file.info | egrep -v '#' | awk '{print$1}'`
file_group=`cat $quardir/$file.info | egrep -v '#' | awk '{print$2}'`
file_mode=`cat $quardir/$file.info | egrep -v '#' | awk '{print$3}'`
file_size=`cat $quardir/$file.info | egrep -v '#' | awk '{print$4}'`
md5_hash=`cat $quardir/$file.info | egrep -v '#' | awk '{print$5}'`
file_path=`cat $quardir/$file.info | egrep -v '#' | awk '{print$6}'`
chown $file_owner.$file_group "$quardir/$file" >> /dev/null 2>&1
chmod $file_mode "$quardir/$file" >> /dev/null 2>&1
mv -f "$quardir/$file" "$file_path"
eout "{restore} quarantined file $file restored to $file_path" 1
elif [ -f "$file" ] && [ -f "$file.info" ]; then
file_owner=`cat $file.info | egrep -v '#' | awk '{print$1}'`
file_group=`cat $file.info | egrep -v '#' | awk '{print$2}'`
file_mode=`cat $file.info | egrep -v '#' | awk '{print$3}'`
file_size=`cat $file.info | egrep -v '#' | awk '{print$4}'`
md5_hash=`cat $file.info | egrep -v '#' | awk '{print$5}'`
file_path=`cat $file.info | egrep -v '#' | awk '{print$6}'`
chown $file_owner.$file_group "$file" >> /dev/null 2>&1
chmod $file_mode "$file" >> /dev/null 2>&1
mv -f "$file" "$file_path"
eout "{restore} quarantined file $file restored to $file_path" 1
else
eout "{restore} invalid file or could not be found" 1
fi
file="$1"
fname=`basename "$file"`
if [ -f "$quardir/$file" ] && [ -f "$quardir/${file}.info" ]; then
file_owner=`egrep -v '\#' "$quardir/${file}.info" | awk -F':' '{print$1}'`
file_group=`egrep -v '\#' "$quardir/${file}.info" | awk -F':' '{print$2}'`
file_mode=`egrep -v '\#' "$quardir/${file}.info" | awk -F':' '{print$3}'`
file_size=`egrep -v '\#' "$quardir/${file}.info" | awk -F':' '{print$4}'`
md5_hash=`egrep -v '\#' "$quardir/${file}.info" | awk -F':' '{print$5}'`
file_path=`egrep -v '\#' "$quardir/${file}.info" | cut -d':' -f9`
chown ${file_owner}.${file_group} "$quardir/$file" >> /dev/null 2>&1
chmod $file_mode "$quardir/$file" >> /dev/null 2>&1
mv -f "$quardir/$file" "$file_path"
eout "{restore} quarantined file $file restored to $file_path" 1
elif [ -f "$file" ] && [ -f "${file}.info" ]; then
file_owner=`egrep -v '\#' "${file}.info" | awk -F':' '{print$1}'`
file_group=`egrep -v '\#' "${file}.info" | awk -F':' '{print$2}'`
file_mode=`egrep -v '\#' "${file}.info" | awk -F':' '{print$3}'`
file_size=`egrep -v '\#' "${file}.info" | awk -F':' '{print$4}'`
md5_hash=`egrep -v '\#' "${file}.info" | awk -F':' '{print$5}'`
file_path=`egrep -v '\#' "${file}.info" | cut -d':' -f9`
chown ${file_owner}.${file_group} "$file" >> /dev/null 2>&1
chmod $file_mode "$file" >> /dev/null 2>&1
mv -f "$file" "$file_path"
eout "{restore} quarantined file $file restored to $file_path" 1
else
eout "{restore} invalid file or could not be found" 1
fi
}

restore_hitlist() {
hitlist="$sessdir/session.hits.$1"
if [ -f "$hitlist" ]; then
val_aquar=`tail -n1 $hitlist | awk '{print$5}'`
val_mquar=`tail -n1 $hitlist | awk '{print$3}'`
if [ "$val_aquar" ]; then
for file in `cat $hitlist | awk '{print$5}'`; do
lbreakifs set
is_autoquar=`tail -n1 $hitlist | awk -F'>' '{print$2}' | egrep -v '^$' | sed 's/.//'`
if [ "$is_autoquar" ]; then
for file in `cat $hitlist | cut -d':' -f2 | cut -d'>' -f2 | sed 's/.//'`; do
if [ -f "$file" ]; then
restore $file
restore "$file"
fi
done
elif [ "$val_mquar" ]; then
for file in `cat $hitlist | awk '{print$3}'`; do
quar_file=`cat $maldet_log | grep -w "$file" | tail -n1 | awk '{print$12}' | tr -d "'"`
restore $quar_file
elif [ ! "$is_autoquar" ]; then
for file in `cat $hitlist | cut -d':' -f2 | sed 's/.//'`; do
quar_file=`cat $quar_history | egrep -w "$file" | cut -d':' -f8 | tail -n1`
restore "$quar_file"
done
else
eout "{restore} could not find a valid hit list to restore." 1
fi
lbreakifs unset
fi
}

Expand Down Expand Up @@ -617,22 +626,22 @@ record_hit() {
file_owner=`$stat -c "%U" "$file"`
file_group=`$stat -c "%G" "$file"`
file_mode=`$stat -c "%a" "$file"`
file_size=`$stat -c "%s" $file`
file_size=`$stat -c "%s" "$file"`
# atime mtime ctime (since epoch)
file_times=`$stat -c "%X %Y %Z" $file`
file_name=`basename "$file"`
file_times=`$stat -c "%X:%Y:%Z" "$file"`
file_name=`basename "$file" 2> /dev/null`
if [ ! "$md5_hash" ]; then
md5_hash=`$md5sum $file | awk '{print$1}'`
md5_hash=`$md5sum "$file" | awk '{print$1}'`
fi
eout "{hit} malware hit $hitname found for $file"
echo "${utime}:${hostid}:${hitname}:${md5_hash}:${file_size}:${file_owner}.${file_group}:${file}" >> $hits_history
echo "${utime}:${hostid}:${hitname}:${md5_hash}:${file_size}:${file_owner}.${file_group}:${file_mode}:${file_times}:${file}" >> $hits_history
fi
}

quarantine() {
file="$1"
hitname="$2"
file_name=`basename $file`
file_name=`basename "$file"`
if [ -f "$file" ] && [ -d "$quardir" ]; then
if [ "$quarantine_hits" == "1" ]; then
file_namewc=`echo $file_name | $wc -m`
Expand All @@ -648,7 +657,7 @@ quarantine() {
chmod 000 "$quardir/$file_name.$rnd"
chown root.root "$quardir/$file_name.$rnd"
fi
echo -e "# owner group mode size(b) md5 path atime(epoch) mtime(epoch) ctime(epoch)\n$file_owner $file_group $file_mode $file_size $md5_hash $file $file_times" > $quardir/$file_name.$rnd.info
echo -e "# owner:group:mode:size(b):md5:atime(epoch):mtime(epoch):ctime(epoch):file(path)\n$file_owner:$file_group:$file_mode:$file_size:$md5_hash:$file_times:$file" > $quardir/$file_name.$rnd.info
eout "{quar} malware quarantined from '$file' to '$quardir/$file_name.$rnd'"
echo "$utime:$hitname:$file:$file_owner:$file_group:$md5_hash:$file_size:$quardir/$file_name.$rnd" >> $quar_history
if [ ! -z "$scan_session" ]; then
Expand All @@ -671,16 +680,18 @@ quarantine() {
quar_hitlist() {
hitlist="$sessdir/session.hits.$1"
if [ -f "$hitlist" ]; then
for file in `cat $hitlist | awk '{print$3}'`; do
lbreakifs set
for file in `cat $hitlist | cut -d':' -f2 | sed 's/.//'`; do
if [ -f "$file" ]; then
file_owner=`$stat -c "%U" "$file"`
file_group=`$stat -c "%G" "$file"`
file_mode=`$stat -c "%a" "$file"`
file_size=`$stat -c "%s" $file`
file_size=`$stat -c "%s" "$file"`
file_times=`$stat -c "%X:%Y:%Z" "$file"`
file_name=`basename "$file"`
file_namewc=`echo $file_name | $wc -m`
file_namewc=`echo "$file_name" | $wc -m`
if [ ! "$md5_hash" ]; then
md5_hash=`$md5sum $file | awk '{print$1}'`
md5_hash=`$md5sum "$file" | awk '{print$1}'`
fi
if [ "$pub" == "1" ]; then
chattr -ia "$file" >> /dev/null 2>&1
Expand All @@ -691,7 +702,7 @@ quar_hitlist() {
fi
rnd="${RANDOM}${RANDOM}"
mv "$file" "$quardir/$file_name.$rnd"
echo -e "# owner group mode size(b) md5 path atime(epoch) mtime(epoch) ctime(epoch)\n$file_owner $file_group $file_mode $file_size $md5_hash $file $file_times" > $quardir/$file_name.$rnd.info
echo -e "# owner:group:mode:size(b):md5:atime(epoch):mtime(epoch):ctime(epoch):file(path)\n$file_owner:$file_group:$file_mode:$file_size:$md5_hash:$file_times:$file" > $quardir/$file_name.$rnd.info
eout "{quar} malware quarantined from '$file' to '$quardir/$file_name.$rnd'" 1
echo "$utime:$hitname:$file:$file_owner:$file_group:$md5_hash:$file_size:$quardir/$file_name.$rnd" >> $quar_history
if [ "$quarantine_suspend_user" == "1" ]; then
Expand All @@ -705,6 +716,7 @@ quar_hitlist() {

fi
done
lbreakifs unset
else
echo "{quar} invalid quarantine hit list, aborting."
exit
Expand All @@ -714,7 +726,9 @@ quar_hitlist() {
scan() {
scan_start_hr=`date +"%b %e %Y %H:%M:%S %z"`
scan_start=`date +"%s"`
spath=`echo $1 | tr '?' '*' | tr ',' ' '`
lbreakifs set
spath=$(for i in `echo "$1" | tr '?' '*' | tr ',' '\n'`; do echo "\"$i\""; done | tr '\n' ' ')
lbreakifs unset
days="$2"
scanid="$datestamp.$$"
if [ "$file_list" ]; then
Expand Down Expand Up @@ -774,15 +788,20 @@ scan() {
fi
fi

if [ ! "${spath:0:1}" = "/" ]; then
if [ ! "${spath:1:1}" = "/" ]; then
eout "{scan} must use absolute path, provided relative path $spath" 1
exit
fi

if [ ! -d $(echo $spath | tr '*' ' ' | awk '{print$1}') ] && [ ! -f $(echo $spath | tr '*' ' ' | awk '{print$1}') ]; then
eout "{scan} invalid path $spath" 1
exit
fi

# if [ ! -d $(echo $spath | tr '*' ' ' | awk '{print$1}') ] && [ ! -f $(echo $spath | tr '*' ' ' | awk '{print$1}') ]; then
# eout "{scan} invalid path $spath" 1
# exit
# fi

# if [[ ! -d "$(echo $spath | tr '*' ' ' | cut -f1)" ]] && [[ ! -f "$(echo $spath | tr '*' ' ' | cut -f1)" ]]; then
# eout "{scan} invalid path $spath" 1
# exit
# fi

scan_session="$tmpdir/.sess.$$"
find_results="$tmpdir/.find.$$"
Expand Down Expand Up @@ -880,8 +899,8 @@ scan() {
file_list_start=`date +"%s"`
tmpscandir="$tmpdir/scan.$RANDOM"
mkdir -p "$tmpscandir" ; chmod 700 $tmpscandir ; cd $tmpscandir
eout "{scan} executed $nice_command $find $spath $spath_tmpdirs -maxdepth $scan_max_depth $find_opts -type f $find_recentopts -size +${scan_min_filesize}c -size -$scan_max_filesize $include_regex -not -perm 000 -not -regex \"$exclude_regex\" $ignore_fext $ignore_root $ignore_user $ignore_group"
$nice_command $find /lmd_find/ $spath $spath_tmpdirs -maxdepth $scan_max_depth $find_opts -type f $find_recentopts -size +${scan_min_filesize}c -size -$scan_max_filesize $include_regex -not -perm 000 -not -regex "$exclude_regex" $ignore_fext $ignore_root $ignore_user $ignore_group 2> /dev/null | grep -vf $ignore_paths > $find_results
eout "{scan} executed eval $nice_command $find $spath $spath_tmpdirs -maxdepth $scan_max_depth $find_opts -type f $find_recentopts -size +${scan_min_filesize}c -size -$scan_max_filesize $include_regex -not -perm 000 $exclude_regex $ignore_fext $ignore_root $ignore_user $ignore_group"
eval $nice_command $find /lmd_find/ $(echo $spath) $spath_tmpdirs -maxdepth $scan_max_depth $find_opts -type f $find_recentopts -size +${scan_min_filesize}c -size -$scan_max_filesize $include_regex -not -perm 000 $exclude_regex $ignore_fext $ignore_root $ignore_user $ignore_group 2> /dev/null | grep -vf $ignore_paths > $find_results
cd $tmpdir
rm -rf $tmpscandir
if [ "$rscan" = "1" ] && [ "$LMDCRON" == "1" ] && [ "$scan_export_filelist" == "1" ]; then
Expand All @@ -900,11 +919,11 @@ scan() {
if [ ! -f "$find_results" ] || [ -z "$(cat $find_results)" ]; then
if [ -z "$hscan" ]; then
if [ "$days" == "all" ]; then
eout "{scan} scan returned zero results, please provide a new path." 1
eout "{scan} scan returned empty file list; check that path exists and contains files in scope of configuration." 1
rm -f $find_results $scan_session $runtime_ndb $runtime_hdb $runtime_hexstrings $clamscan_results $tmpdir/.tmpf*
exit 0
else
eout "{scan} scan returned zero results, please increase days range or provide a new path." 1
eout "{scan} scan returned empty file list; check that path exists, contains files in days range or files in scope of configuration." 1
rm -f $find_results $scan_session $runtime_ndb $runtime_hdb $runtime_hexstrings $clamscan_results
exit 0
fi
Expand Down Expand Up @@ -966,10 +985,11 @@ scan() {
eout "{scan} clamscan returned an error, check $clamscan_log for more details!" 1
echo "$(date +"%b %d %H:%M:%S") $(hostname -s) clamscan end" >> $clamscan_log
fi
for hit in `cat $clamscan_results | egrep -v 'ERROR$|lstat()' | tr -d ':' | sed 's/.UNOFFICIAL//' | awk '{print$2":"$1}'`; do
file=`echo $hit | tr ':' ' ' | awk '{print$2}'`
signame=`echo $hit | tr ':' ' ' | awk '{print$1}'`
clamsig=`echo $signame | grep -iE "HEX|MD5"`
lbreakifs set
for hit in `egrep -v 'ERROR$|lstat()' $clamscan_results | sed -e 's/.UNOFFICIAL//' -e 's/ FOUND$//' | awk -F':' '{print$2":"$1}' | sed 's/.//'`; do
file=`echo "$hit" | cut -d':' -f2`
signame=`echo "$hit" | cut -d':' -f1`
clamsig=`echo "$signame" | grep -iE "HEX|MD5"`
if [ -z "$clamsig" ]; then
signame="{CAV}$signame"
fi
Expand All @@ -984,14 +1004,14 @@ scan() {
cnt="$tot_files"
fi
done
lbreakifs unset
echo
echo "$(date +"%b %d %H:%M:%S") $(hostname -s) clamscan end" >> $clamscan_log
else
if [ -z "$hscan" ]; then
eout "{scan} scan of $spath ($tot_files files) in progress..." 1
fi
SAVEIFS="$IFS"
IFS=$(echo -en "\n\b")
lbreakifs set
if [ ! -f "$scan_session" ]; then
touch $scan_session
fi
Expand All @@ -1008,7 +1028,7 @@ scan() {
fi

done
IFS=$SAVEIFS
lbreakifs unset
fi

if [ -z "$hscan" ]; then
Expand Down Expand Up @@ -1364,18 +1384,20 @@ monitor_check() {
eout "{mon} inotify clamav file scan on $file"
done
fi
for hit in `cat $clamscan_results | egrep -v 'ERROR$|lstat()' | tr -d ':' | sed 's/.UNOFFICIAL//' | awk '{print$2":"$1}'`; do
file=`echo $hit | tr ':' ' ' | awk '{print$2}'`
signame=`echo $hit | tr ':' ' ' | awk '{print$1}'`
clamsig=`echo $signame | grep -iE "HEX|MD5"`
if [ -z "$clamsig" ]; then
signame="{CAV}$signame"
fi
lbreakifs set
for hit in `egrep -v 'ERROR$|lstat()' $clamscan_results | sed -e 's/.UNOFFICIAL//' -e 's/ FOUND$//' | awk -F':' '{print$2":"$1}' | sed 's/.//'`; do
file=`echo "$hit" | cut -d':' -f2`
signame=`echo "$hit" | cut -d':' -f1`
clamsig=`echo "$signame" | grep -iE "HEX|MD5"`
if [ -z "$clamsig" ]; then
signame="{CAV}$signame"
fi
if [ -f "$file" ]; then
record_hit "$file" "$signame"
quarantine "$file" "$signame"
record_hit "$file" "$signame"
quarantine "$file" "$signame"
fi
done
done
lbreakifs unset
scanned_count=`wc -l $monitor_scanlist | awk '{print$1}'`
eout "{mon} scanned ${scanned_count} new/changed files with clamav engine"
rm -f $clamscan_results $monitor_scanlist
Expand Down Expand Up @@ -1590,7 +1612,7 @@ checkout() {

if [ -f "$file" ]; then

filename=`basename $file | tr -d '[:cntrl:]' | tr -d '[:space:]'`
filename=`basename "$file" | tr -d '[:cntrl:]' | tr -d '[:space:]'`
if [ -z "$filename" ]; then
storename="$storename_prefix"
else
Expand Down Expand Up @@ -1620,7 +1642,7 @@ EOT
rm -f $tmpf
fi
for i in `cat $tmpf`; do
filename=`basename $i | tr -d '[:cntrl:]' | tr -d '[:space:]'`
filename=`basename "$i" | tr -d '[:cntrl:]' | tr -d '[:space:]'`
if [ -z "$filename" ]; then
storename="$storename_prefix"
else
Expand Down Expand Up @@ -1648,8 +1670,6 @@ gensigs() {
runtime_hdb="$tmpdir/.runtime.user.$$.hdb"
runtime_hexstrings="$tmpdir/.runtime.hexsigs.$$"
rm -f $runtime_ndb $runtime_hdb $runtime_hexstrings
touch $runtime_ndb $runtime_hdb $runtime_hexstrings
chmod 640 $runtime_ndb $runtime_hdb $runtime_hexstrings
ln -fs $runtime_ndb $sigdir/lmd.user.ndb
ln -fs $runtime_hdb $sigdir/lmd.user.hdb
if [ -s "$sig_cust_hex_file" ]; then
Expand Down Expand Up @@ -1775,7 +1795,7 @@ lmdup() {
sh -c './install.sh' >> /dev/null 2>&1
cp -f $inspath.last/sigs/custom.* $sigdir/ 2> /dev/null
cp -f $inspath.last/clean/custom.* $inspath/clean/ 2> /dev/null
eout "{update} completed update v$ver => v$upstreamver_readable, running signature updates..." 1
eout "{update} completed update v$ver ${installed_hash:0:6} => v$upstreamver_readable ${upstream_md5:0:6}, running signature updates..." 1
$inspath/maldet --update 1
eout "{update} update and config import completed" 1
else
Expand Down
2 changes: 1 addition & 1 deletion files/internals/scan.etpl
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ if [ ! "$tot_hits" == "0" ]; then
fi
if [ -f "$hitlist_file" ]; then
echo "FILE HIT LIST:" >> $tmpf
cat $hitlist_file | column -t >> $tmpf
cat $hitlist_file | column -s ':' -t -o ':' >> $tmpf
fi
fi

Expand Down
4 changes: 2 additions & 2 deletions files/maldet
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,13 @@ else
-x|--exclude-regex)
shift
if [ "$1" ]; then
exclude_regex="$1"
exclude_regex="-not -regex \"$1\""
fi
;;
-i|--include-regex)
shift
if [ "$1" ]; then
include_regex="-regex $1"
include_regex="-regex \"$1\""
fi
;;
--alert-daily|--monitor-report)
Expand Down

0 comments on commit d17700f

Please sign in to comment.