C# 发送匿名邮件

用C#打造匿名邮件群发软件

masepu(本文已发表于黑客防线,转载请注明出处)

电子邮件攻击是最常见的网络攻击手法之一,黑客们通过电子邮件发送木马、病毒或是包含有攻击性或信息获取脚本的特定html代码,使邮箱使用者打开这类邮件就会导致信息泄露甚至电脑被控制。而这种攻击手法常常要和“社会工程学”结合起来,信件要求伪装成邮箱使用者熟悉的发信人,以迷惑对方使其放松警惕,来达到获得重要信息和控制对方电脑的目的。为了深入的了解这种攻击方法,前段时间我打算在网上找一个免费好用的匿名邮件群发软件,来实际测试发送伪造信件的效果,结果上网转了一大圈也没找到一个称心如意的,不是收费就是试用,插件广告一大堆,想来邮件群发软件是被所谓的“邮件营销”用的太多太滥,难得找到好用而且免费的了。仔细想想有这时间精力去网上瞎找,还不如自己写一个合适的匿名群发器呢。有了源代码就掌握了主动权,以后想怎么改都行,再不用看那些“垃圾”邮件群发器的“脸色”了。哈哈,自己动手,丰衣足食,让我们准备好Visual Stdio.NET开发环境,开始编写属于自己的匿名邮件群发软件。
一、匿名发送原理
 现在广泛使用的邮件发送协议是ESMTP,是由SMTP协议发展而来,SMTP协议由于没有身份认证等功能早已不被邮件服务提供商采用,当然如果我们自己架设邮件发送服务器的话可以使用该协议,因为该协议不用身份认证就可以实现完全的匿名邮件发送。现在还有很多免费邮件服务提供商让用户通过网页登录的方式来进行邮件的收发,这种WebMail的方式和上面所说的SMTP协议方式不在本文讨论之列,本文程序采用的ESMTP协议是被现在流行的邮件服务提供商广泛采用的邮件发送协议。在开始编程之前我们首先需要一个支持该协议的邮箱用于发信测试,现在大家使用的大部分邮箱都支持的。在这里我选163、新浪信箱进行测试。下面我们就通过telnet方式手工发送一封匿名邮件,以了解ESMTP协议和匿名效果(注:前面带“>”号的是输入命令)
>telnet smtp.163.com 25     //163邮件发送服务器的域名和端口
220 163.com Anti-spam GT for Coremail System (163com[20081010])
>HELO VVVVVV                //告诉服务器我的机器名,当然是伪造的
250 OK
>AUTH LOGIN                 //要求输入用户名密码
334 dXNlcm5hbWU6
>aWAsDSFc                   //Base64编码过的用户名
334 UGFzc3dvcmQ6
>GzlzNMUz                   //Base64编码过的密码
235 Authentication successful        //提示认证成功
>MAIL FROM:<xxxxxx@163.com>  //发件地址,这个必须是与上面输
      //入的用户名对应的邮箱地址,163服务器会验证,否则无法发信。
250 Mail OK
>RCPT TO:<liuhua@sina.com>   //真实的收件人地址
250 Mail OK
>DATA      //要求发送邮件内容
354 End data with <CR><LF>.<CR><LF>
>From: "fajianren" <fanjianren@163.com>     //伪造的发信人地址
>To: "shoujianren" <shoujianren@sina.com>    //伪造的收信人地址
>Subject: helloo Helloo        //邮件主题
>tfffffffffffffffff           //邮件正文
>
>.                             //输入结束标志
250 Mail OK queued as smtp2,DNGowLD7TkkxNiZKCZ+FCg--.33908S3 1244018310
>quit                          //退出
221 Bye

现在我们登录到收件箱发现已经收到了这封伪造邮件,单从表面上看,我们是分辨不出它的真伪。原因在于ESMTP协议本身存在问题,它允许邮件发送者自己填写发件人和收件人的地址和姓名而并不检查,这就导致了伪造电子邮件的出现。
 

