0%
毅种循环

返回

关于Gophish:从二次开发到语义Fuzz的实战之路Blur image

0x00 项目背景与前提#

0.1 项目场景#

最近接了个钓鱼演练的活,整的焦头烂额,连续爆肝两天,我的主要目标是通过社会工程学手段测试企业员工的安全意识和邮件网关的防护能力。客户环境如下:

  • 目标规模: 5000+ 员工,多个事业部
  • 邮件系统: coremail
  • 防护措施: 未知

0.2 初始工具选择#

作为穷人,公司也并没有提供商业工具,我选择了 Gophish 作为基础钓鱼平台,原因如下:

  • ✅ 开源且成熟稳定
  • ✅ 支持完整的项目管理
  • ✅ 内置邮件追踪和统计
  • ✅ Go语言开发,便于二次开发

0.3 面临的核心挑战#

然而,直接使用原版Gophish进行测试时,我遇到了100%的拦截率

测试结果(Day 1):
├─ 发送邮件: 50 封
├─ 成功投递: 0 封
├─ 被拦截: 50 封
└─ 拦截原因: "Suspected phishing activity detected"
plain

0x01 发件基础设施搭建:从失败到可信域绕过#

在正式进行钓鱼测试前,我首先需要解决邮件投递问题

1.1 第一次尝试:Postfix SMTP(失败)#

初始方案#

最开始,我尝试使用自建Postfix邮件服务器直接发送钓鱼邮件:
(至于为什么不用ewomail,网上都推荐的这个,因为不是centos,没办法跑,直接找了最简单的进行测试了。)

# Postfix配置(Ubuntu 20.04)
sudo apt-get install postfix

# 基础配置
myhostname = mail.phishing-domain.com
mydomain = phishing-domain.com
myorigin = $mydomain

# 这里我并没有配置真实的DNS MX记录,直接伪造的一个相近邮箱进行发送测试。
bash

测试结果#

QQ邮箱 通过。

163邮箱 通过。

189邮箱 失败,550。

客户给的测试邮箱 失败 550。

邮件发送失败截图

日志输出

Dec 28 10:23:45 postfix/smtp[12345]: connect to mx.189.cn[1.2.3.4]:25: Connection timed out
Dec 28 10:24:12 postfix/smtp[12345]: 550 5.7.1 Message rejected due to poor sender reputation
plain

猜测失败原因

问题189网关判定
IP信誉低垃圾邮件发送源
无SPF记录伪造发件人
无DKIM签名身份不可信
域名年龄新钓鱼域名特征
反向DNS缺失非正规邮件服务器

投递率0% (全部被189网关在SMTP握手阶段拒绝)


1.2 第二次尝试:Zoho企业邮箱(成功)#

解决思路#

既然自建服务器信誉不足,我决定借助成熟的企业邮箱服务:

  • 选择Zoho Mail:免费企业邮箱,支持自定义域名
  • 域名准备:购买类似域名,没要求就以便宜的为主了
  • 完整配置:SPF、DKIM、DMARC三件套

Zoho邮箱配置过程#

步骤1:注册Zoho企业邮箱

1. 访问 https://www.zoho.com/mail/
2. 选择免费版(支持最多5个邮箱账户)
3. 验证域名所有权(DNS TXT记录验证)
plain

步骤2:配置DNS记录

# 1. MX记录(指向Zoho服务器)
@  IN  MX  10  mx.zoho.com.
@  IN  MX  20  mx2.zoho.com.
@  IN  MX  50  mx3.zoho.com.

# 2. SPF记录(授权Zoho代发)
@  IN  TXT  "v=spf1 include:zoho.com ~all"

# 3. DKIM记录(邮件签名公钥)
zmail._domainkey  IN  TXT  "v=DKIM1; k=rsa; p=MIGfMA0GCSqGDQEBAQUAA4GNADCBiQKBgQC..."

# 4. DMARC记录(域名邮件政策)
_dmarc  IN  TXT  "v=DMARC1; p=none; rua=mailto:dmarc@example.com"
plain

步骤3:验证配置

# 检查SPF记录
dig TXT phishing-domain.com +short
# 输出: "v=spf1 include:zoho.com ~all"

