mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-26 14:10:59 +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,45 @@
|
||||
# API Reference: Firmware Malware Analysis
|
||||
|
||||
## binwalk CLI
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `binwalk <firmware>` | Scan and display embedded file signatures |
|
||||
| `binwalk -e <firmware>` | Extract identified components |
|
||||
| `binwalk -eM <firmware>` | Recursive extraction with signature scanning |
|
||||
| `binwalk -E <firmware>` | Entropy analysis for encrypted/compressed regions |
|
||||
| `binwalk -A <firmware>` | Scan for executable opcode signatures |
|
||||
|
||||
## binwalk Python API
|
||||
|
||||
```python
|
||||
import binwalk
|
||||
for module in binwalk.scan("firmware.bin", signature=True, extract=True):
|
||||
for result in module.results:
|
||||
print(f"0x{result.offset:X} {result.description}")
|
||||
```
|
||||
|
||||
## chipsec CLI (UEFI Analysis)
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `python chipsec_main.py -m common.bios_wp` | Check BIOS write protection |
|
||||
| `python chipsec_main.py -m common.spi_lock` | Check SPI flash lock status |
|
||||
| `python chipsec_main.py -m common.secureboot` | Verify Secure Boot configuration |
|
||||
| `python chipsec_util.py spi dump <output>` | Dump UEFI firmware from SPI flash |
|
||||
|
||||
## Python Libraries
|
||||
|
||||
| Library | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| `subprocess` | stdlib | Execute binwalk, file, and strings commands |
|
||||
| `hashlib` | stdlib | SHA-256 hashing for firmware integrity |
|
||||
| `re` | stdlib | Pattern matching for IOC extraction |
|
||||
|
||||
## References
|
||||
|
||||
- binwalk: https://github.com/ReFirmLabs/binwalk
|
||||
- Firmadyne: https://github.com/firmadyne/firmadyne
|
||||
- UEFITool: https://github.com/LongSoft/UEFITool
|
||||
- chipsec: https://github.com/chipsec/chipsec
|
||||
- EMBA firmware analyzer: https://github.com/e-m-b-a/emba
|
||||
@@ -0,0 +1,211 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Agent for performing firmware malware analysis.
|
||||
|
||||
Automates firmware extraction with binwalk, filesystem analysis,
|
||||
string extraction, entropy analysis, and IOC identification.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class FirmwareAnalysisAgent:
|
||||
"""Automates firmware image analysis and malware detection."""
|
||||
|
||||
def __init__(self, firmware_path, output_dir):
|
||||
self.firmware_path = Path(firmware_path)
|
||||
self.output_dir = Path(output_dir)
|
||||
self.output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def compute_hash(self):
|
||||
"""Compute SHA-256 hash of the firmware image."""
|
||||
sha256 = hashlib.sha256(self.firmware_path.read_bytes()).hexdigest()
|
||||
return {"sha256": sha256, "size": self.firmware_path.stat().st_size}
|
||||
|
||||
def run_binwalk_scan(self):
|
||||
"""Scan firmware with binwalk to identify embedded components."""
|
||||
result = subprocess.run(
|
||||
["binwalk", str(self.firmware_path)],
|
||||
capture_output=True, text=True
|
||||
)
|
||||
return {"output": result.stdout, "returncode": result.returncode}
|
||||
|
||||
def run_binwalk_extract(self):
|
||||
"""Extract firmware components with binwalk recursive extraction."""
|
||||
extract_dir = self.output_dir / "extracted"
|
||||
result = subprocess.run(
|
||||
["binwalk", "-eM", "-C", str(extract_dir), str(self.firmware_path)],
|
||||
capture_output=True, text=True
|
||||
)
|
||||
return {"extract_dir": str(extract_dir), "returncode": result.returncode}
|
||||
|
||||
def run_entropy_analysis(self):
|
||||
"""Run binwalk entropy analysis to detect encrypted/compressed regions."""
|
||||
result = subprocess.run(
|
||||
["binwalk", "-E", str(self.firmware_path)],
|
||||
capture_output=True, text=True
|
||||
)
|
||||
return {"output": result.stdout}
|
||||
|
||||
def find_filesystem_root(self):
|
||||
"""Locate extracted filesystem root directory."""
|
||||
extract_dir = self.output_dir / "extracted"
|
||||
for root, dirs, files in os.walk(str(extract_dir)):
|
||||
if "squashfs-root" in dirs:
|
||||
return Path(root) / "squashfs-root"
|
||||
if "etc" in dirs and "bin" in dirs:
|
||||
return Path(root)
|
||||
return None
|
||||
|
||||
def search_hardcoded_credentials(self, fs_root):
|
||||
"""Search filesystem for hardcoded credentials."""
|
||||
findings = []
|
||||
patterns = [
|
||||
(r"password|passwd|secret|api_key|token", "credential_keyword"),
|
||||
(r"root:\$[0-9a-zA-Z\$\.\/]+", "password_hash"),
|
||||
(r"ssh-rsa\s+[A-Za-z0-9+/=]+", "ssh_key"),
|
||||
]
|
||||
|
||||
search_dirs = ["etc", "usr/bin", "usr/sbin", "home", "root", "var"]
|
||||
for search_dir in search_dirs:
|
||||
target = fs_root / search_dir
|
||||
if not target.exists():
|
||||
continue
|
||||
for filepath in target.rglob("*"):
|
||||
if not filepath.is_file():
|
||||
continue
|
||||
try:
|
||||
content = filepath.read_text(errors="ignore")
|
||||
for pattern, finding_type in patterns:
|
||||
matches = re.findall(pattern, content, re.IGNORECASE)
|
||||
if matches:
|
||||
findings.append({
|
||||
"file": str(filepath.relative_to(fs_root)),
|
||||
"type": finding_type,
|
||||
"match_count": len(matches),
|
||||
"samples": matches[:3],
|
||||
})
|
||||
except (PermissionError, OSError):
|
||||
continue
|
||||
return findings
|
||||
|
||||
def check_startup_scripts(self, fs_root):
|
||||
"""Analyze startup scripts for backdoor entries."""
|
||||
scripts = []
|
||||
startup_paths = [
|
||||
"etc/init.d", "etc/rc.d", "etc/inittab", "etc/rcS",
|
||||
"etc/crontab", "etc/cron.d",
|
||||
]
|
||||
suspicious_patterns = [
|
||||
r"nc\s+-[el]", r"netcat", r"bash\s+-i", r"wget\s+http",
|
||||
r"curl\s+http.*\|.*sh", r"telnetd", r"/dev/tcp/",
|
||||
]
|
||||
|
||||
for spath in startup_paths:
|
||||
target = fs_root / spath
|
||||
if target.is_file():
|
||||
scripts.append(self._analyze_script(target, fs_root, suspicious_patterns))
|
||||
elif target.is_dir():
|
||||
for f in target.iterdir():
|
||||
if f.is_file():
|
||||
scripts.append(self._analyze_script(f, fs_root, suspicious_patterns))
|
||||
return [s for s in scripts if s]
|
||||
|
||||
def _analyze_script(self, filepath, fs_root, patterns):
|
||||
"""Analyze a single script for suspicious content."""
|
||||
try:
|
||||
content = filepath.read_text(errors="ignore")
|
||||
except (PermissionError, OSError):
|
||||
return None
|
||||
suspicious = []
|
||||
for pattern in patterns:
|
||||
if re.search(pattern, content, re.IGNORECASE):
|
||||
suspicious.append(pattern)
|
||||
return {
|
||||
"file": str(filepath.relative_to(fs_root)),
|
||||
"size": filepath.stat().st_size,
|
||||
"suspicious_patterns": suspicious,
|
||||
"is_suspicious": len(suspicious) > 0,
|
||||
}
|
||||
|
||||
def find_elf_binaries(self, fs_root):
|
||||
"""Identify all ELF binaries in the extracted filesystem."""
|
||||
binaries = []
|
||||
for filepath in fs_root.rglob("*"):
|
||||
if not filepath.is_file():
|
||||
continue
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["file", "--brief", str(filepath)],
|
||||
capture_output=True, text=True
|
||||
)
|
||||
if "ELF" in result.stdout:
|
||||
binaries.append({
|
||||
"file": str(filepath.relative_to(fs_root)),
|
||||
"type": result.stdout.strip(),
|
||||
"size": filepath.stat().st_size,
|
||||
"sha256": hashlib.sha256(filepath.read_bytes()).hexdigest(),
|
||||
})
|
||||
except (PermissionError, OSError):
|
||||
continue
|
||||
return binaries
|
||||
|
||||
def extract_strings_iocs(self, fs_root):
|
||||
"""Extract IOCs (IPs, URLs, domains) from firmware binaries."""
|
||||
iocs = {"ips": set(), "urls": set(), "domains": set()}
|
||||
ip_pattern = re.compile(r"\b(?:\d{1,3}\.){3}\d{1,3}\b")
|
||||
url_pattern = re.compile(r"https?://[^\s\"'<>]+")
|
||||
domain_pattern = re.compile(r"\b[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.[a-z]{2,}\b")
|
||||
|
||||
for filepath in fs_root.rglob("*"):
|
||||
if not filepath.is_file() or filepath.stat().st_size > 10_000_000:
|
||||
continue
|
||||
try:
|
||||
content = filepath.read_bytes().decode("utf-8", errors="ignore")
|
||||
iocs["ips"].update(ip_pattern.findall(content))
|
||||
iocs["urls"].update(url_pattern.findall(content))
|
||||
iocs["domains"].update(domain_pattern.findall(content))
|
||||
except (PermissionError, OSError):
|
||||
continue
|
||||
|
||||
private_ips = {"127.0.0.1", "0.0.0.0", "255.255.255.255"}
|
||||
iocs["ips"] -= private_ips
|
||||
return {k: sorted(v) for k, v in iocs.items()}
|
||||
|
||||
def generate_report(self):
|
||||
"""Run full firmware analysis and generate a report."""
|
||||
report = {"firmware": str(self.firmware_path), "hash": self.compute_hash()}
|
||||
report["binwalk_scan"] = self.run_binwalk_scan()
|
||||
self.run_binwalk_extract()
|
||||
|
||||
fs_root = self.find_filesystem_root()
|
||||
if fs_root:
|
||||
report["credentials"] = self.search_hardcoded_credentials(fs_root)
|
||||
report["startup_scripts"] = self.check_startup_scripts(fs_root)
|
||||
report["elf_binaries"] = self.find_elf_binaries(fs_root)[:50]
|
||||
report["iocs"] = self.extract_strings_iocs(fs_root)
|
||||
else:
|
||||
report["filesystem"] = "No filesystem root found"
|
||||
|
||||
report_path = self.output_dir / "firmware_analysis_report.json"
|
||||
with open(report_path, "w") as f:
|
||||
json.dump(report, f, indent=2, default=list)
|
||||
print(json.dumps(report, indent=2, default=list))
|
||||
return report
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: agent.py <firmware_image> <output_dir>")
|
||||
sys.exit(1)
|
||||
agent = FirmwareAnalysisAgent(sys.argv[1], sys.argv[2])
|
||||
agent.generate_report()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user