mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-11 21:54:56 +03:00
203 lines
7.7 KiB
Python
203 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 os
|
|
import struct
|
|
import subprocess
|
|
import sys
|
|
import datetime
|
|
|
|
try:
|
|
from pwn import ELF, ROP, context
|
|
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()
|