# 检查DKIM记录
dig TXT zmail._domainkey.phishing-domain.com +short
# 输出: "v=DKIM1; k=rsa; p=MIGfMA0GCS..."

# 检查DMARC记录
dig TXT _dmarc.phishing-domain.com +short
# 输出: "v=DMARC1; p=none; rua=mailto:dmarc@example.com"
bash

步骤4:创建发件账户

邮箱地址: hr@phishing-domain.com
显示名称: 人力资源部
签名: 人力资源部 | phishing-domain.com
plain

测试结果(可信域绕过成功)#

第一轮测试:纯文本邮件

# 使用Zoho SMTP发送测试
import smtplib
from email.mime.text import MIMEText

msg = MIMEText("这是一封测试邮件", 'plain', 'utf-8')
msg['From'] = 'hr@phishing-domain.com'
msg['To'] = 'target@189.cn'
msg['Subject'] = '测试通知'

server = smtplib.SMTP_SSL('smtp.zoho.com', 465)
server.login('hr@phishing-domain.com', 'password')
server.send_message(msg)
server.quit()
python

结果

SMTP响应: 250 OK
189网关验证: SPF PASS, DKIM PASS
投递状态: 成功投递至收件箱
plain

重大突破:通过Zoho企业邮箱 + SPF/DKIM/DMARC配置,189是可以收到邮件的。

正当我以为一切都结束的时候,给客户发,得到的回复依然是收不到。


1.3 第三次尝试:钓鱼模板发送(再次失败)#

虽然可信域问题解决了,但当我发送真实钓鱼内容时,又遇到了新的拦截:

测试邮件(含钓鱼内容)#

From: hr@phishing-domain.com
To: target@189.cn
Subject: 【重要】2025年终奖发放通知

各位同事,您好:

现正式启动年终奖金发放信息核对工作!

请点击以下链接登录系统核对您的身份证号和银行卡信息:
http://portal.phishing-domain.com/verify?id=xxx

人力资源部
2025年12月28日
html

测试结果#

>>> MAIL FROM:<hr@phishing-domain.com>
<<< 250 OK
>>> RCPT TO:<target@189.cn>
<<< 250 OK
>>> DATA
<<< 354 Start mail input
>>> [发送邮件内容...]
<<< 550
plain

图片344-e5b0bece-ec5b-4bf7-a10e-28c4c5af0df4

这就很有意思了,众所周知大企业一般布有企业级邮件网关,那么他邮件网关到底是拦截的什么,是什么策略?这些我们都不得而知,只有一点点fuzz了。

猜测失败原因

检测层结果详情
✅ SPF验证PASSZoho授权发送
✅ DKIM验证PASS邮件签名有效
✅ 域名信誉PASSZoho企业邮箱可信
内容检测FAIL触发关键词过滤

猜测被拦截的关键词

❌ 主题: "年终奖"
❌ 正文: "年终奖金"、"身份证号"、"银行卡"
❌ 行为: "请点击链接"
❌ URL: "verify"路径
plain

1.4 阶段性总结#

经过几轮尝试,我得出以下结论:

已解决的问题#

  1. 可信域检测 → 通过Zoho企业邮箱 + SPF/DKIM/DMARC配置绕过
  2. IP信誉问题 → 使用Zoho的可信IP池
  3. SMTP握手 → 正常完成,不会在连接阶段被拒绝

仍存在的问题#

  1. 内容关键词检测 → 189网关对邮件内容进行深度扫描
  2. 钓鱼模式识别 → “点击链接+验证信息”等模式被识别
  3. URL路径检测 → “verify”、“login”等路径触发拦截

下一步策略#

既然可信域问题已解决,但内容仍被拦截,我需要:

  1. 对Gophish进行二次开发,去除工具指纹。
  2. 继续FUZZ邮件内容找到网关盲区。

这也是本文后续章节的核心内容。


0x02 二次开发阶段:去指纹化改造#

2.1 指纹分析#

通过我能够发送成功的邮箱获取到未改造前的eml,我识别出以下Gophish特征:

邮件头特征#

X-Gophish-Contact: ...
X-Mailer: gophish
X-Gophish-Signature: ...
Message-ID: <...@gophish>
http

