フィッシング調査のためのメールヘッダー解析 は何をしますか?
使用タイミング
- フィッシングメールの疑いがある場合、真の発信元を特定するため
- 送信者の真正性を確認し、メールなりすましを検出するため
- インシデント対応時にユーザーがフィッシングリンクをクリックした場合
- 不審なメールの配送経路とリレーサーバーを追跡するため
- SPF、DKIM、DMARCのアライメントを検証し、偽造を特定するため
前提条件
- 不審なメッセージの生メールヘッダー(EML形式またはMSG形式)
- SMTPプロトコルとメールヘッダーフィールドの理解
- SPF/DKIM/DMARC検証のためのDNSルックアップツール(dig, nslookup)へのアクセス
- メールヘッダー分析ツール(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(Sender Policy Framework) | ドメインの許可されたメールサーバーを指定するDNSレコード |
| DKIM(DomainKeys Identified Mail) | メールコンテンツの完全性を検証する暗号署名 |
| 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 | ドメイン登録情報の検索 |
一般的なシナリオ
シナリオ1:CEO詐欺 / ビジネスメール詐欺(BEC) CEOからのメールを装っているが、Reply-ToがGmailアドレスを指している。SPFは送信元IPが偽装されたドメインに許可されていないため失敗し、DKIMは欠落、Fromドメインは類似ドメイン(ceo-company.com vs 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 -> mailbox
認証:
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...) - VTで既知のマルウェア
リスクレベル: 高