构建网络电子邮件病毒检测系统

作者:Dave Jones

作为网络管理员,我处理的最具威胁性和最令人恼火的问题之一是病毒。似乎在过去几年中,病毒威胁增加了十倍。我发现看到较新的病毒能够做什么越来越令人不安。甚至不是它们的能力最令人不安,而是它们进入我们系统的容易程度。最近,我花了两个小时清理用户机器上的 MTX 和 Navidad 病毒。

管理员在病毒预防中通常采取的第一种方法是安装桌面病毒防护程序。这是明智的,但在我看来,保护企业网络免受病毒侵害最安全的方法是首先阻止它们进入系统。到目前为止,病毒,尤其是宏病毒最常见的入口点是企业电子邮件系统。然而,这通常是任何病毒检测解决方案中最容易被忽视的部分。当今市场上的电子邮件病毒软件通常是特定于应用程序的、昂贵的,或者两者兼而有之(更不用说不可靠了)。作为一家中型企业,我们今年没有预算购买现成的防病毒套件,所以我转向了 Linux 和开源。我在互联网上找到了一些可能满足我们需求的有趣项目,但我决定自己编写一个。我希望我们的系统非常易于遵循且易于扩展,而用户无需了解 C 语言或成为 Perl 大师。此外,我希望系统能够利用每个基本 Linux 安装通常都具有的实用程序的强大功能。所有这一切都将确保在我缺席的情况下,其他人可以管理该系统,并且该系统是可移植的。

该系统的基本轮廓包括使用 Bash 脚本、metamail、grep、Obtuse Systems 的 smtpd 产品、Samba 和命令行病毒扫描器。图 1 中可以找到流程图样式的图表。Obtuse Systems 的 SMTP 存储和转发软件包可从 www.obtuse.com/smtpd.html 免费获得。截至撰写本文时,当前版本为 2.0 版。我选择的病毒扫描器是 McAfee Virus Scan for UNIX/Linux,但还有很多其他选择。有些是免费的,有些则不是。请务必选择一个根据其发现设置退出状态代码,并且得到频繁签名更新良好支持的扫描器。

该系统可以设置在现有的 Linux 防火墙上,或者如果您还没有 Linux 防火墙,则可以设置在单独的机器上。如果您选择设置单独的机器作为电子邮件防火墙,则不必非常强大。一台配备 32MB 内存的 200MHz 586 就足够了。我们的网络通过 SDSL 连接到互联网,并受到运行 IP 伪装的 Mandrake Linux 机器的保护。这种设计使得在我们当前的防火墙机器上设置系统变得容易。只要内部电子邮件系统使用 SMTP 或 ESMTP 协议,就无关紧要。在我们的例子中,我们使用 Novell 的 Groupwise 产品。所有 SMTP 流量(端口 25)都应从防火墙上的 SMTP 端口重定向到您在内部设置为电子邮件防火墙的机器(或者在我们的例子中重定向到防火墙本身)。现在让我们继续实际设置。

Building an E-mail Virus Detection System for Your Network

图 1. 网络流量和防火墙设置

我们的第一步是设置文件系统层级结构。图 2 中可以找到此结构的图表。我们将在名为 /var/spool/smtpd 的目录中设置我们的系统。如果您的平均电子邮件量每天超过 25,000 封电子邮件,我建议对专用于电子邮件防火墙的单独硬盘进行分区,并将其挂载在此目录中。基本目录将是 /var/spool/smtpd。在此目录中,我们将创建五个子目录,分别命名为 incoming、outgoing、etc、bin 和 quarantine。首先,成为 root 用户并发出此命令

mkdir -p /var/spool/smtpd/ {etc,bin,incoming,outgoing,quarantine}

Building an E-mail Virus Detection System for Your Network

图 2. 文件系统层级结构

接下来,更改整个层级结构的权限,使其仅可由 uucp 用户访问,因为所有程序都将以此用户身份运行。这些命令将完成这项工作

