mirror of
https://github.com/Gallopsled/pwntools.git
synced 2026-11-08 17:13:31 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5db149adc2 | ||
|
|
ddb5798b8c | ||
|
|
f1624dc8ac | ||
|
|
a824e83bcb | ||
|
|
dff2e807cd | ||
|
|
b8ca473a39 | ||
|
|
09541e042b | ||
|
|
dd92ca6c61 | ||
|
|
5e279e7993 | ||
|
|
846f98294f | ||
|
|
f227796a09 | ||
|
|
baa4fc5a9f | ||
|
|
78df70c986 | ||
|
|
53ecb27948 | ||
|
|
b5de88e118 | ||
|
|
8b1c25f441 | ||
|
|
db0312e0fe | ||
|
|
7b130aec79 | ||
|
|
13960bac08 | ||
|
|
230a42ffc0 | ||
|
|
31465d7570 | ||
|
|
07c7dd6242 | ||
|
|
6f8319519b | ||
|
|
3469f4a4f7 | ||
|
|
b22e3e611d | ||
|
|
3be97b7ab5 | ||
|
|
1a9dce025f | ||
|
|
cbb57c0148 | ||
|
|
92810cbeb2 | ||
|
|
039f2439b5 | ||
|
|
a190726caf | ||
|
|
745f8e7716 | ||
|
|
a3bf833a9a | ||
|
|
f2cb7babcf | ||
|
|
ce0966d186 | ||
|
|
d143af398e | ||
|
|
a1b0ff6b29 | ||
|
|
1b130cfe5d | ||
|
|
c3e39f57f8 | ||
|
|
ede4ed13e0 | ||
|
|
316cf359c1 | ||
|
|
343dff5c51 | ||
|
|
a0d61dcea5 | ||
|
|
f02e5b5e45 | ||
|
|
c293318cbd | ||
|
|
ddf5cdcb3f | ||
|
|
761d446fa3 | ||
|
|
5e012ebf95 | ||
|
|
7d6cb3f61f | ||
|
|
a414d788fe | ||
|
|
4134e60c8d | ||
|
|
88084975ad | ||
|
|
4b14e27523 | ||
|
|
45eb8bcc81 | ||
|
|
8b6e6ed67d | ||
|
|
18a7a9458c | ||
|
|
3cca881881 | ||
|
|
2a68da3dad | ||
|
|
9f5b24d889 | ||
|
|
e9b24a6159 | ||
|
|
39a3b2e8ff | ||
|
|
09caa4ba63 | ||
|
|
a0eeb30e0b | ||
|
|
f1628b80fe | ||
|
|
5c65b8a03e | ||
|
|
c2a61b30db | ||
|
|
82a7074d86 | ||
|
|
8a21b0306d | ||
|
|
c0afb8ef29 | ||
|
|
baed2d5bbc | ||
|
|
cccbc4555c | ||
|
|
df3835a611 | ||
|
|
758b86c4b0 | ||
|
|
16f8c419bc | ||
|
|
1eca50e421 | ||
|
|
d2e84c1a30 | ||
|
|
1c1615da2f | ||
|
|
cb4e01b4df | ||
|
|
00f65f2c53 | ||
|
|
ac2522fe91 | ||
|
|
82f20b28cf | ||
|
|
fd8ed5883e | ||
|
|
5fea8d25a8 | ||
|
|
01fb378320 | ||
|
|
3f8c92b233 | ||
|
|
c846f94c8e | ||
|
|
a5bf7c50f4 | ||
|
|
8066b2353b | ||
|
|
b81c61cae4 | ||
|
|
54d3f674e1 | ||
|
|
14f5ab6b90 | ||
|
|
555dec78d9 | ||
|
|
267879c91a | ||
|
|
2d48220165 | ||
|
|
4d9242ae89 | ||
|
|
fae86c3dec | ||
|
|
24211219d8 | ||
|
|
2c0d63b569 | ||
|
|
e254c5fa62 | ||
|
|
aba16247b4 | ||
|
|
6fc0914dc0 | ||
|
|
8137494932 | ||
|
|
baad3927b9 | ||
|
|
94647d6c10 | ||
|
|
e1aedff092 | ||
|
|
8a2b77131e | ||
|
|
b5dd858897 | ||
|
|
70d42fb076 | ||
|
|
9ede4b8eea | ||
|
|
d944a9ec68 | ||
|
|
bbd82ac6fe | ||
|
|
4439849d66 | ||
|
|
061d0fd953 | ||
|
|
43c4eef53b | ||
|
|
ef40a31ac8 | ||
|
|
59ce329431 |
No files matched your search
@@ -17,4 +17,13 @@ jobs:
|
||||
|
||||
- name: Check changelog for updates
|
||||
run: |
|
||||
git log --stat ${GITHUB_BASE}..HEAD | grep CHANGELOG.md
|
||||
if git log --stat ${GITHUB_BASE}..HEAD | grep CHANGELOG.md; then
|
||||
echo 'Changelog updated :D'
|
||||
else
|
||||
if git log --stat ${GITHUB_BASE}..HEAD | grep '++\|--'; then
|
||||
echo 'Major changes detected, changelog required!'
|
||||
false
|
||||
else
|
||||
echo 'Minor changes detected, no changelog required!'
|
||||
fi
|
||||
fi
|
||||
@@ -2,7 +2,7 @@ name: Continuous Integration
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [2.7, 3.8]
|
||||
@@ -74,11 +74,20 @@ jobs:
|
||||
binutils-arm-linux-gnueabihf \
|
||||
binutils-mips-linux-gnu \
|
||||
binutils-powerpc-linux-gnu \
|
||||
binutils-sparc64-linux-gnu \
|
||||
gcc-multilib \
|
||||
libc6-dbg \
|
||||
$ANDROID_JRE
|
||||
|
||||
- name: Install android avd
|
||||
- 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;) || true
|
||||
|
||||
- name: Install Android AVD
|
||||
if: steps.java-needed.outputs.need
|
||||
run: |
|
||||
USER=travis source travis/install.sh
|
||||
@@ -101,13 +110,12 @@ jobs:
|
||||
- name: Install documentation dependencies
|
||||
run: pip install -r docs/requirements.txt
|
||||
|
||||
- name: Disable broken tests
|
||||
run: |
|
||||
rm -f docs/source/elf/corefile.rst
|
||||
|
||||
- name: Manually install non-broken Unicorn
|
||||
run: pip install unicorn==1.0.2rc3
|
||||
|
||||
- name: Version Check
|
||||
run: PWNLIB_NOTERM=1 pwn version
|
||||
|
||||
- name: Coverage doctests
|
||||
run: |
|
||||
source .android.env || :
|
||||
@@ -186,7 +194,7 @@ jobs:
|
||||
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: build
|
||||
needs: test
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
@@ -199,11 +207,12 @@ jobs:
|
||||
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')
|
||||
needs: build
|
||||
needs: test
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
|
||||
@@ -2,7 +2,7 @@ name: Lint
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
lint:
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.8]
|
||||
@@ -11,9 +11,6 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Cache for pip
|
||||
uses: actions/cache@v1
|
||||
id: cache-pip
|
||||
@@ -26,8 +23,13 @@ jobs:
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Lint
|
||||
- name: Critical lint
|
||||
run: |
|
||||
pip install flake8
|
||||
flake8 . --count --select=E9,F63,F7 --show-source --statistics --exclude=android-?dk # TODO: Add F82
|
||||
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --exclude=pwnlib/constants,android-?dk,.git,__pycache__
|
||||
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'
|
||||
@@ -0,0 +1,28 @@
|
||||
name: Check for merge markers
|
||||
on: [pull_request]
|
||||
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@v2
|
||||
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
|
||||
@@ -20,6 +20,7 @@ addons:
|
||||
- binutils-arm-linux-gnueabihf
|
||||
- binutils-mips-linux-gnu
|
||||
- binutils-powerpc-linux-gnu
|
||||
- binutils-sparc64-linux-gnu
|
||||
- bash-static
|
||||
cache:
|
||||
- pip
|
||||
|
||||
+85
-7
@@ -9,9 +9,16 @@ The table below shows which release corresponds to each branch, and what date th
|
||||
|
||||
| Version | Branch | Release Date |
|
||||
| ---------------- | -------- | ---------------------- |
|
||||
| [4.3.0](#430) | `dev` | Jun 30, 2020 (planned)
|
||||
| [4.2.0](#420) | `beta` | Jun 5, 2020 (planned)
|
||||
| [4.1.1](#411) | `stable` | Jun 3, 2020
|
||||
| [4.5.0](#450) | `dev` | Dec 20, 2020 (planned)
|
||||
| [4.4.0](#440) | `beta` | Nov 20, 2020 (planned)
|
||||
| [4.3.0](#430) | `stable` | Oct 20, 2020
|
||||
| [4.2.0](#420) | | Jul 3, 2020
|
||||
| [4.1.7](#417) | | Jun 30, 2020
|
||||
| [4.1.5](#415) | | Jun 27, 2020
|
||||
| [4.1.4](#414) | | Jun 26, 2020
|
||||
| [4.1.3](#413) | | Jun 23, 2020
|
||||
| [4.1.2](#412) | | Jun 5, 2020
|
||||
| [4.1.1](#411) | | Jun 3, 2020
|
||||
| [4.1.0](#410) | | May 8, 2020
|
||||
| [4.0.1](#401) | | Jan 22, 2020
|
||||
| [4.0.0](#400) | | Jan 09, 2020
|
||||
@@ -49,13 +56,84 @@ The table below shows which release corresponds to each branch, and what date th
|
||||
| [3.0.0](#300) | | Aug 20, 2016
|
||||
| [2.2.0](#220) | | Jan 5, 2015
|
||||
|
||||
## 4.3.0 (`dev`)
|
||||
## 4.5.0 (`dev`)
|
||||
|
||||
To be released on Jun 30, 2020.
|
||||
## 4.4.0 (`beta`)
|
||||
|
||||
## 4.2.0 (`beta`)
|
||||
- [#1541][1541] Use `context.newline` for tubes by default
|
||||
- [#1602][1602] Fix bytes handling in ssh tubes
|
||||
- [#1606][1606] Fix `asm()` and `disasm()` for MSP430, S390
|
||||
- [#1616][1616] Fix `cyclic` cli for 64 bit integers
|
||||
- [#1632][1632] Enable usage of Pwntools in jupyter
|
||||
- [#1633][1633] Open a shell if `pwn template` cannot download the remote file
|
||||
- [#1644][1644] Enable and support SNI for SSL-wrapped tubes
|
||||
- [#1651][1651] Make `pwn shellcraft` faster
|
||||
- [#1654][1654] Docker images (`pwntools/pwntools:stable` etc) now use Python3 by default, and includes assemblers for a few common architectures
|
||||
- [#1667][1667] Add i386 encoder `ascii_shellcode` (Fixed docs in #1693)
|
||||
- Fix syscall instruction lists for SROP on `i386` and `amd64`
|
||||
- Fix migration to another ROP
|
||||
- [#1673][1673] Add `base=` argument to `ROP.chain()` and `ROP.dump()`
|
||||
- [#1675][1675] Gdbserver now correctly accepts multiple libraries in `LD_PRELOAD` and `LD_LIBRARY_PATH`
|
||||
- [#1678][1678] ROPGadget multibr
|
||||
- [#1682][1682] ROPGadget multibr fix
|
||||
- [#1687][1687] Actually import `requests` when doing `from pwn import *`
|
||||
- [#1688][1688] Add `__setattr__` and `__call__` interfaces to `ROP` for setting registers
|
||||
- [#1692][1692] Remove python2 shebangs where appropriate
|
||||
- [#1703][1703] Update libcdb buildid offsets for amd64 and i386
|
||||
|
||||
To be released on Jun 5, 2020.
|
||||
[1541]: https://github.com/Gallopsled/pwntools/pull/1541
|
||||
[1602]: https://github.com/Gallopsled/pwntools/pull/1602
|
||||
[1606]: https://github.com/Gallopsled/pwntools/pull/1606
|
||||
[1616]: https://github.com/Gallopsled/pwntools/pull/1616
|
||||
[1632]: https://github.com/Gallopsled/pwntools/pull/1632
|
||||
[1633]: https://github.com/Gallopsled/pwntools/pull/1633
|
||||
[1644]: https://github.com/Gallopsled/pwntools/pull/1644
|
||||
[1651]: https://github.com/Gallopsled/pwntools/pull/1651
|
||||
[1654]: https://github.com/Gallopsled/pwntools/pull/1654
|
||||
[1667]: https://github.com/Gallopsled/pwntools/pull/1667
|
||||
[1673]: https://github.com/Gallopsled/pwntools/pull/1673
|
||||
[1675]: https://github.com/Gallopsled/pwntools/pull/1675
|
||||
[1678]: https://github.com/Gallopsled/pwntools/pull/1678
|
||||
[1682]: https://github.com/Gallopsled/pwntools/pull/1679
|
||||
[1687]: https://github.com/Gallopsled/pwntools/pull/1687
|
||||
[1688]: https://github.com/Gallopsled/pwntools/pull/1688
|
||||
[1692]: https://github.com/Gallopsled/pwntools/pull/1692
|
||||
[1703]: https://github.com/Gallopsled/pwntools/pull/1703
|
||||
|
||||
## 4.3.0 (`stable`)
|
||||
|
||||
- [#1576][1576] Add `executable=` argument to `ELF.search`
|
||||
- [#1584][1584] Add `jmp_esp`/`jmp_rsp` attribute to `ROP`
|
||||
- [#1592][1592] Fix over-verbose logging of process() environment
|
||||
- [#1593][1593] Colorize output of `pwn template`
|
||||
- [#1601][1601] Add `pwn version` command line tool
|
||||
- [#1605][1605] Add to `fiddling.hexdump` a way to suppress the total at the end
|
||||
- [#1613][1613] Permit `--password` for `pwn template`
|
||||
- [#1616][1616] Fix `cyclic` cli for 64 bit integers
|
||||
- [#1564][1564] Fix `asm()` and `disasm()` for PowerPC64, MIPS64, Sparc64
|
||||
- [#1621][1621] Permit negative values in flat() and fit()
|
||||
|
||||
[1576]: https://github.com/Gallopsled/pwntools/pull/1576
|
||||
[1584]: https://github.com/Gallopsled/pwntools/pull/1584
|
||||
[1592]: https://github.com/Gallopsled/pwntools/pull/1592
|
||||
[1593]: https://github.com/Gallopsled/pwntools/pull/1593
|
||||
[1601]: https://github.com/Gallopsled/pwntools/pull/1601
|
||||
[1605]: https://github.com/Gallopsled/pwntools/pull/1605
|
||||
[1613]: https://github.com/Gallopsled/pwntools/pull/1613
|
||||
[1616]: https://github.com/Gallopsled/pwntools/pull/1616
|
||||
[1564]: https://github.com/Gallopsled/pwntools/pull/1564
|
||||
[1621]: https://github.com/Gallopsled/pwntools/pull/1621
|
||||
|
||||
## 4.2.1
|
||||
|
||||
- [#1625][1625] GDB now properly loads executables with QEMU
|
||||
- [#1663][1663] Change lookup algorithm of `adb.which`
|
||||
- [#1699][1699] Fix broken linux shellcraft templates
|
||||
|
||||
[1625]: https://github.com/Gallopsled/pwntools/pull/1625
|
||||
[1699]: https://github.com/Gallopsled/pwntools/pull/1699
|
||||
|
||||
## 4.2.0
|
||||
|
||||
- [#1436][1436] Add ret2dlresolve automation
|
||||
- [fecf9f] tubes.ssh.process() no longer requires python 2 installed on remote (still requires python, though)
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
# pwntools - CTF toolkit
|
||||

|
||||
|
||||
[](https://docs.pwntools.com/)
|
||||
[](https://pypi.python.org/pypi/pwntools/)
|
||||
[](https://travis-ci.org/Gallopsled/pwntools)
|
||||
[](https://coveralls.io/github/Gallopsled/pwntools?branch=dev)
|
||||
[](https://twitter.com/pwntools)
|
||||
[](https://docs.pwntools.com/)
|
||||
[](https://travis-ci.org/Gallopsled/pwntools)
|
||||

|
||||
[](https://coveralls.io/github/Gallopsled/pwntools?branch=dev)
|
||||
[](http://choosealicense.com/licenses/mit/)
|
||||
[](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.
|
||||
|
||||
@@ -20,10 +21,6 @@ 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/)
|
||||
@@ -32,7 +29,7 @@ To get you started, we've provided some example solutions for past CTF challenge
|
||||
|
||||
# Installation
|
||||
|
||||
Pwntools is best supported on 64-bit Ubuntu LTE releases (12.04, 14.04, 16.04 and 18.04). Most functionality should work on any Posix-like distribution (Debian, Arch, FreeBSD, OSX, etc.). Python >= 2.7 is required (Python 3 suggested as best).
|
||||
Pwntools is best supported on 64-bit Ubuntu LTE releases (14.04, 16.04, 18.04, and 20.04). Most functionality should work on any Posix-like distribution (Debian, Arch, FreeBSD, OSX, etc.). Python >= 2.7 is required (Python 3 suggested as best).
|
||||
|
||||
Most of the functionality of pwntools is self-contained and Python-only. You should be able to get running quickly with
|
||||
|
||||
@@ -40,7 +37,7 @@ Most of the functionality of pwntools is self-contained and Python-only. You sh
|
||||
apt-get update
|
||||
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 git+https://github.com/Gallopsled/pwntools.git@dev
|
||||
python3 -m 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).
|
||||
|
||||
+1
-8
@@ -340,7 +340,7 @@ def linkcode_resolve(domain, info):
|
||||
val = mod
|
||||
for k in info['fullname'].split('.'):
|
||||
val = getattr(val, k, None)
|
||||
if val == None:
|
||||
if val is None:
|
||||
break
|
||||
|
||||
# Special case for shellcraft
|
||||
@@ -410,13 +410,6 @@ def py2_doctest_init(self, checker=None, verbose=None, optionflags=0):
|
||||
checker = Py2OutputChecker()
|
||||
doctest.DocTestRunner.__init__(self, checker, verbose, optionflags)
|
||||
|
||||
class EndlessLoop(Exception): pass
|
||||
def alrm_handler(sig, frame):
|
||||
signal.alarm(180) # three minutes
|
||||
raise EndlessLoop()
|
||||
signal.signal(signal.SIGALRM, alrm_handler)
|
||||
signal.alarm(600) # ten minutes
|
||||
|
||||
if 'doctest' in sys.argv:
|
||||
def setup(app):
|
||||
app.connect('autodoc-skip-member', dont_skip_any_doctests)
|
||||
|
||||
+16
-16
@@ -17,19 +17,19 @@
|
||||
count ,
|
||||
cycle ,
|
||||
dropwhile ,
|
||||
filter ,
|
||||
filterfalse ,
|
||||
groupby ,
|
||||
ifilter ,
|
||||
ifilterfalse ,
|
||||
imap ,
|
||||
islice ,
|
||||
izip ,
|
||||
izip_longest ,
|
||||
map ,
|
||||
permutations ,
|
||||
product ,
|
||||
repeat ,
|
||||
starmap ,
|
||||
takewhile ,
|
||||
tee
|
||||
tee ,
|
||||
zip ,
|
||||
zip_longest
|
||||
|
||||
.. function:: chain
|
||||
|
||||
@@ -63,29 +63,29 @@
|
||||
|
||||
Alias for :func:`itertools.groupby`
|
||||
|
||||
.. function:: ifilter
|
||||
.. function:: filter
|
||||
|
||||
Alias for :func:`itertools.ifilter`
|
||||
Alias for python3-style :func:`filter`
|
||||
|
||||
.. function:: ifilterfalse
|
||||
.. function:: filterfalse
|
||||
|
||||
Alias for :func:`itertools.ifilterfalse`
|
||||
Alias for :func:`itertools.filterfalse`
|
||||
|
||||
.. function:: imap
|
||||
.. function:: map
|
||||
|
||||
Alias for :func:`itertools.imap`
|
||||
Alias for python3-style :func:`map`
|
||||
|
||||
.. function:: islice
|
||||
|
||||
Alias for :func:`itertools.islice`
|
||||
|
||||
.. function:: izip
|
||||
.. function:: zip
|
||||
|
||||
Alias for :func:`itertools.izip`
|
||||
Alias for python3-style :func:`zip`
|
||||
|
||||
.. function:: izip_longest
|
||||
.. function:: zip_longest
|
||||
|
||||
Alias for :func:`itertools.izip_longest`
|
||||
Alias for :func:`itertools.zip_longest`
|
||||
|
||||
.. function:: permutations
|
||||
|
||||
|
||||
@@ -36,5 +36,14 @@ print(shell.echo("single string"))
|
||||
print(shell.echo(["list","of","strings"]))
|
||||
print(shell["echo single statement"])
|
||||
|
||||
# ssh.process() is the most flexible way to run a command)
|
||||
io = shell.process(['/bin/bash', '-c', 'echo Hello $FOO'],
|
||||
env={'FOO': 'World'}, # Set environment
|
||||
stderr='/dev/null', # Override file descriptors
|
||||
aslr=False, # Disable ASLR on processes
|
||||
setuid=False, # Disable setuid bit so processes can be debugged
|
||||
shell=False) # Enable or disable shell evaluation
|
||||
print(io.recvall())
|
||||
|
||||
# Show off the interactive shell
|
||||
shell.interactive()
|
||||
+1
-1
@@ -1 +1 @@
|
||||
xenial
|
||||
bionic
|
||||
@@ -0,0 +1,26 @@
|
||||
############################################################
|
||||
# Dockerfile to build Pwntools container
|
||||
# Based on Ubuntu
|
||||
############################################################
|
||||
|
||||
FROM ubuntu:bionic
|
||||
MAINTAINER Maintainer Gallopsled et al.
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y \
|
||||
build-essential \
|
||||
git \
|
||||
libssl-dev \
|
||||
libffi-dev \
|
||||
python2.7 \
|
||||
python-pip \
|
||||
python-dev \
|
||||
&& pip install --upgrade pip \
|
||||
&& python -m pip install --upgrade pwntools \
|
||||
&& PWNLIB_NOTERM=1 pwn update \
|
||||
&& apt-get install -y sudo \
|
||||
&& useradd -m pwntools \
|
||||
&& passwd --delete --unlock pwntools \
|
||||
&& echo "pwntools ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/pwntools
|
||||
USER pwntools
|
||||
WORKDIR /home/pwntools
|
||||
+1
-1
@@ -80,4 +80,4 @@ info = log.info
|
||||
debug = log.debug
|
||||
success = log.success
|
||||
|
||||
__all__ = [x for x in globals().keys() if x != '__name__']
|
||||
__all__ = [x for x in tuple(globals()) if x != '__name__']
|
||||
+6
-4
@@ -827,10 +827,12 @@ def which(name, all = False, *a, **kw):
|
||||
"""
|
||||
# Unfortunately, there is no native 'which' on many phones.
|
||||
which_cmd = '''
|
||||
echo $PATH | while read -d: directory; do
|
||||
[ -x "$directory/{name}" ] || continue;
|
||||
echo -n "$directory/{name}\\x00";
|
||||
done
|
||||
(IFS=:
|
||||
for directory in $PATH; do
|
||||
[ -x "$directory/{name}" ] || continue;
|
||||
echo -n "$directory/{name}\\x00";
|
||||
done
|
||||
)
|
||||
[ -x "{name}" ] && echo -n "$PWD/{name}\\x00"
|
||||
'''.format(name=name)
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from __future__ import division
|
||||
import ctypes
|
||||
import io
|
||||
import os
|
||||
import six
|
||||
import sys
|
||||
|
||||
from pwnlib.log import getLogger
|
||||
@@ -64,7 +65,7 @@ class BootloaderImage(object):
|
||||
Returns:
|
||||
Contents of the image.
|
||||
"""
|
||||
if isinstance(index_or_name, int):
|
||||
if isinstance(index_or_name, six.integer_types):
|
||||
index = index_or_name
|
||||
else:
|
||||
for i in range(len(self.img_info)):
|
||||
|
||||
+29
-14
@@ -167,6 +167,9 @@ def which_binutils(util):
|
||||
'i386': ['x86_64', 'amd64'],
|
||||
'i686': ['x86_64', 'amd64'],
|
||||
'amd64': ['x86_64', 'i386'],
|
||||
'mips64': ['mips'],
|
||||
'powerpc64': ['powerpc'],
|
||||
'sparc64': ['sparc'],
|
||||
}.get(arch, [])
|
||||
|
||||
# If one of the candidate architectures matches the native
|
||||
@@ -190,16 +193,18 @@ def which_binutils(util):
|
||||
for gutil in utils:
|
||||
# e.g. objdump
|
||||
if arch is None:
|
||||
pattern = gutil
|
||||
patterns = [gutil]
|
||||
|
||||
# e.g. aarch64-linux-gnu-objdump
|
||||
# e.g. aarch64-linux-gnu-objdump, avr-objdump
|
||||
else:
|
||||
pattern = '%s*linux*-%s' % (arch,gutil)
|
||||
patterns = ['%s*linux*-%s' % (arch, gutil),
|
||||
'%s-%s' % (arch, gutil)]
|
||||
|
||||
for dir in environ['PATH'].split(':'):
|
||||
res = sorted(glob(path.join(dir, pattern)))
|
||||
if res:
|
||||
return res[0]
|
||||
for pattern in patterns:
|
||||
for dir in environ['PATH'].split(':'):
|
||||
res = sorted(glob(path.join(dir, pattern)))
|
||||
if res:
|
||||
return res[0]
|
||||
|
||||
# No dice!
|
||||
print_binutils_instructions(util, context)
|
||||
@@ -245,9 +250,9 @@ def _assembler():
|
||||
stderr=subprocess.STDOUT, universal_newlines=True)
|
||||
version = re.search(r' (\d\.\d+)', result).group(1)
|
||||
if version < '2.19':
|
||||
log.warn_once('Your binutils version is too old and may not work!\n' + \
|
||||
'Try updating with: https://docs.pwntools.com/en/stable/install/binutils.html\n' + \
|
||||
'Reported Version: %r' % result.strip())
|
||||
log.warn_once('Your binutils version is too old and may not work!\n'
|
||||
'Try updating with: https://docs.pwntools.com/en/stable/install/binutils.html\n'
|
||||
'Reported Version: %r', result.strip())
|
||||
|
||||
|
||||
return assembler
|
||||
@@ -322,6 +327,7 @@ def _bfdname():
|
||||
'amd64' : 'elf64-x86-64',
|
||||
'arm' : 'elf32-%sarm' % E,
|
||||
'thumb' : 'elf32-%sarm' % E,
|
||||
'avr' : 'elf32-avr',
|
||||
'mips' : 'elf32-trad%smips' % E,
|
||||
'mips64' : 'elf64-trad%smips' % E,
|
||||
'alpha' : 'elf64-alpha',
|
||||
@@ -344,10 +350,13 @@ def _bfdname():
|
||||
def _bfdarch():
|
||||
arch = context.arch
|
||||
convert = {
|
||||
'i386': 'i386',
|
||||
'amd64': 'i386:x86-64',
|
||||
'thumb': 'arm',
|
||||
'ia64': 'ia64-elf64'
|
||||
'amd64': 'i386:x86-64',
|
||||
'i386': 'i386',
|
||||
'ia64': 'ia64-elf64',
|
||||
'mips64': 'mips',
|
||||
'powerpc64': 'powerpc',
|
||||
'sparc64': 'sparc',
|
||||
'thumb': 'arm',
|
||||
}
|
||||
|
||||
if arch in convert:
|
||||
@@ -749,6 +758,12 @@ def disasm(data, vma = 0, byte = True, offset = True, instructions = True):
|
||||
>>> print(disasm(unhex('656664676665400F18A4000000000051'), byte=0, arch='amd64'))
|
||||
0: gs data16 fs data16 rex nop/reserved BYTE PTR gs:[eax+eax*1+0x0]
|
||||
f: push rcx
|
||||
>>> print(disasm(unhex('01000000'), arch='sparc64'))
|
||||
0: 01 00 00 00 nop
|
||||
>>> print(disasm(unhex('60000000'), arch='powerpc64'))
|
||||
0: 60 00 00 00 nop
|
||||
>>> print(disasm(unhex('00000000'), arch='mips64'))
|
||||
0: 00000000 nop
|
||||
"""
|
||||
result = ''
|
||||
|
||||
|
||||
@@ -18,5 +18,6 @@ __all__ = [
|
||||
'scramble',
|
||||
'shellcraft',
|
||||
'unhex',
|
||||
'update'
|
||||
'update',
|
||||
'version'
|
||||
]
|
||||
Regular → Executable
+12
-24
@@ -4,7 +4,6 @@ from __future__ import division
|
||||
|
||||
import argparse
|
||||
import functools
|
||||
import os
|
||||
import re
|
||||
|
||||
import pwnlib
|
||||
@@ -19,25 +18,22 @@ p = common.parser_commands.add_parser(
|
||||
formatter_class = argparse.RawDescriptionHelpFormatter,
|
||||
)
|
||||
|
||||
group = p.add_mutually_exclusive_group()
|
||||
group.add_argument(
|
||||
p.add_argument(
|
||||
'-e', '--exact',
|
||||
metavar = 'constant',
|
||||
# nargs = 1,
|
||||
default = None,
|
||||
help = 'Do an exact match for a constant instead of searching for a regex',
|
||||
action='store_true',
|
||||
help='Do an exact match for a constant instead of searching for a regex',
|
||||
)
|
||||
group.add_argument(
|
||||
|
||||
p.add_argument(
|
||||
'regex',
|
||||
nargs = '?',
|
||||
default = '',
|
||||
help = 'The regex matching constant you want to find',
|
||||
help='The regex matching constant you want to find',
|
||||
)
|
||||
|
||||
p.add_argument(
|
||||
'constant',
|
||||
nargs = '?',
|
||||
default = None,
|
||||
type = safeeval.expr,
|
||||
help = 'The constant to find',
|
||||
)
|
||||
|
||||
@@ -65,7 +61,7 @@ p.add_argument(
|
||||
def main(args):
|
||||
if args.exact:
|
||||
# This is the simple case
|
||||
print(cpp(args.exact).strip())
|
||||
print(cpp(args.regex).strip())
|
||||
else:
|
||||
# New we search in the right module.
|
||||
# But first: We find the right module
|
||||
@@ -80,20 +76,12 @@ def main(args):
|
||||
else:
|
||||
matcher = re.compile(args.regex)
|
||||
|
||||
|
||||
# Evaluate the given constant
|
||||
if args.constant:
|
||||
try:
|
||||
constant = safeeval.expr(args.constant)
|
||||
except:
|
||||
log.error("Could not evaluate constant %r" % args.constant)
|
||||
else:
|
||||
constant = None
|
||||
|
||||
# The found matching constants and the length of the longest string
|
||||
out = []
|
||||
maxlen = 0
|
||||
|
||||
constant = args.constant
|
||||
|
||||
for k in dir(mod):
|
||||
# No python stuff
|
||||
if k.endswith('__') and k.startswith('__'):
|
||||
@@ -104,7 +92,7 @@ def main(args):
|
||||
continue
|
||||
|
||||
# Check the constant
|
||||
if constant != None:
|
||||
if constant is not None:
|
||||
val = getattr(mod, k)
|
||||
if args.mask_mode:
|
||||
if constant & val != val:
|
||||
@@ -124,7 +112,7 @@ def main(args):
|
||||
# If we are in match_mode, then try to find a combination of
|
||||
# constants that yield the exact given value
|
||||
# We do not want to find combinations using the value 0.
|
||||
if not (constant == None or constant == 0) and args.mask_mode:
|
||||
if constant and args.mask_mode:
|
||||
mask = constant
|
||||
good = []
|
||||
out = [(v, k) for v, k in out if v != 0]
|
||||
|
||||
@@ -21,6 +21,7 @@ from pwnlib.commandline import shellcraft
|
||||
from pwnlib.commandline import template
|
||||
from pwnlib.commandline import unhex
|
||||
from pwnlib.commandline import update
|
||||
from pwnlib.commandline import version
|
||||
from pwnlib.commandline.common import parser
|
||||
from pwnlib.context import context
|
||||
|
||||
@@ -43,6 +44,7 @@ commands = {
|
||||
'template': template.main,
|
||||
'unhex': unhex.main,
|
||||
'update': update.main,
|
||||
'version': version.main,
|
||||
}
|
||||
|
||||
def main():
|
||||
|
||||
@@ -18,9 +18,10 @@ parser.add_argument('exe', nargs='?', help='Target binary')
|
||||
parser.add_argument('--host', help='Remote host / SSH server')
|
||||
parser.add_argument('--port', help='Remote port / SSH port', type=int)
|
||||
parser.add_argument('--user', help='SSH Username')
|
||||
parser.add_argument('--pass', help='SSH Password', dest='password')
|
||||
parser.add_argument('--pass', '--password', help='SSH Password', dest='password')
|
||||
parser.add_argument('--path', help='Remote path of file on SSH server')
|
||||
parser.add_argument('--quiet', help='Less verbose template comments', action='store_true')
|
||||
parser.add_argument('--color', help='Print the output in color', choices=['never', 'always', 'auto'], default='auto')
|
||||
|
||||
def main(args):
|
||||
cache = None
|
||||
@@ -57,8 +58,16 @@ def main(args):
|
||||
# Fix Mako formatting bs
|
||||
output = re.sub('\n\n\n', '\n\n', output)
|
||||
|
||||
# Colorize the output if it's a TTY
|
||||
if args.color == 'always' or (args.color == 'auto' and sys.stdout.isatty()):
|
||||
from pygments import highlight
|
||||
from pygments.formatters import TerminalFormatter
|
||||
from pygments.lexers.python import PythonLexer
|
||||
output = highlight(output, PythonLexer(), TerminalFormatter())
|
||||
|
||||
print(output)
|
||||
|
||||
# If redirected to a file, make the resulting script executable
|
||||
if not sys.stdout.isatty():
|
||||
try: os.fchmod(sys.stdout.fileno(), 0o700)
|
||||
except OSError: pass
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import pwnlib
|
||||
pwnlib.args.free_form = False
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.commandline import common
|
||||
|
||||
parser = common.parser_commands.add_parser(
|
||||
'version',
|
||||
help = 'Pwntools version'
|
||||
)
|
||||
|
||||
def main(a):
|
||||
version = pwnlib.version
|
||||
|
||||
git_root = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||
if os.path.exists(os.path.join(git_root, '.git')):
|
||||
gitver = subprocess.check_output(['git', '-C', git_root, 'log', '-1', '--format=%h (%cr)'])
|
||||
branch = subprocess.check_output(['git', '-C', git_root, 'rev-parse', '--abbrev-ref', 'HEAD'])
|
||||
version = '%s-%s-%s' % (version, branch.decode().strip(), gitver.decode())
|
||||
|
||||
log.info("Pwntools v%s" % version)
|
||||
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -92,7 +92,7 @@ class ConstantsModule(ModuleType):
|
||||
# Special case for __all__, we want to return the contextually
|
||||
# relevant module.
|
||||
if key == '__all__':
|
||||
return self.guess().__dict__.keys()
|
||||
return list(self.guess().__dict__.keys())
|
||||
|
||||
# Special case for all other special properties which aren't defined
|
||||
if key.endswith('__'):
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
from pwnlib.data.elf import fmtstr
|
||||
from pwnlib.data.elf import relro
|
||||
from pwnlib.data.elf import ret2dlresolve
|
||||
|
||||
import os
|
||||
path = os.path.dirname(__file__)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
all: i386 amd64
|
||||
|
||||
i386: vuln.c
|
||||
gcc "$^" -fno-stack-protector -no-pie -m32 -o $@
|
||||
|
||||
amd64: vuln.c
|
||||
gcc "$^" -fno-stack-protector -no-pie -o $@
|
||||
@@ -0,0 +1,5 @@
|
||||
import os
|
||||
path = os.path.dirname(__file__)
|
||||
|
||||
def get(x):
|
||||
return os.path.join(path, x)
|
||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -0,0 +1,8 @@
|
||||
#include <unistd.h>
|
||||
void vuln(void){
|
||||
char buf[64];
|
||||
read(STDIN_FILENO, buf, 200);
|
||||
}
|
||||
int main(int argc, char** argv){
|
||||
vuln();
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -21,8 +21,8 @@ class KernelConfig(object):
|
||||
self.excludes = set(excludes)
|
||||
|
||||
#: Kernel version that this check should be enforced on
|
||||
self.minver = map(int, str(minver).split('.'))
|
||||
self.maxver = map(int, str(maxver).split('.'))
|
||||
self.minver = list(map(int, str(minver).split('.')))
|
||||
self.maxver = list(map(int, str(maxver).split('.')))
|
||||
|
||||
def relevant(self, config):
|
||||
|
||||
|
||||
+10
-10
@@ -219,8 +219,8 @@ class Mapping(object):
|
||||
stop += self.stop
|
||||
|
||||
if not (self.start <= start <= stop <= self.stop):
|
||||
log.error("Byte range [%#x:%#x] not within range [%#x:%#x]" \
|
||||
% (start, stop, self.start, self.stop))
|
||||
log.error("Byte range [%#x:%#x] not within range [%#x:%#x]",
|
||||
start, stop, self.start, self.stop)
|
||||
|
||||
data = self._core.read(start, stop-start)
|
||||
|
||||
@@ -431,7 +431,7 @@ class Corefile(ELF):
|
||||
|
||||
Corefiles can also be pulled from remote machines via SSH!
|
||||
|
||||
>>> s = ssh(host='example.pwnme')
|
||||
>>> s = ssh(user='travis', host='example.pwnme', password='demopass')
|
||||
>>> _ = s.set_working_directory()
|
||||
>>> elf = ELF.from_assembly(shellcraft.trap())
|
||||
>>> path = s.upload(elf.path)
|
||||
@@ -551,15 +551,15 @@ class Corefile(ELF):
|
||||
self.load_addr = 0
|
||||
self._address = 0
|
||||
|
||||
if not self.elftype == 'CORE':
|
||||
if self.elftype != 'CORE':
|
||||
log.error("%s is not a valid corefile" % self.file.name)
|
||||
|
||||
if not self.arch in prstatus_types.keys():
|
||||
if self.arch not in prstatus_types:
|
||||
log.warn_once("%s does not use a supported corefile architecture, registers are unavailable" % self.file.name)
|
||||
|
||||
prstatus_type = prstatus_types.get(self.arch, None)
|
||||
prpsinfo_type = prpsinfo_types.get(self.bits, None)
|
||||
siginfo_type = siginfo_types.get(self.bits, None)
|
||||
prstatus_type = prstatus_types.get(self.arch)
|
||||
prpsinfo_type = prpsinfo_types.get(self.bits)
|
||||
siginfo_type = siginfo_types.get(self.bits)
|
||||
|
||||
with log.waitfor("Parsing corefile...") as w:
|
||||
self._load_mappings()
|
||||
@@ -669,8 +669,8 @@ class Corefile(ELF):
|
||||
continue
|
||||
|
||||
if mapping.start == self.at_sysinfo_ehdr \
|
||||
or (not vdso and mapping.size in [0x1000, 0x2000] \
|
||||
and mapping.flags == 5 \
|
||||
or (not vdso and mapping.size in [0x1000, 0x2000]
|
||||
and mapping.flags == 5
|
||||
and self.read(mapping.start, 4) == b'\x7fELF'):
|
||||
mapping.name = '[vdso]'
|
||||
vdso = True
|
||||
|
||||
+48
-14
@@ -90,6 +90,12 @@ log = getLogger(__name__)
|
||||
|
||||
__all__ = ['load', 'ELF']
|
||||
|
||||
def _iter_symbols(sec):
|
||||
# Cache result of iter_symbols.
|
||||
if not hasattr(sec, '_symbols'):
|
||||
sec._symbols = list(sec.iter_symbols())
|
||||
return iter(sec._symbols)
|
||||
|
||||
class Function(object):
|
||||
"""Encapsulates information about a function in an :class:`.ELF` binary.
|
||||
|
||||
@@ -269,6 +275,9 @@ class ELF(ELFFile):
|
||||
self.arch = 'mips64'
|
||||
self.bits = 64
|
||||
|
||||
self._sections = None
|
||||
self._segments = None
|
||||
|
||||
#: IntervalTree which maps all of the loaded memory segments
|
||||
self.memory = intervaltree.IntervalTree()
|
||||
self._populate_memory()
|
||||
@@ -310,7 +319,7 @@ class ELF(ELFFile):
|
||||
config = gz.read()
|
||||
|
||||
if config:
|
||||
self.config = parse_kconfig(config)
|
||||
self.config = parse_kconfig(config.decode())
|
||||
|
||||
#: ``True`` if the ELF is a statically linked executable
|
||||
self.statically_linked = bool(self.elftype == 'EXEC' and self.load_addr)
|
||||
@@ -455,9 +464,6 @@ class ELF(ELFFile):
|
||||
self.checksec(*a, **kw)
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return "ELF(%r)" % self.path
|
||||
|
||||
def get_machine_arch(self):
|
||||
return {
|
||||
'EM_X86_64': 'amd64',
|
||||
@@ -485,6 +491,13 @@ class ELF(ELFFile):
|
||||
""":class:`str`: ELF type (``EXEC``, ``DYN``, etc)"""
|
||||
return describe_e_type(self.header.e_type).split()[0]
|
||||
|
||||
def iter_segments(self):
|
||||
# Yield and cache all the segments in the file
|
||||
if self._segments is None:
|
||||
self._segments = [self.get_segment(i) for i in range(self.num_segments())]
|
||||
|
||||
return iter(self._segments)
|
||||
|
||||
@property
|
||||
def segments(self):
|
||||
"""
|
||||
@@ -537,6 +550,13 @@ class ELF(ELFFile):
|
||||
|
||||
return None
|
||||
|
||||
def iter_sections(self):
|
||||
# Yield and cache all the sections in the file
|
||||
if self._sections is None:
|
||||
self._sections = [self.get_section(i) for i in range(self.num_sections())]
|
||||
|
||||
return iter(self._sections)
|
||||
|
||||
@property
|
||||
def sections(self):
|
||||
"""
|
||||
@@ -842,7 +862,7 @@ class ELF(ELFFile):
|
||||
if not isinstance(sec, SymbolTableSection):
|
||||
continue
|
||||
|
||||
for sym in sec.iter_symbols():
|
||||
for sym in _iter_symbols(sec):
|
||||
# Avoid duplicates
|
||||
if sym.name in self.functions:
|
||||
continue
|
||||
@@ -866,7 +886,7 @@ class ELF(ELFFile):
|
||||
if not isinstance(section, SymbolTableSection):
|
||||
continue
|
||||
|
||||
for symbol in section.iter_symbols():
|
||||
for symbol in _iter_symbols(section):
|
||||
value = symbol.entry.st_value
|
||||
if not value:
|
||||
continue
|
||||
@@ -907,7 +927,7 @@ class ELF(ELFFile):
|
||||
if self.statically_linked:
|
||||
return
|
||||
|
||||
for section in self.iter_sections():
|
||||
for section in self.sections:
|
||||
# We are only interested in relocations
|
||||
if not isinstance(section, RelocationSection):
|
||||
continue
|
||||
@@ -961,7 +981,7 @@ class ELF(ELFFile):
|
||||
|
||||
# Iterate over the dynamic symbol table
|
||||
dynsym = self.get_section_by_name('.dynsym')
|
||||
symbol_iter = dynsym.iter_symbols()
|
||||
symbol_iter = _iter_symbols(dynsym)
|
||||
|
||||
# 'gotsym' is the index of the first GOT symbol
|
||||
gotsym = self.dynamic_value_by_tag('DT_MIPS_GOTSYM')
|
||||
@@ -1003,9 +1023,10 @@ class ELF(ELFFile):
|
||||
# In particular, this is where EBX points when it points into the GOT.
|
||||
dt_pltgot = self.dynamic_value_by_tag('DT_PLTGOT') or 0
|
||||
|
||||
# There are two PLTs we may need to search
|
||||
# There are three PLTs we may need to search
|
||||
plt = self.get_section_by_name('.plt') # <-- Functions only
|
||||
plt_got = self.get_section_by_name('.plt.got') # <-- Functions used as data
|
||||
plt_sec = self.get_section_by_name('.plt.sec')
|
||||
plt_mips = self.get_section_by_name('.MIPS.stubs')
|
||||
|
||||
# Invert the GOT symbols we already have, so we can look up by address
|
||||
@@ -1013,7 +1034,7 @@ class ELF(ELFFile):
|
||||
inv_symbols.update({v:k for k,v in self.symbols.items()})
|
||||
|
||||
with context.local(arch=self.arch, bits=self.bits, endian=self.endian):
|
||||
for section in (plt, plt_got, plt_mips):
|
||||
for section in (plt, plt_got, plt_sec, plt_mips):
|
||||
if not section:
|
||||
continue
|
||||
|
||||
@@ -1034,7 +1055,10 @@ class ELF(ELFFile):
|
||||
return
|
||||
|
||||
banner = self.string(self.symbols.linux_banner)
|
||||
|
||||
|
||||
# convert banner into a utf-8 string since re.search does not accept bytes anymore
|
||||
banner = banner.decode('utf-8')
|
||||
|
||||
# 'Linux version 3.18.31-gd0846ecc
|
||||
regex = r'Linux version (\S+)'
|
||||
match = re.search(regex, banner)
|
||||
@@ -1092,8 +1116,8 @@ class ELF(ELFFile):
|
||||
return_from_main = int(return_from_main[ : return_from_main.index(':') ], 16)
|
||||
return return_from_main
|
||||
|
||||
def search(self, needle, writable = False):
|
||||
"""search(needle, writable = False) -> generator
|
||||
def search(self, needle, writable = False, executable = False):
|
||||
"""search(needle, writable = False, executable = False) -> generator
|
||||
|
||||
Search the ELF's virtual address space for the specified string.
|
||||
|
||||
@@ -1106,6 +1130,7 @@ class ELF(ELFFile):
|
||||
Arguments:
|
||||
needle(str): String to search for.
|
||||
writable(bool): Search only writable sections.
|
||||
executable(bool): Search only executable sections.
|
||||
|
||||
Yields:
|
||||
An iterator for each virtual address that matches.
|
||||
@@ -1123,11 +1148,20 @@ class ELF(ELFFile):
|
||||
|
||||
>>> len(list(bash.search(b'GNU bash'))) > 0
|
||||
True
|
||||
|
||||
It is also possible to search for instructions in executable sections.
|
||||
|
||||
>>> binary = ELF.from_assembly('nop; mov eax, 0; jmp esp; ret')
|
||||
>>> jmp_addr = next(binary.search(asm('jmp esp'), executable = True))
|
||||
>>> binary.read(jmp_addr, 2) == asm('jmp esp')
|
||||
True
|
||||
"""
|
||||
load_address_fixup = (self.address - self.load_addr)
|
||||
|
||||
if writable:
|
||||
segments = self.writable_segments
|
||||
elif executable:
|
||||
segments = self.executable_segments
|
||||
else:
|
||||
segments = self.segments
|
||||
|
||||
@@ -1822,7 +1856,7 @@ class ELF(ELFFile):
|
||||
# Check for Linux configuration, it must contain more than
|
||||
# just the version.
|
||||
if len(self.config) > 1:
|
||||
config_opts = collections.defaultdict(lambda: [])
|
||||
config_opts = collections.defaultdict(list)
|
||||
for checker in kernel_configuration:
|
||||
result, message = checker(self.config)
|
||||
|
||||
|
||||
+25
-9
@@ -36,13 +36,17 @@ def emulate_plt_instructions(elf, got, address, data, targets):
|
||||
data = packing.unpack_many(data, bits=32, endian='little')
|
||||
data = packing.flat(data, bits=32, endian='big')
|
||||
|
||||
uc, ctx = prepare_unicorn_and_context(elf, got, address, data)
|
||||
|
||||
# Brute force addresses, assume that PLT entry points are at 4-byte aligned
|
||||
# Do not emulate more than a handful of instructions.
|
||||
for i, pc in enumerate(range(address, address + len(data), 4)):
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug('%s %#x', fiddling.enhex(data[i*4:(i+1) * 4]), pc)
|
||||
log.debug(elf.disasm(pc, 4))
|
||||
target = emulate_plt_instructions_inner(elf, got, pc, data[i*4:], targets)
|
||||
|
||||
uc.context_restore(ctx)
|
||||
target = emulate_plt_instructions_inner(uc, elf, got, pc, data[i*4:], targets)
|
||||
|
||||
if target in targets:
|
||||
log.debug("%#x -> %#x", pc, target)
|
||||
@@ -50,8 +54,7 @@ def emulate_plt_instructions(elf, got, address, data, targets):
|
||||
|
||||
return rv
|
||||
|
||||
def emulate_plt_instructions_inner(elf, got, pc, data, targets):
|
||||
# Deferred import to not affect load time
|
||||
def prepare_unicorn_and_context(elf, got, address, data):
|
||||
import unicorn as U
|
||||
|
||||
# Instantiate the emulator with the correct arguments for the current
|
||||
@@ -88,15 +91,15 @@ def emulate_plt_instructions_inner(elf, got, pc, data, targets):
|
||||
uc = U.Uc(arch, mode)
|
||||
|
||||
# Map the page of memory, and fill it with the contents
|
||||
start = pc & (~0xfff)
|
||||
stop = (pc + len(data) + 0xfff) & (~0xfff)
|
||||
start = address & (~0xfff)
|
||||
stop = (address + len(data) + 0xfff) & (~0xfff)
|
||||
|
||||
if not (0 <= start <= stop <= (1 << elf.bits)):
|
||||
return None
|
||||
|
||||
uc.mem_map(start, stop-start)
|
||||
uc.mem_write(pc, data)
|
||||
assert uc.mem_read(pc, len(data)) == data
|
||||
uc.mem_write(address, data)
|
||||
assert uc.mem_read(address, len(data)) == data
|
||||
|
||||
# MIPS is unique in that it relies entirely on _DYNAMIC, at the beginning
|
||||
# of the GOT. Each PLT stub loads an address stored here.
|
||||
@@ -129,9 +132,17 @@ def emulate_plt_instructions_inner(elf, got, pc, data, targets):
|
||||
trap = packing.p32(0x34000000, endian=elf.endian)
|
||||
uc.mem_write(magic_addr, trap)
|
||||
|
||||
return uc, uc.context_save()
|
||||
|
||||
def emulate_plt_instructions_inner(uc, elf, got, pc, data, targets):
|
||||
import unicorn as U
|
||||
|
||||
# Hook invalid addresses and any accesses out of the specified address range
|
||||
stopped_addr = []
|
||||
|
||||
# For MIPS. Explanation at prepare_unicorn_and_context.
|
||||
magic_addr = 0xdbdbdbdb
|
||||
|
||||
def hook_mem(uc, access, address, size, value, user_data):
|
||||
# Special case to allow MIPS to dereference the _DYNAMIC pointer
|
||||
# in the GOT.
|
||||
@@ -142,8 +153,10 @@ def emulate_plt_instructions_inner(elf, got, pc, data, targets):
|
||||
uc.emu_stop()
|
||||
return False
|
||||
|
||||
uc.hook_add(U.UC_HOOK_MEM_READ, hook_mem, stopped_addr)
|
||||
uc.hook_add(U.UC_HOOK_MEM_UNMAPPED, hook_mem, stopped_addr)
|
||||
hooks = [
|
||||
uc.hook_add(U.UC_HOOK_MEM_READ, hook_mem, stopped_addr),
|
||||
uc.hook_add(U.UC_HOOK_MEM_UNMAPPED, hook_mem, stopped_addr)
|
||||
]
|
||||
|
||||
# callback for tracing instructions
|
||||
# def hook_code(uc, address, size, user_data):
|
||||
@@ -178,4 +191,7 @@ def emulate_plt_instructions_inner(elf, got, pc, data, targets):
|
||||
if stopped_addr:
|
||||
retval = stopped_addr.pop()
|
||||
|
||||
for hook in hooks:
|
||||
uc.hook_del(hook)
|
||||
|
||||
return retval
|
||||
@@ -44,4 +44,4 @@ data:
|
||||
blacklist = set(raw)
|
||||
|
||||
encode = amd64DeltaEncoder()
|
||||
__all__ = [encode]
|
||||
__all__ = ['encode']
|
||||
@@ -32,7 +32,7 @@ class ArmEncoder(Encoder):
|
||||
enc_dec_loop = b.encDecoderLoopBuilder(dec_loop)
|
||||
dec = b.DecoderBuilder(dec_loop, self.icache_flush)
|
||||
|
||||
output,dec = b.buildInit(dec);
|
||||
output, dec = b.buildInit(dec)
|
||||
|
||||
output += dec
|
||||
output += enc_dec_loop
|
||||
|
||||
@@ -42,10 +42,10 @@ def off_gen(c):
|
||||
return x
|
||||
return 0
|
||||
|
||||
# return an alphanumeric value ret such that c XOR ret is also alphanumeric
|
||||
# =========================================================================
|
||||
# return an alphanumeric value ret such that c XOR ret is also alphanumeric
|
||||
# =========================================================================
|
||||
def alphanumeric_get_complement(c):
|
||||
c &= 0xff;
|
||||
c &= 0xff
|
||||
while True:
|
||||
ret = alphanumeric_get_byte()
|
||||
if alphanumeric_check(c ^ ret):
|
||||
|
||||
+10
-3
@@ -3,9 +3,12 @@
|
||||
r"""
|
||||
File Structure Exploitation
|
||||
|
||||
struct FILE (_IO_FILE) is the structure for File Streams. This offers various targets for exploitation on an existing bug in the code. Examples - _IO_buf_base and _IO_buf_end for reading data to arbitrary location.
|
||||
struct FILE (_IO_FILE) is the structure for File Streams.
|
||||
This offers various targets for exploitation on an existing bug in the code.
|
||||
Examples - ``_IO_buf_base`` and ``_IO_buf_end`` for reading data to arbitrary location.
|
||||
|
||||
Remembering the offsets of various structure members while faking a FILE structure can be difficult, so this python class helps you with that. Example-
|
||||
Remembering the offsets of various structure members while faking a FILE structure can be difficult,
|
||||
so this python class helps you with that. Example-
|
||||
|
||||
>>> context.clear(arch='amd64')
|
||||
>>> fileStr = FileStructure(null=0xdeadbeef)
|
||||
@@ -24,6 +27,7 @@ from __future__ import division
|
||||
|
||||
from pwnlib.context import context
|
||||
from pwnlib.log import getLogger
|
||||
from pwnlib.util.misc import python_2_bytes_compatible
|
||||
from pwnlib.util.packing import pack
|
||||
|
||||
log = getLogger(__name__)
|
||||
@@ -62,6 +66,8 @@ variables={
|
||||
26:{name:'vtable',size:length}
|
||||
}
|
||||
|
||||
del name, size, length
|
||||
|
||||
|
||||
def update_var(l):
|
||||
r"""
|
||||
@@ -91,6 +97,8 @@ def update_var(l):
|
||||
var['unknown2']=48
|
||||
return var
|
||||
|
||||
|
||||
@python_2_bytes_compatible
|
||||
class FileStructure(object):
|
||||
r"""
|
||||
Crafts a FILE structure, with default values for some fields, like _lock which should point to null ideally, set.
|
||||
@@ -187,7 +195,6 @@ class FileStructure(object):
|
||||
else:
|
||||
structure += pack(self.__getattr__(val), self.length[val]*8)
|
||||
return structure
|
||||
__str__ = __bytes__
|
||||
|
||||
def struntil(self,v):
|
||||
r"""
|
||||
|
||||
+1
-3
@@ -11,7 +11,6 @@ from pwnlib.tubes.remote import remote
|
||||
|
||||
env_server = args.get('FLAG_HOST', 'flag-submission-server').strip()
|
||||
env_port = args.get('FLAG_PORT', '31337').strip()
|
||||
env_proto = args.get('FLAG_PROTO', 'tcp').strip()
|
||||
env_file = args.get('FLAG_FILE', '/does/not/exist').strip()
|
||||
env_exploit_name = args.get('EXPLOIT_NAME', 'unnamed-exploit').strip()
|
||||
env_target_host = args.get('TARGET_HOST', 'unknown-target').strip()
|
||||
@@ -24,7 +23,6 @@ def submit_flag(flag,
|
||||
target=env_target_host,
|
||||
server=env_server,
|
||||
port=env_port,
|
||||
proto=env_proto,
|
||||
team=env_team_name):
|
||||
"""
|
||||
Submits a flag to the game server
|
||||
@@ -35,7 +33,7 @@ def submit_flag(flag,
|
||||
target(str): Target identifier, optional
|
||||
server(str): Flag server host name, optional
|
||||
port(int): Flag server port, optional
|
||||
proto(str), Flag server protocol, optional
|
||||
team(str): Team identifier, optional
|
||||
|
||||
Optional arguments are inferred from the environment,
|
||||
or omitted if none is set.
|
||||
|
||||
+3
-4
@@ -834,14 +834,13 @@ class FmtStr(object):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, execute_fmt, offset = None, padlen = 0, numbwritten = 0):
|
||||
def __init__(self, execute_fmt, offset=None, padlen=0, numbwritten=0):
|
||||
self.execute_fmt = execute_fmt
|
||||
self.offset = offset
|
||||
self.padlen = padlen
|
||||
self.numbwritten = numbwritten
|
||||
|
||||
|
||||
if self.offset == None:
|
||||
if self.offset is None:
|
||||
self.offset, self.padlen = self.find_offset()
|
||||
log.info("Found format string offset: %d", self.offset)
|
||||
|
||||
@@ -903,7 +902,7 @@ class FmtStr(object):
|
||||
|
||||
"""
|
||||
fmtstr = randoms(self.padlen).encode()
|
||||
fmtstr += fmtstr_payload(self.offset, self.writes, numbwritten=self.padlen, write_size='byte')
|
||||
fmtstr += fmtstr_payload(self.offset, self.writes, numbwritten=self.padlen + self.numbwritten, write_size='byte')
|
||||
self.execute_fmt(fmtstr)
|
||||
self.writes = {}
|
||||
|
||||
|
||||
+18
-7
@@ -237,13 +237,14 @@ def _gdbserver_args(pid=None, path=None, args=None, which=None, env=None):
|
||||
if pid:
|
||||
gdbserver_args += ['--once', '--attach']
|
||||
|
||||
if env:
|
||||
if env is not None:
|
||||
env_args = []
|
||||
for key in tuple(env):
|
||||
if key.startswith('LD_'): # LD_PRELOAD / LD_LIBRARY_PATH etc.
|
||||
env_args.append('{}={}'.format(key, env.pop(key)))
|
||||
if env_args:
|
||||
gdbserver_args += ['--wrapper', 'env'] + env_args + ['--']
|
||||
else:
|
||||
env_args.append('{}={}'.format(key, env[key]))
|
||||
gdbserver_args += ['--wrapper', 'env', '-i'] + env_args + ['--']
|
||||
|
||||
gdbserver_args += ['localhost:0']
|
||||
gdbserver_args += args
|
||||
@@ -399,7 +400,7 @@ def debug(args, gdbscript=None, exe=None, ssh=None, env=None, sysroot=None, **kw
|
||||
>>> io.interactive() # doctest: +SKIP
|
||||
>>> io.close()
|
||||
"""
|
||||
if isinstance(args, (int, tubes.process.process, tubes.ssh.ssh_channel)):
|
||||
if isinstance(args, six.integer_types + (tubes.process.process, tubes.ssh.ssh_channel)):
|
||||
log.error("Use gdb.attach() to debug a running process")
|
||||
|
||||
if isinstance(args, (bytes, six.text_type)):
|
||||
@@ -496,7 +497,7 @@ def binary():
|
||||
|
||||
if multiarch:
|
||||
return multiarch
|
||||
log.warn_once('Cross-architecture debugging usually requires gdb-multiarch\n' \
|
||||
log.warn_once('Cross-architecture debugging usually requires gdb-multiarch\n'
|
||||
'$ apt-get install gdb-multiarch')
|
||||
|
||||
if not gdb:
|
||||
@@ -631,6 +632,9 @@ def attach(target, gdbscript = '', exe = None, gdb_args = None, ssh = None, sysr
|
||||
if context.os == 'android':
|
||||
pre += 'set gnutarget ' + _bfdname() + '\n'
|
||||
|
||||
if exe:
|
||||
pre += 'file %s\n' % exe
|
||||
|
||||
# let's see if we can find a pid to attach to
|
||||
pid = None
|
||||
if isinstance(target, six.integer_types):
|
||||
@@ -980,7 +984,7 @@ def corefile(process):
|
||||
# This is effectively the same as what the 'gcore' binary does
|
||||
gdb_args = ['-batch',
|
||||
'-q',
|
||||
'--nx',
|
||||
'-nx',
|
||||
'-ex', '"set pagination off"',
|
||||
'-ex', '"set height 0"',
|
||||
'-ex', '"set width 0"',
|
||||
@@ -991,7 +995,14 @@ def corefile(process):
|
||||
with context.local(terminal = ['sh', '-c']):
|
||||
with context.quiet:
|
||||
pid = attach(process, gdb_args=gdb_args)
|
||||
os.waitpid(pid, 0)
|
||||
log.debug("Got GDB pid %d", pid)
|
||||
try:
|
||||
os.waitpid(pid, 0)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if not os.path.exists(corefile_path):
|
||||
log.error("Could not generate a corefile for process %d", process.pid)
|
||||
|
||||
return elf.corefile.Core(corefile_path)
|
||||
|
||||
|
||||
+8
-1
@@ -98,6 +98,7 @@ import logging
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import six
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
@@ -183,6 +184,9 @@ class Progress(object):
|
||||
self.last_status = 0
|
||||
|
||||
def _log(self, status, args, kwargs, msgtype):
|
||||
# Logs are strings, not bytes. Handle Python3 bytes() objects.
|
||||
status = six.ensure_text(status)
|
||||
|
||||
# this progress logger is stopped, so don't generate any more records
|
||||
if self._stopped:
|
||||
return
|
||||
@@ -279,11 +283,14 @@ class Logger(object):
|
||||
self._logger = logger
|
||||
|
||||
def _getlevel(self, levelString):
|
||||
if isinstance(levelString, int):
|
||||
if isinstance(levelString, six.integer_types):
|
||||
return levelString
|
||||
return logging._levelNames[levelString.upper()]
|
||||
|
||||
def _log(self, level, msg, args, kwargs, msgtype, progress = None):
|
||||
# Logs are strings, not bytes. Handle Python3 bytes() objects.
|
||||
msg = six.ensure_text(msg)
|
||||
|
||||
extra = kwargs.get('extra', {})
|
||||
extra.setdefault('pwnlib_msgtype', msgtype)
|
||||
extra.setdefault('pwnlib_progress', progress)
|
||||
|
||||
+6
-5
@@ -5,6 +5,7 @@ import ctypes
|
||||
import functools
|
||||
import string
|
||||
|
||||
import six
|
||||
from six.moves import range
|
||||
|
||||
from pwnlib.context import context
|
||||
@@ -63,7 +64,7 @@ class MemLeak(object):
|
||||
... if addr & 0xff == 0:
|
||||
... return None
|
||||
... return binsh[addr:addr+4]
|
||||
>>> leaker_nonulls.d(0) == None
|
||||
>>> leaker_nonulls.d(0) is None
|
||||
leaking 0x0
|
||||
True
|
||||
>>> leaker_nonulls[0x100:0x104] == binsh[0x100:0x104]
|
||||
@@ -155,17 +156,17 @@ class MemLeak(object):
|
||||
Arguments:
|
||||
address(int): Base address to calculate offsets from
|
||||
field(obj): Instance of a ctypes field
|
||||
expected(int,str): Expected value
|
||||
expected(int,bytes): Expected value
|
||||
|
||||
Return Value:
|
||||
The type of the return value will be dictated by
|
||||
the type of ``field``.
|
||||
"""
|
||||
if not isinstance(expected, (int, bytes)):
|
||||
raise TypeError("Expected value must be an int or bytes")
|
||||
|
||||
if isinstance(expected, int):
|
||||
if isinstance(expected, six.integer_types):
|
||||
expected = pack(expected, bytes=obj.size)
|
||||
elif not isinstance(expected, bytes):
|
||||
raise TypeError("Expected value must be an int or bytes")
|
||||
|
||||
assert obj.size == len(expected)
|
||||
|
||||
|
||||
@@ -109,8 +109,8 @@ class AdbClient(Logger):
|
||||
process(context.adb + ['start-server']).recvall()
|
||||
time.sleep(0.3)
|
||||
else:
|
||||
log.exception('Could not connect to ADB server (%s:%s)' % \
|
||||
(self.host, self.port))
|
||||
log.exception('Could not connect to ADB server (%s:%s)',
|
||||
self.host, self.port)
|
||||
|
||||
# Final attempt...
|
||||
if not self._c:
|
||||
@@ -462,7 +462,7 @@ class AdbClient(Logger):
|
||||
>>> expected = {'mode': 16749, 'size': 0, 'time': 0}
|
||||
>>> pwnlib.protocols.adb.AdbClient().stat('/proc') == expected
|
||||
True
|
||||
>>> pwnlib.protocols.adb.AdbClient().stat('/does/not/exist') == None
|
||||
>>> pwnlib.protocols.adb.AdbClient().stat('/does/not/exist') is None
|
||||
True
|
||||
"""
|
||||
if isinstance(path, six.text_type):
|
||||
|
||||
+1
-1
@@ -243,7 +243,7 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
|
||||
# Collapse constant values
|
||||
#
|
||||
# For eaxmple, {'eax': 0, 'ebx': 0} => {'eax': 0, 'ebx': 'eax'}
|
||||
v_k = defaultdict(lambda: [])
|
||||
v_k = defaultdict(list)
|
||||
for k,v in sorted(in_out.items()):
|
||||
if v not in all_regs and v != 0:
|
||||
v_k[v].append(k)
|
||||
|
||||
+4
-2
@@ -9,6 +9,8 @@ from pwnlib.util import packing
|
||||
|
||||
import six
|
||||
|
||||
from pwnlib.util.misc import python_2_bytes_compatible
|
||||
|
||||
|
||||
class Unresolved(object):
|
||||
"""
|
||||
@@ -55,6 +57,8 @@ class StackAdjustment(Unresolved):
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
@python_2_bytes_compatible
|
||||
class AppendedArgument(Unresolved):
|
||||
"""
|
||||
Encapsulates information about a pointer argument, and the data
|
||||
@@ -186,8 +190,6 @@ class AppendedArgument(Unresolved):
|
||||
|
||||
def __bytes__(self):
|
||||
return packing.flat(self.resolve())
|
||||
if six.PY2:
|
||||
__str__ = __bytes__
|
||||
|
||||
def __repr__(self):
|
||||
if isinstance(self.address, six.integer_types):
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import six
|
||||
|
||||
class Gadget(object):
|
||||
"""
|
||||
@@ -54,12 +55,12 @@ class Gadget(object):
|
||||
|
||||
def __getitem__(self, key):
|
||||
# Backward compatibility
|
||||
if isinstance(key, int):
|
||||
if isinstance(key, six.integer_types):
|
||||
key = self.__indices[key]
|
||||
return getattr(self, key)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
# Backward compatibility
|
||||
if isinstance(key, int):
|
||||
if isinstance(key, six.integer_types):
|
||||
key = self.__indices[key]
|
||||
return setattr(self, key, value)
|
||||
+54
-41
@@ -2,65 +2,61 @@ r"""
|
||||
Provides automatic payload generation for exploiting buffer overflows
|
||||
using ret2dlresolve.
|
||||
|
||||
Example:
|
||||
We use the following example program:
|
||||
|
||||
>>> program = tempfile.mktemp()
|
||||
>>> source = program + ".c"
|
||||
>>> write(source, '''
|
||||
... #include <unistd.h>
|
||||
... void vuln(void){
|
||||
... char buf[64];
|
||||
... read(STDIN_FILENO, buf, 200);
|
||||
... }
|
||||
... int main(int argc, char** argv){
|
||||
... vuln();
|
||||
... }''')
|
||||
>>> cmdline = ["gcc", source, "-fno-stack-protector", "-no-pie", "-m32", "-o", program]
|
||||
>>> process(cmdline).wait_for_close()
|
||||
::
|
||||
|
||||
>>> context.binary = program
|
||||
>>> elf = ELF(program)
|
||||
>>> rop = ROP(elf)
|
||||
#include <unistd.h>
|
||||
void vuln(void){
|
||||
char buf[64];
|
||||
read(STDIN_FILENO, buf, 200);
|
||||
}
|
||||
int main(int argc, char** argv){
|
||||
vuln();
|
||||
}
|
||||
|
||||
We can automate the process of exploitation with these some example binaries.
|
||||
|
||||
>>> context.binary = elf = ELF(pwnlib.data.elf.ret2dlresolve.get('i386'))
|
||||
>>> rop = ROP(context.binary)
|
||||
>>> dlresolve = Ret2dlresolvePayload(elf, symbol="system", args=["echo pwned"])
|
||||
>>> rop.read(0, dlresolve.data_addr) # do not forget this step, but use whatever function you like
|
||||
>>> rop.ret2dlresolve(dlresolve)
|
||||
>>> raw_rop = rop.chain()
|
||||
>>> print(rop.dump()) # doctest: +SKIP
|
||||
0x0000: 0x8049030 read(0, 0x804ce00)
|
||||
0x0004: 0x8049208 <adjust @0x10> pop edi; pop ebp; ret
|
||||
>>> print(rop.dump())
|
||||
0x0000: 0x80482e0 read(0, 0x804ae00)
|
||||
0x0004: 0x80484ea <adjust @0x10> pop edi; pop ebp; ret
|
||||
0x0008: 0x0 arg0
|
||||
0x000c: 0x804ce00 arg1
|
||||
0x0010: 0x8049020 [plt_init] system(0x804ce30)
|
||||
0x0014: 0x4b74 [dlresolve index]
|
||||
0x000c: 0x804ae00 arg1
|
||||
0x0010: 0x80482d0 [plt_init] system(0x804ae24)
|
||||
0x0014: 0x2b84 [dlresolve index]
|
||||
0x0018: b'gaaa' <return address>
|
||||
0x001c: 0x804ce30 arg0
|
||||
>>> p = process(program)
|
||||
0x001c: 0x804ae24 arg0
|
||||
>>> p = elf.process()
|
||||
>>> p.sendline(fit({64+context.bytes*3: raw_rop, 200: dlresolve.payload}))
|
||||
>>> p.recvline()
|
||||
b'pwned\n'
|
||||
|
||||
>>> # and now for 64 bits
|
||||
>>> cmdline = ["gcc", source, "-fno-stack-protector", "-no-pie", "-o", program]
|
||||
>>> process(cmdline).wait_for_close()
|
||||
>>> context.binary = program
|
||||
>>> elf = ELF(program)
|
||||
You can also use ``Ret2dlresolve`` on AMD64:
|
||||
|
||||
>>> context.binary = elf = ELF(pwnlib.data.elf.ret2dlresolve.get('amd64'))
|
||||
>>> rop = ROP(elf)
|
||||
>>> dlresolve = Ret2dlresolvePayload(elf, symbol="system", args=["echo pwned"])
|
||||
>>> rop.read(0, dlresolve.data_addr) # do not forget this step, but use whatever function you like
|
||||
>>> rop.ret2dlresolve(dlresolve)
|
||||
>>> raw_rop = rop.chain()
|
||||
>>> print(rop.dump()) # doctest: +SKIP
|
||||
0x0000: 0x4011aa pop rdi; ret
|
||||
>>> print(rop.dump())
|
||||
0x0000: 0x400593 pop rdi; ret
|
||||
0x0008: 0x0 [arg0] rdi = 0
|
||||
0x0010: 0x4011a8 pop rsi; pop r15; ret
|
||||
0x0018: 0x404e00 [arg1] rsi = 4214272
|
||||
0x0010: 0x400591 pop rsi; pop r15; ret
|
||||
0x0018: 0x601e00 [arg1] rsi = 6299136
|
||||
0x0020: b'iaaajaaa' <pad r15>
|
||||
0x0028: 0x401030 read
|
||||
0x0030: 0x4011aa pop rdi; ret
|
||||
0x0038: 0x404e58 [arg0] rdi = 4214360
|
||||
0x0040: 0x401020 [plt_init] system
|
||||
0x0048: 0x318 [dlresolve index]
|
||||
>>> p = process(program)
|
||||
0x0028: 0x4003f0 read
|
||||
0x0030: 0x400593 pop rdi; ret
|
||||
0x0038: 0x601e48 [arg0] rdi = 6299208
|
||||
0x0040: 0x4003e0 [plt_init] system
|
||||
0x0048: 0x15670 [dlresolve index]
|
||||
>>> p = elf.process()
|
||||
>>> p.sendline(fit({64+context.bytes: raw_rop, 200: dlresolve.payload}))
|
||||
>>> if dlresolve.unreliable:
|
||||
... p.poll(True) == -signal.SIGSEGV
|
||||
@@ -69,6 +65,7 @@ Example:
|
||||
True
|
||||
"""
|
||||
|
||||
import six
|
||||
from copy import deepcopy
|
||||
|
||||
from pwnlib.context import context
|
||||
@@ -82,6 +79,7 @@ ELF32_R_SYM_SHIFT = 8
|
||||
ELF64_R_SYM_SHIFT = 32
|
||||
|
||||
class Elf32_Rel(object):
|
||||
''
|
||||
"""
|
||||
.. code-block:: c
|
||||
|
||||
@@ -103,6 +101,7 @@ class Elf32_Rel(object):
|
||||
|
||||
|
||||
class Elf64_Rel(object):
|
||||
''
|
||||
"""
|
||||
.. code-block:: c
|
||||
|
||||
@@ -124,6 +123,7 @@ class Elf64_Rel(object):
|
||||
|
||||
|
||||
class Elf32_Sym(object):
|
||||
''
|
||||
"""
|
||||
.. code-block:: c
|
||||
|
||||
@@ -158,6 +158,7 @@ class Elf32_Sym(object):
|
||||
|
||||
|
||||
class Elf64_Sym(object):
|
||||
''
|
||||
"""
|
||||
.. code-block:: c
|
||||
|
||||
@@ -192,6 +193,7 @@ class Elf64_Sym(object):
|
||||
|
||||
|
||||
class Queue(list):
|
||||
''
|
||||
def size(self):
|
||||
size = 0
|
||||
for v in self:
|
||||
@@ -205,10 +207,21 @@ class Queue(list):
|
||||
|
||||
|
||||
class MarkedBytes(bytes):
|
||||
''
|
||||
pass
|
||||
|
||||
|
||||
class Ret2dlresolvePayload(object):
|
||||
"""Create a ret2dlresolve payload
|
||||
|
||||
Arguments:
|
||||
elf (ELF): Binary to search
|
||||
symbol (str): Function to search for
|
||||
args (list): List of arguments to pass to the function
|
||||
|
||||
Returns:
|
||||
A ``Ret2dlresolvePayload`` object which can be passed to ``rop.ret2dlresolve``
|
||||
"""
|
||||
def __init__(self, elf, symbol, args, data_addr=None):
|
||||
self.elf = elf
|
||||
self.elf_load_address_fixup = self.elf.address - self.elf.load_addr
|
||||
@@ -344,7 +357,7 @@ class Ret2dlresolvePayload(object):
|
||||
elif isinstance(top, bytes):
|
||||
top = pack(self.data_addr + len(self.payload) + queue.size())
|
||||
queue.append(MarkedBytes(queue[0]))
|
||||
elif isinstance(top, int):
|
||||
elif isinstance(top, six.integer_types):
|
||||
top = pack(top)
|
||||
|
||||
self.payload += top
|
||||
|
||||
+58
-9
@@ -88,6 +88,36 @@ You can also append complex arguments onto stack when the stack pointer is known
|
||||
0x7fffe038: b'-c\x00$'
|
||||
0x7fffe03c: b'ls\x00$'
|
||||
|
||||
ROP also detects 'jmp $sp' gadget to help exploit binaries with NX disabled.
|
||||
You can get this gadget on 'i386':
|
||||
|
||||
>>> context.clear(arch='i386')
|
||||
>>> elf = ELF.from_assembly('nop; jmp esp; ret')
|
||||
>>> rop = ROP(elf)
|
||||
>>> jmp_gadget = rop.jmp_esp
|
||||
>>> elf.read(jmp_gadget.address, 2) == asm('jmp esp')
|
||||
True
|
||||
|
||||
You can also get this gadget on 'amd64':
|
||||
|
||||
>>> context.clear(arch='amd64')
|
||||
>>> elf = ELF.from_assembly('nop; jmp rsp; ret')
|
||||
>>> rop = ROP(elf)
|
||||
>>> jmp_gadget = rop.jmp_rsp
|
||||
>>> elf.read(jmp_gadget.address, 2) == asm('jmp rsp')
|
||||
True
|
||||
|
||||
Gadgets whose address has badchar are filtered out:
|
||||
|
||||
>>> context.clear(arch='i386')
|
||||
>>> elf = ELF.from_assembly('nop; pop eax; jmp esp; int 0x80; jmp esp; ret')
|
||||
>>> rop = ROP(elf, badchars=b'\x02')
|
||||
>>> jmp_gadget = rop.jmp_esp # It returns the second gadget
|
||||
>>> elf.read(jmp_gadget.address, 2) == asm('jmp esp')
|
||||
True
|
||||
>>> rop = ROP(elf, badchars=b'\x02\x06')
|
||||
>>> rop.jmp_esp == None # The address of both gadgets has badchar
|
||||
True
|
||||
|
||||
ROP Example
|
||||
-------------------
|
||||
@@ -302,6 +332,7 @@ from pwnlib.util import lists
|
||||
from pwnlib.util import packing
|
||||
from pwnlib.util.cyclic import cyclic
|
||||
from pwnlib.util.packing import pack
|
||||
from pwnlib.util.misc import python_2_bytes_compatible
|
||||
|
||||
log = getLogger(__name__)
|
||||
__all__ = ['ROP']
|
||||
@@ -340,7 +371,7 @@ class DescriptiveStack(list):
|
||||
descriptions = {}
|
||||
|
||||
def __init__(self, address):
|
||||
self.descriptions = collections.defaultdict(lambda: [])
|
||||
self.descriptions = collections.defaultdict(list)
|
||||
self.address = address or 0
|
||||
self._next_next = 0
|
||||
self._next_last = 0
|
||||
@@ -382,6 +413,7 @@ class DescriptiveStack(list):
|
||||
return '\n'.join(rv)
|
||||
|
||||
|
||||
@python_2_bytes_compatible
|
||||
class ROP(object):
|
||||
r"""Class which simplifies the generation of ROP-chains.
|
||||
|
||||
@@ -751,7 +783,6 @@ class ROP(object):
|
||||
stack.describe(self.describe(slot))
|
||||
if not isinstance(slot, bytes):
|
||||
slot = slot.encode()
|
||||
slot += self.generatePadding(stack.next, len(slot) % context.bytes)
|
||||
|
||||
for chunk in lists.group(context.bytes, slot):
|
||||
stack.append(chunk)
|
||||
@@ -1057,9 +1088,6 @@ class ROP(object):
|
||||
"""Returns: Raw bytes of the ROP chain"""
|
||||
return self.chain()
|
||||
|
||||
def __str__(self):
|
||||
return str(self.chain())
|
||||
|
||||
def __get_cachefile_name(self, files):
|
||||
"""Given an ELF or list of ELF objects, return a cache file for the set of files"""
|
||||
cachedir = os.path.join(tempfile.gettempdir(), 'pwntools-rop-cache-%d.%d' % sys.version_info[:2])
|
||||
@@ -1101,7 +1129,7 @@ class ROP(object):
|
||||
#
|
||||
# - leave
|
||||
# - pop reg
|
||||
# - add $sp, value
|
||||
# - add $sp, <hexadecimal value>
|
||||
# - ret
|
||||
#
|
||||
# Currently, ROPgadget does not detect multi-byte "C2" ret.
|
||||
@@ -1109,7 +1137,7 @@ class ROP(object):
|
||||
#
|
||||
|
||||
pop = re.compile(r'^pop (.{3})')
|
||||
add = re.compile(r'^add [er]sp, (\S+)$')
|
||||
add = re.compile(r'^add [er]sp, ((?:0[xX])?[0-9a-fA-F]+)$')
|
||||
ret = re.compile(r'^ret$')
|
||||
leave = re.compile(r'^leave$')
|
||||
int80 = re.compile(r'int +0x80')
|
||||
@@ -1125,6 +1153,8 @@ class ROP(object):
|
||||
# False
|
||||
# >>> valid('add esp, 0x24')
|
||||
# True
|
||||
# >>> valid('add esp, esi')
|
||||
# False
|
||||
#
|
||||
valid = lambda insn: any(map(lambda pattern: pattern.match(insn), [pop,add,ret,leave,int80,syscall,sysenter]))
|
||||
|
||||
@@ -1306,7 +1336,7 @@ class ROP(object):
|
||||
self.raw(call)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
"""Helper to make finding ROP gadets easier.
|
||||
"""Helper to make finding ROP gadgets easier.
|
||||
|
||||
Also provides a shorthand for ``.call()``:
|
||||
``rop.function(args)`` is equivalent to ``rop.call(function, args)``
|
||||
@@ -1319,7 +1349,7 @@ class ROP(object):
|
||||
True
|
||||
>>> rop.ret_8 == rop.search(move=8)
|
||||
True
|
||||
>>> rop.ret != None
|
||||
>>> rop.ret is not None
|
||||
True
|
||||
"""
|
||||
gadget = collections.namedtuple('gadget', ['address', 'details'])
|
||||
@@ -1343,6 +1373,25 @@ class ROP(object):
|
||||
count = int(attr.split('_')[1])
|
||||
return self.search(move=count)
|
||||
|
||||
#
|
||||
# Check for 'jmp_esp'('i386') or 'jmp_rsp'('amd64')
|
||||
#
|
||||
if attr == 'jmp_esp' and context.arch == 'i386' \
|
||||
or attr == 'jmp_rsp' and context.arch == 'amd64':
|
||||
jmp_sp = {'i386': 'jmp esp',
|
||||
'amd64': 'jmp rsp'
|
||||
}[context.arch]
|
||||
|
||||
insn_asm = b'\xff\xe4'
|
||||
|
||||
for elf in self.elfs:
|
||||
for addr in elf.search(insn_asm, executable = True):
|
||||
if set(pack(addr)) & self._badchars:
|
||||
continue
|
||||
|
||||
return Gadget(addr, [jmp_sp], [], context.bytes)
|
||||
return None
|
||||
|
||||
if attr in ('int80', 'syscall', 'sysenter'):
|
||||
mapping = {'int80': 'int 0x80',
|
||||
'syscall': 'syscall',
|
||||
|
||||
@@ -155,7 +155,7 @@ class module(ModuleType):
|
||||
return hex(n)
|
||||
|
||||
def okay(self, s, *a, **kw):
|
||||
if isinstance(s, int):
|
||||
if isinstance(s, six.integer_types):
|
||||
s = packing.pack(s, *a, **kw)
|
||||
return b'\0' not in s and b'\n' not in s
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ def init_mako():
|
||||
from mako import ast
|
||||
import threading
|
||||
|
||||
if lookup != None:
|
||||
if lookup is not None:
|
||||
return
|
||||
|
||||
class IsInsideManager(object):
|
||||
|
||||
@@ -33,13 +33,13 @@ Example:
|
||||
args = []
|
||||
else:
|
||||
syscall_repr = 'syscall(%s)'
|
||||
if syscall == None:
|
||||
if syscall is None:
|
||||
args = ['?']
|
||||
else:
|
||||
args = [repr(syscall)]
|
||||
|
||||
for arg in [arg0, arg1, arg2, arg3, arg4, arg5]:
|
||||
if arg == None:
|
||||
if arg is None:
|
||||
args.append('?')
|
||||
else:
|
||||
args.append(pretty(arg, False))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<%
|
||||
import six
|
||||
from pwnlib.shellcraft.aarch64 import mov
|
||||
from pwnlib.shellcraft.aarch64.linux import read, readn, mmap
|
||||
from pwnlib import constants as C
|
||||
@@ -28,7 +29,7 @@ Example:
|
||||
protection = C.PROT_READ | C.PROT_WRITE | C.PROT_EXEC
|
||||
flags = C.MAP_ANONYMOUS | C.MAP_PRIVATE
|
||||
|
||||
assert isinstance(fd, int)
|
||||
assert isinstance(fd, six.integer_types)
|
||||
%>
|
||||
%if length is None:
|
||||
/* How many bytes should we receive? */
|
||||
|
||||
@@ -56,13 +56,13 @@ Example:
|
||||
args = []
|
||||
else:
|
||||
syscall_repr = 'syscall(%s)'
|
||||
if syscall == None:
|
||||
if syscall is None:
|
||||
args = ['?']
|
||||
else:
|
||||
args = [repr(syscall)]
|
||||
|
||||
for arg in [arg0, arg1, arg2, arg3, arg4, arg5]:
|
||||
if arg == None:
|
||||
if arg is None:
|
||||
args.append('?')
|
||||
else:
|
||||
args.append(repr(arg))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<%
|
||||
import six
|
||||
from pwnlib.shellcraft import pretty, common, aarch64, registers
|
||||
from pwnlib.shellcraft.registers import aarch64 as regs
|
||||
from pwnlib.util.packing import pack, unpack
|
||||
@@ -39,7 +40,7 @@ if not key in regs:
|
||||
key_str = key
|
||||
key_int = key
|
||||
|
||||
if isinstance(key, int):
|
||||
if isinstance(key, six.integer_types):
|
||||
key_str = pack(key, bytes=4)
|
||||
else:
|
||||
key_int = unpack(key, 'all')
|
||||
|
||||
@@ -76,13 +76,13 @@ Example:
|
||||
args = []
|
||||
else:
|
||||
syscall_repr = 'syscall(%s)'
|
||||
if syscall == None:
|
||||
if syscall is None:
|
||||
args = ['?']
|
||||
else:
|
||||
args = [repr(syscall)]
|
||||
|
||||
for arg in [arg0, arg1, arg2, arg3, arg4, arg5]:
|
||||
if arg == None:
|
||||
if arg is None:
|
||||
args.append('?')
|
||||
else:
|
||||
args.append(pretty(arg, False))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<%
|
||||
import six
|
||||
from pwnlib.shellcraft import amd64, pretty, common
|
||||
from pwnlib.util.packing import pack, unpack
|
||||
from pwnlib.util.lists import group
|
||||
@@ -24,7 +25,7 @@ done = common.label('egghunter_done')
|
||||
next_page = common.label('egghunter_nextpage')
|
||||
|
||||
egg_str = egg
|
||||
if isinstance(egg, int):
|
||||
if isinstance(egg, six.integer_types):
|
||||
egg_str = pack(egg, bytes=4)
|
||||
|
||||
if len(egg_str) % 4:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<%
|
||||
import six
|
||||
from pwnlib.shellcraft.amd64 import push
|
||||
from pwnlib.shellcraft.amd64.linux import read, readn, mmap
|
||||
from pwnlib import constants as C
|
||||
@@ -28,7 +29,7 @@ Example:
|
||||
protection = C.PROT_READ | C.PROT_WRITE | C.PROT_EXEC
|
||||
flags = C.MAP_ANONYMOUS | C.MAP_PRIVATE
|
||||
|
||||
assert isinstance(fd, int)
|
||||
assert isinstance(fd, six.integer_types)
|
||||
%>
|
||||
%if length is None:
|
||||
/* How many bytes should we receive? */
|
||||
|
||||
@@ -92,13 +92,13 @@ Example:
|
||||
args = []
|
||||
else:
|
||||
syscall_repr = 'syscall(%s)'
|
||||
if syscall == None:
|
||||
if syscall is None:
|
||||
args = ['?']
|
||||
else:
|
||||
args = [repr(syscall)]
|
||||
|
||||
for arg in [arg0, arg1, arg2, arg3, arg4, arg5]:
|
||||
if arg == None:
|
||||
if arg is None:
|
||||
args.append('?')
|
||||
else:
|
||||
args.append(repr(arg))
|
||||
|
||||
@@ -6,7 +6,7 @@ Args:
|
||||
</%docstring>
|
||||
<%page args="return_value = None"/>
|
||||
|
||||
% if return_value != None:
|
||||
% if return_value is not None:
|
||||
${amd64.mov('rax', return_value)}
|
||||
% endif
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<%
|
||||
import six
|
||||
from pwnlib.regsort import regsort
|
||||
from pwnlib.shellcraft import registers, eval
|
||||
from pwnlib.shellcraft.amd64 import mov
|
||||
@@ -50,7 +51,7 @@ if isinstance(edx, str):
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
if isinstance(eax, int) and isinstance(edx, int) and eax >> 63 == edx:
|
||||
if isinstance(eax, six.integer_types) and isinstance(edx, six.integer_types) and eax >> 63 == edx:
|
||||
cdq = True
|
||||
reg_context.pop('rdx')
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<%
|
||||
import six
|
||||
from pwnlib.shellcraft import pretty, common, amd64, registers
|
||||
from pwnlib.util.packing import pack, unpack
|
||||
from pwnlib.context import context as ctx
|
||||
@@ -45,7 +46,7 @@ else:
|
||||
key_str = key
|
||||
key_int = key
|
||||
|
||||
if isinstance(key, int):
|
||||
if isinstance(key, six.integer_types):
|
||||
key_str = pack(key, bytes=4)
|
||||
else:
|
||||
key_int = unpack(key, 'all')
|
||||
|
||||
@@ -33,13 +33,13 @@ Example:
|
||||
args = []
|
||||
else:
|
||||
syscall_repr = 'syscall(%s)'
|
||||
if syscall == None:
|
||||
if syscall is None:
|
||||
args = ['?']
|
||||
else:
|
||||
args = [repr(syscall)]
|
||||
|
||||
for arg in [arg0, arg1, arg2, arg3, arg4, arg5]:
|
||||
if arg == None:
|
||||
if arg is None:
|
||||
args.append('?')
|
||||
else:
|
||||
args.append(pretty(arg, False))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<% import six %>
|
||||
<% from pwnlib.shellcraft.arm import mov %>
|
||||
<% from pwnlib.util.packing import unpack %>
|
||||
<% from pwnlib import constants %>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<% import six %>
|
||||
<%page args="filepath, flags = 'O_RDONLY', mode = 0644"/>
|
||||
<%docstring>Opens a file. Leaves the file descriptor in r0.
|
||||
|
||||
|
||||
@@ -54,13 +54,13 @@ Example:
|
||||
args = []
|
||||
else:
|
||||
syscall_repr = 'syscall(%s)'
|
||||
if syscall == None:
|
||||
if syscall is None:
|
||||
args = ['?']
|
||||
else:
|
||||
args = [repr(syscall)]
|
||||
|
||||
for arg in [arg0, arg1, arg2, arg3, arg4, arg5]:
|
||||
if arg == None:
|
||||
if arg is None:
|
||||
args.append('?')
|
||||
else:
|
||||
args.append(repr(arg))
|
||||
|
||||
@@ -15,7 +15,7 @@ Examples:
|
||||
</%docstring>
|
||||
<%page args="return_value = None"/>
|
||||
|
||||
% if return_value != None:
|
||||
% if return_value is not None:
|
||||
${arm.mov('r0', return_value)}
|
||||
% endif
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<%
|
||||
import six
|
||||
from pwnlib.shellcraft import pretty, common, arm, registers
|
||||
from pwnlib.shellcraft.registers import arm as regs
|
||||
from pwnlib.util.packing import pack, unpack
|
||||
@@ -39,7 +40,7 @@ if not key in regs:
|
||||
key_str = key
|
||||
key_int = key
|
||||
|
||||
if isinstance(key, int):
|
||||
if isinstance(key, six.integer_types):
|
||||
key_str = pack(key, bytes=4)
|
||||
else:
|
||||
key_int = unpack(key, 'all')
|
||||
|
||||
@@ -18,13 +18,13 @@ Any of the arguments can be expressions to be evaluated by :func:`pwnlib.constan
|
||||
args = []
|
||||
else:
|
||||
syscall_repr = 'syscall(%s)'
|
||||
if syscall == None:
|
||||
if syscall is None:
|
||||
args = ['?']
|
||||
else:
|
||||
args = [repr(syscall)]
|
||||
|
||||
for arg in [arg0, arg1, arg2, arg3, arg4, arg5]:
|
||||
if arg == None:
|
||||
if arg is None:
|
||||
args.append('?')
|
||||
else:
|
||||
args.append(repr(arg))
|
||||
|
||||
@@ -65,13 +65,13 @@ Example:
|
||||
args = []
|
||||
else:
|
||||
syscall_repr = 'syscall(%s)'
|
||||
if syscall == None:
|
||||
if syscall is None:
|
||||
args = ['?']
|
||||
else:
|
||||
args = [repr(syscall)]
|
||||
|
||||
for arg in [arg0, arg1, arg2, arg3, arg4, arg5]:
|
||||
if arg == None:
|
||||
if arg is None:
|
||||
args.append('?')
|
||||
else:
|
||||
args.append(pretty(arg, False))
|
||||
|
||||
@@ -20,22 +20,22 @@ ${acceptloop}:
|
||||
/* Socket file descriptor is placed in EBP */
|
||||
|
||||
/* sock = socket(AF_INET, SOCK_STREAM, 0) */
|
||||
${i386.linux.push(0)}
|
||||
${i386.linux.push('SOCK_STREAM')}
|
||||
${i386.linux.push('AF_INET')}
|
||||
${i386.push(0)}
|
||||
${i386.push('SOCK_STREAM')}
|
||||
${i386.push('AF_INET')}
|
||||
${i386.linux.syscall('SYS_socketcall', 'SYS_socketcall_socket', 'esp')}
|
||||
|
||||
${i386.linux.mov('esi', 'eax')} /* keep socket fd */
|
||||
${i386.mov('esi', 'eax')} /* keep socket fd */
|
||||
|
||||
/* bind(sock, &addr, sizeof addr); // sizeof addr == 0x10 */
|
||||
${i386.linux.push(0)}
|
||||
${i386.push(0)}
|
||||
/* ${htons(port)} == htons(${port}) */
|
||||
${i386.linux.push('AF_INET | (%d << 16)' % htons(port))}
|
||||
${i386.linux.mov('ecx', 'esp')}
|
||||
${i386.push('AF_INET | (%d << 16)' % htons(port))}
|
||||
${i386.mov('ecx', 'esp')}
|
||||
|
||||
${i386.linux.push(0x10)} /* sizeof addr */
|
||||
${i386.linux.push('ecx')} /* &addr */
|
||||
${i386.linux.push('eax')} /* sock */
|
||||
${i386.push(0x10)} /* sizeof addr */
|
||||
${i386.push('ecx')} /* &addr */
|
||||
${i386.push('eax')} /* sock */
|
||||
${i386.linux.syscall('SYS_socketcall', 'SYS_socketcall_bind', 'esp')}
|
||||
|
||||
/* listen(sock, whatever) */
|
||||
@@ -44,17 +44,17 @@ ${acceptloop}:
|
||||
|
||||
${looplabel}:
|
||||
/* accept(sock, NULL, NULL) */
|
||||
${i386.linux.push(0x0)}
|
||||
${i386.linux.push('esi')} /* sock */
|
||||
${i386.push(0x0)}
|
||||
${i386.push('esi')} /* sock */
|
||||
${i386.linux.syscall('SYS_socketcall', 'SYS_socketcall_accept', 'esp')}
|
||||
|
||||
${i386.linux.mov('ebp', 'eax')} /* keep in-coming socket fd */
|
||||
${i386.mov('ebp', 'eax')} /* keep in-coming socket fd */
|
||||
|
||||
${i386.linux.syscall('SYS_fork')}
|
||||
xchg eax, edi
|
||||
|
||||
test edi, edi
|
||||
${i386.linux.mov('ebx', 'ebp')}
|
||||
${i386.mov('ebx', 'ebp')}
|
||||
cmovz ebx, esi /* on child we close the server sock instead */
|
||||
|
||||
/* close(sock) */
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<%
|
||||
import six
|
||||
from pwnlib.shellcraft import i386, pretty, common
|
||||
from pwnlib.util.packing import pack, unpack
|
||||
from pwnlib.util.lists import group
|
||||
@@ -24,7 +25,7 @@ done = common.label('egghunter_done')
|
||||
next_page = common.label('egghunter_nextpage')
|
||||
|
||||
egg_str = egg
|
||||
if isinstance(egg, int):
|
||||
if isinstance(egg, six.integer_types):
|
||||
egg_str = pack(egg)
|
||||
|
||||
if len(egg_str) % 4:
|
||||
|
||||
@@ -28,7 +28,7 @@ ${looplabel}:
|
||||
pushad
|
||||
|
||||
int 0x80
|
||||
% if port == None:
|
||||
% if port is None:
|
||||
test eax, eax
|
||||
popad
|
||||
pop edx
|
||||
|
||||
@@ -22,6 +22,6 @@
|
||||
%endif
|
||||
${label}:
|
||||
${i386.linux.syscall('SYS_mprotect', 'ebx', 'ecx', 'PROT_READ | PROT_WRITE | PROT_EXEC')}
|
||||
${i386.linux.mov('ecx', 0x1000)}
|
||||
${i386.mov('ecx', 0x1000)}
|
||||
add ebx, ecx
|
||||
jnz ${label}
|
||||
@@ -1,4 +1,5 @@
|
||||
<%
|
||||
import six
|
||||
from pwnlib.shellcraft.i386 import push
|
||||
from pwnlib.shellcraft.i386.linux import read, readn, mmap
|
||||
from pwnlib import constants as C
|
||||
@@ -29,7 +30,7 @@ Example:
|
||||
protection = C.PROT_READ | C.PROT_WRITE | C.PROT_EXEC
|
||||
flags = C.MAP_ANONYMOUS | C.MAP_PRIVATE
|
||||
|
||||
assert isinstance(fd, int)
|
||||
assert isinstance(fd, six.integer_types)
|
||||
%>
|
||||
%if length is None:
|
||||
/* How many bytes should we receive? */
|
||||
|
||||
@@ -90,13 +90,13 @@ Example:
|
||||
args = []
|
||||
else:
|
||||
syscall_repr = 'syscall(%s)'
|
||||
if syscall == None:
|
||||
if syscall is None:
|
||||
args = ['?']
|
||||
else:
|
||||
args = [repr(syscall)]
|
||||
|
||||
for arg in [arg0, arg1, arg2, arg3, arg4, arg5]:
|
||||
if arg == None:
|
||||
if arg is None:
|
||||
args.append('?')
|
||||
else:
|
||||
args.append(pretty(arg, False))
|
||||
|
||||
@@ -6,7 +6,7 @@ Args:
|
||||
</%docstring>
|
||||
<%page args="return_value = None"/>
|
||||
|
||||
% if return_value != None:
|
||||
% if return_value is not None:
|
||||
${i386.mov('eax', return_value)}
|
||||
% endif
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<%
|
||||
import six
|
||||
from pwnlib.regsort import regsort
|
||||
from pwnlib.constants import Constant, eval
|
||||
from pwnlib.shellcraft import registers
|
||||
@@ -44,7 +45,7 @@ if isinstance(edx, str):
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
if isinstance(eax, int) and isinstance(edx, int) and eax >> 31 == edx:
|
||||
if isinstance(eax, six.integer_types) and isinstance(edx, six.integer_types) and eax >> 31 == edx:
|
||||
cdq = True
|
||||
reg_context.pop('edx')
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<%
|
||||
import six
|
||||
from pwnlib.shellcraft import pretty, common, i386, registers
|
||||
from pwnlib.util.packing import pack, unpack
|
||||
from pwnlib.context import context as ctx
|
||||
@@ -44,7 +45,7 @@ else:
|
||||
key_str = key
|
||||
key_int = key
|
||||
|
||||
if isinstance(key, int):
|
||||
if isinstance(key, six.integer_types):
|
||||
key_str = pack(key, bytes=4)
|
||||
else:
|
||||
key_int = unpack(key, 'all')
|
||||
|
||||
@@ -58,13 +58,13 @@ Example:
|
||||
args = []
|
||||
else:
|
||||
syscall_repr = 'syscall(%s)'
|
||||
if syscall == None:
|
||||
if syscall is None:
|
||||
args = ['?']
|
||||
else:
|
||||
args = [repr(syscall)]
|
||||
|
||||
for arg in [arg0, arg1, arg2, arg3, arg4, arg5]:
|
||||
if arg == None:
|
||||
if arg is None:
|
||||
args.append('?')
|
||||
else:
|
||||
args.append(pretty(arg, False))
|
||||
|
||||
@@ -88,13 +88,13 @@ Example:
|
||||
args = []
|
||||
else:
|
||||
syscall_repr = 'syscall(%s)'
|
||||
if syscall == None:
|
||||
if syscall is None:
|
||||
args = ['?']
|
||||
else:
|
||||
args = [repr(syscall)]
|
||||
|
||||
for arg in [arg0, arg1, arg2, arg3, arg4, arg5]:
|
||||
if arg == None:
|
||||
if arg is None:
|
||||
args.append('?')
|
||||
else:
|
||||
args.append(pretty(arg, False))
|
||||
|
||||
@@ -33,13 +33,13 @@ Example:
|
||||
args = []
|
||||
else:
|
||||
syscall_repr = 'syscall(%s)'
|
||||
if syscall == None:
|
||||
if syscall is None:
|
||||
args = ['?']
|
||||
else:
|
||||
args = [repr(syscall)]
|
||||
|
||||
for arg in [arg0, arg1, arg2, arg3, arg4, arg5]:
|
||||
if arg == None:
|
||||
if arg is None:
|
||||
args.append('?')
|
||||
else:
|
||||
args.append(pretty(arg, False))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<%
|
||||
import six
|
||||
from pwnlib.shellcraft.thumb import push
|
||||
from pwnlib.shellcraft.thumb.linux import read, readn, mmap
|
||||
from pwnlib import constants as C
|
||||
@@ -28,7 +29,7 @@ Example:
|
||||
protection = C.PROT_READ | C.PROT_WRITE | C.PROT_EXEC
|
||||
flags = C.MAP_ANONYMOUS | C.MAP_PRIVATE
|
||||
|
||||
assert isinstance(fd, int)
|
||||
assert isinstance(fd, six.integer_types)
|
||||
%>
|
||||
%if length is None:
|
||||
/* How many bytes should we receive? */
|
||||
|
||||
@@ -62,13 +62,13 @@ Example:
|
||||
args = []
|
||||
else:
|
||||
syscall_repr = 'syscall(%s)'
|
||||
if syscall == None:
|
||||
if syscall is None:
|
||||
args = ['?']
|
||||
else:
|
||||
args = [repr(syscall)]
|
||||
|
||||
for arg in [arg0, arg1, arg2, arg3, arg4, arg5]:
|
||||
if arg == None:
|
||||
if arg is None:
|
||||
args.append('?')
|
||||
else:
|
||||
args.append(repr(arg))
|
||||
|
||||
@@ -6,7 +6,7 @@ Args:
|
||||
</%docstring>
|
||||
<%page args="return_value = None"/>
|
||||
|
||||
% if return_value != None:
|
||||
% if return_value is not None:
|
||||
${thumb.mov('r0', return_value)}
|
||||
% endif
|
||||
|
||||
|
||||
@@ -116,9 +116,9 @@ class PathCompleter(Completer):
|
||||
if self.only_dirs:
|
||||
cs = [c for c in cs if os.path.isdir(c)]
|
||||
if self.mask:
|
||||
cs = [c for c in cs if \
|
||||
self.mask.match(os.path.basename(c)) or \
|
||||
os.path.isdir(c)]
|
||||
cs = [c for c in cs
|
||||
if self.mask.match(os.path.basename(c))
|
||||
or os.path.isdir(c)]
|
||||
self._completions = cs
|
||||
|
||||
def complete(self, buffer_left, buffer_right):
|
||||
|
||||
+3
-3
@@ -38,9 +38,9 @@ def getraw(timeout = None):
|
||||
'''Get list of raw key codes corresponding to zero or more key presses'''
|
||||
cs = []
|
||||
c = getch(timeout)
|
||||
while c != None: # timeout
|
||||
while c is not None: # timeout
|
||||
cs.append(c)
|
||||
if c == None: # EOF
|
||||
if c is None: # EOF
|
||||
break
|
||||
c = getch()
|
||||
return cs
|
||||
@@ -196,7 +196,7 @@ _ti_table = None
|
||||
|
||||
def _peek_ti():
|
||||
global _cbuf
|
||||
if _ti_table == None:
|
||||
if _ti_table is None:
|
||||
_init_ti_table()
|
||||
# XXX: Faster lookup, plox
|
||||
for seq, key in _ti_table:
|
||||
|
||||
@@ -183,7 +183,7 @@ class Buffer(Exception):
|
||||
size (int): (Optional) If set and not None, returns the size variable back.
|
||||
|
||||
Returns:
|
||||
Fill size as integer if size == None, else size.
|
||||
Fill size as integer if size is None, else size.
|
||||
"""
|
||||
if size is None:
|
||||
size = self.buffer_fill_size
|
||||
|
||||
+18
-5
@@ -35,12 +35,20 @@ class listen(sock):
|
||||
>>> r.recvline()
|
||||
b'Hello\n'
|
||||
|
||||
>>> # It works with ipv4 by default
|
||||
>>> l = listen()
|
||||
>>> l.spawn_process('/bin/sh')
|
||||
>>> r = remote('localhost', l.lport)
|
||||
>>> r = remote('127.0.0.1', l.lport)
|
||||
>>> r.sendline(b'echo Goodbye')
|
||||
>>> r.recvline()
|
||||
b'Goodbye\n'
|
||||
|
||||
>>> # and it works with ipv6 by defaut, too!
|
||||
>>> l = listen()
|
||||
>>> r = remote('::1', l.lport)
|
||||
>>> r.sendline(b'Bye-bye')
|
||||
>>> l.recvline()
|
||||
b'Bye-bye\n'
|
||||
"""
|
||||
|
||||
#: Local port
|
||||
@@ -66,8 +74,8 @@ class listen(sock):
|
||||
|
||||
_accepter = None
|
||||
|
||||
def __init__(self, port=0, bindaddr = "0.0.0.0",
|
||||
fam = "any", typ = "tcp", *args, **kwargs):
|
||||
def __init__(self, port=0, bindaddr='::',
|
||||
fam='any', typ='tcp', *args, **kwargs):
|
||||
super(listen, self).__init__(*args, **kwargs)
|
||||
|
||||
port = int(port)
|
||||
@@ -77,8 +85,8 @@ class listen(sock):
|
||||
fam = self._get_family(fam)
|
||||
typ = self._get_type(typ)
|
||||
|
||||
if fam == socket.AF_INET6 and bindaddr == '0.0.0.0':
|
||||
bindaddr = '::'
|
||||
if fam == socket.AF_INET and bindaddr == '::':
|
||||
bindaddr = '0.0.0.0'
|
||||
|
||||
h = self.waitfor('Trying to bind to %s on port %d' % (bindaddr, port))
|
||||
|
||||
@@ -91,6 +99,11 @@ class listen(sock):
|
||||
h.status("Trying %s" % self.sockaddr[0])
|
||||
listen_sock = socket.socket(self.family, self.type, self.proto)
|
||||
listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
if self.family == socket.AF_INET6:
|
||||
try:
|
||||
listen_sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, fam == socket.AF_INET6)
|
||||
except (socket.error, AttributeError):
|
||||
self.warn("could not set socket to accept also IPV4")
|
||||
listen_sock.bind(self.sockaddr)
|
||||
self.lhost, self.lport = listen_sock.getsockname()[:2]
|
||||
if self.type == socket.SOCK_STREAM:
|
||||
|
||||
@@ -242,6 +242,9 @@ class process(tube):
|
||||
#: :class:`subprocess.Popen` object that backs this process
|
||||
self.proc = None
|
||||
|
||||
# We need to keep a copy of the un-_validated environment for printing
|
||||
original_env = env
|
||||
|
||||
if shell:
|
||||
executable_val, argv_val, env_val = executable, argv, env
|
||||
else:
|
||||
@@ -298,7 +301,7 @@ class process(tube):
|
||||
|
||||
if self.isEnabledFor(logging.DEBUG):
|
||||
if argv != [self.executable]: message += ' argv=%r ' % self.argv
|
||||
if env not in (os.environ, None): message += ' env=%r ' % self.env
|
||||
if original_env not in (os.environ, None): message += ' env=%r ' % self.env
|
||||
|
||||
with self.progress(message) as p:
|
||||
|
||||
@@ -666,7 +669,7 @@ class process(tube):
|
||||
self.proc.poll()
|
||||
returncode = self.proc.returncode
|
||||
|
||||
if returncode != None and not self._stop_noticed:
|
||||
if returncode is not None and not self._stop_noticed:
|
||||
self._stop_noticed = time.time()
|
||||
signame = ''
|
||||
if returncode < 0:
|
||||
@@ -736,7 +739,7 @@ class process(tube):
|
||||
return False
|
||||
|
||||
try:
|
||||
if timeout == None:
|
||||
if timeout is None:
|
||||
return select.select([self.proc.stdout], [], []) == ([self.proc.stdout], [], [])
|
||||
|
||||
return select.select([self.proc.stdout], [], [], timeout) == ([self.proc.stdout], [], [])
|
||||
@@ -749,12 +752,12 @@ class process(tube):
|
||||
# ValueError: I/O operation on closed file
|
||||
raise EOFError
|
||||
except select.error as v:
|
||||
if v[0] == errno.EINTR:
|
||||
if v.args[0] == errno.EINTR:
|
||||
return False
|
||||
|
||||
def connected_raw(self, direction):
|
||||
if direction == 'any':
|
||||
return self.poll() == None
|
||||
return self.poll() is None
|
||||
elif direction == 'send':
|
||||
return not self.proc.stdin.closed
|
||||
elif direction == 'recv':
|
||||
@@ -823,7 +826,7 @@ class process(tube):
|
||||
fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY)
|
||||
if fd >= 0:
|
||||
os.close(fd)
|
||||
raise Exception('Failed to disconnect from ' +
|
||||
raise Exception('Failed to disconnect from '
|
||||
'controlling tty. It is still possible to open /dev/tty.')
|
||||
# which exception, shouldnt' we catch explicitly .. ?
|
||||
except OSError:
|
||||
|
||||
@@ -99,7 +99,7 @@ class remote(sock):
|
||||
|
||||
sock = socket.socket(self.family, self.type, self.proto)
|
||||
|
||||
if timeout != None and timeout <= 0:
|
||||
if timeout is not None and timeout <= 0:
|
||||
sock.setblocking(0)
|
||||
else:
|
||||
sock.setblocking(1)
|
||||
|
||||
@@ -82,7 +82,7 @@ class serialtube(tube.tube):
|
||||
return False
|
||||
|
||||
def connected_raw(self, direction):
|
||||
return self.conn != None
|
||||
return self.conn is not None
|
||||
|
||||
def close(self):
|
||||
if self.conn:
|
||||
|
||||
@@ -117,7 +117,7 @@ class server(sock):
|
||||
data, rhost = listen_sock.recvfrom(4096)
|
||||
listen_sock.connect(rhost)
|
||||
sock = listen_sock
|
||||
sock.unrecv(data)
|
||||
self.unrecv(data)
|
||||
sock.settimeout(self.timeout)
|
||||
break
|
||||
except socket.error as e:
|
||||
|
||||
@@ -43,7 +43,7 @@ class sock(tube):
|
||||
except IOError as e:
|
||||
if e.errno == errno.EAGAIN:
|
||||
return None
|
||||
elif e.errno in [errno.ECONNREFUSED, errno.ECONNRESET]:
|
||||
elif e.errno in (errno.ECONNREFUSED, errno.ECONNRESET):
|
||||
self.shutdown("recv")
|
||||
raise EOFError
|
||||
elif e.errno == errno.EINTR:
|
||||
@@ -64,7 +64,7 @@ class sock(tube):
|
||||
try:
|
||||
self.sock.sendall(data)
|
||||
except IOError as e:
|
||||
eof_numbers = [errno.EPIPE, errno.ECONNRESET, errno.ECONNREFUSED]
|
||||
eof_numbers = (errno.EPIPE, errno.ECONNRESET, errno.ECONNREFUSED)
|
||||
if e.errno in eof_numbers or 'Socket is closed' in e.args:
|
||||
self.shutdown("send")
|
||||
raise EOFError
|
||||
@@ -122,7 +122,7 @@ class sock(tube):
|
||||
>>> r.connected()
|
||||
True
|
||||
>>> l.close()
|
||||
>>> time.sleep(1) # Avoid race condition
|
||||
>>> time.sleep(0.1) # Avoid race condition
|
||||
>>> r.connected()
|
||||
False
|
||||
"""
|
||||
@@ -208,8 +208,8 @@ class sock(tube):
|
||||
if False not in self.closed.values():
|
||||
self.close()
|
||||
|
||||
def _get_family(self, fam):
|
||||
|
||||
@classmethod
|
||||
def _get_family(cls, fam):
|
||||
if isinstance(fam, six.integer_types):
|
||||
pass
|
||||
elif fam == 'any':
|
||||
@@ -220,13 +220,13 @@ class sock(tube):
|
||||
fam = socket.AF_INET6
|
||||
else:
|
||||
self.error("%s(): socket family %r is not supported",
|
||||
self.__class__.__name__,
|
||||
cls.__name__,
|
||||
fam)
|
||||
|
||||
return fam
|
||||
|
||||
def _get_type(self, typ):
|
||||
|
||||
@classmethod
|
||||
def _get_type(cls, typ):
|
||||
if isinstance(typ, six.integer_types):
|
||||
pass
|
||||
elif typ == "tcp":
|
||||
@@ -235,7 +235,7 @@ class sock(tube):
|
||||
typ = socket.SOCK_DGRAM
|
||||
else:
|
||||
self.error("%s(): socket type %r is not supported",
|
||||
self.__class__.__name__,
|
||||
cls.__name__,
|
||||
typ)
|
||||
|
||||
return typ
|
||||
+12
-7
@@ -182,7 +182,7 @@ class ssh_channel(sock):
|
||||
process has not yet finished and the exit code otherwise.
|
||||
"""
|
||||
|
||||
if self.returncode == None and self.sock \
|
||||
if self.returncode is None and self.sock \
|
||||
and (block or self.sock.exit_status_ready()):
|
||||
while not self.sock.status_event.is_set():
|
||||
self.sock.status_event.wait(0.05)
|
||||
@@ -230,7 +230,7 @@ class ssh_channel(sock):
|
||||
cur = self.recv(timeout = 0.05)
|
||||
cur = cur.replace(b'\r\n',b'\n')
|
||||
cur = cur.replace(b'\r',b'')
|
||||
if cur == None:
|
||||
if cur is None:
|
||||
continue
|
||||
elif cur == b'\a':
|
||||
# Ugly hack until term unstands bell characters
|
||||
@@ -926,6 +926,10 @@ class ssh(Timeout, Logger):
|
||||
#!/usr/bin/env python
|
||||
import os, sys, ctypes, resource, platform, stat
|
||||
from collections import OrderedDict
|
||||
try:
|
||||
integer_types = int, long
|
||||
except NameError:
|
||||
integer_types = int,
|
||||
exe = %(executable)r
|
||||
argv = [bytes(a) for a in %(argv)r]
|
||||
env = %(env)r
|
||||
@@ -1000,7 +1004,7 @@ for fd, newfd in {0: %(stdin)r, 1: %(stdout)r, 2:%(stderr)r}.items():
|
||||
newfd = os.open(newfd, os.O_RDONLY if fd == 0 else (os.O_RDWR|os.O_CREAT))
|
||||
os.dup2(newfd, fd)
|
||||
os.close(newfd)
|
||||
elif isinstance(newfd, int) and newfd != fd:
|
||||
elif isinstance(newfd, integer_types) and newfd != fd:
|
||||
os.dup2(fd, newfd)
|
||||
|
||||
if not %(aslr)r:
|
||||
@@ -1097,7 +1101,7 @@ os.execve(exe, argv, env)
|
||||
|
||||
h.success('pid %i' % python.pid)
|
||||
|
||||
if aslr == False and setuid and (python.uid != python.suid or python.gid != python.sgid):
|
||||
if not aslr and setuid and (python.uid != python.suid or python.gid != python.sgid):
|
||||
effect = "partial" if self.aslr_ulimit else "no"
|
||||
message = "Specfied aslr=False on setuid binary %s\n" % python.executable
|
||||
message += "This will have %s effect. Add setuid=False to disable ASLR for debugging.\n" % effect
|
||||
@@ -1548,6 +1552,7 @@ from ctypes import *; libc = CDLL('libc.so.6'); print(libc.getenv(%r))
|
||||
|
||||
basename = os.path.basename(remote)
|
||||
|
||||
|
||||
local = local or '.'
|
||||
local = os.path.expanduser(local)
|
||||
|
||||
@@ -1556,7 +1561,7 @@ from ctypes import *; libc = CDLL('libc.so.6'); print(libc.getenv(%r))
|
||||
with context.local(log_level='error'):
|
||||
remote_tar = self.mktemp()
|
||||
cmd = 'tar -C %s -czf %s %s' % \
|
||||
(sh_string(dirname),
|
||||
(sh_string(remote),
|
||||
sh_string(remote_tar),
|
||||
sh_string(basename))
|
||||
tar = self.system(cmd)
|
||||
@@ -1621,7 +1626,7 @@ from ctypes import *; libc = CDLL('libc.so.6'); print(libc.getenv(%r))
|
||||
remote(str): The remote filename to save it to. Default is to infer it from the local filename."""
|
||||
|
||||
|
||||
if remote == None:
|
||||
if remote is None:
|
||||
remote = os.path.normpath(filename)
|
||||
remote = os.path.basename(remote)
|
||||
remote = os.path.join(self.cwd, remote)
|
||||
@@ -1742,7 +1747,7 @@ from ctypes import *; libc = CDLL('libc.so.6'); print(libc.getenv(%r))
|
||||
remote = context._decode(self.readlink('-f',remote).strip())
|
||||
libs[remote] = 0
|
||||
|
||||
if directory == None:
|
||||
if directory is None:
|
||||
directory = self.host
|
||||
|
||||
directory = os.path.realpath(directory)
|
||||
|
||||
+2
-2
@@ -97,11 +97,11 @@ def yesno(prompt, default=None):
|
||||
cur = default
|
||||
while True:
|
||||
k = term.key.get()
|
||||
if k in ('y', 'Y', '<left>') and cur != True:
|
||||
if k in ('y', 'Y', '<left>') and cur is not True:
|
||||
cur = True
|
||||
hy.update(yesfocus)
|
||||
hn.update(no)
|
||||
elif k in ('n', 'N', '<right>') and cur != False:
|
||||
elif k in ('n', 'N', '<right>') and cur is not False:
|
||||
cur = False
|
||||
hy.update(yes)
|
||||
hn.update(nofocus)
|
||||
|
||||
+2
-2
@@ -7,13 +7,13 @@ greatest version, Pwntools automatically checks for updates.
|
||||
Since this update check takes a moment, it is only performed once
|
||||
every week. It can be permanently disabled via:
|
||||
|
||||
.. code-block:: bash
|
||||
::
|
||||
|
||||
$ echo never > ~/.pwntools-cache-*/update
|
||||
|
||||
Or adding the following lines to ~/.pwn.conf (or system-wide /etc/pwn.conf):
|
||||
|
||||
.. code-block::
|
||||
::
|
||||
|
||||
[update]
|
||||
interval=never
|
||||
|
||||
+15
-14
@@ -125,9 +125,9 @@ def cyclic(length = None, alphabet = None, n = None):
|
||||
if alphabet is None:
|
||||
alphabet = context.cyclic_alphabet
|
||||
|
||||
if length != None and len(alphabet) ** n < length:
|
||||
log.error("Can't create a pattern length=%i with len(alphabet)==%i and n==%i" \
|
||||
% (length, len(alphabet), n))
|
||||
if length is not None and len(alphabet) ** n < length:
|
||||
log.error("Can't create a pattern length=%i with len(alphabet)==%i and n==%i",
|
||||
length, len(alphabet), n)
|
||||
|
||||
generator = de_bruijn(alphabet, n)
|
||||
out = iters.take(length, generator)
|
||||
@@ -212,9 +212,9 @@ def cyclic_find(subseq, alphabet = None, n = None):
|
||||
subseq = context._encode(subseq)
|
||||
|
||||
if len(subseq) != n:
|
||||
log.warn_once("cyclic_find() expects %i-byte subsequences by default, you gave %r\n"\
|
||||
+ "Unless you specified cyclic(..., n=%i), you probably just want the first 4 bytes.\n"\
|
||||
+ "Truncating the data at 4 bytes. Specify cyclic_find(..., n=%i) to override this.",
|
||||
log.warn_once("cyclic_find() expects %i-byte subsequences by default, you gave %r\n"
|
||||
"Unless you specified cyclic(..., n=%i), you probably just want the first 4 bytes.\n"
|
||||
"Truncating the data at 4 bytes. Specify cyclic_find(..., n=%i) to override this.",
|
||||
n, subseq, len(subseq), len(subseq))
|
||||
subseq = subseq[:n]
|
||||
|
||||
@@ -284,9 +284,9 @@ def cyclic_metasploit(length = None, sets = None):
|
||||
generator = metasploit_pattern(sets)
|
||||
out = iters.take(length, generator)
|
||||
|
||||
if length != None and len(out) < length:
|
||||
log.error("Can't create a pattern of length %i with sets of lengths %s. Maximum pattern length is %i." \
|
||||
% (length, list(map(len, sets)), len(out)))
|
||||
if length is not None and len(out) < length:
|
||||
log.error("Can't create a pattern of length %i with sets of lengths %s. Maximum pattern length is %i.",
|
||||
length, list(map(len, sets)), len(out))
|
||||
|
||||
return _join_sequence(out, sets[0])
|
||||
|
||||
@@ -414,17 +414,18 @@ class cyclic_gen(object):
|
||||
...
|
||||
StopIteration
|
||||
"""
|
||||
|
||||
if length != None:
|
||||
|
||||
if length is not None:
|
||||
self._chunks.append(length)
|
||||
self._total_length += length
|
||||
if len(self._alphabet) ** self._n < self._total_length:
|
||||
log.error("Can't create a pattern length=%i with len(alphabet)==%i and n==%i" \
|
||||
% (self._total_length, len(self._alphabet), self._n))
|
||||
log.error("Can't create a pattern length=%i with len(alphabet)==%i and n==%i",
|
||||
self._total_length, len(self._alphabet), self._n)
|
||||
out = [next(self._generator) for _ in range(length)]
|
||||
else:
|
||||
self._chunks.append(float("inf"))
|
||||
out = list(self._generator)
|
||||
|
||||
out = [next(self._generator) for _ in range(length)] if length != None else [next(self._generator)] + list(self._generator)
|
||||
return _join_sequence(out, self._alphabet)
|
||||
|
||||
def find(self, subseq):
|
||||
|
||||
+21
-10
@@ -592,9 +592,9 @@ def update_cyclic_pregenerated(size):
|
||||
cyclic_pregen += packing._p8lu(next(de_bruijn_gen))
|
||||
|
||||
def hexdump_iter(fd, width=16, skip=True, hexii=False, begin=0, style=None,
|
||||
highlight=None, cyclic=False, groupsize=4):
|
||||
r"""hexdump_iter(s, width = 16, skip = True, hexii = False, begin = 0,
|
||||
style = None, highlight = None, cyclic = False, groupsize=4) -> str generator
|
||||
highlight=None, cyclic=False, groupsize=4, total=True):
|
||||
r"""hexdump_iter(s, width = 16, skip = True, hexii = False, begin = 0, style = None,
|
||||
highlight = None, cyclic = False, groupsize=4, total = True) -> str generator
|
||||
|
||||
Return a hexdump-dump of a string as a generator of lines. Unless you have
|
||||
massive amounts of data you probably want to use :meth:`hexdump`.
|
||||
@@ -609,6 +609,7 @@ def hexdump_iter(fd, width=16, skip=True, hexii=False, begin=0, style=None,
|
||||
style(dict): Color scheme to use.
|
||||
highlight(iterable): Byte values to highlight.
|
||||
cyclic(bool): Attempt to skip consecutive, unmodified cyclic lines
|
||||
total(bool): Set to True, if total bytes should be printed
|
||||
|
||||
Returns:
|
||||
A generator producing the hexdump-dump one line at a time.
|
||||
@@ -750,13 +751,14 @@ def hexdump_iter(fd, width=16, skip=True, hexii=False, begin=0, style=None,
|
||||
line = line_fmt % {'offset': offset, 'hexbytes': hexbytes, 'printable': printable}
|
||||
yield line
|
||||
|
||||
line = "%08x" % (begin + numb)
|
||||
yield line
|
||||
if total:
|
||||
line = "%08x" % (begin + numb)
|
||||
yield line
|
||||
|
||||
def hexdump(s, width=16, skip=True, hexii=False, begin=0,
|
||||
style=None, highlight=None, cyclic=False, groupsize=4):
|
||||
r"""hexdump(s, width = 16, skip = True, hexii = False, begin = 0,
|
||||
style = None, highlight = None, cyclic = False, groupsize=4) -> str generator
|
||||
def hexdump(s, width=16, skip=True, hexii=False, begin=0, style=None,
|
||||
highlight=None, cyclic=False, groupsize=4, total=True):
|
||||
r"""hexdump(s, width = 16, skip = True, hexii = False, begin = 0, style = None,
|
||||
highlight = None, cyclic = False, groupsize=4, total = True) -> str
|
||||
|
||||
Return a hexdump-dump of a string.
|
||||
|
||||
@@ -770,6 +772,7 @@ def hexdump(s, width=16, skip=True, hexii=False, begin=0,
|
||||
style(dict): Color scheme to use.
|
||||
highlight(iterable): Byte values to highlight.
|
||||
cyclic(bool): Attempt to skip consecutive, unmodified cyclic lines
|
||||
total(bool): Set to True, if total bytes should be printed
|
||||
|
||||
Returns:
|
||||
A hexdump-dump in the form of a string.
|
||||
@@ -930,6 +933,13 @@ def hexdump(s, width=16, skip=True, hexii=False, begin=0,
|
||||
00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAAAAAAAAAAAAAA│
|
||||
00000010 41 41 41 41 41 41 41 41 │AAAAAAAA│
|
||||
00000018
|
||||
|
||||
>>> print(hexdump('A'*24, width=16, total=False))
|
||||
00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│
|
||||
00000010 41 41 41 41 41 41 41 41 │AAAA│AAAA│
|
||||
>>> print(hexdump('A'*24, width=16, groupsize=8, total=False))
|
||||
00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAAAAAA│AAAAAAAA│
|
||||
00000010 41 41 41 41 41 41 41 41 │AAAAAAAA│
|
||||
"""
|
||||
s = packing.flat(s)
|
||||
return '\n'.join(hexdump_iter(BytesIO(s),
|
||||
@@ -940,7 +950,8 @@ def hexdump(s, width=16, skip=True, hexii=False, begin=0,
|
||||
style,
|
||||
highlight,
|
||||
cyclic,
|
||||
groupsize))
|
||||
groupsize,
|
||||
total))
|
||||
|
||||
def negate(value, width = None):
|
||||
"""
|
||||
|
||||
+11
-11
@@ -821,7 +821,7 @@ def bruteforce(func, alphabet, length, method = 'upto', start = None, databag =
|
||||
|
||||
h = log.waitfor('Bruteforcing')
|
||||
cur_iteration = 0
|
||||
if start != None:
|
||||
if start is not None:
|
||||
consume(i, iterator)
|
||||
for e in iterator:
|
||||
cur = ''.join(e)
|
||||
@@ -837,7 +837,7 @@ def bruteforce(func, alphabet, length, method = 'upto', start = None, databag =
|
||||
if res:
|
||||
h.success('Found key: "%s"' % cur)
|
||||
return cur
|
||||
if start != None:
|
||||
if start is not None:
|
||||
consume(N - 1, iterator)
|
||||
|
||||
h.failure('No matches found')
|
||||
@@ -871,10 +871,10 @@ def mbruteforce(func, alphabet, length, method = 'upto', start = None, threads =
|
||||
context.log_level = oldloglevel
|
||||
databag["result"] = res
|
||||
|
||||
if start == None:
|
||||
if start is None:
|
||||
start = (1, 1)
|
||||
|
||||
if threads == None:
|
||||
if threads is None:
|
||||
try:
|
||||
threads = multiprocessing.cpu_count()
|
||||
except NotImplementedError:
|
||||
@@ -906,9 +906,9 @@ def mbruteforce(func, alphabet, length, method = 'upto', start = None, threads =
|
||||
while not done:
|
||||
# log status
|
||||
current_item_list = ",".join(["\"%s\"" % x["current_item"]
|
||||
for x in shareddata if x != None])
|
||||
items_done = sum([x["items_done"] for x in shareddata if x != None])
|
||||
items_total = sum([x["items_total"] for x in shareddata if x != None])
|
||||
for x in shareddata if x is not None])
|
||||
items_done = sum([x["items_done"] for x in shareddata if x is not None])
|
||||
items_total = sum([x["items_total"] for x in shareddata if x is not None])
|
||||
|
||||
progress = 100.0 * items_done / items_total if items_total != 0 else 0.0
|
||||
|
||||
@@ -916,23 +916,23 @@ def mbruteforce(func, alphabet, length, method = 'upto', start = None, threads =
|
||||
|
||||
# handle finished threads
|
||||
for i in range(threads):
|
||||
if processes[i] and processes[i].exitcode != None:
|
||||
if processes[i] and processes[i].exitcode is not None:
|
||||
# thread has terminated
|
||||
res = shareddata[i]["result"]
|
||||
processes[i].join()
|
||||
processes[i] = None
|
||||
|
||||
# if successful, kill all other threads and return success
|
||||
if res != None:
|
||||
if res is not None:
|
||||
for i in range(threads):
|
||||
if processes[i] != None:
|
||||
if processes[i] is not None:
|
||||
processes[i].terminate()
|
||||
processes[i].join()
|
||||
processes[i] = None
|
||||
h.success('Found key: "%s"' % res)
|
||||
return res
|
||||
|
||||
if all([x == None for x in processes]):
|
||||
if all([x is None for x in processes]):
|
||||
done = True
|
||||
time.sleep(0.3)
|
||||
h.failure('No matches found')
|
||||
Loaded 100 of 109 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user