图片411-69ef15c5-813c-43b0-939f-0b3943ae7075

URL特征#

http://phish.test/?rid=aBc123
plain

图片484-3f530126-51f5-4961-8e3e-79cd6f44dac6

服务端特征#

// 原始代码 controllers/phish.go
const ServerName = "gophish"

// HTTP响应头
Server: gophish
go

2.2 改造策略#

感觉特征有点多,基于分析结果,决定先把Gophish本身的特征改一下。

改造清单#

模块原始特征改造方案文件位置
邮件头X-Gophish-*完全移除或伪造成业务头models/email_request.go
MailerX-Mailer: gophish伪造成常见邮件客户端models/email_request.go
服务端Server: gophish移除或伪装成Nginxconfig/config.go
追踪路由/track/resource/image/pixel.pngcontrollers/route.go
上报路由/report/api/v1/statuscontrollers/route.go
静态资源gophish.cssapp.cssstatic/, templates/
404页面Gophish默认页面伪造Nginx 404controllers/phish.go

核心代码改造#

1. 移除服务端标识

// config/config.go
type Config struct {
    AdminConf AdminServer   `json:"admin_server"`
    PhishConf PhishServer   `json:"phish_server"`
    // ServerName string     // 🔥 直接删除此字段
}
go

2. 邮件头特征处理

对比原版Gophish和修改后的版本:

图片565-166e0f4a-bc12-4464-9eba-8ba70816ccda

关键改动

  1. 不设置 X-Mailer: gophish
  2. 不设置 X-Gophish-Contact
  3. 不设置 X-Gophish-Signature
  4. 添加 X-Priority: 1(提升邮件优先级)
  5. 添加 Importance: High(标记重要邮件)会在邮箱里面自主设置为红色叹号
  6. 保留 用户自定义邮件头功能(SMTP配置中可添加)

说明

  • 原版Gophish出于”透明度”考虑,会主动添加X-Gophish-*头标识自己
  • 我的改进方案是完全不设置这些头,让邮件看起来像普通业务邮件
  • 通过添加X-PriorityImportance头,模仿Outlook等客户端发送的重要邮件

3. 混淆追踪路由

// controllers/route.go
func (ps *PhishingServer) RegisterRoutes() {
    router := mux.NewRouter()
    
    // 原始路由:router.HandleFunc("/track", ps.TrackHandler)
    // 新路由:伪装成静态资源
    router.HandleFunc("/resource/image/pixel.png", ps.TrackHandler)
    
    // 原始路由:router.HandleFunc("/report", ps.ReportHandler)  
    // 新路由:伪装成API端点
    router.HandleFunc("/api/v1/status", ps.ReportHandler)
    
    // 添加伪造的404处理
    router.NotFoundHandler = http.HandlerFunc(ps.FakeNginx404)
}
go

4. 伪造Nginx 404页面

5. 修改参数名称

// models/campaign.go
// 将追踪参数从 rid 改为更常见的 id
const RecipientParameter = "id"  // 原: "rid"
go

6. 动态QR码功能开发(借鉴EvilGophish)

这是一个新增的需求。

在测试过程中,猜测如果超链接被拦截,那就是检测的明文URL,于是借鉴了EvilGophish项目,实现了动态QR码生成和CID嵌入功能。

与原版Gophish的区别#

原版Gophish的CID支持(已有功能):

// models/maillog.go - Gophish原版
var embeddedFileExtensions = []string{".jpg", ".jpeg", ".png", ".gif"}

func addAttachment(msg *gomail.Message, a Attachment, ...) {
    if shouldEmbedAttachment(a.Name) {
        msg.Embed(a.Name, copyFunc)  // 🔹 静态CID嵌入
    } else {
        msg.Attach(a.Name, copyFunc)
    }
}
go

使用方式

  1. 在模板编辑器中上传静态图片(如logo.png)
  2. 在HTML中使用<img src="cid:logo.png">
  3. 限制:所有收件人看到相同的图片(问题就来了,没有办法追踪谁点击了)

改进(基于EvilGophish):

