Análise de Artefatos de Malware em Cadeia de Suprimentos
Visão Geral
Ataques à cadeia de suprimentos comprometem canais legítimos de distribuição de software para entregar malware por meio de mecanismos de atualização confiáveis. Exemplos notáveis incluem SolarWinds SUNBURST (2020, afetando mais de 18.000 clientes), 3CX SmoothOperator (2023, um ataque em cascata originado da Trading Technologies) e inúmeras campanhas de envenenamento de pacotes npm/PyPI. A análise envolve comparar binários trojanizados com versões legítimas, identificar código injetado em artefatos de build, examinar anomalias de assinatura de código e rastrear a cadeia de infecção desde o comprometimento inicial até a entrega do payload. Em 2025, ataques à cadeia de suprimentos representam 30% de todas as violações, um aumento de 100% em relação aos anos anteriores.
Quando Usar
- Ao investigar incidentes de segurança que exigem análise de artefatos de malware de cadeia de suprimentos
- Ao criar regras de detecção ou consultas de threat hunting para este domínio
- Quando analistas de SOC precisam de procedimentos estruturados para este tipo de análise
- Ao validar a cobertura de monitoramento de segurança para técnicas de ataque relacionadas
Pré-requisitos
- Python 3.9+ com
pefile,ssdeep,hashlib - Ferramentas de diff binário (BinDiff, Diaphora)
- Ferramentas de verificação de assinatura de código (sigcheck, codesign)
- Ferramentas de análise de composição de software (SCA)
- Acesso a versões legítimas de software para comparação
- Monitoramento de repositórios de pacotes (npm, PyPI, NuGet)
Fluxo de Trabalho
Passo 1: Análise de Comparação Binária
#!/usr/bin/env python3
"""Compara binário trojanizado com a versão legítima."""
import hashlib
import pefile
import sys
import json
def compare_pe_files(legitimate_path, suspect_path):
"""Compara estruturas de arquivo PE entre versões legítima e suspeita."""
legit_pe = pefile.PE(legitimate_path)
suspect_pe = pefile.PE(suspect_path)
report = {"differences": [], "suspicious_sections": [], "import_changes": []}
# Compara seções
legit_sections = {s.Name.rstrip(b'\x00').decode(): {
"size": s.SizeOfRawData,
"entropy": s.get_entropy(),
"characteristics": s.Characteristics,
} for s in legit_pe.sections}
suspect_sections = {s.Name.rstrip(b'\x00').decode(): {
"size": s.SizeOfRawData,
"entropy": s.get_entropy(),
"characteristics": s.Characteristics,
} for s in suspect_pe.sections}
# Encontra seções novas ou modificadas
for name, props in suspect_sections.items():
if name not in legit_sections:
report["suspicious_sections"].append({
"name": name, "reason": "Nova seção não presente na versão legítima",
"size": props["size"], "entropy": round(props["entropy"], 2),
})
elif abs(props["size"] - legit_sections[name]["size"]) > 1024:
report["suspicious_sections"].append({
"name": name, "reason": "Tamanho da seção alterado significativamente",
"legit_size": legit_sections[name]["size"],
"suspect_size": props["size"],
})
# Compara imports
legit_imports = set()
if hasattr(legit_pe, 'DIRECTORY_ENTRY_IMPORT'):
for entry in legit_pe.DIRECTORY_ENTRY_IMPORT:
for imp in entry.imports:
if imp.name:
legit_imports.add(f"{entry.dll.decode()}!{imp.name.decode()}")
suspect_imports = set()
if hasattr(suspect_pe, 'DIRECTORY_ENTRY_IMPORT'):
for entry in suspect_pe.DIRECTORY_ENTRY_IMPORT:
for imp in entry.imports:
if imp.name:
suspect_imports.add(f"{entry.dll.decode()}!{imp.name.decode()}")
new_imports = suspect_imports - legit_imports
if new_imports:
report["import_changes"] = list(new_imports)
# Verifica assinatura de código
report["legit_signed"] = bool(legit_pe.OPTIONAL_HEADER.DATA_DIRECTORY[4].Size)
report["suspect_signed"] = bool(suspect_pe.OPTIONAL_HEADER.DATA_DIRECTORY[4].Size)
return report
def hash_file(filepath):
"""Calcula múltiplos hashes para um arquivo."""
hashes = {}
with open(filepath, 'rb') as f:
data = f.read()
for algo in ['md5', 'sha1', 'sha256']:
h = hashlib.new(algo)
h.update(data)
hashes[algo] = h.hexdigest()
return hashes
if __name__ == "__main__":
if len(sys.argv) < 3:
print(f"Uso: {sys.argv[0]} <binario_legitimo> <binario_suspeito>")
sys.exit(1)
report = compare_pe_files(sys.argv[1], sys.argv[2])
print(json.dumps(report, indent=2))
Critérios de Validação
- Componentes trojanizados identificados por meio de diff binário
- Código injetado isolado e analisado separadamente
- Anomalias de assinatura de código documentadas
- Linha do tempo da infecção reconstruída a partir de artefatos de build
- Escopo de impacto downstream avaliado em sistemas afetados
- IOCs extraídos para detecção e bloqueio