File size: 2,191 Bytes
14b1bbe | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | """
Pwntools-based PoC assembler.
Produces a runnable Python script for every confirmed crash that a human
researcher (or downstream Bounty Gateway) can review and submit. When
``pwntools`` isn't installed the assembler still emits a self-contained
Python file using the standard library that demonstrates the input.
"""
from __future__ import annotations
import os
import textwrap
from typing import Any
try: # pragma: no cover
from pwn import context # type: ignore # noqa: F401
_PWN = True
except Exception: # noqa: BLE001
_PWN = False
class PwntoolsSynth:
def assemble(self, crash: dict[str, Any], rop_chain: list[str]) -> dict[str, Any]:
binary = crash.get("harness", "<binary>")
crash_input = crash.get("path", "<input>")
chain_lit = ", ".join(repr(g) for g in rop_chain) or "# no gadgets"
if _PWN:
template = textwrap.dedent(f"""\
# Auto-generated by Rhodawk Mythos
from pwn import *
context.log_level = 'error'
p = process({binary!r})
rop = ROP({binary!r})
gadgets = [{chain_lit}]
with open({crash_input!r}, 'rb') as f:
payload = f.read()
p.sendline(payload)
print(p.recvall(timeout=2))
""")
else:
template = textwrap.dedent(f"""\
# Auto-generated by Rhodawk Mythos (no-pwntools fallback)
import subprocess, sys
with open({crash_input!r}, 'rb') as f:
payload = f.read()
proc = subprocess.run([{binary!r}], input=payload,
capture_output=True, timeout=5)
sys.stdout.write(proc.stdout.decode(errors='replace'))
sys.stderr.write(proc.stderr.decode(errors='replace'))
""")
out_path = os.path.join("/tmp", f"poc_{crash.get('id', 'x')}.py")
try:
with open(out_path, "w") as fh:
fh.write(template)
except OSError:
pass
return {"path": out_path, "code": template, "uses_pwntools": _PWN}
|