分析勒索軟體洩漏網站情報 是做什麼的?
概述
採用雙重勒索模式的勒索軟體組織,在 Tor 隱藏服務上維護資料洩漏網站(Data Leak Sites, DLS),這些網站會公佈受害者名稱、竊取的資料樣本以及倒數計時器,藉此施加付款壓力。在 2025 年上半年,共有 96 個活躍的勒索軟體組織,每月約公佈 535 名受害者。監控這些網站可獲得關於活躍威脅組織、目標產業、地理模式以及新興勒索軟體家族的寶貴情報。本技能涵蓋如何安全收集 DLS 情報、提取結構化資料、追蹤群組活動趨勢,以及產出針對特定產業的風險評估。
使用時機
- 調查安全事件,需要分析勒索軟體洩漏網站情報時
- 為此領域建立偵測規則或威脅狩獵查詢時
- SOC 分析師需要針對此分析類型取得結構化流程時
- 驗證相關攻擊技術的安全監控涵蓋範圍時
先決條件
- Python 3.9 以上版本,並安裝
requests、beautifulsoup4、pandas、matplotlib函式庫 - 用於存取 .onion 網站的 Tor 代理(SOCKS5)或商業 DLS 監控服務
- 了解勒索軟體雙重勒索商業模式
- 熟悉主要勒索軟體家族(Qilin、Akira、LockBit、BlackCat、Clop)
- 可存取勒索軟體追蹤資訊源(Ransomwatch、RansomLook、DarkFeed)
關鍵概念
雙重勒索模式
現代勒索軟體組織會加密受害者資料,並在加密前外洩資料。洩漏網站作為公開施壓的手段:受害者及其倒數計時器、部分資料樣本和檔案樹會被列出。如果未支付贖金,完整資料就會被公開。部分組織已轉向三重勒索,加入 DDoS 威脅或直接聯繫受害者的客戶。
DLS 情報價值
洩漏網站提供的資訊包括:受害者識別資訊(公司名稱、產業別、國家)、攻擊時間線(列出時間、截止日期、資料公佈時間)、資料量估計、組織能力評估(目標產業、攻擊頻率、營運節奏)以及趨勢分析(新興組織、組織更名、執法單位打擊行動)。
安全收集做法
切勿在生產環境中直接存取 DLS 網站。應使用專用監控服務(Ransomwatch、DarkFeed、KELA、Flashpoint)、Tor 隔離的研究用虛擬機、商業威脅情報平台,或社群維護的資料集。所有分析應在獲得適當授權的隔離環境中進行。
工作流程
步驟 1:從公開資訊源攝取勒索軟體洩漏網站資料
import requests
import json
import pandas as pd
from datetime import datetime, timedelta
from collections import Counter
class RansomwareIntelCollector:
"""從公開追蹤來源收集勒索軟體 DLS 情報。"""
RANSOMWATCH_API = "https://raw.githubusercontent.com/joshhighet/ransomwatch/main/posts.json"
RANSOMWATCH_GROUPS = "https://raw.githubusercontent.com/joshhighet/ransomwatch/main/groups.json"
def __init__(self):
self.posts = []
self.groups = []
def fetch_ransomwatch_data(self):
"""從 ransomwatch 擷取勒索軟體受害者公告。"""
resp = requests.get(self.RANSOMWATCH_API, timeout=30)
if resp.status_code == 200:
self.posts = resp.json()
print(f"[+] 從 ransomwatch 載入 {len(self.posts)} 筆受害者公告")
else:
print(f"[-] 擷取公告失敗:{resp.status_code}")
resp = requests.get(self.RANSOMWATCH_GROUPS, timeout=30)
if resp.status_code == 200:
self.groups = resp.json()
print(f"[+] 載入 {len(self.groups)} 個勒索軟體組織設定檔")
return self.posts
def get_recent_victims(self, days=30):
"""取得最近 N 天內公告的受害者。"""
cutoff = datetime.now() - timedelta(days=days)
recent = []
for post in self.posts:
try:
discovered = datetime.fromisoformat(
post.get("discovered", "").replace("Z", "+00:00")
)
if discovered.replace(tzinfo=None) >= cutoff:
recent.append(post)
except (ValueError, TypeError):
continue
print(f"[+] 最近 {days} 天內有 {len(recent)} 名受害者")
return recent
def get_group_activity(self, group_name):
"""取得特定勒索軟體組織的所有公告。"""
group_posts = [
p for p in self.posts
if p.get("group_name", "").lower() == group_name.lower()
]
print(f"[+] {group_name}:共 {len(group_posts)} 名受害者")
return group_posts
collector = RansomwareIntelCollector()
collector.fetch_ransomwatch_data()
recent = collector.get_recent_victims(days=30)
步驟 2:分析組織活動與趨勢
def analyze_group_trends(posts, top_n=15):
"""分析勒索軟體組織活動趨勢。"""
group_counts = Counter(p.get("group_name", "unknown") for p in posts)
monthly_activity = {}
for post in posts:
try:
date = datetime.fromisoformat(
post.get("discovered", "").replace("Z", "+00:00")
)
month_key = date.strftime("%Y-%m")
group = post.get("group_name", "unknown")
if month_key not in monthly_activity:
monthly_activity[month_key] = Counter()
monthly_activity[month_key][group] += 1
except (ValueError, TypeError):
continue
analysis = {
"total_posts": len(posts),
"unique_groups": len(group_counts),
"top_groups": group_counts.most_common(top_n),
"monthly_totals": {
month: sum(counts.values())
for month, counts in sorted(monthly_activity.items())
},
"monthly_top_groups": {
month: counts.most_common(5)
for month, counts in sorted(monthly_activity.items())
},
}
print(f"\n=== 勒索軟體組織活動 ===")
print(f"追蹤中的受害者總數:{analysis['total_posts']}")
print(f"活躍組織:{analysis['unique_groups']}")
print(f"\n前 {top_n} 大組織:")
for group, count in analysis["top_groups"]:
print(f" {group}:{count} 名受害者")
return analysis
trends = analyze_group_trends(collector.posts)
步驟 3:產業與地理區域風險評估
def assess_sector_risk(posts, target_sector=None, target_country=None):
"""評估特定產業或地理區域的勒索軟體風險。"""
sector_data = {}
country_data = {}
for post in posts:
# 提取產業資訊(並非所有資訊源都包含此欄位)
sector = post.get("sector", post.get("industry", "unknown"))
country = post.get("country", "unknown")
if sector not in sector_data:
sector_data[sector] = {"count": 0, "groups": Counter(), "recent": []}
sector_data[sector]["count"] += 1
sector_data[sector]["groups"][post.get("group_name", "")] += 1
if country not in country_data:
country_data[country] = {"count": 0, "groups": Counter()}
country_data[country]["count"] += 1
country_data[country]["groups"][post.get("group_name", "")] += 1
# 產業風險評分
total = len(posts)
risk_assessment = {
"total_victims": total,
"sectors": {},
"countries": {},
}
for sector, data in sorted(sector_data.items(), key=lambda x: -x[1]["count"]):
pct = (data["count"] / total * 100) if total > 0 else 0
risk_assessment["sectors"][sector] = {
"victim_count": data["count"],
"percentage": round(pct, 1),
"top_groups": data["groups"].most_common(5),
"risk_level": (
"critical" if pct > 15
else "high" if pct > 8
else "medium" if pct > 3
else "low"
),
}
for country, data in sorted(country_data.items(), key=lambda x: -x[1]["count"]):
pct = (data["count"] / total * 100) if total > 0 else 0
risk_assessment["countries"][country] = {
"victim_count": data["count"],
"percentage": round(pct, 1),
"top_groups": data["groups"].most_common(5),
}
return risk_assessment
risk = assess_sector_risk(collector.posts)
步驟 4:追蹤新興與更名組織
def track_new_groups(posts, lookback_days=90):
"""識別新出現的勒索軟體組織。"""
group_first_seen = {}
for post in posts:
group = post.get("group_name", "")
try:
date = datetime.fromisoformat(
post.get("discovered", "").replace("Z", "+00:00")
)
if group not in group_first_seen or date < group_first_seen[group]["first_seen"]:
group_first_seen[group] = {
"first_seen": date,
"first_victim": post.get("post_title", ""),
}
except (ValueError, TypeError):
continue
cutoff = datetime.now() - timedelta(days=lookback_days)
new_groups = {
group: info for group, info in group_first_seen.items()
if info["first_seen"].replace(tzinfo=None) >= cutoff
}
# 統計每個新組織的受害者總數
for group in new_groups:
victims = [p for p in posts if p.get("group_name") == group]
new_groups[group]["total_victims"] = len(victims)
new_groups[group]["avg_per_month"] = round(
len(victims) / max(1, lookback_days / 30), 1
)
print(f"\n=== 新組織(最近 {lookback_days} 天) ===")
for group, info in sorted(new_groups.items(), key=lambda x: -x[1]["total_victims"]):
print(f" {group}:{info['total_victims']} 名受害者,"
f"首次出現於 {info['first_seen'].strftime('%Y-%m-%d')}")
return new_groups
new_groups = track_new_groups(collector.posts, lookback_days=90)
步驟 5:產生情報報告
def generate_ransomware_intel_report(trends, risk, new_groups):
"""產生勒索軟體威脅情報報告。"""
report = f"""# 勒索軟體威脅情報報告
產生時間:{datetime.now().isoformat()}
## 執行摘要
- **追蹤中的受害者總數**:{trends['total_posts']}
- **活躍勒索軟體組織數**:{trends['unique_groups']}
- **新組織(最近 90 天)**:{len(new_groups)}
## 主要活躍組織
| 排名 | 組織 | 受害者數 |
|------|------|----------|
"""
for i, (group, count) in enumerate(trends["top_groups"][:10], 1):
report += f"| {i} | {group} | {count} |\n"
report += "\n## 新興組織\n"
for group, info in sorted(new_groups.items(), key=lambda x: -x[1]["total_victims"])[:10]:
report += f"- **{group}**:自 {info['first_seen'].strftime('%Y-%m-%d')} 起共 {info['total_victims']} 名受害者\n"
report += "\n## 產業風險評估\n"
report += "| 產業 | 受害者數 | 佔比 | 風險等級 |\n|------|----------|------|----------|\n"
for sector, data in list(risk["sectors"].items())[:10]:
report += f"| {sector} | {data['victim_count']} | {data['percentage']}% | {data['risk_level'].upper()} |\n"
report += """
## 建議
1. 每日監控您組織及供應鏈合作夥伴的 DLS 資訊源
2. 優先修補主要活躍組織所利用的漏洞
3. 實施離線備份策略以降低勒索籌碼
4. 針對勒索軟體情境進行桌上演練
5. 與產業 ISAC 及威脅分享社群分享入侵指標
"""
with open("ransomware_intel_report.md", "w") as f:
f.write(report)
print("[+] 報告已儲存:ransomware_intel_report.md")
return report
generate_ransomware_intel_report(trends, risk, new_groups)
驗證標準
- 已從公開追蹤資訊源攝取勒索軟體受害者資料
- 已分析群組活動趨勢並提供每月細目
- 已產出產業與地理區域風險評估
- 已識別新興組織並提供活動指標
- 已產生具有可行建議的情報報告
- 所有收集工作均透過授權的公開來源進行