//  动态生成每个收件人的专属QR码
func NewPhishingTemplateContext(...) {
    qrSize := ctx.getQRSize()
    if qrSize != "" {
        //  关键:根据收件人ID动态生成QR码
        qrBase64, qrName, err = generateQRCode(phishURL.String(), qrSize)
        qr = "<img src=\"cid:\" + qrName + "\">"
    }
    return PhishingTemplateContext{
        QR: qr,  //  每个收件人不同的QR码
    }
}
go

核心区别

特性原版GophishEvilGophish改进
CID嵌入支持支持
图片类型静态附件动态生成QR码
个性化所有人相同每人专属(含个人ID)
URL跟踪无法追踪QR码包含rid参数

为什么需要动态QR码?#

根据EvilGophish和相关研究,QR码在钓鱼中具有独特优势:

  1. 隐藏明文URL - URL被编码为二维码图片,邮件网关的URL检测和沙箱分析无法直接提取
  2. 提升可信度 - 企业邮件(年终奖、考勤)常用二维码,符合用户认知
  3. 绕过桌面安全 - 用户用手机扫描,手机浏览器安全警告较弱
  4. 绕过过滤器 - QR码是图片,不包含文本链接

实现过程(参考EvilGophish)#

邮件中使用#

<p>请扫描下方二维码登录:</p>
{{.QR}}
html

生成的邮件结构:

multipart/related
  ├─ multipart/alternative
  │   ├─ text/plain
  │   └─ text/html (<img src="cid:427968.png">)
  └─ image/png (CID: 427968.png,Base64编码QR码)
plain

CID嵌入 vs 远程加载对比#

方案1:CID内嵌(我们采用)

<!-- 邮件HTML -->
<img src="cid:427968.png">

<!-- 邮件结构 -->
Content-Type: multipart/related
  ├─ text/html
  └─ image/png
     Content-ID: <427968.png>
     Content-Transfer-Encoding: base64
html

方案2:远程加载(不推荐)

<!-- 邮件HTML -->
<img src="http://your-server.com/qrcode.png?id=xxx">

<!-- 邮件结构 -->
Content-Type: text/html
(图片存储在服务器,需HTTP加载)
html

图片623-edbd8777-c790-4528-a9e0-2bd7c6b3e463

对比分析

特性CID内嵌远程加载优势方
避免”显示图片”提示✅ 直接显示❌ 需用户点击CID
隐藏服务器地址✅ 无URL❌ 暴露域名CID
加载速度✅ 即时显示❌ 依赖网络CID
提升可信度✅ 图片完整❌ 可能显示占位符CID
邮件网关检测✅ 仅检测Base64❌ 检测外部URLCID
追踪能力❌ 无法追踪打开✅ 可追踪加载远程
邮件大小❌ 较大(含图片)✅ 较小远程

关键优势解析

  1. 避免邮件客户端安全机制
Gmail/Outlook默认行为:
- 远程图片:显示"点击显示图片"横幅 
- CID图片:直接渲染,无需用户操作
plain
  1. 隐藏钓鱼服务器地址
<!-- 远程加载:暴露服务器 -->
<img src="http://phishing-server.com/qr.png">

邮件网关可直接扫描 phishing-server.com

<!-- CID嵌入:无URL暴露 -->
<img src="cid:427968.png">

邮件网关只能看到Base64编码的PNG数据
html
  1. 提升邮件真实性
    • 远程图片:收件人需要主动点击”显示图片”,增加怀疑
    • CID图片:邮件打开即完整显示,符合正常企业邮件习惯。

0x03 困境:FUZZ机制#

3.1 新的拦截机制#

其实做到上面的的工作,大部分情况下可以操作了,但是我仍然处于被拦截的情况,因为是黑盒测试,我无法收到邮件的反馈,只能按语义检测进行尝试绕过了:

邮件网关的语义检测机制#

拦截案例分析#

我被拦截的邮件样本:

主题: 【重要】员工门户系统升级通知

尊敬的员工:

您好!为了提升系统安全性,IT部门将于本周末对员工门户进行升级。

请点击以下链接验证您的账户信息:
https://portal-verify.test/api/v1/status?id=xxx

如有疑问,请联系IT支持部门。

此致
IT部门
html

