mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-11 10:03:42 +03:00
Add folder anatomy (scripts/agent.py + references/api-reference.md) for 648 cybersecurity skills
Complete skill folder anatomy across all cybersecurity skills: - scripts/agent.py: 80-150 line Python agents using real libraries (impacket, boto3, azure-mgmt-*, kubernetes, pefile, yara, scapy, shodan, stix2, etc.) - references/api-reference.md: real API documentation with method signatures - LICENSE: MIT license for all skill folders
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Threat Intelligence Feed Integration Agent - Ingests STIX/TAXII and open-source TI feeds."""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import argparse
|
||||
import hashlib
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import requests
|
||||
from taxii2client.v21 import Server, Collection
|
||||
from stix2 import Indicator, Bundle, parse
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def ingest_taxii_feed(taxii_url, collection_url, username, password, hours_back=24):
|
||||
"""Ingest indicators from a TAXII 2.1 server collection."""
|
||||
added_after = (datetime.utcnow() - timedelta(hours=hours_back)).strftime(
|
||||
"%Y-%m-%dT%H:%M:%S.000Z"
|
||||
)
|
||||
collection = Collection(collection_url, user=username, password=password)
|
||||
response = collection.get_objects(added_after=added_after, type=["indicator"])
|
||||
indicators = []
|
||||
for obj in response.get("objects", []):
|
||||
indicator = parse(obj)
|
||||
indicators.append({
|
||||
"id": str(indicator.id),
|
||||
"pattern": indicator.pattern,
|
||||
"valid_from": str(indicator.valid_from),
|
||||
"source": "taxii",
|
||||
})
|
||||
logger.info("Ingested %d indicators from TAXII feed", len(indicators))
|
||||
return indicators
|
||||
|
||||
|
||||
def ingest_urlhaus_feed():
|
||||
"""Ingest recent malicious URLs from Abuse.ch URLhaus."""
|
||||
url = "https://urlhaus-api.abuse.ch/v1/urls/recent/limit/100/"
|
||||
resp = requests.post(url, timeout=30)
|
||||
data = resp.json()
|
||||
indicators = []
|
||||
for entry in data.get("urls", []):
|
||||
indicators.append({
|
||||
"type": "url",
|
||||
"value": entry["url"],
|
||||
"threat": entry.get("threat", "unknown"),
|
||||
"status": entry.get("url_status", "unknown"),
|
||||
"tags": entry.get("tags", []),
|
||||
"source": "urlhaus",
|
||||
})
|
||||
logger.info("Ingested %d URLs from URLhaus", len(indicators))
|
||||
return indicators
|
||||
|
||||
|
||||
def ingest_feodotracker():
|
||||
"""Ingest C2 IP blocklist from Abuse.ch Feodo Tracker."""
|
||||
url = "https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.json"
|
||||
resp = requests.get(url, timeout=30)
|
||||
indicators = []
|
||||
for entry in resp.json():
|
||||
indicators.append({
|
||||
"type": "ipv4",
|
||||
"value": entry["ip_address"],
|
||||
"port": entry.get("port"),
|
||||
"malware": entry.get("malware", "unknown"),
|
||||
"first_seen": entry.get("first_seen"),
|
||||
"source": "feodotracker",
|
||||
})
|
||||
logger.info("Ingested %d C2 IPs from Feodo Tracker", len(indicators))
|
||||
return indicators
|
||||
|
||||
|
||||
def normalize_to_stix(indicators):
|
||||
"""Convert raw indicators to STIX 2.1 Indicator objects."""
|
||||
pattern_map = {
|
||||
"ipv4": lambda v: f"[ipv4-addr:value = '{v}']",
|
||||
"domain": lambda v: f"[domain-name:value = '{v}']",
|
||||
"url": lambda v: f"[url:value = '{v}']",
|
||||
"sha256": lambda v: f"[file:hashes.'SHA-256' = '{v}']",
|
||||
}
|
||||
stix_objects = []
|
||||
for ioc in indicators:
|
||||
ioc_type = ioc.get("type", "url")
|
||||
pattern_fn = pattern_map.get(ioc_type, pattern_map["url"])
|
||||
stix_ind = Indicator(
|
||||
name=f"{ioc_type}: {ioc['value']}",
|
||||
pattern=pattern_fn(ioc["value"]),
|
||||
pattern_type="stix",
|
||||
valid_from=datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||
labels=[ioc.get("source", "unknown")],
|
||||
)
|
||||
stix_objects.append(stix_ind)
|
||||
logger.info("Normalized %d indicators to STIX 2.1", len(stix_objects))
|
||||
return stix_objects
|
||||
|
||||
|
||||
def deduplicate(indicators):
|
||||
"""Deduplicate indicators across feeds by type:value hash."""
|
||||
seen = set()
|
||||
unique = []
|
||||
for ioc in indicators:
|
||||
key = hashlib.sha256(f"{ioc.get('type', '')}:{ioc['value']}".encode()).hexdigest()
|
||||
if key not in seen:
|
||||
seen.add(key)
|
||||
unique.append(ioc)
|
||||
logger.info("Deduplicated: %d -> %d unique indicators", len(indicators), len(unique))
|
||||
return unique
|
||||
|
||||
|
||||
def export_stix_bundle(stix_objects, output_path):
|
||||
"""Export STIX 2.1 bundle to JSON file."""
|
||||
bundle = Bundle(objects=stix_objects)
|
||||
with open(output_path, "w") as f:
|
||||
f.write(bundle.serialize(pretty=True))
|
||||
logger.info("STIX bundle exported to %s (%d indicators)", output_path, len(stix_objects))
|
||||
|
||||
|
||||
def push_to_splunk_ti(splunk_url, session_key, indicators):
|
||||
"""Push indicators to Splunk ES threat intelligence framework."""
|
||||
headers = {"Authorization": f"Splunk {session_key}"}
|
||||
pushed = 0
|
||||
for ioc in indicators:
|
||||
data = {"ip": ioc["value"], "description": f"{ioc.get('source')}: {ioc['value']}"}
|
||||
resp = requests.post(
|
||||
f"{splunk_url}/services/data/threat_intel/item/ip_intel",
|
||||
headers=headers, data=data, verify=False,
|
||||
)
|
||||
if resp.status_code == 201:
|
||||
pushed += 1
|
||||
logger.info("Pushed %d indicators to Splunk TI", pushed)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Threat Intelligence Feed Integration Agent")
|
||||
parser.add_argument("--taxii-url", help="TAXII 2.1 server URL")
|
||||
parser.add_argument("--taxii-collection", help="TAXII collection URL")
|
||||
parser.add_argument("--taxii-user", help="TAXII username")
|
||||
parser.add_argument("--taxii-pass", help="TAXII password")
|
||||
parser.add_argument("--urlhaus", action="store_true", help="Ingest URLhaus feed")
|
||||
parser.add_argument("--feodo", action="store_true", help="Ingest Feodo Tracker feed")
|
||||
parser.add_argument("--output", default="ti_bundle.json", help="STIX bundle output")
|
||||
args = parser.parse_args()
|
||||
|
||||
all_indicators = []
|
||||
|
||||
if args.taxii_url and args.taxii_collection:
|
||||
taxii_iocs = ingest_taxii_feed(
|
||||
args.taxii_url, args.taxii_collection, args.taxii_user, args.taxii_pass
|
||||
)
|
||||
all_indicators.extend(taxii_iocs)
|
||||
|
||||
if args.urlhaus:
|
||||
all_indicators.extend(ingest_urlhaus_feed())
|
||||
|
||||
if args.feodo:
|
||||
all_indicators.extend(ingest_feodotracker())
|
||||
|
||||
unique = deduplicate(all_indicators)
|
||||
stix_objects = normalize_to_stix(unique)
|
||||
export_stix_bundle(stix_objects, args.output)
|
||||
logger.info("Feed integration complete: %d total indicators", len(unique))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user