Análisis de Relaciones de Familias de Malware con Malpedia
Resumen
Malpedia es una plataforma colaborativa mantenida por Fraunhofer FKIE que cataloga familias de malware con sus alias, reglas YARA, asociaciones con actores de amenazas e informes de referencia. Con más de 2600 familias de malware documentadas, sirve como el recurso definitivo para comprender linajes de malware, rastrear la evolución de variantes y vincular malware a grupos de amenazas específicos. Esta habilidad cubre la consulta a la API de Malpedia, el mapeo de relaciones entre familias de malware, la extracción de reglas YARA para detección y la construcción de inteligencia sobre ecosistemas de malware utilizados por adversarios.
Cuándo Usarlo
- Al investigar incidentes de seguridad que requieren analizar relaciones de familias de malware con Malpedia.
- Al construir reglas de detección o consultas de caza de amenazas para este dominio.
- Cuando analistas de SOC necesitan procedimientos estructurados para este tipo de análisis.
- Al validar la cobertura de monitoreo de seguridad para técnicas de ataque relacionadas.
Requisitos Previos
- Python 3.9+ con las librerías
requests,yara-python,stix2. - Clave API de Malpedia (registrarse en https://malpedia.caad.fkie.fraunhofer.de/).
- Comprensión de la clasificación de malware y las convenciones de nomenclatura.
- Familiaridad con la sintaxis de reglas YARA para detección.
- Acceso a muestras de malware para validación (opcional).
Conceptos Clave
Modelo de Datos de Malpedia
Malpedia organiza el malware en Familias (ej., "win.cobalt_strike"), cada una contiene: alias (nombres específicos de proveedores como "Beacon", "CobaltStrike"), reglas YARA (contribuidas por la comunidad y proveedores), asociaciones con actores (grupos de amenazas que usan la familia), informes de referencia (informes de CTI que documentan la familia) y hashes de muestras (muestras representativas para cada variante).
Nomenclatura de Familias de Malware
Malpedia utiliza el formato plataforma.nombre_familia (ej., win.emotet, elf.mirai, apk.flubot). Las plataformas incluyen win (Windows), elf (Linux), apk (Android), osx (macOS) y py (Python). Esta nomenclatura estandarizada resuelve el problema de "muchos nombres" donde diferentes proveedores asignan nombres distintos al mismo malware.
Relaciones entre Familias
Las familias de malware tienen relaciones que incluyen: padre-hijo (reutilización de código, bifurcaciones), loader-payload (Emotet carga TrickBot, que carga Ryuk), autoría compartida (el mismo actor de amenaza desarrolla múltiples herramientas) e infraestructura compartida (marcos C2 comunes).
Flujo de Trabajo
Paso 1: Consultar la API de Malpedia para Familias de Malware
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):
"""Obtiene la lista de todas las familias de malware."""
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)} familias de malware")
return families
return {}
def get_family_info(self, family_name):
"""Obtiene información detallada sobre una familia de malware."""
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"[+] Familia: {family_name}")
print(f" Alias: {info.get('alt_names', [])}")
print(f" Actores: {[a.get('value', '') for a in info.get('attribution', [])]}")
print(f" URLs: {len(info.get('urls', []))} referencias")
return info
print(f"[-] Familia no encontrada: {family_name}")
return None
def get_family_yara(self, family_name):
"""Obtiene reglas YARA para una familia de malware."""
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"[+] Reglas YARA para {family_name}: {rule_count} reglas")
return rules
return {}
def get_actor_families(self, actor_name):
"""Obtiene las familias de malware asociadas con un actor de amenaza."""
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)} familias de malware")
return data
return {}
def search_families(self, keyword):
"""Busca familias por palabra clave."""
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"[+] Búsqueda '{keyword}': {len(matches)} coincidencias")
return matches
client = MalpediaClient("TU_CLAVE_API_MALPEDIA")
families = client.get_family_list()
emotet_info = client.get_family_info("win.emotet")
Paso 2: Mapear Relaciones entre Familias de Malware
class MalwareFamilyMapper:
def __init__(self, malpedia_client):
self.client = malpedia_client
self.relationship_graph = defaultdict(list)
def map_actor_ecosystem(self, actor_name):
"""Mapea el ecosistema de malware utilizado por un actor de amenaza."""
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=== Ecosistema de Malware de {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" Alias: {fam['aliases'][:5]}")
if shared:
print(f" También usado por: {shared}")
return ecosystem
def find_shared_tooling(self, actor_names):
"""Encuentra familias de malware compartidas entre actores de amenaza."""
actor_families = {}
for actor in actor_names:
data = self.client.get_actor_families(actor)
actor_families[actor] = set(data.get("families", {}).keys())
# Encuentra solapamientos
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=== Análisis de Herramientas Compartidas ===")
for pair, families in shared.items():
print(f" {pair}: {len(families)} familias compartidas")
for f in families[:5]:
print(f" - {f}")
return shared
def build_loader_payload_chain(self, family_name):
"""Construye la cadena de entrega loader-payload para una familia."""
info = self.client.get_family_info(family_name)
if not info:
return {}
chain = {
"family": family_name,
"description": info.get("description", ""),
"known_loaders": [],
"known_payloads": [],
}
# Cadenas de entrega conocidas comunes
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")
Paso 3: Extraer y Compilar Reglas YARA
def compile_yara_ruleset(client, family_names, output_file="malware_yara_rules.yar"):
"""Compila reglas YARA para múltiples familias de malware."""
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"// Fuente: {source} - Familia: {family}\n{rule}")
elif isinstance(rules, str):
all_rules.append(f"// Fuente: {source} - Familia: {family}\n{rules}")
with open(output_file, "w") as f:
f.write(f"// Reglas YARA de Malpedia - {len(all_rules)} reglas\n")
f.write(f"// Familias: {', '.join(family_names)}\n\n")
for rule in all_rules:
f.write(rule + "\n\n")
print(f"[+] Compiladas {len(all_rules)} reglas YARA en {output_file}")
return all_rules
compile_yara_ruleset(client, ["win.emotet", "win.trickbot", "win.cobalt_strike"])
Criterios de Validación
- API de Malpedia consultada exitosamente para familias de malware.
- Información de la familia recuperada con alias, actores y referencias.
- Relaciones actor-familia mapeadas correctamente.
- Herramientas compartidas entre actores identificadas.
- Reglas YARA extraídas y compiladas para detección.
- Cadenas loader-payload documentadas para inteligencia de amenazas.