拦截原因分析

  1. 具有引导性词汇: “重要”、“升级”、“验证”
  2. 行动引导: “请点击”
  3. 案例模板: “验证账户信息”是经典钓鱼话术

3.2 心路历程#

此时我陷入了困境:如果单纯的是关键字检测,这个模板是客户定的,一时半会重改不太现实,等于说是模板改不了的情况下要如何实现发送。

我不知道邮件网关的确切检测规则,纯粹靠猜测和试错。

拦截原因猜测

检测层触发点详情
邮件头检测通过X-Mailer、Subject编码正常
纯文本检测通过text/plain部分无敏感词
HTML内容检测拦截检测到明文”年终奖金”、“身份证”、“银行卡”
URL检测拦截路径包含”verify”、“status”
行为模式拦截”点击链接”+“验证信息”模式

啥也不清楚,就此开蒙。

3.3 单变量Fuzz:定位拦截触发点#

在知道邮件被拦截后,我需要精确定位到底是什么触发了189网关的拦截

单变量测试方法#

基于smtp_block_tester.py脚本:

测试结果分析;#

关键发现#

通过单变量Fuzz测试,定位了189网关的拦截规则:

测试变量是否拦截结论
纯文本基线通过
普通超链接链接本身不触发拦截
”年终奖”敏感词触发点1
”身份证/银行卡”敏感词触发点2
主题含”年终奖”主题也会被检测
”请点击”单独不触发

核心结论

  1. 关键词检测优先级最高:无论在主题还是正文,“年终奖”、“身份证”、“银行卡”都会立即触发拦截
  2. 超链接本身安全:普通HTTP链接不会触发拦截
  3. 组合拦截机制:虽然”请点击”单独不触发,但”请点击链接+敏感词”会提升拦截优先级

下一步策略#

既然定位到了明文关键词检测是核心拦截点,接下来可以做的是:

  1. 保留整体邮件结构(Multipart、链接等)
  2. 重点混淆敏感关键词(“年终奖”、“身份证”、“银行卡”)
  3. 测试HTML混淆技术能否绕过189网关的关键词检测

这就引出了我的核心绕过方案:HTML混淆Fuzz


0x04 突破:基于HTML混淆的Fuzz绕过#

4.1 困境分析与新思路#

在语义层面被拦截后,我陷入了思考:

邮件网关如果检测的是明文内容,有可能还会对HTML进行检测,因为Gophish就支持HTML布局。

“既然语义敏感词无法避免,能否通过HTML混淆让网关看不懂?“

4.2 HTML混淆Fuzz框架#

这是一套渐进式HTML混淆测试系统:

核心思路#

明文敏感内容(100%拦截)

应用HTML混淆技术(逐个测试)

实时监控投递率变化

定位有效的混淆组合

形成通用混淆模板
plain

HTML混淆武器库#

基于WAF绕过经验,我准备了以下混淆技术:

混淆技术原理示例
HTML实体编码将敏感字符转为Unicode实体年终奖&#x5E74;&#x7EC8;&#x5956;
CSS文字反转用CSS reverse文字顺序年终奖<span class="r">奖终年</span>
HTML注释截断在敏感词中插入注释验证验<!-- x -->证
零宽字符插入插入不可见字符分割身份证身<span style="display:none">_</span>份证
字体大小0隐藏通过CSS隐藏干扰字符银行卡银<span style="font-size:0">.</span>行卡

自动化Fuzz测试工具#

4.3 Fuzz测试实战过程#

第一轮:单一混淆技术测试#

针对”年终奖”关键词,测试各种混淆:

结论:所有混淆技术都有效!邮件网关只检测明文,不解析HTML混淆。

第二轮:组合混淆测试#

测试实际钓鱼场景的完整邮件:

测试结果

组合方式投递结果说明
全部明文✗ 拦截基线
仅CSS反转✓ 成功单一混淆有效
仅HTML实体✓ 成功单一混淆有效
混合混淆✓ 成功多种混淆叠加最佳
混合+注释✓ 成功可读性和绕过兼顾

第三轮:Multipart/Alternative测试#

结论:添加纯文本版本可显著提升投递率!

测试对比

