-- 更新修复 - 2019 年 5 月 5 日 --

-- 更新修复 - 2019 年 5 月 5 日 --

maldet / Rfxn Linux MalDetect 文档即使没有找到任何内容,也可以使用以下命令获取电子邮件报告:

-e, --report SCANID email
   View scan report of most recent scan or of a specific SCANID and optionally
   e-mail the report to a supplied e-mail address
   e.g: maldet --report
   e.g: maldet --report list
   e.g: maldet --report 050910-1534.21135
   e.g: maldet --report SCANID [email protected]

一切都非常简单,但我不确定如何在此处将电子邮件地址作为第二个参数传递,同时允许第一个参数(扫描 ID)恢复为默认值,以便 maldet 将最新报告通过电子邮件发送到此自定义电子邮件地址。我希望能够使用它(例如在 cron 中)定期检查 Maldet 是否正在扫描并能够按预期发送电子邮件报告。

我已经尝试过maldet --report "" [email protected]在 bash 中传递空变量的标准方法,但它会忽略它并在控制台中输出看起来像空报告的内容。

我也尝试过诸如和之类的东西,但它会响应。maldet --report 0 [email protected]maldet --report " " [email protected]{report} no report found, aborting

如果相关的话,环境是 Centos。

答案1

要么作者maldet没有提供这种可能性,要么忽略了记录。从外部猜测是不可能的。最好的前进方式是特里姆大学:在程序源代码中查找它如何处理该-e选项,以及是否有办法同时启动“最近扫描”分支并激活电子邮件选项。

答案2

抱歉,又提起一个老问题。每次扫描后,我都尝试让 maldet 通过电子邮件发送报告,但遇到了同样的问题。我按照 @Tilman 的建议深入研究了源代码。负责发送报告电子邮件的函数 view_report() 可以在/usr/local/maldetect/internals/functionsv1.6.4 中的第 645-706 行中找到。具体查看负责的代码(第 681-696 行),我们发现只有当 SCANID(存储为$rid)是后缀时才会发送邮件,即190429-0343.31494,对应于存在于/usr/local/maldetect/sess/以下位置的报告的文件名:session.190429-0343.31494

if [ -f "$sessdir/session.$rid" ] && [ ! -z "$(echo $2 | grep '\@')" ]; then
    if [ -f "$mail" ]; then
        cat $sessdir/session.$rid | $mail -s "$email_subj" "$2"
    elif [ -f "$sendmail" ]; then
        if ! grep -q "SUBJECT: " "$sessdir/session.$rid"; then
            echo -e "SUBJECT: $email_subj\n$(cat $sessdir/session.$rid)" > $sessdir/session.$rid
        fi
        cat $sessdir/session.$rid | $sendmail -t "$2"
    else
        eout "{scan} no \$mail or \$sendmail binaries found, e-mail alerts disabled."
        exit
    fi

    eout "{report} report ID $rid sent to $2" 1
    exit
fi

处理空 SCANID 的代码紧接着此代码(第 697-705 行):

if [ "$rid" == "" ] && [ -f "$sessdir/session.last" ]; then
    rid=`cat $sessdir/session.last`
    $EDITOR $sessdir/session.$rid
elif [ -f "$sessdir/session.$rid" ]; then
    $EDITOR $sessdir/session.$rid
else
    echo "{report} no report found, aborting."
    exit
fi

我原本以为处理空 SCANID 的代码会简单地抓取最新的 SCANID 并通过电子邮件发送。它实际上做的是查看/usr/local/maldetect/sess/session.lastmaldet 存储最新 SCANID 的位置。然后,出于某种原因,它会在终端编辑器中打开相应的报告,而不是直接将其打印出来。请注意,实际上没有任何可用的代码可以通过电子邮件发送最新的报告。

-- 更新修复 - 2019 年 5 月 5 日 --

