mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-11 21:54:56 +03:00
c47eed6a64
- Fix 25 shell=True subprocess calls with list-based commands - Fix 49 verify=False in defensive skills (env-var override) - Add timeout to 231 HTTP/subprocess/socket calls - Fix 6 SQL injection patterns with whitelist validation - Replace 8 __import__() with standard imports - Remove 701 unused imports across 442 files - Add authorized-testing disclaimers to all offensive skills - Complete 11 incomplete skill directories - Expand 10 stub SKILL.md files with full content - Fix 2 YAML parse errors in frontmatter - Fix 5 pre-existing syntax errors - Convert 22 hardcoded paths/ports to environment variables - Back up 21 redundant skill pairs to .bak - Fix 2 global declaration errors - 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE) - 0 compile errors across all 724 agent.py files
208 lines
7.2 KiB
Python
208 lines
7.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Agent for Linux memory forensics using LiME acquisition and Volatility 3."""
|
|
|
|
import json
|
|
import subprocess
|
|
import argparse
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
|
|
def acquire_memory_lime(output_path, lime_format="lime"):
|
|
"""Acquire memory using LiME kernel module."""
|
|
kernel_version = subprocess.run(
|
|
["uname", "-r"], capture_output=True, text=True, timeout=120
|
|
).stdout.strip()
|
|
lime_module = f"lime-{kernel_version}.ko"
|
|
if not Path(lime_module).exists():
|
|
lime_module = "lime.ko"
|
|
cmd = ["insmod", lime_module, f"path={output_path}", f"format={lime_format}"]
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
|
|
return {
|
|
"status": "success" if result.returncode == 0 else "failed",
|
|
"output_path": output_path,
|
|
"format": lime_format,
|
|
"kernel": kernel_version,
|
|
"stderr": result.stderr,
|
|
}
|
|
|
|
|
|
def run_vol3_plugin(image_path, plugin_name, extra_args=None):
|
|
"""Run a Volatility 3 plugin and capture output."""
|
|
cmd = ["vol3", "-f", image_path, plugin_name]
|
|
if extra_args:
|
|
cmd.extend(extra_args)
|
|
try:
|
|
result = subprocess.run(
|
|
cmd, capture_output=True, text=True, timeout=300,
|
|
)
|
|
lines = result.stdout.strip().splitlines()
|
|
return {"plugin": plugin_name, "output": lines, "error": result.stderr.strip()}
|
|
except subprocess.TimeoutExpired:
|
|
return {"plugin": plugin_name, "output": [], "error": "Timeout"}
|
|
|
|
|
|
def parse_pslist_output(lines):
|
|
"""Parse Volatility linux.pslist output into structured data."""
|
|
processes = []
|
|
for line in lines:
|
|
parts = line.split()
|
|
if len(parts) >= 4 and parts[0].isdigit():
|
|
processes.append({
|
|
"pid": int(parts[0]),
|
|
"ppid": int(parts[1]) if parts[1].isdigit() else 0,
|
|
"name": parts[-1],
|
|
})
|
|
return processes
|
|
|
|
|
|
def list_processes(image_path):
|
|
"""List all processes from memory image."""
|
|
result = run_vol3_plugin(image_path, "linux.pslist")
|
|
return parse_pslist_output(result.get("output", []))
|
|
|
|
|
|
def extract_bash_history(image_path):
|
|
"""Extract bash command history from memory."""
|
|
result = run_vol3_plugin(image_path, "linux.bash")
|
|
commands = []
|
|
for line in result.get("output", []):
|
|
parts = line.split(None, 3)
|
|
if len(parts) >= 4 and parts[0].isdigit():
|
|
commands.append({
|
|
"pid": int(parts[0]),
|
|
"name": parts[1],
|
|
"timestamp": parts[2] if len(parts) > 2 else "",
|
|
"command": parts[3] if len(parts) > 3 else "",
|
|
})
|
|
return commands
|
|
|
|
|
|
def list_network_connections(image_path):
|
|
"""List network connections from memory."""
|
|
result = run_vol3_plugin(image_path, "linux.sockstat")
|
|
connections = []
|
|
for line in result.get("output", []):
|
|
if "TCP" in line or "UDP" in line:
|
|
connections.append(line.strip())
|
|
return connections
|
|
|
|
|
|
def list_kernel_modules(image_path):
|
|
"""List loaded kernel modules to detect rootkits."""
|
|
result = run_vol3_plugin(image_path, "linux.lsmod")
|
|
modules = []
|
|
for line in result.get("output", []):
|
|
parts = line.split()
|
|
if parts and not parts[0].startswith("Offset"):
|
|
modules.append({"name": parts[-1] if parts else line.strip()})
|
|
return modules
|
|
|
|
|
|
def detect_hidden_processes(image_path):
|
|
"""Compare pslist vs psscan to find hidden processes."""
|
|
pslist = run_vol3_plugin(image_path, "linux.pslist")
|
|
psscan = run_vol3_plugin(image_path, "linux.psscan")
|
|
pslist_pids = set()
|
|
for line in pslist.get("output", []):
|
|
parts = line.split()
|
|
if parts and parts[0].isdigit():
|
|
pslist_pids.add(int(parts[0]))
|
|
hidden = []
|
|
for line in psscan.get("output", []):
|
|
parts = line.split()
|
|
if parts and parts[0].isdigit():
|
|
pid = int(parts[0])
|
|
if pid not in pslist_pids and pid > 0:
|
|
hidden.append({"pid": pid, "line": line.strip()})
|
|
return hidden
|
|
|
|
|
|
def detect_suspicious_commands(bash_history):
|
|
"""Flag suspicious commands in bash history."""
|
|
suspicious_patterns = [
|
|
"curl.*|.*sh", "wget.*&&.*chmod", "base64.*-d",
|
|
"nc.*-e", "python.*-c.*import.*socket",
|
|
"nohup", "rm.*-rf.*/var/log", "history.*-c",
|
|
"iptables.*-F", "chmod.*777", "chattr.*-i",
|
|
]
|
|
import re
|
|
findings = []
|
|
for entry in bash_history:
|
|
cmd = entry.get("command", "")
|
|
for pattern in suspicious_patterns:
|
|
if re.search(pattern, cmd, re.IGNORECASE):
|
|
findings.append({
|
|
"pid": entry["pid"],
|
|
"command": cmd,
|
|
"pattern": pattern,
|
|
"severity": "HIGH",
|
|
})
|
|
break
|
|
return findings
|
|
|
|
|
|
def check_malfind(image_path):
|
|
"""Run malfind to detect injected code."""
|
|
result = run_vol3_plugin(image_path, "linux.malfind")
|
|
return result.get("output", [])
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="LiME + Volatility 3 Forensics Agent")
|
|
parser.add_argument("--image", help="Path to memory image")
|
|
parser.add_argument("--acquire", help="Output path for LiME acquisition")
|
|
parser.add_argument("--output", default="memory_forensics_report.json")
|
|
parser.add_argument("--action", choices=[
|
|
"acquire", "pslist", "bash", "network", "modules",
|
|
"hidden", "malfind", "full_analysis"
|
|
], default="full_analysis")
|
|
args = parser.parse_args()
|
|
|
|
report = {"generated_at": datetime.utcnow().isoformat(), "findings": {}}
|
|
|
|
if args.action == "acquire" and args.acquire:
|
|
result = acquire_memory_lime(args.acquire)
|
|
report["findings"]["acquisition"] = result
|
|
print(f"[+] Memory acquisition: {result['status']}")
|
|
return
|
|
|
|
if not args.image:
|
|
print("[-] --image required for analysis actions")
|
|
return
|
|
|
|
if args.action in ("pslist", "full_analysis"):
|
|
procs = list_processes(args.image)
|
|
report["findings"]["processes"] = procs
|
|
print(f"[+] Processes: {len(procs)}")
|
|
|
|
if args.action in ("bash", "full_analysis"):
|
|
history = extract_bash_history(args.image)
|
|
report["findings"]["bash_history"] = history
|
|
suspicious = detect_suspicious_commands(history)
|
|
report["findings"]["suspicious_commands"] = suspicious
|
|
print(f"[+] Bash commands: {len(history)}, Suspicious: {len(suspicious)}")
|
|
|
|
if args.action in ("network", "full_analysis"):
|
|
conns = list_network_connections(args.image)
|
|
report["findings"]["connections"] = conns
|
|
print(f"[+] Network connections: {len(conns)}")
|
|
|
|
if args.action in ("modules", "full_analysis"):
|
|
modules = list_kernel_modules(args.image)
|
|
report["findings"]["kernel_modules"] = modules
|
|
print(f"[+] Kernel modules: {len(modules)}")
|
|
|
|
if args.action in ("hidden", "full_analysis"):
|
|
hidden = detect_hidden_processes(args.image)
|
|
report["findings"]["hidden_processes"] = hidden
|
|
print(f"[+] Hidden processes: {len(hidden)}")
|
|
|
|
with open(args.output, "w") as f:
|
|
json.dump(report, f, indent=2, default=str)
|
|
print(f"[+] Report saved to {args.output}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|