【失败尝试】自研SMTP服务器前置中间件
Security Classification: 【C-1】 | Publish Time:2024-06-25 | Category:Coding | EditOld Version | Diff | Latest Version
Expiry Notice: The article was published three months ago. Please independently assess the validity of the technical methods and code mentioned within. :)
AI Summary: 本文讨论了在使用内网穿透的情况下,如何解决邮件发送和接收中的IP地址异常问题。由于内网穿透导致发件人IP与SPF记录不一致,邮件可能被标记为垃圾邮件,且关闭SPF会带来邮件伪造的风险。为解决这些问题,作者提出了自研SMTP服务器前置中间件的方案,通过接管邮件服务器的25端口流量并进行透传来处理邮件。 在实现中,作者尝试解析TLS流量以获取明文邮件内容,但发现现代邮件服务提供商通常要求使用TLS加密。为此,作者尝试通过修改ClientHello环节的加密套件列表来强制降级TLS连接,成功接收到明文流量。然与Gmail的TLS 1.3协议不兼容,导致无法降级并获取邮件信息。 最终,作者意识到邮件伪造问题难以解决,因此放弃了使用群晖MailPlus与内网穿透的方案,尽管在此过程中学习了网络原理与协议解析的相关知识。 --- (From Model:gpt-4o-mini-2024-07-18)
前言
上一篇我们说到,使用内网穿透之后,会导致发件人IP异常。这是由于内网穿透代理转发数据,获取到了内网IP。所以开启了SPF校验会导致所有邮件都不可达,会被群晖邮服退信。
而发信直接使用的内网25端口,不会再次经过内网穿透的外网服务器,会导致发送邮件的IP与SPF标记的IP不一致,让邮件容易进入垃圾箱。
发信的缓解措施只有使用第三方smtp服务器进行发件,这样虽然在第三方邮件服务器有记录,但至少自己这边也有备份,当然,还要去配置这个发件邮箱进行自动转发,或者直接在邮件声明回复地址。
但是收信如何解决邮件伪造亟待解决。关闭了SPF,那么邮箱伪造的邮件都会随便进入邮箱。
自建SMTP协议前置中间件
原理:在查找域名邮局服务器的时候一定会建立25端口连接,那么实际上我们只要接管邮件服务器的25端口流量,再透传给上游的npc客户端的25端口就行了。
这一步在go语言使用io.copy即可,我们也确实获取到了一些数据流量:
图中的流量我进行了hex编码,解码后伪造邮箱的发送可以拿到整个明文流量:
这里的通信流程如下:
1、客户端(其他邮箱服务器)首先发送 EHLO 命令来标识自己并请求服务器列出其支持的SMTP扩展。服务器响应了一系列的 250 状态码,列出了它支持的扩展
2、客户端发送明文数据
3、客户端发送QUIT命令用于终止SMTP会话。客户端在完成邮件传输后,或者想要结束会话时,会发送这个命令。
4、250 2.0.0 Ok: queued as 4W7YXF61R0z9YXj 是由服务器发送的,确认邮件已经成功排队。
5、221 2.0.0 Bye 是由服务器发送的,确认接受客户端的 QUIT 命令,并准备关闭会话。
为什么单独拎出来这一点?因为我们发现使用QQ邮箱、outlook等大型邮件服务器,在第一步请求smtp拓展的时候发现群晖邮服出现了250-STARTTLS,将会使用TLS加密传输内容。
这也就是为什么这些邮箱传输内容无法解码了。我们原本的意图是,拿到明文传输的邮件内容,获取From里的关键信息,然后通过ns解析获取spf信任IP,再与发件人的IP进行对比。如果不一致,我的中间件将会识别邮件为垃圾邮件,同时我也能够做一些数据修改,增强拓展性。
但是由于部分邮箱使用了TLS,这就比较难办了。
不应答StartTLS拓展,强制降级
能想到的是让中间件对拓展列表展示时,忽略掉3235302d5354415254544c530d0a
。
测试之后发现,QQ邮箱和其他许多现代邮件服务提供商通常要求使用TLS(Transport Layer Security)加密来保护邮件传输的安全性。这意味着,当邮件服务器尝试与QQ邮箱服务器建立SMTP连接时,必须支持并启用STARTTLS扩展。
解密TLS流量
TLS加密要经过握手,在buf的特征上是以160303…这样开头,里面的各个op记录了各种信息。例如服务器传递的证书、双方传递使用的随机数、选择的加密方法等。通过预主密钥和随机数,最后生成主密钥,才能够解密后面的加密内容,也就是170303开头的应用数据。
所以需要一个好的tls握手包解析工具,在github和网上并没有找到好用的,于是我打算自己实现,也为了更好的理解tls的协议传输。
参考:https://aandds.com/blog/network-tls.html
https://datatracker.ietf.org/doc/html/rfc5246
Comment List