由于阻止 LMD 执行完整性检查(如我最初的修复程序中所要求的)存在潜在的安全风险,因此我使用 LMD 的 custom.cron 创建了一个替代解决方案。这样做的好处是完整性检查仍然有效,并且电子邮件脚本应该在更新后仍然存在。您无需触碰 LMD 内部文件或 maldet daily cron。

确保$email_alert="1"$email_addr=中至少设置为一个正确的电子邮件地址/usr/local/maldetect/conf.maldet。然后将以下内容添加到/usr/local/maldetect/cron/custom.cron,它将在 maldet 每日 cron 结束时自动运行:

##
# Please use this file for preservation of custom LMD execution code for the daily cronjob.
# NOTE: scripts in this file are called at the end of maldet daily cron as $custom_cron_exec
##

# log_cron="1" enable logging, log_cron="0" disable logging 
# applies only to the code in this file
log_cron="1"

# logging function borrowed from /maldetect/internals/functions
eout() {
    if [ "$log_cron" == "1" ]; then
        msg="$1"
        stdout="$2"
        appn=maldet
        if [ ! -d "$logdir" ]; then
            mkdir -p $logdir ; chmod 700 $logdir
        fi
        if [ ! -f "$maldet_log" ]; then
            touch $maldet_log
        fi
        log_size=`$wc -l $maldet_log | awk '{print$1}'`
        if [ "$log_size" -ge "20000" ]; then
            trim=1000
            printf "%s\n" "$trim,${log_size}d" w | ed -s $maldet_log 2> /dev/null
        fi
        if [ ! "$msg" == "" ]; then
            echo "$(date +"%b %d %H:%M:%S") $(hostname -s) $appn($$): $msg" >> $maldet_log
            if [ ! -z "$stdout" ]; then
                echo "$appn($$): $msg"
            fi
        fi
    fi
}

eout "{cron} running $cron_custom_exec"

##
# LMD Daily Email v1.0.0
# Author: kdub Email: [email protected] Date: May 5th, 2019
# https://github.com/kdubdev/linux-malware-detect/blob/master/files/cron/custom.cron
# Script to send email of newest report after daily scan. More info:
# https://serverfault.com/questions/805158/how-to-get-an-email-report-of-whatever-the-most-recent-maldet-scan-is
# #
de_version='v1.0.0'
eout "{cron} starting LMD Cron Email $de_version"
eout "{cron} $intcnf shows email_alert=$email_alert email_addr=$email_addr"

# Default email subject defined in /usr/local/maldetect/internals/internals.conf
# is email_subj="maldet alert from $(hostname)"
# comment this line to use the default email_subj or change to what you want
printf -v email_subj '[%s] %s: Scan Report' "$(hostname)" "$appn($$)"

# uncomment email_addr below to override recipients. Separate multiple emails with ,
# use $email_addr to include recipient defined in /usr/local/maldetect/conf.maldet
# email_addr="$email_addr,[email protected],[email protected]"

# this is the email text inserted before the report
body_intro="Here are the results of the latest LMD scan:"
# this is the email text inserted after the report
printf -v body_footer "Email provided by LMD Cron Email %s\nCron file: %s\nLog file: %s" "$de_version" "$cron_custom_exec" "$maldet_log"

