Analyzes raw email headers for phishing investigations: parses Received chains, key fields, verifies SPF/DKIM/DMARC to detect forgery and trace sources.
npx claudepluginhub killvxk/cybersecurity-skills-zhThis skill uses the workspace's default tool permissions.
- 调查疑似钓鱼(Phishing)邮件以确定其真实来源时
Analyzes email headers to detect phishing via Received chains, SPF/DKIM/DMARC failures, IP origins, and routing anomalies using Python scripts and tools like MXToolbox.
Analyzes email headers for phishing by extracting/parsing raw headers, tracing delivery paths, and validating SPF/DKIM/DMARC to detect spoofing.
Parse and analyze email headers to trace phishing origins, verify sender authenticity, and detect spoofing via SPF, DKIM, DMARC validation. For incident response and forensics.
Share bugs, ideas, or general feedback.
# 从 Outlook 导出: 打开邮件 > 文件 > 属性 > Internet 头部
# 从 Gmail 导出: 打开邮件 > 三个点 > 显示原始邮件
# 从 Thunderbird 导出: 查看 > 消息源码
# 如果从取证镜像处理 EML 文件
cp /mnt/evidence/Users/suspect/AppData/Local/Microsoft/Outlook/phishing_email.eml \
/cases/case-2024-001/email/
# 如果处理 PST 文件,提取单个消息
pip install pypff
python3 << 'PYEOF'
import pypff
pst = pypff.file()
pst.open("/cases/case-2024-001/email/outlook.pst")
root = pst.get_root_folder()
def extract_messages(folder, path=""):
for i in range(folder.get_number_of_sub_messages()):
msg = folder.get_sub_message(i)
headers = msg.get_transport_headers()
subject = msg.get_subject()
if headers:
filename = f"/cases/case-2024-001/email/msg_{i}_{subject[:30]}.txt"
with open(filename, 'w') as f:
f.write(headers)
for i in range(folder.get_number_of_sub_folders()):
extract_messages(folder.get_sub_folder(i))
extract_messages(root)
PYEOF
# 使用 Python email 库解析头部
python3 << 'PYEOF'
import email
from email import policy
with open('/cases/case-2024-001/email/phishing_email.eml', 'r') as f:
msg = email.message_from_file(f, policy=policy.default)
print("=== 关键头部字段 ===")
print(f"From: {msg['From']}")
print(f"To: {msg['To']}")
print(f"Subject: {msg['Subject']}")
print(f"Date: {msg['Date']}")
print(f"Message-ID: {msg['Message-ID']}")
print(f"Reply-To: {msg['Reply-To']}")
print(f"Return-Path: {msg['Return-Path']}")
print(f"X-Mailer: {msg['X-Mailer']}")
print(f"X-Originating-IP: {msg['X-Originating-IP']}")
print("\n=== Received 头部(从底部到顶部 = 时间顺序)===")
received_headers = msg.get_all('Received')
if received_headers:
for i, header in enumerate(reversed(received_headers)):
print(f"\n跳 {i+1}: {header.strip()}")
print("\n=== 认证结果 ===")
auth_results = msg.get_all('Authentication-Results')
if auth_results:
for result in auth_results:
print(result)
print(f"\nARC-Authentication-Results: {msg.get('ARC-Authentication-Results', '不存在')}")
print(f"Received-SPF: {msg.get('Received-SPF', '不存在')}")
print(f"DKIM-Signature: {msg.get('DKIM-Signature', '不存在')}")
PYEOF
# 提取信封发件人域名
SENDER_DOMAIN="example-corp.com"
# 检查 SPF 记录
dig TXT $SENDER_DOMAIN +short | grep "v=spf1"
# 示例: "v=spf1 include:_spf.google.com include:sendgrid.net ~all"
# 检查 DKIM 记录(选择器来自 DKIM-Signature 头部,例如 "s=selector1")
DKIM_SELECTOR="selector1"
dig TXT ${DKIM_SELECTOR}._domainkey.${SENDER_DOMAIN} +short
# 检查 DMARC 记录
dig TXT _dmarc.${SENDER_DOMAIN} +short
# 示例: "v=DMARC1; p=reject; rua=mailto:dmarc@example-corp.com; pct=100"
# 对照 SPF 验证发送 IP
# 从第一个 Received 头部提取 IP
SENDING_IP="203.0.113.45"
# 使用 Python 手动进行 SPF 检查
python3 << 'PYEOF'
import spf # pip install pyspf
result, explanation = spf.check2(
i='203.0.113.45',
s='sender@example-corp.com',
h='mail.example-corp.com'
)
print(f"SPF 结果: {result}")
print(f"说明: {explanation}")
# 结果: pass(通过), fail(失败), softfail(软失败), neutral(中性), none(无), temperror(临时错误), permerror(永久错误)
PYEOF
# 检查发送 IP 是否在已知恶意 IP 列表中
# 查询 AbuseIPDB 或 VirusTotal
curl -s "https://api.abuseipdb.com/api/v2/check?ipAddress=${SENDING_IP}" \
-H "Key: YOUR_API_KEY" -H "Accept: application/json" | python3 -m json.tool
# 对发件人域名进行 WHOIS 查询
whois $SENDER_DOMAIN | grep -iE '(registrar|creation|expiration|registrant|nameserver)'
# 检查域名年龄(最近注册的域名可疑)
# DNS 记录调查
dig A $SENDER_DOMAIN +short
dig MX $SENDER_DOMAIN +short
dig NS $SENDER_DOMAIN +short
# 对发送 IP 进行反向 DNS 查询
dig -x $SENDING_IP +short
# 检查仿冒/错字域名
# 使用视觉相似度与合法域名进行比较
python3 << 'PYEOF'
import Levenshtein # pip install python-Levenshtein
legitimate = "microsoft.com"
suspicious = "micr0soft.com"
distance = Levenshtein.distance(legitimate, suspicious)
ratio = Levenshtein.ratio(legitimate, suspicious)
print(f"编辑距离: {distance}")
print(f"相似度: {ratio:.2%}")
if ratio > 0.8:
print("警告: 可能是错字/仿冒域名!")
PYEOF
# 在 VirusTotal 上检查域名声誉
curl -s "https://www.virustotal.com/api/v3/domains/${SENDER_DOMAIN}" \
-H "x-apikey: YOUR_VT_API_KEY" | python3 -m json.tool
# 检查 Reply-To 是否与 From 不同(常见钓鱼指标)
python3 -c "
import email
with open('/cases/case-2024-001/email/phishing_email.eml') as f:
msg = email.message_from_file(f)
from_addr = email.utils.parseaddr(msg['From'])[1]
reply_to = email.utils.parseaddr(msg.get('Reply-To', msg['From']))[1]
if from_addr != reply_to:
print(f'警告: From ({from_addr}) != Reply-To ({reply_to})')
else:
print('From 和 Reply-To 匹配')
"
# 从邮件正文提取 URL
python3 << 'PYEOF'
import email
import re
from email import policy
with open('/cases/case-2024-001/email/phishing_email.eml', 'r') as f:
msg = email.message_from_file(f, policy=policy.default)
body = msg.get_body(preferencelist=('html', 'plain'))
if body:
content = body.get_content()
urls = re.findall(r'https?://[^\s<>"\']+', content)
print("=== 邮件正文中发现的 URL ===")
for url in set(urls):
print(f" {url}")
# 检查 URL 混淆(显示文本 != href)
href_pattern = re.findall(r'<a[^>]*href=["\']([^"\']+)["\'][^>]*>(.*?)</a>', content, re.DOTALL)
print("\n=== 超链接分析 ===")
for href, text in href_pattern:
display_url = re.findall(r'https?://[^\s<]+', text)
if display_url and display_url[0] != href:
print(f" 不匹配: 显示='{display_url[0]}' -> 实际='{href}'")
# 提取附件并计算哈希值
print("\n=== 附件 ===")
for part in msg.walk():
if part.get_content_disposition() == 'attachment':
filename = part.get_filename()
content = part.get_payload(decode=True)
import hashlib
sha256 = hashlib.sha256(content).hexdigest()
print(f" 文件: {filename}, 大小: {len(content)}, SHA-256: {sha256}")
with open(f'/cases/case-2024-001/email/attachments/{filename}', 'wb') as af:
af.write(content)
PYEOF
# 将附件哈希提交给 VirusTotal
# 将 URL 提交给 URLhaus 或 PhishTank 进行声誉检查
| 概念 | 定义 |
|---|---|
| SPF(发件人策略框架) | 指定域名授权邮件服务器的 DNS 记录 |
| DKIM(域名密钥识别邮件) | 验证电子邮件内容完整性的加密签名 |
| DMARC | 将 SPF 和 DKIM 结合用于发件人身份验证的策略框架 |
| Received 头部 | 服务器添加的头部,显示投递链中的每一跳(从底部到顶部读取) |
| Return-Path | 用于退信消息的信封发件人地址;可能与 From 不同 |
| Message-ID | 由原始邮件服务器分配的唯一标识符 |
| X-Originating-IP | 原始发件人 IP 地址(由某些邮件服务添加) |
| 头部伪造 | 攻击者可以伪造 From、Reply-To 和其他头部,但不能伪造 Received 链 |
| 工具 | 用途 |
|---|---|
| MXToolbox | 在线邮件头部分析器和 DNS 查询工具 |
| dig/nslookup | 用于 SPF、DKIM、DMARC 验证的 DNS 记录查询 |
| pyspf | Python SPF 记录验证库 |
| dkimpy | Python DKIM 签名验证库 |
| PhishTool | 专业钓鱼邮件分析平台 |
| VirusTotal | URL 和文件声誉检查服务 |
| AbuseIPDB | IP 地址声誉数据库 |
| whois | 域名注册信息查询 |
场景:CEO 欺诈/商业邮件攻击(BEC) 邮件声称来自 CEO,但 Reply-To 指向 Gmail 地址,SPF 失败(因为发送 IP 未被伪造域名授权),DKIM 缺失,From 域名是仿冒域名(ceo-company.com vs company.com)。
场景:凭据收割钓鱼 邮件包含显示为"login.microsoft.com"但 href 指向仿冒域名的链接,附件是包含带凭据外泄 JavaScript 的假登录页面的 HTML 文件,发送域名三天前刚注册。
场景:通过附件投递恶意软件 带有包含宏的 Office 文档附件的邮件,发件人域名通过 SPF 但账户已被入侵,DKIM 签名有效(从合法基础设施发送),附件 SHA-256 与 VirusTotal 上的已知恶意软件匹配。
场景:使用合法服务的鱼叉式钓鱼(Spearphishing) 攻击者使用合法的邮件营销服务发送钓鱼邮件,SPF 和 DKIM 通过(因为该服务被授权),钓鱼内容在内容中而非基础设施中,需要 URL 和内容分析而非头部认证检查。
电子邮件头部分析报告:
主题: "紧急: 需要支付发票"
发件人: accounting@examp1e-corp.com(已伪造)
Reply-To: payments.urgent@gmail.com(不匹配)
Return-Path: <bounce@mail-server.xyz>
日期: 2024-01-15 09:23:45 UTC
投递路径(4 跳):
跳 1: mail-server.xyz [203.0.113.45] -> relay1.isp.com
跳 2: relay1.isp.com -> mx.target-company.com
跳 3: mx.target-company.com -> internal-filter.target.com
跳 4: internal-filter.target.com -> 邮箱
认证结果:
SPF: 失败(203.0.113.45 未被 examp1e-corp.com 授权)
DKIM: 无(没有签名)
DMARC: 失败(p=none,未强制执行)
钓鱼指标:
- 仿冒域名(examp1e-corp.com vs example-corp.com,96% 相似)
- From/Reply-To 不匹配
- 域名在邮件发送前 2 天注册
- 正文中的 URL 指向凭据收割页面
- 附件: invoice.xlsm(SHA-256: a3f2...)- VirusTotal 上的已知恶意软件
风险级别: 高危