Ralphare/phishing-email-analyzer
GitHub: Ralphare/phishing-email-analyzer
一款防御性钓鱼邮件分诊工具,通过解析 .eml 文件对邮件身份验证、URL、附件及社会工程学特征进行加权风险评分,帮助安全分析师快速判断邮件威胁等级。
Stars: 0 | Forks: 0
# Phishalyzer — 钓鱼邮件分析器

这是一款防御性分流工具,它接收原始的 `.eml` 文件,并生成一份清晰、带有详细解释的钓鱼风险报告,附带 0-100 的加权评分。专为 SOC 风格的工作流构建:它不仅会标记问题,还会像资深分析师指导新人排查可疑邮件那样,解释每一项发现*为何*重要。
100% 使用 Python 标准库。完全离线运行。对于格式错误的输入(如损坏的 MIME、伪造的字符集和缺失的标头),它们会被作为分析发现记录下来,而绝不会引发崩溃异常。
## 检查内容
**1. 邮件身份验证 (SPF / DKIM / DMARC)**
解析接收邮件服务器写入的 `Authentication-Results` 标头并解读裁定结果,包括一些隐蔽的异常情况:DKIM 验证通过但与可见的 From: 域名*未对齐*,存在冲突的(可能是攻击者注入的)Authentication-Results 标头,以及 Reply-To / Return-Path 域名与 From: 域名不一致。
**2. URL**
从纯文本和 HTML 正文中提取所有链接(包括经过防御性处理的 `hxxp://` 表示法),然后标记:
- 针对约 25 个常被冒充品牌的域名伪装/拼写错误检测(基于编辑距离:`paypa1-secure.com` 与 `paypal` 的编辑距离仅为 1)
- 将受信任品牌名称硬塞到不相关域名的子域中(`paypal.com.account-verify.net`)
- 原始 IP 链接、URL 缩短服务、`user@host` 混淆
- 可见文本显示为一个域名,而 href 实际指向另一个域名的 HTML 锚点 —— 这正是“点击前先悬停检查”所要防范的骗局
- 指向登录类页面的纯 HTTP 链接
**3. 附件**
枚举所有附件(包括为躲避简单扫描器而标记为 `inline` 的附件),并标记可直接执行的文件类型(`.exe`、`.scr`、`.js` 等)、双重扩展名(`invoice.pdf.exe`)、启用宏的 Office 格式(`.docm`、`.xlsm`)、旧版 Office 格式、归档/磁盘镜像容器、HTML 附件,以及后宏时代的诱导文件(`.one`、`.xll`、`.chm`)。
**4. 正文社会工程学
通过模式匹配识别钓鱼邮件实际使用的语言:紧急性与最后期限、账号停用威胁、直接索取凭证/付款请求、虚假发票、奖品诱饵、CEO 欺诈中的保密要求(“帮个小忙”、礼品卡)、通用问候语 —— 此外还包括发送域名并不具备该品牌所有权,却在显示名称中声称代表该品牌的情况。
**5. 加权评分**
各项发现带有严重程度(INFO=0 …… CRITICAL=40 分),且在每个类别内部收益递减,因此一次 DMARC 失败的权重会大于十次弱关键词命中;一封包含 30 个链接的垃圾邮件也不会因为错误的原因而拉满分值。裁定分级:0–19 可能为安全,20–44 低风险,45–69 可疑,70–100 极可能为钓鱼邮件。
## 项目结构
```
phishing-analyzer/
├── analyze.py # CLI entry point
├── requirements.txt
├── README.md
├── phishalyzer/
│ ├── __init__.py
│ ├── eml_parser.py # crash-proof .eml loading & decoding
│ ├── findings.py # shared Finding dataclass
│ ├── auth_checks.py # SPF / DKIM / DMARC interpretation
│ ├── url_checks.py # link extraction & lookalike detection
│ ├── attachment_checks.py # dangerous file-type flagging
│ ├── body_checks.py # social-engineering language signals
│ ├── scoring.py # weighted 0–100 score
│ └── report.py # console + JSON report rendering
└── samples/
├── benign_newsletter.eml # scores 0 — LIKELY BENIGN
├── subtle_borderline.eml # scores 55 — SUSPICIOUS
└── obvious_phishing.eml # scores 100 — HIGH RISK
```
## 安装
要求 Python 3.10+。离线使用无任何依赖:
```
git clone && cd phishing-analyzer
python3 analyze.py samples/obvious_phishing.eml # that's it
```
可选 — 启用 `--online` DNS 查询(检查发件人域名是否甚至发布了 SPF/DMARC 记录):
```
pip install -r requirements.txt
```
## 用法
```
python3 analyze.py # human-readable report
python3 analyze.py --json # machine-readable (SIEM/jq)
python3 analyze.py --no-color # plain text (files, tickets)
python3 analyze.py --online # + live DNS SPF/DMARC lookups
```
退出代码:`0` 分析完成,`2` 文件无法读取。
## 示例输出(节选自 obvious_phishing.eml)
```
==============================================================================
PHISHING EMAIL ANALYSIS REPORT
==============================================================================
From: PayPal Security Team
Subject: URGENT: Your account will be suspended within 24 hours
Reply-To: recovery-desk@mail-blast-747.xyz
URLs found: 4
Attachments: 1 (SecurityForm.pdf.exe)
==============================================================================
RISK SCORE: 100/100 VERDICT: HIGH RISK — LIKELY PHISHING
Strong, converging indicators of phishing. Quarantine, report to your
security team, and hunt for other recipients of the same campaign.
==============================================================================
[AUTHENTICATION]
--------------------------------------------------------------------------
[CRITICAL] DMARC: fail
The visible sender 'paypal.com' could NOT be verified.
Why it matters: neither SPF nor DKIM passed in alignment with the
visible From: domain — the classic signature of From:-header spoofing.
[URLS]
--------------------------------------------------------------------------
[CRITICAL] Likely typosquatted domain
'paypa1-secure-verification.com' looks like 'paypal.com'
(token 'paypa1' is 1 edit(s) from 'paypal').
[CRITICAL] Link text doesn't match real destination
Visible text shows 'paypal.com' but the link goes to
'paypa1-secure-verification.com'.
...
```
运行所有三个示例以查看完整的分数范围:
```
for f in samples/*.eml; do python3 analyze.py "$f"; done
```
## 各项检查如何映射到真实的钓鱼策略
| 检查项 | 拦截的真实场景策略 |
|---|---|
| DMARC 失败 | From: 标头欺骗 —— 在发送自攻击者基础设施的同时,显示为 `service@paypal.com`。DMARC 是唯一能够验证*用户实际看到*的地址的协议。 |
| SPF 失败 / 软失败 | 来自未经授权服务器的直接欺骗;从未关心过信封域策略的简陋攻击者基础设施。 |
| 未对齐的 DKIM 通过 | “技术上已签名”的邮件,但其签名属于攻击者自己的域名 —— 来自 `evil.com` 的有效签名根本不能用来证明其与 `paypal.com` 有任何关系。 |
| Reply-To 不匹配 | BEC/凭证收集:伪造 From: 地址,但将回复路由到攻击者控制的邮箱。 |
| 域名伪装检测 | 注册外观相似的域名(`paypa1`、`micros0ft`、`arnazon`),专门因为它们能在一瞥之间不被识破。 |
| 子域名中的品牌名 | `paypal.com.security-check.net` —— 利用从左到右的阅读习惯;只有最右侧的可注册域名才能标识所有者。 |
| 文本/href 不匹配 | 锚点显示受信任的 URL,而 href 指向其他地方 —— 这种做法没有任何合法理由。 |
| 缩短服务与原始 IP | 隐藏目的地并规避信誉过滤;使用没有注册域名的临时或受损主机。 |
| 可执行文件 / 双重扩展名附件 | 利用 Windows 隐藏已知扩展名的恶意软件释放器(`invoice.pdf.exe` 会显示为 `invoice.pdf`)。 |
| 启用宏的 Office | Emotet/Qakbot 时代的传播链:诱导文本告诉受害者点击“启用内容”,从而运行 VBA payload。 |
| 归档文件 / ISO 镜像 | 规避过滤器并绕过 Mark-of-the-Web 清除,导致 SmartScreen 无法发出警告。 |
| 紧急性 / 账号威胁 / 索取凭证语言 | 钓鱼攻击的心理核心:人为制造最后期限和对损失的恐惧,从而让受害者放弃进行核实验证。 |
| 保密 + 礼品卡措辞 | CEO 欺诈:冒充权威,将受害者与任何可能会说“这是个骗局”的人隔离开来。 |
| 通用问候语 | 群发钓鱼工具包无法实现个性化;而你的银行知道你的名字。 |
## 设计说明
- **解读裁定,而非重新验证。** 身份验证结果来自接收服务器写入的 `Authentication-Results` 标头,因为投递时的检查(针对实际连接的 IP)在事后是无法重现的 —— 而且这让该工具能够保持完全离线。
- **信任但要验证标头本身。** 存在多个冲突的 Authentication-Results 标头会被标记,因为攻击者会预先注入伪造的“通过”标头,期望工具会盲目信任第一个标头。
- **评分是分流辅助手段,而非最终裁定。** 报告对此作了明确说明。一个完美的评分并不能洗清一封没有链接的定向 BEC 邮件的嫌疑;最终还是需要分析师去阅读各项具体发现。
## 后续扩展计划
1. **附件内容检查** — 对附件进行哈希处理 (SHA-256),提取并扫描 ZIP 内部,使用 `oletools` 检测 OLE/OOXML 文件中的 VBA 宏,并可选择针对本地威胁情报列表查询哈希值。
2. **接收链跳分析** — 自下而上遍历 `Received:` 标头,以发现地理/ASN 异常及伪造的早期节点。
3. **同形异义词/IDN 检测** — 将域名伪装检查扩展到 punycode(`xn--`)域名和 Unicode 易混淆字符(例如带有西里尔字母 'а' 的 `pаypal.com`)。
4. **批处理模式 + CSV/JSONL 导出** — 分析整个邮箱的导出文件,并将结果作为自定义事件馈送到您的 Wazuh 实例中以用于仪表板展示。
5. **本地 URL 信誉缓存** — 在进行任何在线查询之前,可选地参考离线列表(例如已下载的 OpenPhish/URLhaus 快照)。
## 范围与道德规范
仅限防御性分析:该工具仅进行解析和报告;绝不联系 URL、引爆附件或生成内容。示例“钓鱼”邮件是用于测试检测器的静态测试文本。
标签:Python, 安全运营, 扫描框架, 无后门, 逆向工具, 邮件安全, 钓鱼检测