chown -R uucp.uucp /var/spool/smtpd
chmod -R 700 /var/spool/smtpd

现在我们将设置系统的第一个组件。您需要从前面提到的 Obtuse Systems 网站获取 smtpd 软件包。切换到下载目录并通过发出命令解压缩 tarball

tar -zxvf smtpd-2.0.tar.gz
现在更改到 smtpd-2.0 目录并编辑 Makefile 以反映以下更改
SPOOLDIR = /var/spool/smtpd
SPOOLSUBDIR = incoming
POLL_TIME = 300
PARANOID_SMTP = 1
JUNIPER_SUPPORT = 0
CHECK_IDENT = 0
我们想要的是 smtpd 将邮件存储在 incoming 子目录中,而 smtpfwdd 从 outgoing 目录中读取邮件。为了实现这一点,我们必须在文件 smtpfwdd.c 中插入一行。在第 75 行插入以下两行
// Pull mail from the outgoing subdir.
#define SPOOLSUBDIR "outgoing"
最后,使用以下命令编译和安装软件包
make
make install
接下来,我们需要用一些文件填充 /var/spool/smtpd/etc 目录,以允许 smtpd 正确运行。将 resolv.conf 文件从 /etc 复制到 /var/spool/smtpd/etc 目录,然后将 localtime 文件从 /etc 复制到此处。您还应该将 antirelay_check_rules_example 文件从 smtpd-2.0 发行目录复制到 /var/spool/smtpd/etc 并将其重命名为 smtpd_check_rules。如果需要,您可以在 Obtuse Systems 网站上查找有关如何创建检查规则的说明。我至少会放入一个 antirelay 规则以开始。要使 smtpd 程序自动启动,请在您的 /etc/inetd.conf 文件中放入类似于以下的条目
smtp    stream tcp nowait root /usr/local/sbin/smtpd    smptd
此行应替换可能存在的任何其他 SMTP 条目。我们需要从 /etc/rc.d/rc.local(或您当地的 rc 文件)手动启动 smtpfwdd。因此,继续并将如下条目添加到您的启动文件中
### Start the smtpfwdd forwarding daemon
/usr/local/sbin/smtpfwdd
最后,您需要关闭可能正在运行的任何其他邮件传输代理 (MTA)。这些将包括 Postfix、sendmail、qmail 等。在 Red Hat 系统上,您只需运行 setup 实用程序,从系统服务菜单中取消选中任何 MTA 并重新启动即可。请注意,某些 MTA 作为其他进程的子进程运行,例如 Postfix,并且根本无法直接杀死。如果可以重新启动机器,请继续并立即执行此操作。如果不能,那么您可以发出以下命令来启动并运行 smtpd 和 smtpfwdd
kill -HUP inetdpid
/usr/local/sbin/smtpfwdd
其中 inetdpid 是 inetd 的进程 ID。

一旦 smtpd 和 smtpfwdd 守护程序正在运行,您可以通过在电子邮件防火墙的端口 25(smtp 端口)上启动 Telnet 会话来测试设置,如下所示

telnet email.firewall.com 25

其中 email.firewall.com 是您的电子邮件防火墙的主机名。

您应该收到一个提示,显示

220 email.firewall.com SMTP ready,
Who are you gonna pretend to be today?

如果您收到任何其他提示,那么您可能忘记关闭服务器上正在运行的 MTA。ps -e 应该会证实这一点。

让我们看看我们目前的情况。此时,您应该有一台运行 smtpd 守护程序并接受电子邮件的机器。所有接收到的电子邮件都作为简单的 ASCII 文本文件存储在 /var/spool/smtpd/incoming 目录中。要测试这一点,请尝试发出以下命令

telnet email.firewall.com 25
helo firewall.com
mail from: joe@firewall.com
rcpt to:
data
This is a test.
.
quit

