Analyzing Supply Chain Malware Artifacts
Overview
Supply chain attacks compromise legitimate software distribution channels to deliver malware through trusted update mechanisms. Notable examples include SolarWinds SUNBURST (2020, affecting 18,000+ customers), 3CX SmoothOperator (2023, a cascading supply chain attack originating from Trading Technologies), and numerous npm/PyPI package poisoning campaigns. Analysis involves comparing trojanized binaries against legitimate versions, identifying injected code in build artifacts, examining code signing anomalies, and tracing the infection chain from initial compromise through payload delivery. As of 2025, supply chain attacks account for 30% of all breaches, a 100% increase from prior years.
When to Use
- When investigating security incidents that require analyzing supply chain malware artifacts
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
Prerequisites
- Python 3.9+ with
pefile, ssdeep, hashlib
- Binary diff tools (BinDiff, Diaphora)
- Code signing verification tools (sigcheck, codesign)
- Software composition analysis (SCA) tools
- Access to legitimate software versions for comparison
- Package repository monitoring (npm, PyPI, NuGet)
Workflow
Step 1: Binary Comparison Analysis
#!/usr/bin/env python3
"""Compare trojanized binary against legitimate version."""
import hashlib
import pefile
import sys
import json
def compare_pe_files(legitimate_path, suspect_path):
"""Compare PE file structures between legitimate and suspect versions."""
legit_pe = pefile.PE(legitimate_path)
suspect_pe = pefile.PE(suspect_path)
report = {"differences": [], "suspicious_sections": [], "import_changes": []}
# Compare sections
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}
# Find new or modified sections
for name, props in suspect_sections.items():
if name not in legit_sections:
report["suspicious_sections"].append({
"name": name, "reason": "New section not in legitimate version",
"size": props["size"], "entropy": round(props["entropy"], 2),
})
elif abs(props["size"] - legit_sections[name]["size"]) > 1024:
report["suspicious_sections"].append({
"name": name, "reason": "Section size significantly changed",
"legit_size": legit_sections[name]["size"],
"suspect_size": props["size"],
})
# Compare 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)
# Check code signing
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):
"""Calculate multiple hashes for a file."""
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"Usage: {sys.argv[0]} <legitimate_binary> <suspect_binary>")
sys.exit(1)
report = compare_pe_files(sys.argv[1], sys.argv[2])
print(json.dumps(report, indent=2))
Validation Criteria
- Trojanized components identified through binary diffing
- Injected code isolated and analyzed separately
- Code signing anomalies documented
- Infection timeline reconstructed from build artifacts
- Downstream impact scope assessed across affected systems
- IOCs extracted for detection and blocking
References
Source: mukul975/Anthropic-Cybersecurity-Skills → skills/analyzing-supply-chain-malware-artifacts/SKILL.md
1---2name: analyzing-supply-chain-malware-artifacts3description: Investigate supply chain attack artifacts including trojanized software updates, compromised build pipelines, and sideloaded dependencies to identify intrusion vectors and scope of compromise.4---5
6# Analyzing Supply Chain Malware Artifacts
7
8## Overview
9
10Supply chain attacks compromise legitimate software distribution channels to deliver malware through trusted update mechanisms. Notable examples include SolarWinds SUNBURST (2020, affecting 18,000+ customers), 3CX SmoothOperator (2023, a cascading supply chain attack originating from Trading Technologies), and numerous npm/PyPI package poisoning campaigns. Analysis involves comparing trojanized binaries against legitimate versions, identifying injected code in build artifacts, examining code signing anomalies, and tracing the infection chain from initial compromise through payload delivery. As of 2025, supply chain attacks account for 30% of all breaches, a 100% increase from prior years.
11
12
13## When to Use
14
15- When investigating security incidents that require analyzing supply chain malware artifacts
16- When building detection rules or threat hunting queries for this domain
17- When SOC analysts need structured procedures for this analysis type
18- When validating security monitoring coverage for related attack techniques
19
20## Prerequisites
21
22- Python 3.9+ with `pefile`, `ssdeep`, `hashlib`
23- Binary diff tools (BinDiff, Diaphora)
24- Code signing verification tools (sigcheck, codesign)
25- Software composition analysis (SCA) tools
26- Access to legitimate software versions for comparison
27- Package repository monitoring (npm, PyPI, NuGet)
28
29## Workflow
30
31### Step 1: Binary Comparison Analysis
32
33```python
34#!/usr/bin/env python3
35"""Compare trojanized binary against legitimate version."""
36import hashlib
37import pefile
38import sys
39import json
40
41
42def compare_pe_files(legitimate_path, suspect_path):
43 """Compare PE file structures between legitimate and suspect versions."""
44 legit_pe = pefile.PE(legitimate_path)
45 suspect_pe = pefile.PE(suspect_path)
46
47 report = {"differences": [], "suspicious_sections": [], "import_changes": []}
48
49 # Compare sections
50 legit_sections = {s.Name.rstrip(b'\x00').decode(): {
51 "size": s.SizeOfRawData,
52 "entropy": s.get_entropy(),
53 "characteristics": s.Characteristics,
54 } for s in legit_pe.sections}
55
56 suspect_sections = {s.Name.rstrip(b'\x00').decode(): {
57 "size": s.SizeOfRawData,
58 "entropy": s.get_entropy(),
59 "characteristics": s.Characteristics,
60 } for s in suspect_pe.sections}
61
62 # Find new or modified sections
63 for name, props in suspect_sections.items():
64 if name not in legit_sections:
65 report["suspicious_sections"].append({
66 "name": name, "reason": "New section not in legitimate version",
67 "size": props["size"], "entropy": round(props["entropy"], 2),
68 })
69 elif abs(props["size"] - legit_sections[name]["size"]) > 1024:
70 report["suspicious_sections"].append({
71 "name": name, "reason": "Section size significantly changed",
72 "legit_size": legit_sections[name]["size"],
73 "suspect_size": props["size"],
74 })
75
76 # Compare imports
77 legit_imports = set()
78 if hasattr(legit_pe, 'DIRECTORY_ENTRY_IMPORT'):
79 for entry in legit_pe.DIRECTORY_ENTRY_IMPORT:
80 for imp in entry.imports:
81 if imp.name:
82 legit_imports.add(f"{entry.dll.decode()}!{imp.name.decode()}")
83
84 suspect_imports = set()
85 if hasattr(suspect_pe, 'DIRECTORY_ENTRY_IMPORT'):
86 for entry in suspect_pe.DIRECTORY_ENTRY_IMPORT:
87 for imp in entry.imports:
88 if imp.name:
89 suspect_imports.add(f"{entry.dll.decode()}!{imp.name.decode()}")
90
91 new_imports = suspect_imports - legit_imports
92 if new_imports:
93 report["import_changes"] = list(new_imports)
94
95 # Check code signing
96 report["legit_signed"] = bool(legit_pe.OPTIONAL_HEADER.DATA_DIRECTORY[4].Size)
97 report["suspect_signed"] = bool(suspect_pe.OPTIONAL_HEADER.DATA_DIRECTORY[4].Size)
98
99 return report
100
101
102def hash_file(filepath):
103 """Calculate multiple hashes for a file."""
104 hashes = {}
105 with open(filepath, 'rb') as f:
106 data = f.read()
107 for algo in ['md5', 'sha1', 'sha256']:
108 h = hashlib.new(algo)
109 h.update(data)
110 hashes[algo] = h.hexdigest()
111 return hashes
112
113
114if __name__ == "__main__":
115 if len(sys.argv) < 3:
116 print(f"Usage: {sys.argv[0]} <legitimate_binary> <suspect_binary>")
117 sys.exit(1)
118 report = compare_pe_files(sys.argv[1], sys.argv[2])
119 print(json.dumps(report, indent=2))
120```
121
122## Validation Criteria
123
124- Trojanized components identified through binary diffing
125- Injected code isolated and analyzed separately
126- Code signing anomalies documented
127- Infection timeline reconstructed from build artifacts
128- Downstream impact scope assessed across affected systems
129- IOCs extracted for detection and blocking
130
131## References
132
133- [ReversingLabs - 3CX Supply Chain Analysis](https://www.reversinglabs.com/blog/what-went-wrong-with-the-3cx-software-supply-chain-attack-and-how-it-could-have-been-prevented)
134- [Fortinet - SolarWinds Supply Chain Attack](https://www.fortinet.com/resources/cyberglossary/solarwinds-cyber-attack)
135- [Picus - 3CX SmoothOperator Analysis](https://www.picussecurity.com/resource/blog/smoothoperator-analysis-of-3cxdesktopapp-supply-chain-attack)
136- [MITRE ATT&CK T1195 - Supply Chain Compromise](https://attack.mitre.org/techniques/T1195/)
137
138---
139
140**Source:** [`mukul975/Anthropic-Cybersecurity-Skills`](https://github.com/mukul975/Anthropic-Cybersecurity-Skills) → `skills/analyzing-supply-chain-malware-artifacts/SKILL.md`