分析電子郵件標頭以調查釣魚攻擊 是做什麼的?
使用時機
- 調查可疑的釣魚郵件,以判斷其真實來源
- 驗證寄件者真實性並偵測電子郵件偽造
- 使用者已點擊釣魚連結時的應變處理
- 追蹤可疑郵件的送達路徑與中繼伺服器
- 驗證 SPF、DKIM 與 DMARC 的一致性,以識別偽造
必要條件
- 可疑郵件的原始電子郵件標頭(EML 或 MSG 格式)
- 了解 SMTP 協定與電子郵件標頭欄位
- 使用 DNS 查詢工具(dig、nslookup)進行 SPF/DKIM/DMARC 驗證的能力
- 電子郵件標頭分析工具(MHA、emailheaders.net 概念)
- 安裝 Python 以及電子郵件解析函式庫以進行自動化分析
- 使用威脅情資平台查詢 IP/網域信譽
工作流程
步驟 1:提取原始電子郵件標頭
# 從 Outlook 匯出:開啟郵件 > 檔案 > 內容 > 網際網路標題
# 從 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
步驟 2:解析電子郵件標頭鏈
# 使用 Python 電子郵件函式庫解析標頭
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
步驟 3:驗證 SPF、DKIM 與 DMARC 記錄
# 擷取信封寄件者網域
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:[email protected]; pct=100"
# 驗證發送 IP 是否符合 SPF
# 從第一個 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='[email protected]',
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
步驟 4:分析寄件者網域與基礎設施
# 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 一致')
"
步驟 5:檢查郵件內文與附件
# 從郵件內文提取 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(DomainKeys 識別郵件) | 密碼學簽章,驗證郵件內容完整性 |
| DMARC | 結合 SPF 與 DKIM 的政策架構,用於寄件者驗證 |
| Received 標頭 | 伺服器新增的標頭,顯示送達鏈中的每個跳點(由下至上閱讀) |
| Return-Path | 用於退信的信封寄件者地址;可能與 From 不同 |
| Message-ID | 原始郵件伺服器指派的唯一識別碼 |
| X-Originating-IP | 原始寄件者 IP 位址(部分郵件服務會加入) |
| 標頭偽造 | 攻擊者可偽造 From、Reply-To 等標頭,但無法偽造 Received 鏈 |
工具與系統
| 工具 | 用途 |
|---|---|
| MXToolbox | 線上電子郵件標頭分析器與 DNS 查詢 |
| dig/nslookup | DNS 記錄查詢,用於 SPF、DKIM、DMARC 驗證 |
| pyspf | Python SPF 記錄驗證函式庫 |
| dkimpy | Python DKIM 簽章驗證函式庫 |
| PhishTool | 專門的釣魚郵件分析平台 |
| VirusTotal | URL 與檔案信譽檢查服務 |
| AbuseIPDB | IP 位址信譽資料庫 |
| whois | 網域註冊資訊查詢 |
常見場景
場景 1:執行長詐騙 / 企業電子郵件入侵 郵件聲稱來自執行長,但 Reply-To 指向 Gmail 地址;SPF 驗證失敗,因為發送 IP 未獲得該偽造網域的授權;缺少 DKIM;寄件者網域為相似網域(ceo-company.com 而非 company.com)。
場景 2:憑證竊取釣魚 郵件包含顯示文字為 "login.microsoft.com" 但 href 指向相似網域的超連結;附件為 HTML 檔案,內含偽造登入頁面與憑證外洩 JavaScript;寄件者網域僅註冊 3 天。
場景 3:透過附件傳遞惡意軟體 郵件附帶含巨集的 Office 文件;寄件者網域 SPF 驗證通過(但該帳戶已遭入侵);DKIM 簽章有效(透過合法基礎設施發送);附件 SHA-256 雜湊與 VirusTotal 上的已知惡意軟體相符。
場景 4:利用合法服務的魚叉式釣魚 攻擊者使用合法的電子郵件行銷服務發送釣魚郵件;SPF 與 DKIM 通過,因為該服務已獲得授權;釣魚行為存在於郵件內容而非基礎設施;需要 URL 與內容分析,而非標頭驗證檢查。
輸出格式
電子郵件標頭分析報告:
主旨: "緊急:需支付發票"
From: [email protected](已偽造)
Reply-To: [email protected](不一致)
Return-Path: <[email protected]>
日期: 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 與 example-corp.com 相似度 96%)
- From/Reply-To 不一致
- 網域於郵件寄送前 2 天註冊
- 郵件內文 URL 指向憑證竊取頁面
- 附件:invoice.xlsm(SHA-256:a3f2...)- VirusTotal 上已知的惡意軟體
風險等級:高