其中 you@domain.com 是您的电子邮件地址。务必在单独一行上以句点结束您的消息正文。这告诉服务器您已完成发送文本。

如果一切顺利,您现在应该在 /var/spool/smtpd/incoming 目录中看到一个文本文件,其中包含我们的 SMTP 会话的内容。现在将该文件移动到 /var/spool/smtpd/outgoing 目录中。几分钟后,该文件应该消失,您应该在您的主邮箱中收到该电子邮件。smtpd 将电子邮件保存为名为 smtpd?????? 的文本文件,其中 ?????? 是随机生成的消息 ID。smtpfwdd 读取这些文本文件并将它们转发到目标服务器。成功转发文件后,它将被删除。

那么邮件是如何从 incoming 移动到 outgoing 的呢?这就是我们的电子邮件扫描脚本将发挥作用的地方。该脚本将逐个搜索 incoming 目录中的每个电子邮件文件,并查找病毒内容。如果该文件不包含病毒,则将其移动到 outgoing 目录。如果包含病毒,则将其移动到 quarantine 目录。就这么简单。但在邮件扫描脚本工作之前,我们需要安装一个功能正常的病毒检测软件。现在让我们关注这一点。

我们需要的是一个基于命令行的病毒扫描器。我选择了 McAfee Virus Scan for UNIX/Linux,所以这就是我在此处描述的内容。McAfee 产品具有直观的退出状态代码列表,因此很容易集成到 shell 脚本中。您可以通过访问 www.nai.com 并使用电子商店来获得该产品。安装该产品后,您需要确保 uucp 可以执行它。为此,请转到 /usr/local/uvscan 目录并执行此命令

chmod -R 755 *

现在测试一下并确保它工作。成为 uucp 并发出此命令

/usr/local/uvscan/uvscan --version
如果测试成功,那么我们可以继续更新病毒签名文件。签名文件(或有时称为定义文件)是任何病毒扫描器的命脉。因此,我们希望自动化频繁更新它们的过程。至少每两周检查一次这些更新非常重要,因为通常每月至少发布三次新版本。为此,我们必须首先创建一个名为 sigupdate 的 Bash 脚本,并将其放置在 /var/spool/smtpd/bin 目录中。与往常一样,确保该脚本由 uucp 用户拥有并可执行。脚本的内容如清单 1 所示,应该很容易理解。sigupdate 文件应设置为每周运行一次,最好在低流量时段运行。我们稍后将通过为其插入 crontab 条目来执行此操作。您还需要在 uucp 用户的主目录中创建一个名为 .netrc 的文件。编辑此文件,使其如下所示
machine ftp.nai.com
login anonymous
password admin@domain.com
macdef init
cd pub/antivirus/datfiles/4.x
bin
prompt
mget dat-*.tar
close
bye
清单 1. sigupdate 脚本

.netrc 文件控制预定义 FTP 主机的会话。这是使我们的 FTP 会话自动化的最佳方法。您可以参考 FTP 手册页以获取有关 netrc 语法的帮助。在 sigupdate 和 .netrc 准备就绪后,立即运行 sigupdate。更新完成后,执行此命令

/usr/local/uvscan/uvscan --version

查看病毒数据文件创建日期;它应该是最近的,通常不超过一个月。如果不是,您将需要检查 sigupdate 是否从命令行正确运行。

现在让我们继续介绍主要的邮件扫描脚本。我们将其命名为 scanmail,它将存储在 /var/spool/smtpd/bin 目录中。此脚本将直接操作 smtpd 创建的电子邮件文本文件。创建该文件并使其由 uucp 拥有并可执行。您将在清单 2 中找到完整的脚本[可在 ftp.linuxjournal.com/pub/lj/listings/issue92/4882.tgz 获取]。它有大量注释,因此我将在此处给您一个概述。

