diff --git a/CHANGELOG.md b/CHANGELOG.md index 340a69638..58749e48e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,7 @@ The table below shows which release corresponds to each branch, and what date th ## 5.0.0 (`dev`) +- [#2638][2638] feat: add disable_corefiles context option - [#2598][2598] aarch64: Fix ABI definition - [#2419][2419] riscv: avoid compressed instructions (if you need compressed, use .option rvc) - [#2551][2551] Detect when kitty is being used as terminal @@ -102,6 +103,7 @@ The table below shows which release corresponds to each branch, and what date th - [#2610][2610] Fix `log.progress` ignoring `context.log_console` - [#2615][2615] tube/process: Fix redirecting stderr to stdout on Windows +[2638]: https://github.com/Gallopsled/pwntools/pull/2638 [2598]: https://github.com/Gallopsled/pwntools/pull/2598 [2419]: https://github.com/Gallopsled/pwntools/pull/2419 [2551]: https://github.com/Gallopsled/pwntools/pull/2551 diff --git a/pwnlib/context/__init__.py b/pwnlib/context/__init__.py index 9445d974d..842ffdfd3 100644 --- a/pwnlib/context/__init__.py +++ b/pwnlib/context/__init__.py @@ -358,6 +358,7 @@ class ContextType(object): 'cyclic_alphabet': string.ascii_lowercase.encode(), 'cyclic_size': 4, 'delete_corefiles': False, + 'disable_corefiles': False, 'device': os.getenv('ANDROID_SERIAL', None) or None, 'encoding': 'auto', 'endian': 'little', @@ -1485,6 +1486,18 @@ def delete_corefiles(self, v): """ return bool(v) + @_validator + def disable_corefiles(self, v): + """Whether pwntools automatically disable corefiles generation. + + When enabled, sets RLIMIT_CORE to (0,-1) to prevent core dump creation + entirely, which is useful for brute-force scenarios and repeated segfault + crashes where core files consume excessive disk space + + Default value is ``False``. + """ + return bool(v) + @_validator def rename_corefiles(self, v): """Whether pwntools automatically renames corefiles. diff --git a/pwnlib/elf/corefile.py b/pwnlib/elf/corefile.py index 2915f0465..60d226446 100644 --- a/pwnlib/elf/corefile.py +++ b/pwnlib/elf/corefile.py @@ -484,6 +484,22 @@ class Corefile(ELF): >>> core.sp in core.stack False + context.disable_corefiles disables the automatic corefile generation + for crashed processes. For running processes, io.corefile still invoke + GDB to generate a coredump. + + >>> context.clear(arch='amd64') + >>> context.disable_corefiles = True + >>> elf = ELF.from_assembly(shellcraft.crash()) + >>> io = elf.process() + >>> io.wait(1) + >>> io.corefile is None + True + >>> io = process('bash') + >>> core = io.corefile + >>> core is not None + True + Corefile gracefully handles the stack being filled with garbage, including argc / argv / envp being overwritten. diff --git a/pwnlib/tubes/process.py b/pwnlib/tubes/process.py index 6e36b61be..871240297 100644 --- a/pwnlib/tubes/process.py +++ b/pwnlib/tubes/process.py @@ -436,9 +436,12 @@ def __preexec_fn(self): except Exception: self.exception("Could not disable ASLR") - # Assume that the user would prefer to have core dumps. + # Check that the user would prefer to have core dumps or not. try: - resource.setrlimit(resource.RLIMIT_CORE, (-1, -1)) + if context.disable_corefiles: + resource.setrlimit(resource.RLIMIT_CORE, (0, -1)) + else: + resource.setrlimit(resource.RLIMIT_CORE, (-1, -1)) except Exception: pass @@ -1400,8 +1403,8 @@ def corefile(self): If the process is alive, attempts to create a coredump with GDB. - If the process is dead, attempts to locate the coredump created - by the kernel. + If the process is dead: returns None if context.disable_corefiles is enabled, + otherwise attempts to locate the coredump created by the kernel. """ # If the process is still alive, try using GDB import pwnlib.elf.corefile @@ -1414,6 +1417,9 @@ def corefile(self): self.error("Could not create corefile with GDB for %s", self.executable) return corefile + if context.disable_corefiles : + self._corefile = None + return self._corefile # Handle race condition against the kernel or QEMU to write the corefile # by waiting up to 5 seconds for it to be written. t = Timeout()