二、C#编写匿名群发
下面,开始编程实现匿名邮件群发功能。这里使用C#中封装好的TcpClient类,它可以直接为TCP网络服务提供客户端连接,不用再使用复杂的socket套接字接口类了。收件人列表和发件帐户列表分别存放和显示在richTextBox和ListView控件中,以实现使用不同帐户发送大量邮件的功能。这样做是为了避免同一邮箱帐户在同一段时间内因发送大量邮件而被邮件服务提供商锁定。以下是程序匿名发送部分的一些代码:
  for (int i = 0; i < richTextBox2.Lines.Length; i++)  //发送次数
  {//建立与SMTP服务器的套接字
    TcpClient SmtpServ = new TcpClient(SMTPHoststr, 25);
    NetworkStream NetStrm = SmtpServ.GetStream();
    StreamReader RDStrm = new StreamReader(SmtpServ.GetStream());
    Data = "HELO server " + CRLF; //在这里我们就默认叫server吧
    szData = System.Text.Encoding.ASCII.GetBytes(Data.
                          ToCharArray());
NetStrm.Write(szData, 0, szData.Length);
//发送要求认证命令
Data = "AUTH LOGIN " + CRLF;
szData = System.Text.Encoding.ASCII.GetBytes(Data.ToCharArray());
NetStrm.Write(szData, 0, szData.Length);
//发送base64编码过的用户名
byte[] b = System.Text.Encoding.ASCII.GetBytes(namestr);
string s = Convert.ToBase64String(b);
Data = s + CRLF;
szData = System.Text.Encoding.ASCII.GetBytes(Data.ToCharArray());
NetStrm.Write(szData, 0, szData.Length);
//发送base64编码过的密码
b = System.Text.Encoding.ASCII.GetBytes(passwordstr);
s = Convert.ToBase64String(b);
Data = s + CRLF;
szData = System.Text.Encoding.ASCII.GetBytes(Data.ToCharArray());
NetStrm.Write(szData, 0, szData.Length);
//发送发件人信息
Data = "MAIL FROM: " + "<" + Senderstr + ">" + CRLF;
szData = System.Text.Encoding.ASCII.GetBytes(Data.ToCharArray());
NetStrm.Write(szData, 0, szData.Length); 
//发送接收人信息
Data = "RCPT TO: " + "<" + richTextBox2.Lines[i].ToString() + ">" + CRLF;
szData = System.Text.Encoding.ASCII.GetBytes(Data.ToCharArray());
NetStrm.Write(szData, 0, szData.Length);
listBox1.Items.Add(RDStrm.ReadLine());
//发送Data命令
Data = "DATA" + CRLF;
szData = System.Text.Encoding.ASCII.GetBytes(Data.ToCharArray());
NetStrm.Write(szData, 0, szData.Length);
//发送数据内容 其中包括伪造的发、收件人地址和姓名;
Data = ChangeString + "SUBJECT: " + textBox4.Text + CRLF + MIMEString + 
       CRLF + richTextBox1.Text + CRLF;
szData = System.Text.Encoding.ASCII.GetBytes(Data.ToCharArray());
NetStrm.Write(szData, 0, szData.Length);
Data = CRLF + "." + CRLF;
szData = System.Text.Encoding.ASCII.GetBytes(Data.ToCharArray());
NetStrm.Write(szData, 0, szData.Length);
//退出SMTP服务器
Data = "QUIT " + CRLF;
szData = System.Text.Encoding.ASCII.GetBytes(Data.ToCharArray());
NetStrm.Write(szData, 0, szData.Length);
// 关闭连接
NetStrm.Close();
RDStrm.Close();
  }
以上只是部分代码,整个程序编写完成后能够实现通过输入多个支持ESMTP协议的邮箱帐户向大量邮箱发送匿名邮件的功能。
三、程序效果
通过该程序向多个不同的邮件服务提供商邮箱发送匿名测试邮件,包括yahoo、hotmail、gmail、yeah、163、126、qq、sina邮箱(申请这么多种信箱搞测试,累呀),测试发件帐户选用的是163信箱,邮件的查看方式采用的是登录到邮箱页面上直接查看,结果表明,除了发送到hotmail邮箱的匿名测试邮件在打开后会显示真实的发信人邮箱地址外其余均能够正常实现匿名。
        效果
邮箱   发件人名 发件邮箱 收件人名 收件邮箱
雅虎中国    
雅虎    
hotmail    
gmail    
yeah    
163    
126    
QQ    
sina    
四、防范方法
如何有效的防范这些匿名的邮件,以避免被网络钓鱼邮件所欺骗呢?最有效的方法就是仔细分析可疑邮件的邮件头信息。在邮件头中包含的Received字段可以显示出邮件发送的完整轨迹。在邮件被发往目的地的过程中,每个中转服务器都会在邮件头中增加一条Received字段,这样一个邮件中就会有多条Received字段。所以要追踪到邮件的来源,可以采用自下向上的分析各条Received字段的方法。我们以发往sina的匿名邮件头为例,来探寻一下匿名邮件发送者的真面目。Received: from server (unknown [221.13.187.11])
by smtp11 (Coremail) with SMTP id D8CowLBL1IdlSypKdmHpBA--.12983S2;
这是第一条(自下而上)记录,虽然服务器名称显示的是我伪造的,可后面紧跟的IP地址却是我的真实地址,这个地址可以让匿名邮件发送者完全暴露,无处可逃(当然发送匿名邮件时使用代理的话,这个地址就是代理的IP地址了)。
Received: from m12-15.163.com ([220.181.12.15])
  by irxd5-185.sinamail.sina.com.cn with ESMTP; 06 Jun 2009 18:56:41 +0800
上面第二条记录显示这封邮件被名为m12-15.163.com的服务器传送,显然如果这封匿名信件显示的发件地址不是来自163的话,那么它就一定是伪造的了。像这样对每一条Received字段进行分析,我们就可以掌握完整的邮件发送轨迹。在这封邮件的最上面有一条记录:Return-path:<xxxxxx@163.com>, 它完全暴露了真实发件人的电子信箱地址。当然并不是每个邮件服务提供商邮件中都有此字段。此外,我们可以再看看Message-ID字段:Message-Id: <4B3A4A67.05B67A.08726@m12-15.163.com>从这条记录可以看出,发信账户属于163。通过以上方法,我们可以识别出大部分的匿名邮件。当然,如果匿名邮件发送者通过代理来发送邮件,我们就很难找到它的真实发件IP地址了,同时Message-ID字段,信件发送时间都可以伪造,不同的邮件服务提供商邮件头所包含的信息也不尽相同,有时候一封精心伪造的邮件是很难识别出来的,需要涉及到很多知识,这里就不多说了。
五、总结和改进
文章中仔细分析和解决了邮件匿名和群发的问题。但对于邮件发送的内容编码没有仔细处理,如果需要发送非ASCII文本信息的话就需要事先对发送内容进行编码,如采用Base64编码的话就需要在DATA命令后发送Content-
Transfer-Encoding:Base64命令,同时信件内容要进行Base64编码,这样就可以正常发送非ASCII内容信息的邮件了。同时程序没有太多的异常处理代码,也没有采用多线程发送,有需要的朋友可以自己加上。(本程序采用C#在Visual Stdio.net 2005下编译通过。)

转:http://blog.csdn.net/masepu/article/details/5331031 

posted @ 2011-07-26 11:50  把爱延续  阅读(3429)  评论(0编辑  收藏  举报