使用 Malpedia 分析惡意軟體家族關係
概述
Malpedia 是由 Fraunhofer FKIE 維護的協作平台,收錄了惡意軟體家族及其別名、YARA 規則、威脅行為者關聯和參考報告。該平台記錄了超過 2,600 個惡意軟體家族,是了解惡意軟體譜系、追蹤變種演化以及將惡意軟體連結到特定威脅組織的權威資源。此技能涵蓋了查詢 Malpedia API、繪製惡意軟體家族關係圖譜、提取用於偵測的 YARA 規則,以及建立關於對手所用惡意軟體生態系的情報。
使用時機
- 在調查安全事件時,需要使用 Malpedia 分析惡意軟體家族關係
- 在為此領域建立偵測規則或威脅狩獵查詢時
- 當 SOC 分析師需要此分析類型的結構化程序時
- 在驗證相關攻擊技術的安全監控覆蓋範圍時
先決條件
- Python 3.9+,並安裝
requests、yara-python、stix2函式庫 - Malpedia API 金鑰(請在 https://malpedia.caad.fkie.fraunhofer.de/ 註冊)
- 了解惡意軟體分類和命名慣例
- 熟悉 YARA 規則語法以進行偵測
- 可存取惡意軟體樣本進行驗證(可選)
關鍵概念
Malpedia 資料模型
Malpedia 將惡意軟體組織成「家族」(例如 win.cobalt_strike),每個家族包含:別名(供應商特定的名稱,如 "Beacon"、"CobaltStrike")、YARA 規則(社群和供應商貢獻的)、行為者關聯(使用該家族的威脅組織)、參考報告(記錄該家族的 CTI 報告)以及樣本雜湊(每個變種的代表性樣本)。
惡意軟體家族命名
Malpedia 使用 平台.家族名稱 的格式(例如 win.emotet、elf.mirai、apk.flubot)。平台包括 win(Windows)、elf(Linux)、apk(Android)、osx(macOS)和 py(Python)。這種標準化命名解決了「多名」問題,即不同供應商對同一惡意軟體賦予不同名稱。
家族關係
惡意軟體家族具有以下關係:父子(程式碼重用、分支)、加載器-有效載荷(Emotet 加載 TrickBot,再加載 Ryuk)、共享作者(同一威脅行為者開發多種工具)以及共享基礎設施(共同的 C2 框架)。
工作流程
步驟 1:查詢 Malpedia API 以取得惡意軟體家族
import requests
import json
from collections import defaultdict
class MalpediaClient:
BASE_URL = "https://malpedia.caad.fkie.fraunhofer.de/api"
def __init__(self, api_key):
self.headers = {"Authorization": f"apitoken {api_key}"}
def get_family_list(self):
"""取得所有惡意軟體家族的列表。"""
resp = requests.get(f"{self.BASE_URL}/list/families",
headers=self.headers, timeout=30)
if resp.status_code == 200:
families = resp.json()
print(f"[+] Malpedia: {len(families)} 個惡意軟體家族")
return families
return {}
def get_family_info(self, family_name):
"""取得惡意軟體家族的詳細資訊。"""
resp = requests.get(f"{self.BASE_URL}/get/family/{family_name}",
headers=self.headers, timeout=30)
if resp.status_code == 200:
info = resp.json()
print(f"[+] 家族: {family_name}")
print(f" 別名: {info.get('alt_names', [])}")
print(f" 行為者: {[a.get('value', '') for a in info.get('attribution', [])]}")
print(f" URL: {len(info.get('urls', []))} 個參考")
return info
print(f"[-] 找不到家族: {family_name}")
return None
def get_family_yara(self, family_name):
"""取得惡意軟體家族的 YARA 規則。"""
resp = requests.get(f"{self.BASE_URL}/get/yara/{family_name}",
headers=self.headers, timeout=30)
if resp.status_code == 200:
rules = resp.json()
rule_count = sum(len(v) for v in rules.values()) if isinstance(rules, dict) else 0
print(f"[+] {family_name} 的 YARA 規則: {rule_count} 條規則")
return rules
return {}
def get_actor_families(self, actor_name):
"""取得與威脅行為者相關聯的惡意軟體家族。"""
resp = requests.get(f"{self.BASE_URL}/get/actor/{actor_name}",
headers=self.headers, timeout=30)
if resp.status_code == 200:
data = resp.json()
families = data.get("families", {})
print(f"[+] {actor_name}: {len(families)} 個惡意軟體家族")
return data
return {}
def search_families(self, keyword):
"""根據關鍵字搜尋家族。"""
all_families = self.get_family_list()
matches = {
name: info for name, info in all_families.items()
if keyword.lower() in name.lower()
or keyword.lower() in str(info.get("alt_names", [])).lower()
}
print(f"[+] 搜尋 '{keyword}': {len(matches)} 個符合")
return matches
client = MalpediaClient("YOUR_MALPEDIA_API_KEY")
families = client.get_family_list()
emotet_info = client.get_family_info("win.emotet")
步驟 2:繪製惡意軟體家族關係圖譜
class MalwareFamilyMapper:
def __init__(self, malpedia_client):
self.client = malpedia_client
self.relationship_graph = defaultdict(list)
def map_actor_ecosystem(self, actor_name):
"""繪製威脅行為者使用的惡意軟體生態系。"""
actor_data = self.client.get_actor_families(actor_name)
families = actor_data.get("families", {})
ecosystem = {
"actor": actor_name,
"families": [],
"family_count": len(families),
}
for family_name in families:
info = self.client.get_family_info(family_name)
if info:
ecosystem["families"].append({
"name": family_name,
"aliases": info.get("alt_names", []),
"description": info.get("description", "")[:200],
"shared_actors": [
a.get("value", "")
for a in info.get("attribution", [])
],
"reference_count": len(info.get("urls", [])),
})
print(f"\n=== {actor_name} 惡意軟體生態系 ===")
for fam in ecosystem["families"]:
shared = [a for a in fam["shared_actors"] if a != actor_name]
print(f" {fam['name']}")
print(f" 別名: {fam['aliases'][:5]}")
if shared:
print(f" 也被用於: {shared}")
return ecosystem
def find_shared_tooling(self, actor_names):
"""尋找威脅行為者之間共享的惡意軟體工具。"""
actor_families = {}
for actor in actor_names:
data = self.client.get_actor_families(actor)
actor_families[actor] = set(data.get("families", {}).keys())
# 找出重疊
shared = {}
for i, actor1 in enumerate(actor_names):
for actor2 in actor_names[i+1:]:
common = actor_families[actor1] & actor_families[actor2]
if common:
shared[f"{actor1} <-> {actor2}"] = sorted(common)
print(f"\n=== 共享工具分析 ===")
for pair, families in shared.items():
print(f" {pair}: {len(families)} 個共享家族")
for f in families[:5]:
print(f" - {f}")
return shared
def build_loader_payload_chain(self, family_name):
"""建立某個家族的加載器-有效載荷傳遞鏈。"""
info = self.client.get_family_info(family_name)
if not info:
return {}
chain = {
"family": family_name,
"description": info.get("description", ""),
"known_loaders": [],
"known_payloads": [],
}
# 已知的常見傳遞鏈
known_chains = {
"win.emotet": {"loaders": ["email/macro"], "payloads": ["win.trickbot", "win.qakbot", "win.cobalt_strike"]},
"win.trickbot": {"loaders": ["win.emotet"], "payloads": ["win.ryuk", "win.conti", "win.cobalt_strike"]},
"win.qakbot": {"loaders": ["email/macro", "win.emotet"], "payloads": ["win.cobalt_strike", "win.blackbasta"]},
"win.cobalt_strike": {"loaders": ["win.emotet", "win.trickbot", "win.qakbot"], "payloads": ["ransomware"]},
}
if family_name in known_chains:
chain["known_loaders"] = known_chains[family_name]["loaders"]
chain["known_payloads"] = known_chains[family_name]["payloads"]
return chain
mapper = MalwareFamilyMapper(client)
ecosystem = mapper.map_actor_ecosystem("Wizard Spider")
shared = mapper.find_shared_tooling(["Wizard Spider", "FIN7", "Lazarus Group"])
chain = mapper.build_loader_payload_chain("win.emotet")
步驟 3:提取並編譯 YARA 規則
def compile_yara_ruleset(client, family_names, output_file="malware_yara_rules.yar"):
"""編譯多個惡意軟體家族的 YARA 規則。"""
all_rules = []
for family in family_names:
yara_data = client.get_family_yara(family)
if isinstance(yara_data, dict):
for source, rules in yara_data.items():
if isinstance(rules, list):
for rule in rules:
all_rules.append(f"// Source: {source} - Family: {family}\n{rule}")
elif isinstance(rules, str):
all_rules.append(f"// Source: {source} - Family: {family}\n{rules}")
with open(output_file, "w") as f:
f.write(f"// Malpedia YARA Rules - {len(all_rules)} rules\n")
f.write(f"// Families: {', '.join(family_names)}\n\n")
for rule in all_rules:
f.write(rule + "\n\n")
print(f"[+] 已編譯 {len(all_rules)} 條 YARA 規則至 {output_file}")
return all_rules
compile_yara_ruleset(client, ["win.emotet", "win.trickbot", "win.cobalt_strike"])
驗證標準
- 成功查詢 Malpedia API 以取得惡意軟體家族
- 檢索的家族資訊包含別名、行為者和參考資料
- 正確繪製行為者-家族關係圖譜
- 識別出行為者之間的共享工具
- 提取並編譯 YARA 規則以進行偵測
- 記錄加載器-有效載荷鏈以用於威脅情報