mirror of
https://github.com/Gallopsled/pwntools.git
synced 2026-11-08 08:06:05 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5db149adc2 | ||
|
|
ddb5798b8c | ||
|
|
f227796a09 | ||
|
|
baa4fc5a9f | ||
|
|
53ecb27948 | ||
|
|
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
@@ -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 || :
|
||||
@@ -199,6 +207,7 @@ jobs:
|
||||
TARGET=${BRANCH%-staging}
|
||||
git branch -f "$TARGET"
|
||||
git push origin "$TARGET"
|
||||
git push origin --delete "$BRANCH"
|
||||
|
||||
pypi:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -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'
|
||||
@@ -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
|
||||
|
||||
+47
-6
@@ -9,9 +9,10 @@ The table below shows which release corresponds to each branch, and what date th
|
||||
|
||||
| Version | Branch | Release Date |
|
||||
| ---------------- | -------- | ---------------------- |
|
||||
| [4.4.0](#440) | `dev` | Sep 1, 2020 (planned)
|
||||
| [4.3.0](#430) | `beta` | Aug 1, 2020 (planned)
|
||||
| [4.2.0](#420) | `stable` | Jul 3, 2020 (planned)
|
||||
| [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
|
||||
@@ -55,13 +56,51 @@ 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.4.0 (`dev`)
|
||||
## 4.5.0 (`dev`)
|
||||
|
||||
## 4.4.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
|
||||
|
||||
[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 (`beta`)
|
||||
## 4.3.0 (`stable`)
|
||||
|
||||
- [#1576][1576] Add `executable=` argument to `ELF.search`
|
||||
- [#1584][1584] Add `jmp_esp`/`jmp_rsp` attribute to `ROP`
|
||||
@@ -70,6 +109,7 @@ The table below shows which release corresponds to each branch, and what date th
|
||||
- [#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()
|
||||
|
||||
@@ -80,10 +120,11 @@ The table below shows which release corresponds to each branch, and what date th
|
||||
[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 (`stable`)
|
||||
## 4.2.1
|
||||
|
||||
- [#1625][1625] GDB now properly loads executables with QEMU
|
||||
- [#1663][1663] Change lookup algorithm of `adb.which`
|
||||
|
||||
@@ -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__']
|
||||
@@ -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.
+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
|
||||
|
||||
+43
-12
@@ -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()
|
||||
@@ -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
|
||||
|
||||
@@ -1095,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.
|
||||
|
||||
@@ -1109,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.
|
||||
@@ -1126,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
|
||||
|
||||
@@ -1825,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 = {}
|
||||
|
||||
|
||||
+15
-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:
|
||||
@@ -983,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"',
|
||||
@@ -994,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
|
||||
|
||||
+54
-7
@@ -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])
|
||||
@@ -1308,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)``
|
||||
@@ -1321,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'])
|
||||
@@ -1345,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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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')
|
||||
+30
-7
@@ -10,6 +10,8 @@ import socket
|
||||
import stat
|
||||
import string
|
||||
|
||||
import six
|
||||
|
||||
from pwnlib.context import context
|
||||
from pwnlib.log import getLogger
|
||||
from pwnlib.util import fiddling
|
||||
@@ -195,6 +197,9 @@ def run_in_new_terminal(command, terminal = None, args = None):
|
||||
variable), a new pane will be opened.
|
||||
- If GNU Screen is detected (by the presence of the ``$STY`` environment
|
||||
variable), a new screen will be opened.
|
||||
- If WSL (Windows Subsystem for Linux) is detected (by the presence of
|
||||
a ``wsl.exe`` binary in the ``$PATH`` and ``/proc/sys/kernel/osrelease``
|
||||
containing ``Microsoft``), a new ``cmd.exe`` window will be opened.
|
||||
|
||||
Arguments:
|
||||
command (str): The command to run.
|
||||
@@ -207,7 +212,6 @@ def run_in_new_terminal(command, terminal = None, args = None):
|
||||
Returns:
|
||||
PID of the new terminal process
|
||||
"""
|
||||
|
||||
if not terminal:
|
||||
if context.terminal:
|
||||
terminal = context.terminal[0]
|
||||
@@ -215,18 +219,26 @@ def run_in_new_terminal(command, terminal = None, args = None):
|
||||
elif which('pwntools-terminal'):
|
||||
terminal = 'pwntools-terminal'
|
||||
args = []
|
||||
elif 'TERM_PROGRAM' in os.environ:
|
||||
terminal = os.environ['TERM_PROGRAM']
|
||||
args = []
|
||||
elif 'DISPLAY' in os.environ and which('x-terminal-emulator'):
|
||||
terminal = 'x-terminal-emulator'
|
||||
args = ['-e']
|
||||
elif 'TMUX' in os.environ and which('tmux'):
|
||||
terminal = 'tmux'
|
||||
args = ['splitw']
|
||||
elif 'STY' in os.environ and which('screen'):
|
||||
terminal = 'screen'
|
||||
args = ['-t','pwntools-gdb','bash','-c']
|
||||
elif 'TERM_PROGRAM' in os.environ:
|
||||
terminal = os.environ['TERM_PROGRAM']
|
||||
args = []
|
||||
elif 'DISPLAY' in os.environ and which('x-terminal-emulator'):
|
||||
terminal = 'x-terminal-emulator'
|
||||
args = ['-e']
|
||||
else:
|
||||
is_wsl = False
|
||||
if os.path.exists('/proc/sys/kernel/osrelease'):
|
||||
with open('/proc/sys/kernel/osrelease', 'rb') as f:
|
||||
is_wsl = b'icrosoft' in f.read()
|
||||
if is_wsl and which('cmd.exe') and which('wsl.exe') and which('bash.exe'):
|
||||
terminal = 'cmd.exe'
|
||||
args = ['/c', 'start', 'bash.exe', '-c']
|
||||
|
||||
if not terminal:
|
||||
log.error('Could not find a terminal binary to use. Set context.terminal to your terminal.')
|
||||
@@ -436,3 +448,14 @@ def register_sizes(regs, in_sizes):
|
||||
smaller[r] = [r_ for r_ in l if sizes[r_] < sizes[r]]
|
||||
|
||||
return lists.concat(regs), sizes, bigger, smaller
|
||||
|
||||
|
||||
def python_2_bytes_compatible(klass):
|
||||
"""
|
||||
A class decorator that defines __str__ methods under Python 2.
|
||||
Under Python 3 it does nothing.
|
||||
"""
|
||||
if six.PY2:
|
||||
if '__str__' not in klass.__dict__:
|
||||
klass.__str__ = klass.__bytes__
|
||||
return klass
|
||||
+39
-5
@@ -91,7 +91,7 @@ def getifaddrs():
|
||||
`netmask` are themselves dictionaries. Their structure depend on
|
||||
`family`. If `family` is not :const:`socket.AF_INET` or
|
||||
:const:`socket.AF_INET6` they will be empty.
|
||||
"""
|
||||
"""
|
||||
libc = ctypes.CDLL(ctypes.util.find_library('c'))
|
||||
getifaddrs = libc.getifaddrs
|
||||
getifaddrs.restype = ctypes.c_int
|
||||
@@ -136,7 +136,7 @@ def interfaces(all = False):
|
||||
A dictionary mapping each of the hosts interfaces to a list of it's
|
||||
addresses. Each entry in the list is a tuple ``(family, addr)``, and
|
||||
`family` is either :const:`socket.AF_INET` or :const:`socket.AF_INET6`.
|
||||
"""
|
||||
"""
|
||||
out = {}
|
||||
for ifa in getifaddrs():
|
||||
name = ifa['name']
|
||||
@@ -168,7 +168,7 @@ def interfaces4(all = False):
|
||||
Examples:
|
||||
>>> interfaces4(all=True) # doctest: +ELLIPSIS
|
||||
{...'127.0.0.1'...}
|
||||
"""
|
||||
"""
|
||||
out = {}
|
||||
for name, addrs in interfaces(all = all).items():
|
||||
addrs = [addr for fam, addr in addrs if fam == socket.AF_INET]
|
||||
@@ -193,7 +193,7 @@ def interfaces6(all = False):
|
||||
Examples:
|
||||
>>> interfaces6() # doctest: +ELLIPSIS
|
||||
{...'::1'...}
|
||||
"""
|
||||
"""
|
||||
out = {}
|
||||
for name, addrs in interfaces(all = all).items():
|
||||
addrs = [addr for fam, addr in addrs if fam == socket.AF_INET6]
|
||||
@@ -213,7 +213,7 @@ def sockaddr(host, port, network = 'ipv4'):
|
||||
|
||||
Returns:
|
||||
A tuple containing the sockaddr buffer, length, and the address family.
|
||||
"""
|
||||
"""
|
||||
address_family = {'ipv4':socket.AF_INET,'ipv6':socket.AF_INET6}[network]
|
||||
|
||||
for family, _, _, _, ip in socket.getaddrinfo(host, None, address_family):
|
||||
@@ -237,3 +237,37 @@ def sockaddr(host, port, network = 'ipv4'):
|
||||
sockaddr += host
|
||||
length = len(sockaddr) + 4 # Save five bytes 'push 0'
|
||||
return (sockaddr, length, getattr(address_family, "name", address_family))
|
||||
|
||||
def sock_match(local, remote, fam=socket.AF_UNSPEC, typ=0):
|
||||
"""
|
||||
Given two addresses, returns a function comparing address pairs from
|
||||
psutil library against these two. Useful for filtering done in
|
||||
:func:`pwnlib.util.proc.pidof`.
|
||||
"""
|
||||
def sockinfos(addr, f, t):
|
||||
if not addr:
|
||||
return set()
|
||||
if f not in (socket.AF_UNSPEC, socket.AF_INET, socket.AF_INET6):
|
||||
return {addr}
|
||||
infos = set(socket.getaddrinfo(addr[0], addr[1], f, t))
|
||||
|
||||
# handle mixed IPv4-to-IPv6 and the other way round connections
|
||||
for f, t, proto, _canonname, sockaddr in tuple(infos):
|
||||
if f == socket.AF_INET and t != socket.SOCK_RAW:
|
||||
infos |= set(socket.getaddrinfo(sockaddr[0], sockaddr[1], socket.AF_INET6, t, proto, socket.AI_V4MAPPED))
|
||||
return infos
|
||||
|
||||
if local is not None:
|
||||
local = sockinfos(local, fam, typ)
|
||||
remote = sockinfos(remote, fam, typ)
|
||||
|
||||
def match(c):
|
||||
laddrs = sockinfos(c.laddr, c.family, c.type)
|
||||
raddrs = sockinfos(c.raddr, c.family, c.type)
|
||||
if not (raddrs & remote):
|
||||
return False
|
||||
if local is None:
|
||||
return True
|
||||
return bool(laddrs & local)
|
||||
|
||||
return match
|
||||
+47
-9
@@ -42,9 +42,12 @@ from six.moves import range
|
||||
|
||||
from pwnlib.context import LocalNoarchContext
|
||||
from pwnlib.context import context
|
||||
from pwnlib.log import getLogger
|
||||
|
||||
from pwnlib.util import iters
|
||||
|
||||
mod = sys.modules[__name__]
|
||||
log = getLogger(__name__)
|
||||
|
||||
def pack(number, word_size = None, endianness = None, sign = None, **kwargs):
|
||||
"""pack(number, word_size = None, endianness = None, sign = None, **kwargs) -> str
|
||||
@@ -113,7 +116,7 @@ def pack(number, word_size = None, endianness = None, sign = None, **kwargs):
|
||||
if not isinstance(number, six.integer_types):
|
||||
raise ValueError("pack(): number must be of type (int,long) (got %r)" % type(number))
|
||||
|
||||
if sign not in [True, False]:
|
||||
if not isinstance(sign, bool):
|
||||
raise ValueError("pack(): sign must be either True or False (got %r)" % sign)
|
||||
|
||||
if endianness not in ['little', 'big']:
|
||||
@@ -124,18 +127,18 @@ def pack(number, word_size = None, endianness = None, sign = None, **kwargs):
|
||||
if number == 0:
|
||||
word_size = 8
|
||||
elif number > 0:
|
||||
if sign == False:
|
||||
word_size = ((number.bit_length() - 1) | 7) + 1
|
||||
else:
|
||||
if sign:
|
||||
word_size = (number.bit_length() | 7) + 1
|
||||
else:
|
||||
word_size = ((number.bit_length() - 1) | 7) + 1
|
||||
else:
|
||||
if sign == False:
|
||||
if not sign:
|
||||
raise ValueError("pack(): number does not fit within word_size")
|
||||
word_size = ((number + 1).bit_length() | 7) + 1
|
||||
elif not isinstance(word_size, six.integer_types) or word_size <= 0:
|
||||
raise ValueError("pack(): word_size must be a positive integer or the string 'all'")
|
||||
|
||||
if sign == True:
|
||||
if sign:
|
||||
limit = 1 << (word_size-1)
|
||||
if not -limit <= number < limit:
|
||||
raise ValueError("pack(): number does not fit within word_size")
|
||||
@@ -487,6 +490,7 @@ def make_unpacker(word_size = None, endianness = None, sign = None, **kwargs):
|
||||
return lambda number: unpack(number, word_size, endianness, sign)
|
||||
|
||||
def _fit(pieces, preprocessor, packer, filler):
|
||||
|
||||
# Pulls bytes from `filler` and adds them to `pad` until it ends in `key`.
|
||||
# Returns the index of `key` in `pad`.
|
||||
pad = bytearray()
|
||||
@@ -524,6 +528,14 @@ def _fit(pieces, preprocessor, packer, filler):
|
||||
|
||||
# Build output
|
||||
out = b''
|
||||
|
||||
# Negative indices need to be removed and then re-submitted
|
||||
negative = {k:v for k,v in pieces.items() if isinstance(k, int) and k<0}
|
||||
|
||||
for k in negative:
|
||||
del pieces[k]
|
||||
|
||||
# Positive output
|
||||
for k, v in sorted(pieces.items()):
|
||||
if k < len(out):
|
||||
raise ValueError("flat(): data at offset %d overlaps with previous data which ends at offset %d" % (k, len(out)))
|
||||
@@ -535,7 +547,24 @@ def _fit(pieces, preprocessor, packer, filler):
|
||||
# Recursively flatten data
|
||||
out += _flat([v], preprocessor, packer, filler)
|
||||
|
||||
return filler, out
|
||||
# Now do negative indices
|
||||
out_negative = b''
|
||||
if negative:
|
||||
most_negative = min(negative.keys())
|
||||
for k, v in sorted(negative.items()):
|
||||
k += -most_negative
|
||||
|
||||
if k < len(out_negative):
|
||||
raise ValueError("flat(): data at offset %d overlaps with previous data which ends at offset %d" % (k, len(out)))
|
||||
|
||||
# Fill up to offset
|
||||
while len(out_negative) < k:
|
||||
out_negative += p8(next(filler))
|
||||
|
||||
# Recursively flatten data
|
||||
out_negative += _flat([v], preprocessor, packer, filler)
|
||||
|
||||
return filler, out_negative + out
|
||||
|
||||
def _flat(args, preprocessor, packer, filler):
|
||||
out = []
|
||||
@@ -543,7 +572,7 @@ def _flat(args, preprocessor, packer, filler):
|
||||
|
||||
if not isinstance(arg, (list, tuple, dict)):
|
||||
arg_ = preprocessor(arg)
|
||||
if arg_ != None:
|
||||
if arg_ is not None:
|
||||
arg = arg_
|
||||
|
||||
if hasattr(arg, '__flat__'):
|
||||
@@ -559,7 +588,7 @@ def _flat(args, preprocessor, packer, filler):
|
||||
elif isinstance(arg, six.integer_types):
|
||||
val = packer(arg)
|
||||
elif isinstance(arg, bytearray):
|
||||
val = str(arg)
|
||||
val = bytes(arg)
|
||||
else:
|
||||
raise ValueError("flat(): Flat does not support values of type %s" % type(arg))
|
||||
|
||||
@@ -714,6 +743,12 @@ def flat(*args, **kwargs):
|
||||
b'aaaaXaaaY'
|
||||
>>> fit({4: {4: 'XXXX'}})
|
||||
b'aaaabaaaXXXX'
|
||||
|
||||
Negative indices are also supported, though this only works for integer
|
||||
keys.
|
||||
|
||||
>>> flat({-4: 'x', -1: 'A', 0: '0', 4:'y'})
|
||||
b'xaaA0aaay'
|
||||
"""
|
||||
# HACK: To avoid circular imports we need to delay the import of `cyclic`
|
||||
from pwnlib.util import cyclic
|
||||
@@ -964,3 +999,6 @@ def dd(dst, src, count = 0, skip = 0, seek = 0, truncate = False):
|
||||
dst = dst.decode('utf8')
|
||||
|
||||
return dst
|
||||
|
||||
del op, size, end, sign
|
||||
del name, routine, mod
|
||||
+8
-16
@@ -9,6 +9,7 @@ import psutil
|
||||
|
||||
from pwnlib import tubes
|
||||
from pwnlib.log import getLogger
|
||||
from .net import sock_match
|
||||
from pwnlib.timeout import Timeout
|
||||
|
||||
log = getLogger(__name__)
|
||||
@@ -42,29 +43,20 @@ def pidof(target):
|
||||
return [target.pid]
|
||||
|
||||
elif isinstance(target, tubes.sock.sock):
|
||||
local = target.sock.getsockname()
|
||||
remote = target.sock.getpeername()
|
||||
|
||||
def match(c):
|
||||
return (c.raddr, c.laddr, c.status) == (local, remote, 'ESTABLISHED')
|
||||
|
||||
return [c.pid for c in psutil.net_connections() if match(c)]
|
||||
local = target.sock.getsockname()
|
||||
remote = target.sock.getpeername()
|
||||
match = sock_match(remote, local, target.family, target.type)
|
||||
return [c.pid for c in psutil.net_connections() if match(c)]
|
||||
|
||||
elif isinstance(target, tuple):
|
||||
host, port = target
|
||||
|
||||
host = socket.gethostbyname(host)
|
||||
|
||||
def match(c):
|
||||
return c.raddr == (host, port)
|
||||
|
||||
match = sock_match(None, target)
|
||||
return [c.pid for c in psutil.net_connections() if match(c)]
|
||||
|
||||
elif isinstance(target, tubes.process.process):
|
||||
return [target.proc.pid]
|
||||
return [target.proc.pid]
|
||||
|
||||
else:
|
||||
return pid_by_name(target)
|
||||
return pid_by_name(target)
|
||||
|
||||
def pid_by_name(name):
|
||||
"""pid_by_name(name) -> int list
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
__version__ = '4.2.2'
|
||||
__version__ = '4.3.0'
|
||||
@@ -83,7 +83,7 @@ setup(
|
||||
name = 'pwntools',
|
||||
python_requires = '>=2.7',
|
||||
packages = find_packages(),
|
||||
version = '4.2.2',
|
||||
version = '4.3.0',
|
||||
data_files = [('',
|
||||
glob.glob('*.md') + glob.glob('*.txt')),
|
||||
],
|
||||
|
||||
@@ -91,15 +91,17 @@ RUN echo y | android update sdk --no-ui --all --filter sys-img-armeabi-v7a-andro
|
||||
# PWNTOOLS TEST REQUIREMENTS
|
||||
#==============================================================================
|
||||
|
||||
# Install pwntools from 'dev3', to get all of the latest dependencies
|
||||
# Install pwntools from 'dev', to get all of the latest dependencies
|
||||
# Then uninstall pwntools so we have a clean slate, but still have
|
||||
# all of its dependencies installed.
|
||||
WORKDIR /root
|
||||
RUN git clone https://github.com/Gallopsled/pwntools
|
||||
WORKDIR /root/pwntools
|
||||
RUN git checkout dev3
|
||||
RUN git checkout dev
|
||||
RUN pip3 install --upgrade --editable .
|
||||
RUN pip3 install --upgrade --requirement docs/requirements.txt
|
||||
RUN pip2 install --upgrade --editable .
|
||||
RUN pip2 install --upgrade --requirement docs/requirements.txt
|
||||
RUN pip3 uninstall --yes pwntools
|
||||
WORKDIR /root
|
||||
RUN rm -rf pwntools
|
||||
@@ -138,7 +140,7 @@ USER root
|
||||
# Setting Python3 as the default
|
||||
RUN echo 'alias python=python3' >> ~/.bashrc
|
||||
|
||||
RUN apt-get install -y strace nano vim tmux
|
||||
RUN apt-get install -y strace nano vim tmux socat bash-static
|
||||
|
||||
# Entry point
|
||||
USER travis
|
||||
@@ -150,4 +152,8 @@ ADD run.sh .
|
||||
COPY pwntools.tar.gz .
|
||||
RUN tar xf pwntools.tar.gz
|
||||
RUN sudo rm -f pwntools.tar.gz
|
||||
RUN pip2 install -e .
|
||||
RUN pip2 install -r docs/requirements.txt
|
||||
RUN pip3 install -e .
|
||||
RUN pip3 install -r docs/requirements.txt
|
||||
ENTRYPOINT bash run.sh
|
||||
Loaded 100 of 102 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user