* feat(libcdb): use local debuginfod client cache before hitting servers (#2623)
If gdb / eu-debuginfod-find / abrt has already downloaded the matching
debuginfo for our libc's build-id (cached at $DEBUGINFOD_CACHE_PATH or
$XDG_CACHE_HOME/debuginfod_client/ or ~/.cache/debuginfod_client/),
unstrip_libc() now reuses it directly instead of doing another network
round-trip via debuginfod servers. Validated by ELF magic so non-ELF
junk in the cache is ignored.
Closes#2623
* Update CHANGELOG.md for #2726
* Check our own cache before looking at debuginfod-client
---------
Co-authored-by: Chris (ChrisJr404) <[email protected]>
Co-authored-by: Peace-Maker <[email protected]>
* Add Type Annotations for parts of pwnlib/util
* fix: use Callable in pwnlib/util/lists.py
* fix: Import Errors
* fix: use getLogger in pwnlib/util/net
* feat: use collections.abc.Buffer where appropriate
* fix: remove collections.abc.Buffer to use Sequence
* add CHANGELOG.md entry
* Improve packing and fiddling types
* Introduce own `BytesLike` type instead of 3.12 Buffer
* Improve web.wget types
* Use TypedDict in util.net
Specify generics properly.
* Improve pwnlib.proc types
* Improve pwnlib.util.lists types
* Fix util.splash types
* Make TypeVars private
* Improve util.hexdump types
* Remove partial types from packing.fit/flat
Those require more work to be useful.
* Fix implicit wget return
* Fix term.text type export
* Fix js_escape return type
* Fix sh_string doctest types
* Fix usage of ssh_channel as ssh_process
We access the pid, so a plain ssh_channel is not enough.
* Improve util.lists types
* Improve packing.dd types
* Fix relying on socket.AddressFamily type at runtime
The type is only in typeshed and not the real socket module. Don't access it at runtime, only at type checking.
* Fix lists.findall with string needle
* Fix dd on two files
* Update mypy-baseline.txt
* Remove testing artifacts from mypy-baseline.txt
---------
Co-authored-by: peace-maker <[email protected]>
* Support paginated libc.rip API requests
libc.rip used to truncate the result set but supports pagination now. Fetch all results reliably now by requesting all pages.
Fixes#2651
* Update CHANGELOG
* docs(args): clarify reserved args map to context, not args.NOASLR
Reserved magic arguments such as DEBUG and NOASLR are consumed as hooks
that adjust context (context.log_level, context.aslr) and are never
stored in the args dict, so args.NOASLR is always the empty string.
The pwnup template comment previously claimed these settings 'show up
in args', which reinforced the wrong mental model and led users to
check args.NOASLR instead of context.aslr. Clarify both the template
comment and the pwnlib.args module docstring.
Fixes#2564
* docs: add changelog entry for args/pwnup.mako docstring clarification
CI requires a CHANGELOG.md entry for changes touching pwnlib/args.py
and pwnlib/data/templates/pwnup.mako.
* Add support for debugging with x64dbg on Windows
Add x64dbg option to `context.debugger` to attach using x64dbg in `windbg.debug()`.
The path to the x96dbg.exe is looked up in the path and through the "Debug with x64dbg" shell extension you can install optionally when first launching the x96dbg.exe launcher.
You can specify the path using `context.x64dbg_binary` too.
* Refactor exclusion of `context.debugger="auto"` while handling `"auto"`
Co-authored-by: Christian Clauss <[email protected]>
* Update CHANGELOG
* Remove absolute path workaround
x64dbg 2026.05.27 fixed passing absolute paths to a script file using -cf.
* Remove bare raise
log.error raises already.
* Fix linting error of winreg import on linux
The module is only available on Windows. So ignore the error when linting on another platform.
---------
Co-authored-by: Christian Clauss <[email protected]>
The external debuginfod servers are really slow or won't respond at all like debuginfod.ubuntu.com.
The caching in CI doesn't help since we only cache it for 3 month and the query fails afterwards most of the time. We cache the negative response too which doesn't help if the service is flakey itself :D
* ROP: Add labels to reference gadgets dynamically
Allow to assign a name to a point in the ROP chain using `ROP.setlabel(name)`
and reference it somewhere else using `ROP.uselabel(name, offset)`.
You have to know the location of your chain in memory to resolve the
right addresses. This allows to specify addresses relative to your ROP chain payload in your chain.
Refs #2583
* Update ret2dlresolve test output
* Update CHANGELOG
* Rename functions to `label` and `ref`
This is less verbose than `setlabel` and `uselabel` but still descriptive enough to be able to guess what they do.
* fix: improve exception handling in process.py and adb.py
- process.py: restore bare except with pylint disable (intentional: catches
non-Exception errors during Python interpreter shutdown)
- adb.py: use specific (OSError, EOFError) instead of broad except Exception
* fix: add missing import for remote in adb.py
The bare except was silently catching NameError from the missing
remote import. Added 'from pwnlib.tubes.remote import remote' to
fix the actual underlying bug.
* docs: add changelog entry for PR #2743
* docs: move changelog reference link near 5.0.0 release section
* fix: catch PwnlibException in emulator AVD name lookup
The bare except was catching PwnlibException raised by remote() when
connection fails. Replacing with except (OSError, EOFError) caused
PwnlibException to propagate, potentially causing retry loops in
Android CI.
Fix by adding PwnlibException to the exception tuple.
* fix: prevent __getattr__ infinite recursion with context.device setter
When context.device setter accesses device.arch, it triggers AdbDevice's
__getattr__ (instead of the arch property). __getattr__ then calls
context.local(device=self), which triggers the setter again, causing
infinite recursion.
Fix: check if the attribute exists on the class via MRO.__dict__
before entering the context.local() path. This lets Python's normal
property resolution handle class-defined attributes.
* revert: remove __getattr__ MRO guard
Peace-maker correctly points out that __getattr__ is only called when
normal attribute lookup fails, so the MRO guard is unnecessary.
The infinite recursion is a pre-existing bug unrelated to this PR.
* Assign to `_avd` instead of `avd`
---------
Co-authored-by: mshzy <[email protected]>
Co-authored-by: peace-maker <[email protected]>
* fix(ssh): use POSIX separator for path detection in ssh.which
On Windows, `os.path.sep` is '\\', which fails to detect POSIX paths.
Hardcoding '/' ensures consistent path detection since the `ssh`
module targets POSIX-compliant systems.
* Update CHANGELOG.md
* feat(context): add path_sep and pathlist_sep to context, make the path seperator dependent on the context.os
* fix(ssh): declare path separator as private member in ssh
* fix(ssh): remote path handling with pathlib
* fix(ssh): replace os.path.basename functions with pathlib for path handling
* fix(ssh): ensure remote paths are decoded to str
* guide users to libc_start_main_return for __libc_start_main_ret
looking up __libc_start_main_ret on ELF(libc).sym just threw a plain
KeyError/AttributeError even though libcdb shows that symbol, which is
confusing (issue 2563). it's not a real symbol so we can't just add it,
and computing it means disassembling __libc_start_main which we don't
want to do for everyone by default.
so for now the symbols dotdict raises a message pointing at the existing
ELF.libc_start_main_return property when you ask for that key. lazy auto
calc can come later. added a doctest covering both sym['...'] and
sym.__libc_start_main_ret access, tests pass.
* use bare super() in symboldict
peace-maker noted new code can use py3 super(), so drop the
redundant (symboldict, self) args.
* add changelog entry for 2746
---------
Co-authored-by: peace-maker <[email protected]>
The nginx docs say that you have to specify the $request_uri manually when a variable is used in the `proxy_pass` value.
Since we just put `/` at the end, all requests were rewritten to `/` instead of the intended e.g. `/api/find` endpoints.
https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
This broke in #2718 but didn't manifest right away since the responses were still cached in CI. Now after the cache expired the fetch failed.
* Fix some global type hint errors
Errors in global scope should be fixed before we're enabling strict mode in mypy and tackle the local problems.
* Remove pwnlib.util.pairwise since it's in itertools now
pairwise was added to itertools itself in 3.10.
https://docs.python.org/3/library/itertools.html#itertools.pairwise
* Fix atexception handlers in term mode
The colored-traceback module registers its own `sys.excepthook` but doesn't call the original handler.
Reorder the includes such that the colored-traceback is setup before and our own hooks afterwards.
We always call the old excepthook and forward the exception to the colored-traceback after firing our own handlers.
It worked before in non-term mode when stderr wasn't a tty and colors were disabled.
* Update CHANGELOG
* Import atexception in doctests
* feat(libcdb): add extra_mirrors arg + PWN_EXTRA_LIBC_MIRRORS env to download_libraries (#2666)
When the libc.rip URL points at a deb.debian.org / archive.ubuntu.com /
security.debian.org URL whose package has been pulled (e.g. older
vulnerable libc versions like 'GLIBC 2.36-9+deb12u6'), download_libraries
now also tries the same /pool/... path against any user-supplied mirror
prefix(es). Mirrors can be passed via the new keyword argument
extra_mirrors=... (str or list) or the comma/whitespace-separated
PWN_EXTRA_LIBC_MIRRORS environment variable.
Closes#2666
* Update CHANGELOG.md for #2725
* Rename environment variable to `PWNLIB_EXTRA_LIBC_MIRRORS`
All our other user-facing environment variables are `PWNLIB_` instead of `PWN_`.
* Move `import re` to toplevel
* Add type hints to touched functions
* Add example usage for download_libraries with extra_mirrors parameter
* Fix envvar in CHANGELOG
---------
Co-authored-by: Chris (ChrisJr404) <[email protected]>
Co-authored-by: Peace-Maker <[email protected]>
* Add typehints to timeout module
Co-authored-by: Copilot <[email protected]>
* Add typehints to device class
* Add typehints to PwnlibException
* Add general typehints for term.text module
Since the available module attributes are handled dynamically like `text.green()` or `text.green_on_white()` or `text.underline_red()`, it's not feasible to type out all possible combinations.
Just tell the type checker that all module attibutes have the same type and thus avoid the `error: Module has no attribute "bold_blue" [attr-defined]` errors.
* Add typehints for config module
* Add typehints for hashes module
The guaranteed algorithms in hashlib are pretty stable and we can generate the list out proper type checking and auto complete.
Still add a check in CI that notifies us if there are changes in the future.
* Add atexception and atexit types
atexception.unregister was not documented correctly since the function expects an identifier returned by `atexception.register` instead of the handler function.
* Fix toplevel type hints in shellcraft.internal
* Fix toplevel type hints in term.key
---------
Co-authored-by: Copilot <[email protected]>
* add ":" to Distro string
* Update cache file path to include username
Include username in cache file path for better uniqueness.
* Added public_key+fingerprint for ssh class & Modified ssh checksec_cache path to be more unique & checksec is per ssh server and not attached to a user
* Fix typeo
* Revert indentation to 10 chars
* ssh: Fix downloading data to tmp on Windows
Allows the checksec output of the target server to be generated.
Filenames cannot contain a colon ":".
* Update CHANGELOG
---------
Co-authored-by: Peace-Maker <[email protected]>
* refactor: optimize completion script
And deprecate an interface
* chore: update changelog
* refactor: full patch of zsh comp script
* fix: add missing message in output
* fix: a typo and a missing help
* feat: allow -l to match multiple arguments
* feat: optimize completion logic
1. move all complicated functions in front of pwn()
2. add file completion for libcdb subcommands
3. add completion for pwn errno
* Allow running with Unicorn 2.1.[34] but throw when emulating MIPS
Unicorn 2.1.5 wasn't released for a while and 2.1.2 doesn't have binary wheels for Python 3.14.
This made installing pwntools on newer Python versions more annoying since you had to build Unicorn yourself.
The only problem with the blocked versions is MIPS emulation, so only avoid that while allowing to use Unicorn 2.1.3 or 2.1.4 for other architectures.
Refs #2621
* Update CHANGELOG
* fix(ssh): resolve PermissionError on Windows during SFTP upload
On Windows, `tempfile.NamedTemporaryFile()` holds an exclusive lock on the file.
Previously, `sftp.put()` attempted to re-open the file by its path, causing a
`PermissionError: [Errno 13]`. This commit replaces `put` with `putfo`, passing a file object directly to bypass the tempfile entirely.
* Update CHANGELOG.md
Update CHANGELOG.md to include new entries and links.
* Start to gradually add type hints
Use mypy-baseline to ignore all existing errors for now while avoiding adding new ones in new code.
* Remove Python 2 fallback imports
* Remove py2compat layer
* Avoid redefining a tube helper function
* Remove explicit new-style class (object) syntax
old-style classes were removed in Python 3 so there is no distinction anymore.
* Ignore type error in shellcraft helper script
* Fix repeatedly changing `linux_dirent.d_name`
* Avoid typechecking windows_termcap on Linux
We run mypy on Linux in CI, ignore Windows related import errors
* Run mypy-baseline in CI
* Add type hint plan to CONTRIBUTING
* Sort the mypy baseline
Run with `--sort-baseline` for better diffs.
`mypy | mypy-baseline sync --sort-baseline`
* Switch dev dependencies to dependency-groups
The dependency groups aren't baked into build metadata and won't appear on Pypi.
* Remove python-dateutil dependency
It is only used for parsing the `ro.build.date` string in Android adb.
Since we use `ro.build.date.utc` now as primary build time source,
don't require `python-dateutil` anymore, but keep optional support.
* Update CHANGELOG
* Fix _build_date() crash on non-standard locale date strings (#2513)
Some Android devices return locale-dependent strings in ro.build.date
(e.g. '2017年 11月 14日 星期二 09:55:07 CST' for Chinese locale) that
dateutil.parser.parse() cannot handle, causing wait_for_device() to
crash with a ParserError.
Fix: prefer ro.build.date.utc (integer epoch timestamp) which is
locale-independent and available on all Android devices. Fall back
to ro.build.date with error handling if the UTC property is missing.
* Add CHANGELOG entry for #2513 fix
* Simplify _build_date(): prefer ro.build.date.utc, keep minimal fallback
Address review: ro.build.date.utc is set by the AOSP build system
and available on all standard Android devices. Simplified comments
to reflect this is the primary path, with ro.build.date kept only
as a fallback for non-standard builds.
* Move CHANGELOG entry
* Fix Python 2.7 compatibility
* Disable intro doctest connecting to `ftp.ubuntu.com`
The FTP server is throttled in CI or just really slow. We already test the basic tcp tubes in the `remote` tests.
---------
Co-authored-by: coder999999999 <[email protected]>
Co-authored-by: peace-maker <[email protected]>
* Enable basic tubes/process test on Windows
Many tests are Linux specific using qemu or /proc etc. So only test the basic process interaction for now.
* Cleanup docs without using ellipsis for Windows output
* Set newline to b'\r\n' for local Windows processes
But only change it automatically if `context.newline` wasn't set manually.
* Disable process.terminate() test on Windows
Windows doesn't support sending SIGTERM to other processes.
https://docs.python.org/3/library/subprocess.html#subprocess.Popen.send_signal
* libcdb CI cache: add another dns server
[emerg] 1#1: host not found in upstream "debuginfod.elfutils.org" in /etc/nginx/nginx.conf:26
The cache should still start despite not being able to resolve some domain.
* Rename `windbg.debug(windbgscript=)` parameter to dbgscript
Prepare to support more debuggers than windbg.
* Pass dbgscript in file instead of inline
This way we don't have to deal with shell escaping the dbgscript commands.
* Add `context.debugger` to select which debugger to use
Allow to choose the debugger to start when using `windbg.attach`.
By default it autodetects which debugger is available.
You can specify the path to the debuggers using
`context.windbg_binary` and `context.windbgx_binary`.
* Check if default windbg installation location exists
* Update CHANGELOG
* fix: pad bytes fields to correct field size in FileStructure
When setting bytes fields (e.g. _IO_save_base) on FileStructure, the
value was padded to context.bytes instead of the actual field size from
self.length[val]. This caused struct.pack errors for fields whose size
differs from the pointer size.
Fixes#2693
* Cleanup test and add CHANGELOG
---------
Co-authored-by: nightcityblade <[email protected]>
Co-authored-by: Peace-Maker <[email protected]>
* ssh: Discard stderr of `lsb_release`
The "No LSB modules are available." spam interferes with parsing the output for the initial checksec distro parsing when connecting to a new host.
* Update CHANGELOG
* Add `reveal_ptr_same_page`
Reveals a pointer mangled using PROTECT_PTR without knowing where it is stored.
Only works when the pointer points to the same page as it is stored on, which happens regularly in normal tcache next-ptrs.
* Update CHANGELOG
* Close SSH client when authentication failed
The TCP connection stayed open after an exception was thrown
during authentication, even when a `with`-statement guarding the call.
Close the connection before re-raising the exception.
Fixes#2678
* Update CHANGELOG
* ssh: support raw string input for 'key' argument
Implement support for passing the actual private key as a string or bytes, as specified in the documentation. This prevents an AttributeError by converting the string to the appropriate Paramiko PKey object (RSA/ECDSA/Ed25519).
* update changelog
* Add tests for ssh connection using a key
* Cleanup docs
---------
Co-authored-by: Your Name <[email protected]>
Co-authored-by: Peace-Maker <[email protected]>
* Fix `server.close()` not closing the listen socket
It would block on `accept` forever, not freeing the listening port.
Break out of `accept()` regularly to check if the socket was closed in the meantime and stop the thread.
* Update CHANGELOG
* Fix `listen.close()` not closing the listen socket
If `close()` was called before a connection was accepted,
the listen socket would not be closed.
* Fix closing listen socket on Windows
Windows throws an ENOTSOCK instead of an EBADF.
* Keep timeout on child socket tube