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
Trigger phrases:
"analyzing supply chain malware artifacts"
"Investigate supply chain attack artifacts including trojanized software updates,"
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
- Isolate the sample — ensure the malware is in a sandboxed environment with no network access
- Record file metadata — hash the sample and note file type, size, and compile timestamp
- Static analysis — examine strings, imports, and disassembled code without execution
- Dynamic analysis — execute in a monitored sandbox and record behavior (file, registry, network)
- Document IOCs — extract indicators of compromise and write the analysis report
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
When NOT to Use
- You need to perform the attack, not analyze it (use performing-* skills)
- Task is about detection, not analysis (use detecting-* skills)
- You need to implement controls (use implementing-* skills)
- Task is about threat hunting, not post-incident analysis (use hunting-* skills)
- You don't have access to the artifacts/logs to analyze
- Task requires real-time monitoring (use SOC tools)
Red Flags
- Performing actions without explicit written authorization from the asset owner
- Testing against production systems without a defined scope and rules of engagement
- Analyzing malware on a machine connected to the production network
- Failing to isolate the analysis environment from the internet
- Executing samples without proper containment (VM, sandbox)
Verification
- All steps executed successfully against a test environment before production use
- Output documented with screenshots or logs demonstrating expected behavior
- Sample hash recorded and verified (MD5, SHA-1, SHA-256)
- Analysis environment confirmed isolated from production network
- Indicators of compromise (IOCs) extracted and documented
References
Process
- Analyze the task requirements
- Apply domain expertise
- Verify output quality
Anti-Rationalization Table
| Rationalization |
Reality |
| "We are too small to be targeted" |
Automated attacks target everyone. Size does not matter. |
| "Security slows us down" |
A breach slows you down 100x more. Build security in from the start. |
| "We will fix it after launch" |
Vulnerabilities in production are exploited within hours. Fix before deploy. |
1---2name: analyzing-supply-chain-malware-artifacts3description: Use when investigate supply chain attack artifacts including trojanized software updates, compromised build pipelines, and sideloaded dependencies to identify intrusion vectors and scope of compromise. Use when working with analyzing supply chain malware artifacts.4license: Apache-2.05---67# Analyzing Supply Chain Malware Artifacts89## Overview1011Supply 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.121314## When to Use15**Trigger phrases:**16- "analyzing supply chain malware artifacts"17- "Investigate supply chain attack artifacts including trojanized software updates,"181920- When investigating security incidents that require analyzing supply chain malware artifacts21- When building detection rules or threat hunting queries for this domain22- When SOC analysts need structured procedures for this analysis type23- When validating security monitoring coverage for related attack techniques2425## Prerequisites2627- Python 3.9+ with `pefile`, `ssdeep`, `hashlib`28- Binary diff tools (BinDiff, Diaphora)29- Code signing verification tools (sigcheck, codesign)30- Software composition analysis (SCA) tools31- Access to legitimate software versions for comparison32- Package repository monitoring (npm, PyPI, NuGet)3334## Workflow35361. **Isolate the sample** — ensure the malware is in a sandboxed environment with no network access372. **Record file metadata** — hash the sample and note file type, size, and compile timestamp383. **Static analysis** — examine strings, imports, and disassembled code without execution394. **Dynamic analysis** — execute in a monitored sandbox and record behavior (file, registry, network)405. **Document IOCs** — extract indicators of compromise and write the analysis report41### Step 1: Binary Comparison Analysis4243```python44#!/usr/bin/env python345"""Compare trojanized binary against legitimate version."""46import hashlib47import pefile48import sys49import json505152def compare_pe_files(legitimate_path, suspect_path):53 """Compare PE file structures between legitimate and suspect versions."""54 legit_pe = pefile.PE(legitimate_path)55 suspect_pe = pefile.PE(suspect_path)5657 report = {"differences": [], "suspicious_sections": [], "import_changes": []}5859 # Compare sections60 legit_sections = {s.Name.rstrip(b'\x00').decode(): {61 "size": s.SizeOfRawData,62 "entropy": s.get_entropy(),63 "characteristics": s.Characteristics,64 } for s in legit_pe.sections}6566 suspect_sections = {s.Name.rstrip(b'\x00').decode(): {67 "size": s.SizeOfRawData,68 "entropy": s.get_entropy(),69 "characteristics": s.Characteristics,70 } for s in suspect_pe.sections}7172 # Find new or modified sections73 for name, props in suspect_sections.items():74 if name not in legit_sections:75 report["suspicious_sections"].append({76 "name": name, "reason": "New section not in legitimate version",77 "size": props["size"], "entropy": round(props["entropy"], 2),78 })79 elif abs(props["size"] - legit_sections[name]["size"]) > 1024:80 report["suspicious_sections"].append({81 "name": name, "reason": "Section size significantly changed",82 "legit_size": legit_sections[name]["size"],83 "suspect_size": props["size"],84 })8586 # Compare imports87 legit_imports = set()88 if hasattr(legit_pe, 'DIRECTORY_ENTRY_IMPORT'):89 for entry in legit_pe.DIRECTORY_ENTRY_IMPORT:90 for imp in entry.imports:91 if imp.name:92 legit_imports.add(f"{entry.dll.decode()}!{imp.name.decode()}")9394 suspect_imports = set()95 if hasattr(suspect_pe, 'DIRECTORY_ENTRY_IMPORT'):96 for entry in suspect_pe.DIRECTORY_ENTRY_IMPORT:97 for imp in entry.imports:98 if imp.name:99 suspect_imports.add(f"{entry.dll.decode()}!{imp.name.decode()}")100101 new_imports = suspect_imports - legit_imports102 if new_imports:103 report["import_changes"] = list(new_imports)104105 # Check code signing106 report["legit_signed"] = bool(legit_pe.OPTIONAL_HEADER.DATA_DIRECTORY[4].Size)107 report["suspect_signed"] = bool(suspect_pe.OPTIONAL_HEADER.DATA_DIRECTORY[4].Size)108109 return report110111112def hash_file(filepath):113 """Calculate multiple hashes for a file."""114 hashes = {}115 with open(filepath, 'rb') as f:116 data = f.read()117 for algo in ['md5', 'sha1', 'sha256']:118 h = hashlib.new(algo)119 h.update(data)120 hashes[algo] = h.hexdigest()121 return hashes122123124if __name__ == "__main__":125 if len(sys.argv) < 3:126 print(f"Usage: {sys.argv[0]} <legitimate_binary> <suspect_binary>")127 sys.exit(1)128 report = compare_pe_files(sys.argv[1], sys.argv[2])129 print(json.dumps(report, indent=2))130```131132## Validation Criteria133134- Trojanized components identified through binary diffing135- Injected code isolated and analyzed separately136- Code signing anomalies documented137- Infection timeline reconstructed from build artifacts138- Downstream impact scope assessed across affected systems139- IOCs extracted for detection and blocking140141## When NOT to Use142143- You need to perform the attack, not analyze it (use performing-* skills)144- Task is about detection, not analysis (use detecting-* skills)145- You need to implement controls (use implementing-* skills)146- Task is about threat hunting, not post-incident analysis (use hunting-* skills)147- You don't have access to the artifacts/logs to analyze148- Task requires real-time monitoring (use SOC tools)149150151## Red Flags152153- Performing actions without explicit written authorization from the asset owner154- Testing against production systems without a defined scope and rules of engagement155- Analyzing malware on a machine connected to the production network156- Failing to isolate the analysis environment from the internet157- Executing samples without proper containment (VM, sandbox)158159## Verification160161- All steps executed successfully against a test environment before production use162- Output documented with screenshots or logs demonstrating expected behavior163- Sample hash recorded and verified (MD5, SHA-1, SHA-256)164- Analysis environment confirmed isolated from production network165- Indicators of compromise (IOCs) extracted and documented166167## References168169- [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)170- [Fortinet - SolarWinds Supply Chain Attack](https://www.fortinet.com/resources/cyberglossary/solarwinds-cyber-attack)171- [Picus - 3CX SmoothOperator Analysis](https://www.picussecurity.com/resource/blog/smoothoperator-analysis-of-3cxdesktopapp-supply-chain-attack)172- [MITRE ATT&CK T1195 - Supply Chain Compromise](https://attack.mitre.org/techniques/T1195/)173174## Process1751761. Analyze the task requirements1772. Apply domain expertise1783. Verify output quality179180## Anti-Rationalization Table181182| Rationalization | Reality |183|---|---|184| "We are too small to be targeted" | Automated attacks target everyone. Size does not matter. |185| "Security slows us down" | A breach slows you down 100x more. Build security in from the start. |186| "We will fix it after launch" | Vulnerabilities in production are exploited within hours. Fix before deploy. |