Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-SkillsFramework mappings
MITRE ATT&CK
T1046 on the official MITRE ATT&CK siteT1057 on the official MITRE ATT&CK siteT1082 on the official MITRE ATT&CK siteT1083 on the official MITRE ATT&CK siteT1195 on the official MITRE ATT&CK siteT1195.001 on the official MITRE ATT&CK siteT1195.002 on the official MITRE ATT&CK siteT1199 on the official MITRE ATT&CK site
NIST CSF 2.0
When to Use
- When proactively hunting for indicators of hunting for supply chain compromise in the environment
- After threat intelligence indicates active campaigns using these techniques
- During incident response to scope compromise related to these techniques
- When EDR or SIEM alerts trigger on related indicators
- During periodic security assessments and purple team exercises
Prerequisites
- EDR platform with process and network telemetry (CrowdStrike, MDE, SentinelOne)
- SIEM with relevant log data ingested (Splunk, Elastic, Sentinel)
- Sysmon deployed with comprehensive configuration
- Windows Security Event Log forwarding enabled
- Threat intelligence feeds for IOC correlation
Workflow
- Formulate Hypothesis: Define a testable hypothesis based on threat intelligence or ATT&CK gap analysis.
- Identify Data Sources: Determine which logs and telemetry are needed to validate or refute the hypothesis.
- Execute Queries: Run detection queries against SIEM and EDR platforms to collect relevant events.
- Analyze Results: Examine query results for anomalies, correlating across multiple data sources.
- Validate Findings: Distinguish true positives from false positives through contextual analysis.
- Correlate Activity: Link findings to broader attack chains and threat actor TTPs.
- Document and Report: Record findings, update detection rules, and recommend response actions.
Key Concepts
| Concept | Description |
|---|---|
| T1195.001 | Compromise Software Dependencies |
| T1195.002 | Compromise Software Supply Chain |
| T1199 | Trusted Relationship |
Tools & Systems
| Tool | Purpose |
|---|---|
| CrowdStrike Falcon | EDR telemetry and threat detection |
| Microsoft Defender for Endpoint | Advanced hunting with KQL |
| Splunk Enterprise | SIEM log analysis with SPL queries |
| Elastic Security | Detection rules and investigation timeline |
| Sysmon | Detailed Windows event monitoring |
| Velociraptor | Endpoint artifact collection and hunting |
| Sigma Rules | Cross-platform detection rule format |
Common Scenarios
- Scenario 1: SolarWinds-style update mechanism compromise
- Scenario 2: Compromised npm/PyPI package with backdoor
- Scenario 3: Tampered build server deploying malicious artifacts
- Scenario 4: Vendor VPN software update delivering malware
Output Format
Hunt ID: TH-HUNTIN-[DATE]-[SEQ]
Technique: T1195.001
Host: [Hostname]
User: [Account context]
Evidence: [Log entries, process trees, network data]
Risk Level: [Critical/High/Medium/Low]
Confidence: [High/Medium/Low]
Recommended Action: [Containment, investigation, monitoring]Source materials
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md1.9 KB
API Reference: Hunting for Supply Chain Compromise
NPM Lock File Analysis
import json
data = json.load(open("package-lock.json"))
packages = data.get("packages", {})
for name, info in packages.items():
resolved = info.get("resolved", "")
has_script = info.get("hasInstallScript", False)pip-audit
pip-audit --format=json --output=audit.json
pip-audit --require=requirements.txt --desc# Programmatic usage
from pip_audit._cli import audit
# Or parse JSON output
import subprocess, json
result = subprocess.run(["pip-audit", "--format=json"], capture_output=True, text=True)
vulns = json.loads(result.stdout)Hash Verification
import hashlib
sha = hashlib.sha256()
with open("binary.exe", "rb") as f:
for chunk in iter(lambda: f.read(8192), b""):
sha.update(chunk)
print(sha.hexdigest())Dependency Confusion Checks
| Registry | Check Command | Risk |
|---|---|---|
| npm | npm view <pkg> name |
Package exists publicly |
| PyPI | pip index versions <pkg> |
Package exists publicly |
| Maven | mvn dependency:resolve |
Artifact on Maven Central |
Splunk SPL - Build Anomaly Detection
index=cicd sourcetype=build_logs
| where match(_raw, "(?i)(curl.*\|.*sh|wget.*chmod|--registry\s+http)")
| table _time build_id job_name _rawSupply Chain Indicators
| Indicator | Severity | Category |
|---|---|---|
| Known compromised package | CRITICAL | Package takeover |
| Non-standard registry URL | HIGH | Dependency confusion |
| Install scripts in deps | MEDIUM | Post-install hooks |
| Git URL dependencies | MEDIUM | Unpinned source |
| Pipe to shell in CI | CRITICAL | Remote code execution |
References
- MITRE T1195: https://attack.mitre.org/techniques/T1195/
- pip-audit: https://github.com/pypa/pip-audit
- npm audit: https://docs.npmjs.com/cli/v9/commands/npm-audit
standards.md1.6 KB
Standards and References - Hunting For Supply Chain Compromise
MITRE ATT&CK Mappings
| Technique | Name | Description |
|---|---|---|
| T1195.001 | Compromise Software Dependencies | See attack.mitre.org/techniques/T1195/001 |
| T1195.002 | Compromise Software Supply Chain | See attack.mitre.org/techniques/T1195/002 |
| T1199 | Trusted Relationship | See attack.mitre.org/techniques/T1199 |
Detection Data Sources
| Source | Event ID | Purpose |
|---|---|---|
| Sysmon | 1 | Process creation with command line |
| Sysmon | 3 | Network connection initiated |
| Sysmon | 7 | Image loaded (DLL) |
| Sysmon | 10 | Process access (LSASS) |
| Sysmon | 11 | File creation |
| Sysmon | 12/13 | Registry create/set |
| Sysmon | 22 | DNS query |
| Sysmon | 25 | Process tampering |
| Windows Security | 4624 | Successful logon |
| Windows Security | 4625 | Failed logon |
| Windows Security | 4648 | Explicit credential logon |
| Windows Security | 4672 | Special privileges assigned |
| Windows Security | 4688 | Process creation |
| Windows Security | 4697 | Service installed |
| Windows Security | 4698 | Scheduled task created |
| Windows Security | 4769 | Kerberos TGS requested |
| Windows Security | 5140 | Network share accessed |
References
- MITRE ATT&CK Framework: https://attack.mitre.org/
- Sigma Detection Rules: https://github.com/SigmaHQ/sigma
- LOLBAS Project: https://lolbas-project.github.io/
- Atomic Red Team Tests: https://github.com/redcanaryco/atomic-red-team
- Red Canary Threat Detection Report
- SANS Threat Hunting Summit Resources
workflows.md3.0 KB
Detailed Hunting Workflow - Hunting For Supply Chain Compromise
Phase 1: Data Collection and Querying
Splunk SPL Query
index=sysmon EventCode=1
| where match(ParentImage, "(?i)(update|installer|setup|patch|deploy)")
| where match(Image, "(?i)(cmd|powershell|wscript|cscript|mshta)")
| where NOT match(ParentImage, "(?i)(Windows\\SoftwareDistribution)")
| table _time Computer User ParentImage Image CommandLineKQL Query (Microsoft Defender for Endpoint)
DeviceProcessEvents
| where InitiatingProcessFileName matches regex @"(?i)(update|installer|setup|patch)"
| where FileName in~ ("cmd.exe","powershell.exe","wscript.exe")
| project Timestamp, DeviceName, InitiatingProcessFileName, FileName, ProcessCommandLinePhase 2: Baseline and Anomaly Detection
Step 2.1 - Establish Normal Behavior Baseline
- Collect 30 days of historical data for the targeted technique
- Document expected patterns, frequencies, and legitimate use cases
- Identify known false positive sources and document exceptions
- Build statistical baseline (mean, standard deviation) for key metrics
Step 2.2 - Identify Anomalies
- Compare current activity against the 30-day baseline
- Flag events exceeding 3 standard deviations from normal
- Prioritize anomalies by risk score and potential business impact
- Cross-reference with threat intelligence for known IOCs
Phase 3: Investigation and Correlation
Step 3.1 - Deep Dive Analysis
- For each anomaly, collect full process tree context
- Correlate with network activity, file operations, and authentication events
- Check binary signatures, file hashes, and certificate validity
- Review user account context and access patterns
Step 3.2 - Attack Chain Reconstruction
- Map findings to MITRE ATT&CK kill chain stages
- Identify initial access vector if applicable
- Trace lateral movement and privilege escalation paths
- Determine data access and potential exfiltration
Phase 4: Validation and Response
Step 4.1 - True/False Positive Determination
- Verify findings with system owners and IT operations
- Check change management records for authorized activities
- Validate user context (authorized actions vs. compromised account)
- Document determination rationale for each finding
Step 4.2 - Response Actions
- For confirmed threats: initiate incident response procedures
- For detection gaps: create or update detection rules
- For false positives: tune existing rules and update exclusions
- Update threat hunting playbook with lessons learned
Phase 5: Documentation and Reporting
Step 5.1 - Hunt Report
- Summarize hypothesis, methodology, and findings
- Include all queries executed and their results
- Document IOCs discovered and detection rules created
- Provide recommendations for security improvements
Step 5.2 - Knowledge Base Update
- Add findings to threat intelligence platform
- Update MITRE ATT&CK coverage heatmap
- Share detection rules via Sigma format
- Schedule follow-up hunts for related techniques
Scripts 2
agent.py6.9 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for hunting supply chain compromise indicators in software dependencies and builds."""
import json
import argparse
import hashlib
import re
import subprocess
from datetime import datetime
from pathlib import Path
KNOWN_COMPROMISED_PACKAGES = {
"event-stream": "npm", "ua-parser-js": "npm", "coa": "npm",
"colors": "npm", "faker": "npm", "node-ipc": "npm",
"ctx": "pypi", "phpass": "pypi",
}
def scan_npm_lockfile(lockfile_path):
"""Scan package-lock.json for suspicious dependencies."""
with open(lockfile_path) as f:
data = json.load(f)
findings = []
packages = data.get("packages", data.get("dependencies", {}))
for name, info in packages.items():
pkg_name = name.split("node_modules/")[-1] if "node_modules/" in name else name
if not pkg_name:
continue
if pkg_name in KNOWN_COMPROMISED_PACKAGES:
findings.append({
"package": pkg_name, "version": info.get("version", ""),
"severity": "CRITICAL", "reason": "known_compromised",
})
resolved = info.get("resolved", "")
if resolved and not resolved.startswith("https://registry.npmjs.org/"):
findings.append({
"package": pkg_name, "resolved": resolved,
"severity": "HIGH", "reason": "non_standard_registry",
})
if info.get("hasInstallScript", False):
findings.append({
"package": pkg_name, "version": info.get("version", ""),
"severity": "MEDIUM", "reason": "install_script",
})
return findings
def scan_pip_requirements(req_path):
"""Scan pip requirements.txt for suspicious packages."""
findings = []
with open(req_path) as f:
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
match = re.match(r"^([a-zA-Z0-9_.-]+)", line)
if not match:
continue
pkg = match.group(1)
if pkg.lower() in KNOWN_COMPROMISED_PACKAGES:
findings.append({
"package": pkg, "line": line,
"severity": "CRITICAL", "reason": "known_compromised",
})
if "--index-url" in line or "--extra-index-url" in line:
findings.append({
"package": pkg, "line": line,
"severity": "HIGH", "reason": "custom_index",
})
if re.search(r"git\+https?://", line):
findings.append({
"package": pkg, "line": line,
"severity": "MEDIUM", "reason": "git_dependency",
})
return findings
def verify_binary_hashes(manifest_path):
"""Verify binary hashes against a known-good manifest."""
with open(manifest_path) as f:
manifest = json.load(f)
results = []
for entry in manifest:
filepath = entry.get("path", "")
expected_hash = entry.get("sha256", "")
if not Path(filepath).exists():
results.append({"path": filepath, "status": "MISSING", "severity": "HIGH"})
continue
sha = hashlib.sha256()
with open(filepath, "rb") as bf:
for chunk in iter(lambda: bf.read(8192), b""):
sha.update(chunk)
actual = sha.hexdigest()
if actual != expected_hash:
results.append({
"path": filepath, "expected": expected_hash, "actual": actual,
"status": "MISMATCH", "severity": "CRITICAL",
})
return results
def scan_build_logs(log_path):
"""Scan CI/CD build logs for supply chain indicators."""
suspicious_patterns = [
(r"curl\s+.*\|\s*(sh|bash)", "CRITICAL", "pipe_to_shell"),
(r"wget\s+.*&&\s*chmod\s+\+x", "HIGH", "download_and_execute"),
(r"npm\s+install\s+--registry\s+(?!https://registry\.npmjs\.org)", "HIGH", "custom_registry"),
(r"pip\s+install\s+--index-url\s+(?!https://pypi\.org)", "HIGH", "custom_pypi"),
(r"docker\s+pull\s+(?!docker\.io/|gcr\.io/|ghcr\.io/)", "MEDIUM", "untrusted_registry"),
]
findings = []
with open(log_path) as f:
for i, line in enumerate(f, 1):
for pattern, severity, category in suspicious_patterns:
if re.search(pattern, line, re.IGNORECASE):
findings.append({
"line_number": i, "content": line.strip()[:300],
"pattern": category, "severity": severity,
})
return findings
def check_dependency_confusion(internal_packages, public_registry="npm"):
"""Check if internal package names exist on public registries."""
findings = []
for pkg in internal_packages:
try:
if public_registry == "npm":
result = subprocess.run(
["npm", "view", pkg, "name"], capture_output=True, text=True, timeout=10)
else:
result = subprocess.run(
["pip", "index", "versions", pkg], capture_output=True, text=True, timeout=10)
if result.returncode == 0:
findings.append({
"package": pkg, "registry": public_registry,
"severity": "CRITICAL", "reason": "dependency_confusion_risk",
})
except (subprocess.TimeoutExpired, FileNotFoundError):
continue
return findings
def main():
parser = argparse.ArgumentParser(description="Supply Chain Compromise Hunter")
parser.add_argument("--npm-lock", help="Path to package-lock.json")
parser.add_argument("--pip-req", help="Path to requirements.txt")
parser.add_argument("--manifest", help="Path to hash manifest JSON")
parser.add_argument("--build-log", help="Path to CI/CD build log")
parser.add_argument("--output", default="supply_chain_hunt_report.json")
args = parser.parse_args()
report = {"generated_at": datetime.utcnow().isoformat(), "findings": {}}
if args.npm_lock:
f = scan_npm_lockfile(args.npm_lock)
report["findings"]["npm_scan"] = f
print(f"[+] NPM lock findings: {len(f)}")
if args.pip_req:
f = scan_pip_requirements(args.pip_req)
report["findings"]["pip_scan"] = f
print(f"[+] Pip requirements findings: {len(f)}")
if args.manifest:
f = verify_binary_hashes(args.manifest)
report["findings"]["hash_verification"] = f
print(f"[+] Binary hash mismatches: {len([x for x in f if x.get('status') == 'MISMATCH'])}")
if args.build_log:
f = scan_build_logs(args.build_log)
report["findings"]["build_log_scan"] = f
print(f"[+] Build log findings: {len(f)}")
with open(args.output, "w") as fout:
json.dump(report, fout, indent=2, default=str)
print(f"[+] Report saved to {args.output}")
if __name__ == "__main__":
main()
process.py3.6 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Supply Chain Compromise Detection - Analyzes logs for T1195.002 indicators."""
import json, csv, argparse, datetime, re
from collections import defaultdict
from pathlib import Path
DETECTION_PATTERNS = [
r'update.*cmd\\.exe',
r'installer.*powershell',
r'setup.*wscript',
r'patch.*mshta',
]
def parse_logs(path):
p = Path(path)
if p.suffix == ".json":
with open(p, encoding="utf-8") as f:
data = json.load(f)
return data if isinstance(data, list) else data.get("events", [])
elif p.suffix == ".csv":
with open(p, encoding="utf-8-sig") as f:
return [dict(r) for r in csv.DictReader(f)]
return []
def analyze_event(event):
cmd = event.get("CommandLine", event.get("command_line", event.get("ProcessCommandLine", "")))
content = event.get("Task_Content", event.get("Parameters", event.get("RawEventData", "")))
search_text = f"{cmd} {content}"
risk = 0
indicators = []
for pattern in DETECTION_PATTERNS:
if re.search(pattern, search_text, re.IGNORECASE):
risk += 25
indicators.append(f"Pattern match: {pattern}")
if not indicators:
return None
risk = min(risk, 100)
return {
"technique": "T1195.002",
"command_line": cmd[:500] if cmd else content[:500],
"hostname": event.get("Computer", event.get("DeviceName", event.get("hostname", "unknown"))),
"user": event.get("User", event.get("AccountName", event.get("UserId", "unknown"))),
"timestamp": event.get("_time", event.get("timestamp", event.get("UtcTime", event.get("Timestamp", "")))),
"risk_score": risk,
"risk_level": "CRITICAL" if risk >= 75 else "HIGH" if risk >= 50 else "MEDIUM" if risk >= 25 else "LOW",
"indicators": indicators,
}
def run_hunt(input_path, output_dir):
print(f"[*] Supply Chain Compromise Hunt - {datetime.datetime.now().isoformat()}")
events = parse_logs(input_path)
findings = [f for f in (analyze_event(e) for e in events) if f]
Path(output_dir).mkdir(parents=True, exist_ok=True)
slug = "hunting_for_supply_c"
with open(Path(output_dir) / f"{slug}_findings.json", "w", encoding="utf-8") as f:
json.dump({"hunt_id": f"TH-{datetime.date.today()}", "total_events": len(events), "findings": findings}, f, indent=2)
with open(Path(output_dir) / "hunt_report.md", "w", encoding="utf-8") as f:
f.write(f"# Supply Chain Compromise Hunt Report\n\n")
f.write(f"**Date**: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"**Findings**: {len(findings)}\n\n")
for finding in sorted(findings, key=lambda x: x["risk_score"], reverse=True)[:20]:
f.write(f"### [{finding['risk_level']}] {finding['technique']}\n")
f.write(f"- **Host**: {finding['hostname']}\n")
f.write(f"- **Indicators**: {', '.join(finding['indicators'])}\n\n")
print(f"[+] {len(findings)} findings written to {output_dir}")
def main():
p = argparse.ArgumentParser(description="Supply Chain Compromise Detection")
sp = p.add_subparsers(dest="cmd")
h = sp.add_parser("hunt"); h.add_argument("--input", "-i", required=True); h.add_argument("--output", "-o", default="./hunting_for_sup_output")
sp.add_parser("queries")
args = p.parse_args()
if args.cmd == "hunt": run_hunt(args.input, args.output)
elif args.cmd == "queries":
print("=== Detection Queries ===")
print("See references/workflows.md for platform-specific queries")
else: p.print_help()
if __name__ == "__main__": main()
Assets 1
template.mdtext/markdown · 2.6 KBKeep exploring