# this is a very weak email validation, just looking for @
if [ "$email_alert" == "1" ] && [ ! -z "$(echo $email_addr | grep '\@')" ]; then
# email_alert is true and email provided, send newest report
    if [ -f "$sessdir/session.last" ]; then    
        # Get most recent scan id
        rid=$(cat "$sessdir/session.last")
        if [ ! -z "$rid" ]; then
            # session.list contains something
            if [ -f "$sessdir/session.$rid" ]; then
                # report exists, get contents
                body=$(cat "$sessdir/session.$rid")
                eout "{cron} reading report $sessdir/session.$rid"
            else
                # report doesn't exist   
                body="{cron} unable to find report $sessdir/session.$rid."
            fi
            if [ -z "$body" ]; then
                # report file exists but is empty
                body="{cron} report $sessdir/session.$rid is empty."
            fi          
        else
            # session.last is empty  
            body="{cron} $sessdir/session.last is empty."
        fi
    else    
        # session.last doesn't exist
        body="{cron} unable to find $sessdir/session.last."
    fi
    # log if body starts with {cron} ie there's a problem reading report
    if [[ $body == '{cron}'* ]]; then
        eout "$body"
    fi

    # add intro and footer to body
    body=$(printf "%s\n\n%s\n\n%s\n\n" "$body_intro" "$body" "$body_footer")

    if [ -f "$mail" ]; then
        printf "%s" "$body" | $mail -s "$email_subj" "$email_addr"
        eout "{cron} mail sent using $mail to $email_addr, subject: $email_subj."
    elif [ -f "$sendmail" ]; then
        printf "%s\n%s" "$email_subj" "$body" | $sendmail -t "$email_addr"
        eout "{cron} mail sent using $sendmail to $email_addr, subject: $email_subj."
    fi
fi
eout "{cron} mail latest report finished."
eout "{cron} done running $cron_custom_exec"

您也可以在此处查看更新https://github.com/kdubdev/linux-malware-detect/blob/master/files/cron/custom.cron

在脚本中,您可以禁用日志记录、覆盖电子邮件主题和/或收件人,以及自定义电子邮件正文简介和页脚。该脚本有大量注释,因此您可以跟进或进行更改。

我欢迎任何反馈或改进建议。

-- 以下是原始修复 --

为了修复这个问题并添加其他改进,我修改了 view_report() 并进行了以下更改:

  • 添加选项“newest”作为别名--report,以--report ""允许$ maldet --report newest [email protected]
  • 使用或$ maldet --report newest [email protected]$ maldet --report "" [email protected]
  • 不再需要使用编辑器查看报告,而是直接打印到终端
  • 改进日志记录

第一的:您需要进行设置,autoupdate_version_hashed="0"/usr/local/maldetect/conf.maldet防止 LMD 在运行更新检查时自动覆盖您所做的任何更改。请注意,这是一个潜在的安全问题:

# This controls validating the LMD executable MD5 hash with known
# good upstream hash value. This allows LMD to replace the the
# executable / force a reinstallation in the event the LMD executable
# is tampered with or corrupted. If you intend to make customizations
# to the LMD executable, you should disable this feature.
# [0 = disabled, 1 = enabled]
autoupdate_version_hashed="0"

第二:将当前的view_report() /usr/local/maldetect/internals/functions(645-706 行) 替换为:

view_report() {
    # $1 is first arg passed from command line ex. $ maldet --report $1 $2
    rid="$1"
    # $ maldet --report list
    if [ "$rid" == "list" ]; then
        tmpf="$tmpdir/.areps$$"
        for file in `ls $sessdir/session.[0-9]* 2> /dev/null`; do
            SCANID=`cat $file | grep "SCAN ID" | sed 's/SCAN ID/SCANID/'`
            FILES=`cat $file | grep "TOTAL FILES" | sed 's/TOTAL //'`
            HITS=`cat $file | grep "TOTAL HITS" | sed 's/TOTAL //'`
            CLEAN=`cat $file | grep "TOTAL CLEANED" | sed 's/TOTAL //'`
            TIME=`cat $file | grep -E "^TIME|^STARTED" | sed -e 's/TIME: //' -e 's/STARTED: //' | awk '{print$1,$2,$3,$4}'`
            TIME_U=`date -d "$TIME" "+%s" 2> /dev/null`
                        ETIME=`cat $file | grep "ELAPSED" | awk '{print$1,$2}' | sed 's/ELAPSED/RUNTIME/'`
            if [ -z "$ETIME" ]; then
                ETIME="RUNTIME: unknown"
            fi
            if [ ! -z "$SCANID" ] && [ ! -z "$TIME" ]; then
                clean_zero=`echo $CLEAN | awk '{print$2}'`
                if [ -z "$clean_zero" ]; then
                    CLEAN="CLEANED:  0"
                fi
                echo "$TIME_U | $TIME | $SCANID | $ETIME | $FILES | $HITS | $CLEAN" >> $tmpf
            fi
        done
        if [ -f "$tmpf" ]; then
            if [ "$OSTYPE" == "FreeBSD" ]; then
                cat $tmpf | sort -k1 -n | cut -d'|' -f2-7 | column -t | more
            else
                cat $tmpf | sort -k1 -n | tac | cut -d'|' -f2-7 | column -t | more
            fi
            rm -f $tmpf 2> /dev/null
            exit 0
        else
            eout  "{list} unable to find report data for list, check \$sessdir"
            exit 1
        fi
    fi
    # If no SCANID is provided or "recent" then set $rid to most recent. 
    # $ maldet --report "" or $maldet --report newest
    if { [ "$rid" == "" ] || [ "$rid" == "newest" ]; } && [ -f "$sessdir/session.last" ]; then
        rid=`cat $sessdir/session.last`
    fi
    # make sure report exists
    if [ -f "$sessdir/session.$rid" ]; then
        # if email is provided, then send the report and exit
        if [ ! -z "$(echo $2 | grep '\@')" ]; then
            if [ -f "$mail" ]; then
                cat $sessdir/session.$rid | $mail -s "$email_subj" "$2"
            elif [ -f "$sendmail" ]; then
                if ! grep -q "SUBJECT: " "$sessdir/session.$rid"; then
                    echo -e "SUBJECT: $email_subj\n$(cat $sessdir/session.$rid)" > $sessdir/session.$rid
                fi
                cat $sessdir/session.$rid | $sendmail -t "$2"
            else
                # eout is an internal function to log to maldet_log and echo
                eout "{scan} no \$mail or \$sendmail binaries found, e-mail alerts disabled."
                exit
            fi
            eout "{report} report ID $rid sent to $2" 1
            exit        
        # no email is provided so show report and exit
        else
            printf '%b\n' "$(cat $sessdir/session.$rid)"
            exit
        fi
    # can't find requested report so log & echo error
    else
        eout "{report} unable to find report session.\$rid, aborting."
        exit
    fi
}

/usr/local/maldetect/internals/functions您也可以在此处的拉取请求中找到整个更新的文件:https://github.com/kdubdev/linux-malware-detect/blob/patch-1/files/internals/functions

最后的:/etc/cron.daily/maldet如果您希望在每次每日扫描后收到电子邮件, 请在末尾添加以下行:$inspath/maldet --report newest [email protected]

注意:如果不清楚,可以互换使用-e--report

答案3

您应该编辑/usr/local/maldetect/conf.maldet第 22 行并将其替换为有效地址。email_addr="[email protected]"

编辑:

我错误地阅读了原始帖子,但这个设置可以帮助其他人。

答案4

我的解决方案是查找文件中最新的扫描报告 ID/usr/local/maldetect/sess/session.last

像这样的包装脚本是从 Cron 调用的

#!/bin/bash

recipient=${recipient:[email protected]}

# Upgrade Maldet and Update the signatures
maldet -d
maldet -u

# Perform a scan on files created in the last week
maldet -r / 7
logger -t "system_scan" "Maldet Task ended with RC=$?"

# Send the last scan via email
maldet -e $(cat /usr/local/maldetect/sess/session.last) "$recipient"

请注意,“收件人”将提供默认值,但用户可以覆盖它,例如:
[email protected] ./scan.sh

一些陷阱:

  1. 检查 session.last 文件的位置是否有效!!我不确定这是否是一个记录在案的功能,因此它可能会改变
  2. 如果运行多次扫描,结果可能不可预测。maldet -e list可以使用解析结果来获取报告列表。
  3. 我没有尝试处理任何步骤的错误,也没有尝试捕获错误输出等。

相关内容