从第 19 行开始,scanmail 首先切换到 incoming 目录并将电子邮件文件名存储在数组变量中。然后,它循环遍历每个文件名,并使用 grep 在文件中搜索特定模式。对每封电子邮件进行两次扫描。第一次扫描 grep 查找明显不好的附件。此扫描的模式存储在名为 matches.bad 的文件中,我们稍后将创建该文件。如果 grep 命中匹配项,则该文件将被隔离,并且一封电子邮件将发送给管理员,其中包含时间戳、文件名、发件人以及收件人。

如果未找到匹配项,则对电子邮件进行第二次扫描。这次 grep 使用名为 matches.doc 的文件来搜索可能包含宏病毒或嵌入式病毒的附件。如果这次找到匹配项,则使用 metamail 程序将附件解码为动态生成的临时目录。临时目录是通过使用电子邮件的名称并在末尾连接“_d”来创建的。然后使用我们的命令行病毒扫描器扫描临时目录的内容。如果在此处检测到病毒(通过检查扫描器的退出状态),scanmail 会隔离电子邮件和附件,并向管理员发送电子邮件警报。还会向发件人发送一封礼貌的电子邮件,说明他们可能需要检查其系统是否存在病毒,并给出检测到的病毒的名称。

此时,如果未发现病毒,则将电子邮件移动到 outgoing 目录,smtpfwdd 在那里将其传递到内部电子邮件服务器。smtpfwdd 每五分钟扫描一次 outgoing 目录以查找要传递的邮件。

接下来要做的是设置我们的文件名列表,scanmail 将使用这些列表来搜索可疑附件。scanmail 使用 grep 工具搜索文件。我们将利用 -f 开关使 grep 从特定的文本文件中提取模式列表。文本文件的布局很简单,每行只有一个模式。grep 然后将匹配文件中列出的任何模式。切换到 /var/spool/smtpd/etc 目录并创建两个名为 matches.bad 和 matches.doc 的文件。在 matches.bad 文件中,我们列出所有我们绝对不希望未经管理员检查就进入我们网络的文件名模式。

另一方面,matches.doc 文件应包含可能包含嵌入式病毒的文档的文件名模式,例如 Word 文档或电子表格。创建这些文件时,对每一行使用 filename=.*\.exe 的形式。这样做是为了您不会因为 mime 编码中恰好与 grep 正在搜索的内容匹配的随机字符串而收到误报。此外,请务必不要在文件中包含任何空行,因为 grep 会将空行解释为要搜索的模式,并将匹配所有电子邮件。Vim 是创建这些文件的好编辑器,因为您可以轻松看到任何空行。您可以在清单 3 中找到我使用的文件的内容。

清单 3. grep 模式文件

我们将使用的另一个脚本名为 daysumm,位于 /var/spool/smtpd/bin 中。创建此文件,如清单 4 所示。daysumm 向管理员发送一份当天的电子邮件活动报告。它显示了当天收到了多少封电子邮件、检测到多少病毒以及它们是什么病毒。此文件应在 cron 中设置为每天晚上 11:59 PM 运行。daysumm 脚本依赖于 /var/spool/smtpd/etc 中的 virus.$date 和 email.$date 文件。这些是动态创建的文本文件,由 scanmail 更新,并且与日期相关。因此,daysumm 必须在午夜之前运行,否则时间戳将更改,并且将读取错误的文件。

清单 4. daysumm 脚本

如果您会注意到,每次我们从防火墙本身发送电子邮件时,例如从脚本发送电子邮件时,我们都会在后面加上命令 sendmail -q。-q 开关告诉 sendmail 启动,检查是否有任何传出邮件,发送它,然后退出。它有效地刷新了所有本地出站 sendmail 队列。这是必要的,因为机器上不再运行 MTA。smtpd 软件包不是 MTA,而只是存储和转发代理。它可以被认为是专用的邮件中继程序。如果没有此命令,您将永远不会收到任何源自电子邮件防火墙本身的邮件。

