Agent skill
extracting-iocs-from-samples
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/extracting-iocs-from-samples
SKILL.md
name: extracting-iocs-from-samples description: >- Systematically extract Indicators of Compromise (IOCs) from malware samples including hashes, domains, IPs, URLs, mutexes, file paths, and registry keys. domain: cybersecurity subdomain: malware-analysis tags:
- ioc-extraction
- threat-intelligence
- stix
- openioc
- malware-triage
- hash-analysis
- network-indicators version: "1.0" author: defconxt license: AGPL-3.0 metadata: mitre-attack: ["T1587.001"]
Extracting IOCs from Samples
Overview
Indicators of Compromise (IOCs) are forensic artifacts — file hashes, IP addresses, domain names, URLs, mutexes, registry keys, and behavioral patterns — that identify malicious activity. Systematic IOC extraction from malware samples enables threat detection, hunting, blocking, and intelligence sharing. IOCs feed into SIEMs, EDR platforms, firewalls, and threat intelligence platforms (TIPs). Output formats include STIX 2.1, OpenIOC, CSV, and JSON for automated ingestion.
Prerequisites
- Python 3.10+ with
iocextract,pefile,yara-python,stix2 strings,flossfor string extraction- VirusTotal API key for enrichment
- MISP or OpenCTI for IOC sharing
- Isolated analysis environment
Key Concepts
IOC Types and Confidence
| IOC Type | Example | Confidence | Shelf Life |
|---|---|---|---|
| File hash (SHA256) | a1b2c3... |
Very High | Permanent (for that sample) |
| File hash (MD5) | d4e5f6... |
High | Permanent (collision risk) |
| Domain | evil.example.com |
Medium-High | Weeks-months |
| IP address | 192.168.1.100 |
Medium | Days-weeks (dynamic IPs) |
| URL | http://evil.com/payload |
High | Days-weeks |
| Mutex | Global\\MyMutex |
High | Months (sample-specific) |
| Registry key | HKLM\...\Run\malware |
Medium | Varies |
| User-Agent | Mozilla/5.0 Custom/1.0 |
Medium | Months |
| YARA rule | Behavioral pattern | Very High | Months-years |
| JARM hash | TLS fingerprint | High | Months |
IOC Pyramid of Pain
From easiest (bottom) to hardest (top) for attackers to change:
- Hash values — trivial to change (recompile)
- IP addresses — easy to change (new infrastructure)
- Domain names — moderate effort (new registration)
- Network artifacts — significant effort (new C2 profile)
- Host artifacts — significant effort (new TTPs)
- Tools — hard (develop new tooling)
- TTPs — very hard (change methodology)
Workflow
Step 1: Hash Generation
# Multiple hash types
md5sum sample.exe
sha1sum sample.exe
sha256sum sample.exe
ssdeep sample.exe # Fuzzy hash for similarity
tlsh sample.exe # Trend Micro Locality Sensitive Hash
imphash sample.exe # Import hash (pefile)
# Python hash generation
python3 -c "
import hashlib, pefile
data = open('sample.exe', 'rb').read()
print(f'MD5: {hashlib.md5(data).hexdigest()}')
print(f'SHA1: {hashlib.sha1(data).hexdigest()}')
print(f'SHA256: {hashlib.sha256(data).hexdigest()}')
pe = pefile.PE('sample.exe')
print(f'Imphash: {pe.get_imphash()}')
"
Step 2: String-Based IOC Extraction
# Raw strings
strings -a -n 6 sample.exe > strings.txt
# FLOSS for obfuscated strings
floss sample.exe -j > floss_output.json
# Extract with regex patterns
grep -oP 'https?://[^\s"'"'"']+' strings.txt # URLs
grep -oP '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' strings.txt # IPs
grep -oP '[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}' strings.txt # Domains
grep -oP 'HKLM\\[^\s"]+|HKCU\\[^\s"]+' strings.txt # Registry
Step 3: Automated IOC Extraction
#!/usr/bin/env python3
"""Comprehensive IOC extraction from malware samples."""
import hashlib
import re
import json
from pathlib import Path
from ipaddress import ip_address
# IOC regex patterns
IOC_PATTERNS = {
"ipv4": r'\b(?:(?:25[0-5]|2[0-4]\d|1?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|1?\d\d?)\b',
"ipv6": r'\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b',
"url": r'https?://[^\s<>"\'{}|\\^`\[\]]+',
"domain": r'\b[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.[a-zA-Z]{2,6}\b',
"email": r'\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\b',
"md5": r'\b[a-fA-F0-9]{32}\b',
"sha1": r'\b[a-fA-F0-9]{40}\b',
"sha256": r'\b[a-fA-F0-9]{64}\b',
"registry": r'(?:HKLM|HKCU|HKCR|HKU|HKCC)\\[^\s"\']+',
"filepath_win": r'[A-Z]:\\(?:[^\s<>"\'|]+\\)*[^\s<>"\'|]+',
"filepath_unix": r'(?:/(?:tmp|var|etc|usr|opt|home|root)/[^\s"\']+)',
"mutex": r'(?:Global\\|Local\\)[^\s"\']+',
"useragent": r'Mozilla/5\.0[^\r\n"\']{10,}',
"bitcoin": r'\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\b',
}
# False positive filters
FP_DOMAINS = {'example.com', 'microsoft.com', 'google.com', 'localhost',
'schema.org', 'w3.org', 'xmlsoap.org'}
FP_IPS = {'0.0.0.0', '127.0.0.1', '255.255.255.255'}
def extract_iocs(text: str) -> dict:
"""Extract all IOC types from text."""
iocs = {}
for ioc_type, pattern in IOC_PATTERNS.items():
matches = set(re.findall(pattern, text))
# Filter false positives
if ioc_type == "domain":
matches -= FP_DOMAINS
matches = {d for d in matches if '.' in d and not d.endswith('.exe')}
elif ioc_type == "ipv4":
matches -= FP_IPS
matches = {ip for ip in matches if is_routable(ip)}
iocs[ioc_type] = sorted(matches)
return {k: v for k, v in iocs.items() if v}
def is_routable(ip_str: str) -> bool:
"""Check if IP is routable (not private/reserved)."""
try:
ip = ip_address(ip_str)
return not (ip.is_private or ip.is_reserved or ip.is_loopback)
except ValueError:
return False
def extract_from_file(filepath: str) -> dict:
"""Full IOC extraction pipeline for a file."""
path = Path(filepath)
data = path.read_bytes()
text = data.decode('utf-8', errors='replace')
# File hashes
file_iocs = {
"file_hashes": {
"md5": hashlib.md5(data).hexdigest(),
"sha1": hashlib.sha1(data).hexdigest(),
"sha256": hashlib.sha256(data).hexdigest(),
},
"file_size": len(data),
"file_name": path.name,
}
# String-based IOCs
string_iocs = extract_iocs(text)
file_iocs["network_iocs"] = {
"urls": string_iocs.get("url", []),
"domains": string_iocs.get("domain", []),
"ips": string_iocs.get("ipv4", []),
"emails": string_iocs.get("email", []),
}
file_iocs["host_iocs"] = {
"registry_keys": string_iocs.get("registry", []),
"file_paths": string_iocs.get("filepath_win", []) + string_iocs.get("filepath_unix", []),
"mutexes": string_iocs.get("mutex", []),
}
file_iocs["crypto"] = {
"bitcoin_addresses": string_iocs.get("bitcoin", []),
}
return file_iocs
Step 4: VirusTotal Enrichment
import requests
def enrich_hash_vt(sha256: str, api_key: str) -> dict:
"""Enrich file hash via VirusTotal API."""
url = f"https://www.virustotal.com/api/v3/files/{sha256}"
headers = {"x-apikey": api_key}
resp = requests.get(url, headers=headers, timeout=30)
if resp.status_code == 200:
data = resp.json()["data"]["attributes"]
return {
"detection_ratio": f"{data['last_analysis_stats']['malicious']}/{sum(data['last_analysis_stats'].values())}",
"first_seen": data.get("first_submission_date"),
"names": data.get("names", [])[:5],
"tags": data.get("tags", []),
"type": data.get("type_description", ""),
}
return {"error": f"VT API returned {resp.status_code}"}
Step 5: Export as STIX 2.1
from stix2 import Indicator, Bundle, Malware, Relationship
from datetime import datetime
def export_stix(iocs: dict) -> str:
"""Export IOCs as STIX 2.1 bundle."""
objects = []
# File hash indicator
sha256 = iocs["file_hashes"]["sha256"]
file_indicator = Indicator(
name=f"Malware hash: {iocs['file_name']}",
pattern=f"[file:hashes.'SHA-256' = '{sha256}']",
pattern_type="stix",
valid_from=datetime.utcnow(),
)
objects.append(file_indicator)
# Network indicators
for domain in iocs.get("network_iocs", {}).get("domains", []):
ind = Indicator(
name=f"Malicious domain: {domain}",
pattern=f"[domain-name:value = '{domain}']",
pattern_type="stix",
valid_from=datetime.utcnow(),
)
objects.append(ind)
for ip in iocs.get("network_iocs", {}).get("ips", []):
ind = Indicator(
name=f"Malicious IP: {ip}",
pattern=f"[ipv4-addr:value = '{ip}']",
pattern_type="stix",
valid_from=datetime.utcnow(),
)
objects.append(ind)
bundle = Bundle(objects=objects)
return bundle.serialize(pretty=True)
Detection
title: Extracting Iocs From Samples Detection
id: ea5ef027-7667-4f5c-9eb4-e2bd476e0913
status: experimental
description: Detects suspicious activity related to extracting iocs from samples techniques in malware analysis context
logsource:
category: process_creation
product: windows
detection:
selection:
CommandLine: "*extracting*iocs*"
condition: selection
level: high
tags:
- attack.t1587.001
- attack.execution
falsepositives:
- Sandbox detonation environments analyzing submitted samples
Verification
- All hash types generated (MD5, SHA1, SHA256, imphash, ssdeep)
- Network IOCs extracted (domains, IPs, URLs)
- Host IOCs extracted (registry, files, mutexes)
- False positives filtered (private IPs, common domains)
- IOCs enriched via VT/threat intel
- Output exported in standard format (STIX/CSV/JSON)
- IOCs shared with detection team and TIP
References
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?