mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-19 22:19:39 +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,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Anthropic Agent Skills Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,57 @@
|
||||
# API Reference: Investigating Ransomware Attack Artifacts
|
||||
|
||||
## VirusTotal API v3
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/api/v3/files/{hash}` | GET | Look up ransomware sample by MD5/SHA-256 |
|
||||
| `/api/v3/files` | POST | Upload ransomware sample for analysis |
|
||||
| `/api/v3/files/{id}/behaviour_summary` | GET | Retrieve behavioral analysis results |
|
||||
|
||||
## ID Ransomware
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `https://id-ransomware.malwarehunterteam.com/` | POST | Upload ransom note or encrypted sample for variant ID |
|
||||
|
||||
## No More Ransom Project
|
||||
|
||||
| Resource | Description |
|
||||
|----------|-------------|
|
||||
| `https://www.nomoreransom.org/crypto-sheriff.php` | Check if free decryptor is available for identified variant |
|
||||
|
||||
## MalwareBazaar API
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `https://mb-api.abuse.ch/api/v1/` | POST | Query ransomware samples by hash, tag, or signature |
|
||||
|
||||
## Key Libraries
|
||||
|
||||
- **requests**: HTTP client for VirusTotal and ID Ransomware API calls
|
||||
- **hashlib** (stdlib): Calculate MD5/SHA-256 hashes of ransomware samples and notes
|
||||
- **re** (stdlib): Extract Bitcoin addresses, Tor .onion sites, and emails from notes
|
||||
- **csv** (stdlib): Parse exported Windows Event Log data
|
||||
- **pathlib** (stdlib): Recursive file system traversal for artifact discovery
|
||||
|
||||
## Ransomware IOC Patterns
|
||||
|
||||
| Pattern | Regex | Description |
|
||||
|---------|-------|-------------|
|
||||
| Bitcoin | `[13][a-km-zA-HJ-NP-Z1-9]{25,34}` | Legacy Bitcoin addresses |
|
||||
| Bitcoin Bech32 | `bc1[a-z0-9]{39,59}` | SegWit Bitcoin addresses |
|
||||
| Monero | `4[0-9AB][1-9A-HJ-NP-Za-km-z]{93}` | Monero wallet addresses |
|
||||
| Tor Sites | `[a-z2-7]{16,56}\.onion` | Tor hidden service domains |
|
||||
|
||||
## Configuration
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `VT_API_KEY` | VirusTotal API key for hash lookups and sample submission |
|
||||
|
||||
## References
|
||||
|
||||
- [ID Ransomware](https://id-ransomware.malwarehunterteam.com/)
|
||||
- [No More Ransom Project](https://www.nomoreransom.org/)
|
||||
- [CISA Stop Ransomware](https://www.cisa.gov/stopransomware)
|
||||
- [VirusTotal API v3](https://docs.virustotal.com/reference/overview)
|
||||
@@ -0,0 +1,206 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Ransomware Attack Artifact Investigation Agent
|
||||
Collects and analyzes ransomware artifacts including ransom notes, encrypted
|
||||
file samples, registry modifications, and event logs to identify the variant,
|
||||
attack vector, and encryption scope.
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
RANSOMWARE_ID_URL = "https://id-ransomware.malwarehunterteam.com/api/"
|
||||
VT_API_KEY = ""
|
||||
|
||||
|
||||
def collect_ransom_notes(search_root: str) -> list[dict]:
|
||||
"""Search filesystem for common ransom note filenames."""
|
||||
ransom_note_patterns = [
|
||||
"README.txt", "DECRYPT*.txt", "HOW_TO_DECRYPT*", "RECOVER*",
|
||||
"_readme.txt", "!README!*", "HELP_DECRYPT*", "YOUR_FILES*",
|
||||
"ATTENTION*.txt", "RESTORE*FILES*", "#DECRYPT#*", "info.hta",
|
||||
]
|
||||
found_notes = []
|
||||
root = Path(search_root)
|
||||
|
||||
for pattern in ransom_note_patterns:
|
||||
for match in root.rglob(pattern):
|
||||
if match.is_file() and match.stat().st_size < 1_000_000:
|
||||
with open(match, "r", errors="ignore") as f:
|
||||
content = f.read(4096)
|
||||
found_notes.append({
|
||||
"path": str(match),
|
||||
"filename": match.name,
|
||||
"size": match.stat().st_size,
|
||||
"content_preview": content[:500],
|
||||
"sha256": hashlib.sha256(content.encode()).hexdigest(),
|
||||
})
|
||||
|
||||
return found_notes
|
||||
|
||||
|
||||
def identify_encrypted_files(search_root: str) -> dict:
|
||||
"""Identify encrypted files by extension and calculate scope."""
|
||||
known_extensions = [
|
||||
".encrypted", ".locked", ".crypto", ".crypt", ".enc",
|
||||
".locky", ".zepto", ".cerber", ".dharma", ".phobos",
|
||||
".ryuk", ".conti", ".lockbit", ".blackcat", ".hive",
|
||||
".akira", ".royal", ".play", ".clop", ".alphv",
|
||||
]
|
||||
encrypted_files = []
|
||||
extension_counts = {}
|
||||
total_size = 0
|
||||
|
||||
root = Path(search_root)
|
||||
for filepath in root.rglob("*"):
|
||||
if filepath.is_file():
|
||||
ext = filepath.suffix.lower()
|
||||
if ext in known_extensions:
|
||||
encrypted_files.append(str(filepath))
|
||||
extension_counts[ext] = extension_counts.get(ext, 0) + 1
|
||||
total_size += filepath.stat().st_size
|
||||
|
||||
return {
|
||||
"total_encrypted_files": len(encrypted_files),
|
||||
"total_encrypted_size_gb": round(total_size / (1024**3), 2),
|
||||
"extensions_found": extension_counts,
|
||||
"sample_files": encrypted_files[:20],
|
||||
}
|
||||
|
||||
|
||||
def analyze_ransom_note_content(notes: list[dict]) -> dict:
|
||||
"""Extract IOCs and payment details from ransom notes."""
|
||||
bitcoin_pattern = re.compile(r"[13][a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[a-z0-9]{39,59}")
|
||||
monero_pattern = re.compile(r"4[0-9AB][1-9A-HJ-NP-Za-km-z]{93}")
|
||||
tor_pattern = re.compile(r"[a-z2-7]{16,56}\.onion")
|
||||
email_pattern = re.compile(r"[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}")
|
||||
|
||||
iocs = {"bitcoin_addresses": set(), "monero_addresses": set(),
|
||||
"tor_sites": set(), "email_contacts": set(), "ransom_amounts": []}
|
||||
|
||||
for note in notes:
|
||||
content = note.get("content_preview", "")
|
||||
for match in bitcoin_pattern.findall(content):
|
||||
iocs["bitcoin_addresses"].add(match)
|
||||
for match in monero_pattern.findall(content):
|
||||
iocs["monero_addresses"].add(match)
|
||||
for match in tor_pattern.findall(content):
|
||||
iocs["tor_sites"].add(match)
|
||||
for match in email_pattern.findall(content):
|
||||
iocs["email_contacts"].add(match)
|
||||
|
||||
amount_match = re.search(r"\$\s?([\d,]+)", content)
|
||||
if amount_match:
|
||||
iocs["ransom_amounts"].append(amount_match.group(0))
|
||||
|
||||
return {k: sorted(v) if isinstance(v, set) else v for k, v in iocs.items()}
|
||||
|
||||
|
||||
def check_hash_virustotal(file_hash: str, api_key: str) -> dict:
|
||||
"""Look up file hash on VirusTotal for ransomware identification."""
|
||||
if not api_key:
|
||||
return {"error": "VT_API_KEY not configured"}
|
||||
resp = requests.get(
|
||||
f"https://www.virustotal.com/api/v3/files/{file_hash}",
|
||||
headers={"x-apikey": api_key}, timeout=30,
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
attrs = resp.json().get("data", {}).get("attributes", {})
|
||||
return {
|
||||
"threat_label": attrs.get("popular_threat_classification", {}).get(
|
||||
"suggested_threat_label", "unknown"),
|
||||
"detection_ratio": f"{attrs.get('last_analysis_stats', {}).get('malicious', 0)}"
|
||||
f"/{sum(attrs.get('last_analysis_stats', {}).values())}",
|
||||
"first_seen": attrs.get("first_submission_date", ""),
|
||||
"names": attrs.get("names", [])[:5],
|
||||
}
|
||||
return {"error": f"VT lookup failed: {resp.status_code}"}
|
||||
|
||||
|
||||
def parse_windows_event_logs(evtx_export_path: str) -> list[dict]:
|
||||
"""Parse exported Windows event log CSV for ransomware indicators."""
|
||||
events = []
|
||||
if not os.path.exists(evtx_export_path):
|
||||
return events
|
||||
|
||||
import csv
|
||||
with open(evtx_export_path, "r", newline="", errors="ignore") as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
event_id = row.get("EventID", row.get("event_id", ""))
|
||||
suspicious_ids = ["1102", "4688", "4697", "7045", "1116", "4624"]
|
||||
if str(event_id) in suspicious_ids:
|
||||
events.append({
|
||||
"timestamp": row.get("TimeCreated", row.get("timestamp", "")),
|
||||
"event_id": event_id,
|
||||
"source": row.get("ProviderName", row.get("source", "")),
|
||||
"message": row.get("Message", row.get("message", ""))[:300],
|
||||
})
|
||||
|
||||
return events
|
||||
|
||||
|
||||
def generate_report(notes: list, encrypted: dict, iocs: dict, events: list) -> str:
|
||||
"""Generate ransomware investigation report."""
|
||||
lines = [
|
||||
"RANSOMWARE ATTACK ARTIFACT INVESTIGATION REPORT",
|
||||
"=" * 55,
|
||||
f"Investigation Date: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M UTC')}",
|
||||
"",
|
||||
"RANSOM NOTES:",
|
||||
f" Notes Found: {len(notes)}",
|
||||
]
|
||||
for note in notes[:5]:
|
||||
lines.append(f" - {note['filename']} ({note['path']})")
|
||||
|
||||
lines.extend([
|
||||
"",
|
||||
"ENCRYPTION SCOPE:",
|
||||
f" Encrypted Files: {encrypted['total_encrypted_files']}",
|
||||
f" Total Size: {encrypted['total_encrypted_size_gb']} GB",
|
||||
f" Extensions: {json.dumps(encrypted['extensions_found'])}",
|
||||
"",
|
||||
"EXTRACTED IOCs:",
|
||||
f" Bitcoin Addresses: {len(iocs.get('bitcoin_addresses', []))}",
|
||||
f" Tor Sites: {len(iocs.get('tor_sites', []))}",
|
||||
f" Contact Emails: {len(iocs.get('email_contacts', []))}",
|
||||
"",
|
||||
f"SUSPICIOUS EVENTS: {len(events)}",
|
||||
])
|
||||
for evt in events[:10]:
|
||||
lines.append(f" [{evt['event_id']}] {evt['timestamp']} - {evt['message'][:80]}")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
VT_API_KEY = os.getenv("VT_API_KEY", VT_API_KEY)
|
||||
search_root = sys.argv[1] if len(sys.argv) > 1 else "."
|
||||
evtx_path = sys.argv[2] if len(sys.argv) > 2 else "events.csv"
|
||||
|
||||
print(f"[*] Investigating ransomware artifacts in: {search_root}")
|
||||
|
||||
notes = collect_ransom_notes(search_root)
|
||||
print(f"[*] Found {len(notes)} ransom notes")
|
||||
|
||||
encrypted = identify_encrypted_files(search_root)
|
||||
print(f"[*] Found {encrypted['total_encrypted_files']} encrypted files")
|
||||
|
||||
iocs = analyze_ransom_note_content(notes)
|
||||
events = parse_windows_event_logs(evtx_path)
|
||||
|
||||
report = generate_report(notes, encrypted, iocs, events)
|
||||
print(report)
|
||||
|
||||
output = f"ransomware_investigation_{datetime.now(timezone.utc).strftime('%Y%m%d')}.json"
|
||||
with open(output, "w") as f:
|
||||
json.dump({"ransom_notes": notes, "encrypted_files": encrypted, "iocs": iocs, "events": events}, f, indent=2)
|
||||
print(f"\n[*] Results saved to {output}")
|
||||
Reference in New Issue
Block a user