邮件格式投递率说明
纯HTML(混淆)68%部分网关仍拦截
HTML+TXT(TXT安全)89%显著提升!
HTML+TXT(两者都混淆)72%TXT也会被检测

最佳实践:纯文本使用安全词汇,HTML中进行混淆

第四轮:CID图片嵌入测试#

为了进一步提升可信度,我测试了CID图片(邮件内嵌图片):

测试结果

  • CID图片不会被URL检测拦截
  • 可以隐藏真实钓鱼链接
  • 提升邮件可信度(看起来像官方邮件)

4.4 Fuzz成果总结#

经过几天的持续测试,得出以下结论:

有效的HTML混淆技术#

黄金组合方案#

最终测试数据对比#

┌────────────────────────────────────────┐
│        邮件网关绕过率演进图           │
└────────────────────────────────────────┘

明文邮件:                    ████ 24%
单一HTML实体编码:            ████████████ 68%
单一CSS反转:                 ██████████████ 72%
混合HTML混淆:                ████████████████ 85%
混合混淆+Multipart:          ███████████████████ 89%
混合+Multipart+CID图片:      █████████████████████ 92.4%
plain

0x05 最终解决方案:Gophish集成与模板优化#

基于Fuzz测试的发现,我将混淆技术集成到Gophish平台中。

5.1 Gophish邮件生成改造#

核心改动#

我在gophishV4Modified/models/email_request.go中实现了Multipart/Alternative支持:

改造要点

  1. 引入html2text库:自动将HTML转换为纯文本
  2. Multipart/Alternative结构
    • 先设置text/plain(安全内容)
    • 再添加text/html(混淆内容)
  3. 业务邮件头:添加X-PriorityImportance提升信任度

5.2 钓鱼邮件模板设计#

基于Fuzz测试结果,我创建了新的钓鱼模板:

钓鱼模板.html(真实版本)#

对应的纯文本版本(可选)#

如果手动指定Text模板,使用安全词汇:

各位同事,您好:

这是关于2025年度工作总结和核对的通知。

请查看相关文档并完成信息确认。

如有问题,欢迎随时联系。

此致
人力资源部
2025年12月28日
latex

策略:纯文本完全干净,邮件网关检测纯文本时无异常;用户打开邮件时默认显示HTML(包含混淆的敏感内容)。

5.3 动态模板生成器(可选)#

为了避免重复模板被机器学习识别,可以实现变体生成:

5.4 URL路由混淆增强#

配合HTML混淆,我也优化了追踪链接:

5.5 最终方案架构#


0x06 最终测试与成果#

6.1 全量测试#

应用所有绕过技术后,我189的测试邮箱终于进信了。

图片674-5253d3d1-b08c-447b-beaa-a8efa4317d23

同时以此策略改了以下邮件标题换为行政通知不出现年终奖等内容,防止邮件title检测,发送了一份测试邮件到客户的企业邮箱:

图片758-d25c8132-926d-4f76-859e-571d078b369a

第二天就收到了好消息:

图片830-c85c45b1-6e88-4d89-8064-aa81a0306c9b

我擦累终于完事了。

提供一个发送成功的EML信息以供fuzz。

AI分析如下:

图片957-6af55fd9-a33d-4e5c-9f29-190544108515

AI分析截图2

开始大批量的进行安全测试:

大批量安全测试截图

最终测试截图


0x07 后记#

这次从0到1的绕过之旅,历时4天,最终完成这个需求。

随着AI技术的发展,邮件网关的检测能力会越来越强。下一步的研究方向可能包括:

  • 利用合法平台(如Google Docs、OneDrive)进行跳转
  • 转向SMS钓鱼(Smishing)等其他渠道

安全对抗是一场永无止境的竞赛。保持学习,持续创新。


附录#

A. Gophish改造Checklist#

B. 参考资源#

Gophish官方资源#

Gophish二次开发与改造#

Evilginx与MFA绕过#

邮件网关绕过技术#

红队钓鱼实战#


END

关于Gophish:从二次开发到语义Fuzz的实战之路
https://astro-pure.js.org/blog/gophish-semantic-fuzz
本文作者 r3rk04·謊言無法穿透石灰水泥
发布于 2026年2月1日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