我们现在应该通过 cron 守护程序自动化整个过程。我们将通过 uucp 用户的个人 crontab 文件来执行此操作。确保您以 uucp 身份登录并发出命令 crontab -e。这将打开 uucp 的 cron 表进行编辑。为 scanmail、daysumm 和 sigupdate 脚本创建以下条目

MAILTO=""
# Run the scanmail script every two minutes
*/2 * * * * /var/spool/smtpd/bin/scanmail
# Run the daysumm script every night at 11:59PM
59 23 * * * /var/spool/smtpd/bin/daysumm
# Run sigupdate every Thursday at 4:00PM
0 16 * * 4 /var/spool/smtpd/bin/sigupdate

您可以根据需要调整运行时间。关于 scanmail 运行频率的主要考虑因素是您的平均每日电子邮件量。如果您的每日邮件量超过 10,000 封,我建议将间隔设置为每两分钟一次,并将 smtpfwdd 设置为每五分钟运行一次。这样做是为了您不会一次性向内部服务器发送大量电子邮件。如果您的每日邮件量约为 1,000 封或更少,则 scanmail 可以每十分钟运行一次,smtpfwdd 可以每 20 分钟扫描一次。此外,不要遗漏 crontab 顶部的 MAILTO="" 条目。这样做是为了 crond 不会向 uucp 用户发送任何有关已完成 cron 作业的邮件。每两分钟发送一次电子邮件会很快累积,而 uucp 从不检查自己的邮件。

我还设置了一个 Samba 共享,以允许我从我的 Windows 机器访问 /var/spool/smtpd 层级结构。这对于主要使用 Windows 的管理员很有帮助。它可以防止我每次需要检查病毒警告消息时都打开 ssh 会话。您可以通过在您的 /etc/smb.conf 文件中添加如下条目来完成此操作

[mail-gate]
   Comment = Email firewall directories
   Path = /var/spool/smtpd
   Valid users =
   Admin users =
   Browseable = No
   Read Only = No

其中 you 是您的 Samba 用户名。

最后一步是将所有传入的 SMTP 连接从您的防火墙重定向到您的新扫描服务器。如果您的防火墙使用 IP 伪装,这是一项简单的任务。只需执行命令

ipmasqadm portfw -a -P tcp -L firewall 25 -R destination 25

其中 firewall 是防火墙的地址,destination 是您的新扫描服务器的地址。

如果您已决定直接在现有防火墙上运行电子邮件防火墙,则无需进行任何更改。如果您有其他防火墙产品,则需要阅读文档以了解如何进行端口重定向。这不应该太麻烦,但您可能需要联系您的产品的制造商以了解情况。请务必将此重定向命令放入您的启动脚本中,以便它们在重新启动后仍然存在。

如果一切顺利,您现在应该拥有一个可操作的电子邮件病毒防火墙。尝试从免费的网络电子邮件帐户向自己发送一些测试消息,以确保一切正常。我定期向自己发送感染了宏病毒的文档,以确保系统仍然正常运行。我可以想到很多方法来扩展这个基本系统以做其他事情。特别有希望的是 daysumm 脚本,它可以大大增强。我目前正在开发一个 CGI 脚本,该脚本将在 intranet 页面中报告当前统计信息,例如平均每日邮件量。这只是该系统可以帮助您管理和保护您的电子邮件系统的一百种方法之一,对公司预算几乎没有或没有影响。如果有人想出一些扩展系统的酷方法,请告诉我。我很乐意听到。

Building an E-mail Virus Detection System for Your Network
电子邮件:davejones@pearcebevill.com

Dave Jones 在阿拉巴马州伯明翰担任网络管理员已有三年。当他不坐在电脑前时,他可以被发现享受烟斗或与妻子和女儿一起观看 X 档案。您可以通过 davidashleyjones@hotmail.com 与他联系。

加载 Disqus 评论