Files
Anthropic-Cybersecurity-Skills/skills/performing-binary-exploitation-analysis/scripts/agent.py
T
mukul975 c47eed6a64 Production hardening: security fixes, code quality, 724 skills complete
- 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
2026-03-19 13:26:49 +01:00

201 lines
7.7 KiB
Python

#!/usr/bin/env python3
"""Binary exploitation analysis agent.
# For authorized security testing and CTF challenges only
Analyzes ELF binaries for security mitigations, discovers ROP gadgets,
and assists exploit development using pwntools and checksec.
"""
import argparse
import json
import subprocess
import sys
import datetime
try:
from pwn import ELF, ROP
HAS_PWNTOOLS = True
except ImportError:
HAS_PWNTOOLS = False
def run_checksec(binary_path):
"""Analyze binary security mitigations using checksec."""
if HAS_PWNTOOLS:
try:
elf = ELF(binary_path, checksec=False)
return {
"arch": elf.arch,
"bits": elf.bits,
"endian": elf.endian,
"nx": elf.nx,
"pie": elf.pie,
"canary": elf.canary,
"relro": "Full" if elf.relro == "Full" else ("Partial" if elf.relro else "None"),
"stripped": not elf.sym,
"static": elf.statically_linked,
}
except Exception as e:
return {"error": str(e)}
try:
result = subprocess.run(["checksec", "--file", binary_path, "--output", "json"],
capture_output=True, text=True, timeout=10)
if result.stdout:
return json.loads(result.stdout)
except (FileNotFoundError, subprocess.TimeoutExpired, json.JSONDecodeError):
pass
return {"error": "Neither pwntools nor checksec available"}
def find_rop_gadgets(binary_path, max_gadgets=20):
"""Find ROP gadgets using pwntools or ROPgadget."""
if HAS_PWNTOOLS:
try:
elf = ELF(binary_path, checksec=False)
rop = ROP(elf)
gadgets = []
for gadget in rop.gadgets.values():
if len(gadgets) >= max_gadgets:
break
gadgets.append({
"address": hex(gadget.address),
"insns": "; ".join(gadget.insns),
})
return gadgets
except Exception as e:
return [{"error": str(e)}]
try:
result = subprocess.run(
["ROPgadget", "--binary", binary_path, "--count", str(max_gadgets)],
capture_output=True, text=True, timeout=30
)
gadgets = []
for line in result.stdout.splitlines():
if " : " in line:
parts = line.split(" : ", 1)
gadgets.append({"address": parts[0].strip(), "insns": parts[1].strip()})
return gadgets[:max_gadgets]
except (FileNotFoundError, subprocess.TimeoutExpired):
return [{"error": "Neither pwntools ROP nor ROPgadget available"}]
def find_useful_functions(binary_path):
"""Find useful functions for exploitation (system, exec, write, etc.)."""
if not HAS_PWNTOOLS:
return {"error": "pwntools not available"}
try:
elf = ELF(binary_path, checksec=False)
interesting = ["system", "execve", "exec", "popen", "gets", "strcpy",
"sprintf", "read", "write", "puts", "printf", "mprotect"]
found = {}
for func in interesting:
addr = elf.sym.get(func) or elf.plt.get(func)
if addr:
found[func] = hex(addr)
got_entries = {}
for name in ["system", "printf", "puts", "__libc_start_main"]:
if name in elf.got:
got_entries[name] = hex(elf.got[name])
return {"functions": found, "got_entries": got_entries}
except Exception as e:
return {"error": str(e)}
def find_vulnerable_functions(binary_path):
"""Identify potentially vulnerable functions in the binary."""
dangerous = {"gets": "Unbounded read - guaranteed buffer overflow",
"strcpy": "No length check - possible overflow",
"strcat": "No length check - possible overflow",
"sprintf": "No length check - possible overflow",
"scanf": "Possible format string / overflow",
"vsprintf": "No length check - possible overflow"}
if not HAS_PWNTOOLS:
return {"error": "pwntools not available"}
try:
elf = ELF(binary_path, checksec=False)
found = []
for func, reason in dangerous.items():
if func in elf.plt or func in elf.sym:
found.append({"function": func, "reason": reason,
"address": hex(elf.plt.get(func, elf.sym.get(func, 0)))})
return found
except Exception as e:
return [{"error": str(e)}]
def analyze_binary(binary_path):
"""Full binary exploitation analysis."""
report = {
"binary": binary_path,
"timestamp": datetime.datetime.utcnow().isoformat() + "Z",
"checksec": run_checksec(binary_path),
"dangerous_functions": find_vulnerable_functions(binary_path),
"useful_functions": find_useful_functions(binary_path),
"rop_gadgets": find_rop_gadgets(binary_path, max_gadgets=15),
}
mitigations = report["checksec"]
if isinstance(mitigations, dict) and "error" not in mitigations:
report["exploit_difficulty"] = "HARD" if all([
mitigations.get("nx"), mitigations.get("pie"),
mitigations.get("canary"), mitigations.get("relro") == "Full"
]) else "MEDIUM" if mitigations.get("nx") else "EASY"
return report
def main():
parser = argparse.ArgumentParser(
description="Binary exploitation analysis agent (authorized testing only)"
)
parser.add_argument("binary", nargs="?", help="Path to ELF binary")
parser.add_argument("--checksec-only", action="store_true", help="Only run checksec")
parser.add_argument("--gadgets", type=int, default=15, help="Max ROP gadgets to find")
parser.add_argument("--output", "-o", help="Output JSON report path")
args = parser.parse_args()
print("[*] Binary Exploitation Analysis Agent")
print("[*] For authorized security testing and CTF challenges only")
print(f" pwntools available: {HAS_PWNTOOLS}")
if not args.binary:
print("\nUsage: python agent.py /path/to/binary [--checksec-only] [--gadgets 20]")
print(" Analyzes: mitigations, dangerous functions, ROP gadgets, GOT entries")
print(json.dumps({"demo": True, "pwntools": HAS_PWNTOOLS}, indent=2))
sys.exit(0)
if args.checksec_only:
result = run_checksec(args.binary)
print(json.dumps(result, indent=2))
sys.exit(0)
report = analyze_binary(args.binary)
checksec = report.get("checksec", {})
if isinstance(checksec, dict) and "error" not in checksec:
print(f"\n[*] Architecture: {checksec.get('arch')} ({checksec.get('bits')}-bit)")
print(f" NX: {checksec.get('nx')} | PIE: {checksec.get('pie')} | "
f"Canary: {checksec.get('canary')} | RELRO: {checksec.get('relro')}")
print(f" Exploit difficulty: {report.get('exploit_difficulty', '?')}")
dangerous = report.get("dangerous_functions", [])
if isinstance(dangerous, list) and dangerous:
print(f"\n[!] Dangerous functions found: {len(dangerous)}")
for d in dangerous:
if "error" not in d:
print(f" {d['function']} @ {d['address']}: {d['reason']}")
gadgets = report.get("rop_gadgets", [])
if gadgets and "error" not in gadgets[0]:
print(f"\n[*] ROP gadgets found: {len(gadgets)}")
for g in gadgets[:5]:
print(f" {g['address']}: {g['insns']}")
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
print(json.dumps({"difficulty": report.get("exploit_difficulty", "unknown"),
"gadgets": len(gadgets)}, indent=2))
if __name__ == "__main__":
main()