mirror of
https://github.com/Gallopsled/pwntools.git
synced 2026-11-08 01:58:16 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ebcbee34b | ||
|
|
d25d62c126 | ||
|
|
5392611ed5 | ||
|
|
475ffa632e | ||
|
|
602efd2790 | ||
|
|
2f7f0de984 | ||
|
|
16b507e197 | ||
|
|
53f041a4d2 | ||
|
|
b2a5b76cf7 | ||
|
|
9c2f0f4e89 | ||
|
|
7ba3a1b32f | ||
|
|
d1edd275d9 | ||
|
|
cb4991c41d | ||
|
|
48616c633d | ||
|
|
323975f343 | ||
|
|
f65c258956 | ||
|
|
f5e16d3db6 | ||
|
|
d55874a6d3 | ||
|
|
0426d498d9 | ||
|
|
a2c67e5075 | ||
|
|
54e722819b | ||
|
|
7ed118763b | ||
|
|
5a370162e5 | ||
|
|
253ab78e4c | ||
|
|
e997c17397 | ||
|
|
0acc8ee499 | ||
|
|
f14e0e5652 | ||
|
|
aaa83983ad | ||
|
|
1b76a27bd5 | ||
|
|
1241073391 | ||
|
|
cfcd79e169 | ||
|
|
706a784904 | ||
|
|
70c96330de | ||
|
|
cae3cddc07 | ||
|
|
5373dcdeed | ||
|
|
5d4bf3db6c | ||
|
|
fbfa54ad61 | ||
|
|
b323264032 | ||
|
|
332c9d2031 | ||
|
|
2c841eaa21 | ||
|
|
d2c6184a00 | ||
|
|
e5645e7b53 | ||
|
|
09dbe0a54d | ||
|
|
0bd0de78f9 | ||
|
|
546061e577 | ||
|
|
5ebc8b5bb7 | ||
|
|
b83a6c7db8 | ||
|
|
5d9792fb4c | ||
|
|
1c54e347f2 | ||
|
|
7545dafffb | ||
|
|
3acec5421f | ||
|
|
620364dd1d | ||
|
|
b441cf967a | ||
|
|
76c21548db | ||
|
|
30c34b785a | ||
|
|
6c304d3511 | ||
|
|
dc297e17ae | ||
|
|
fa402ceb57 | ||
|
|
483adb8e2d | ||
|
|
76fe04e356 | ||
|
|
82312baba0 | ||
|
|
d101a775aa | ||
|
|
5fda6580e8 | ||
|
|
9185437626 | ||
|
|
420f99c5d0 | ||
|
|
98052e4166 | ||
|
|
e971856c74 | ||
|
|
b3f941c3f5 | ||
|
|
67e11a9aeb | ||
|
|
fd731154ff | ||
|
|
906bc94a5f | ||
|
|
db03e7de10 | ||
|
|
97e03fd29f | ||
|
|
09b8bb93a7 | ||
|
|
f9133b1680 | ||
|
|
8aa21bd99a | ||
|
|
9af20c778f | ||
|
|
d1621dca87 | ||
|
|
39970c3847 | ||
|
|
8d11fb8594 | ||
|
|
aec3fa6879 | ||
|
|
ab6602407e | ||
|
|
42ab0c985d | ||
|
|
b215828133 | ||
|
|
e3af4ce6a7 | ||
|
|
96c6edcc37 | ||
|
|
b198ec8633 | ||
|
|
c8a87381e8 |
No files matched your search
@@ -6,4 +6,4 @@ When reporting an issue, be sure that you are running the latest released versio
|
||||
|
||||
Please verify that your issue occurs on 64-bit Ubuntu 14.04. You can use the Dockerfile in `extra/docker/Dockerfile` to save time.
|
||||
|
||||
If possible, provide a proof-of-concept which demonstrates the problem. Include any binaries or scripts necessary to reproduce the issue.
|
||||
If possible, provide a proof-of-concept which demonstrates the problem. Include any binaries or scripts necessary to reproduce the issue, and please include the full debug output via setting the environment variable `PWNLIB_DEBUG=1`.
|
||||
File renamed without changes.
+5
-1
@@ -13,6 +13,7 @@ addons:
|
||||
- mksh
|
||||
- zsh
|
||||
- pandoc
|
||||
- gdb
|
||||
cache:
|
||||
- pip
|
||||
- directories:
|
||||
@@ -22,11 +23,14 @@ cache:
|
||||
python:
|
||||
- "2.7"
|
||||
before_install:
|
||||
- echo $-
|
||||
- source travis/install.sh
|
||||
- source travis/ssh_setup.sh
|
||||
- echo $-
|
||||
install:
|
||||
- pip install --upgrade pip
|
||||
- pip install --upgrade --editable .
|
||||
- pip install --requirement docs/requirements.txt
|
||||
- pip install --upgrade --requirement docs/requirements.txt
|
||||
before_script:
|
||||
- PWNLIB_NOTERM=1 python -c 'from pwn import *; print pwnlib.term.term_mode'
|
||||
- PWNLIB_NOTERM=1 python -c 'from pwn import *; print pwnlib.term.term_mode'
|
||||
|
||||
+95
-8
@@ -9,9 +9,15 @@ The table below shows which release corresponds to each branch, and what date th
|
||||
|
||||
| Version | Branch | Release Date |
|
||||
| ---------------- | -------- | ---------------------- |
|
||||
| [3.4.0](#340) | `dev` | Feb 4, 2017 (planned)
|
||||
| [3.3.0](#330) | `beta` | Dec 24, 2016 (planned)
|
||||
| [3.2.1](#321) | `stable` | Dec 24, 2016
|
||||
| [3.6.0](#350) | `dev` | May 6, 2017 (planned)
|
||||
| [3.5.0](#350) | `beta` | Mar 25, 2017 (planned)
|
||||
| [3.4.0](#340) | `stable` | Feb 13, 2017
|
||||
| [3.3.4](#334) | | Jan 12, 2016
|
||||
| [3.3.3](#333) | | Jan 10, 2016
|
||||
| [3.3.2](#332) | | Jan 10, 2016
|
||||
| [3.3.1](#331) | | Jan 10, 2016
|
||||
| [3.3.0](#330) | | Dec 24, 2016
|
||||
| [3.2.1](#321) | | Dec 24, 2016
|
||||
| [3.2.0](#320) | | Nov 12, 2016
|
||||
| [3.1.1](#311) | | Oct 23, 2016
|
||||
| [3.1.0](#310) | | Oct 2, 2016
|
||||
@@ -22,13 +28,94 @@ 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
|
||||
|
||||
|
||||
## 3.6.0
|
||||
|
||||
To be released on May 6, 2017.
|
||||
|
||||
## 3.5.0
|
||||
|
||||
To be released on Mar 25, 2017.
|
||||
|
||||
## 3.4.0
|
||||
|
||||
To be released on Feb 4, 2017.
|
||||
- [#800][800] Add `shell=` option to `ssh.process()`
|
||||
- [#806][806] Add `context.buffer_size` for fine-tuning `tube` performance
|
||||
+ Also adds `buffer_fill_size=` argument for all tubes
|
||||
- [b83a6c7][b83a6c7] Fix undocumented `process.leak` function
|
||||
- [546061e][546061e] Modify `coredump_filter` of all spawned processes, so that core dumps are more complete
|
||||
- [#809][809] Add several functions to `adb` (`unlink`, `mkdir`, `makedirs`, `isdir`, `exists`)
|
||||
- [#817][817] Make disconnection detection more robust
|
||||
|
||||
[800]: https://github.com/Gallopsled/pwntools/pull/800
|
||||
[806]: https://github.com/Gallopsled/pwntools/pull/806
|
||||
[809]: https://github.com/Gallopsled/pwntools/pull/809
|
||||
[817]: https://github.com/Gallopsled/pwntools/pull/817
|
||||
[5d9792f]: https://github.com/Gallopsled/pwntools/commit/5d9792f
|
||||
[b83a6c7]: https://github.com/Gallopsled/pwntools/commit/b83a6c7
|
||||
[546061e]: https://github.com/Gallopsled/pwntools/commit/546061e
|
||||
|
||||
## 3.3.4
|
||||
|
||||
- [#850][850] and [#846][846] fix issues with `hexdump` and the `phd` command-line utility, when using pipes (e.g. `echo foo | phd`)
|
||||
- [#852][852] Fixes register ordering in `regsort`
|
||||
- [#853][853] Fixes the registers restored in `shellcraft.amd64.popad`
|
||||
|
||||
[846]: https://github.com/gallopsled/pwntools/pull/846
|
||||
[850]: https://github.com/gallopsled/pwntools/pull/850
|
||||
[852]: https://github.com/gallopsled/pwntools/pull/852
|
||||
[853]: https://github.com/gallopsled/pwntools/pull/853
|
||||
|
||||
## 3.3.3
|
||||
|
||||
- [#843][843] fixed a bug in `amd64.mov`.
|
||||
|
||||
[843]: https://github.com/gallopsled/pwntools/pull/843
|
||||
|
||||
## 3.3.2
|
||||
|
||||
- [#840][840] fixed a regression introduced by [#837][837].
|
||||
|
||||
[840]: https://github.com/gallopsled/pwntools/pull/840
|
||||
|
||||
## 3.3.1
|
||||
|
||||
- [#833][833] Fixed a performance-impacting bug in the adb module.
|
||||
- [#837][837] Fixed a bug([#836][836]) causing `hexdump(cyclic=True)` to throw an exception.
|
||||
|
||||
[833]: https://github.com/Gallopsled/pwntools/pull/833
|
||||
[837]: https://github.com/Gallopsled/pwntools/pull/837
|
||||
[836]: https://github.com/Gallopsled/pwntools/issues/836
|
||||
|
||||
## 3.3.0
|
||||
|
||||
To be released on Dec 24, 2016.
|
||||
- [b198ec8][b198ec8] Added `tube.stream()` function, which is like `tube.interact()` without a prompt or keyboard input.
|
||||
+ Effectively, this is similar to `cat file` and just prints data as fast as it is received.
|
||||
- [aec3fa6][aec3fa6] Disable update checks against GitHub
|
||||
+ These checks frequently broke due to GitHub query limits
|
||||
- [#757][757] Fixed `adb.wait_for_device()` re-use of the same connection
|
||||
- [f9133b1][f9133b1] Add a `STDERR` magic argument to make logging go to `stderr` instead of `stdout`
|
||||
+ Usage is e.g. `python foo.py STDERR` or `PWNLIB_STDERR=1 python foo.py`
|
||||
+ Also adds `context.log_console` to log to any file or terminal
|
||||
- [67e11a9][67e11a9] Add faster error checking to `cyclic()` when provided very large values
|
||||
- [5fda658][5fda658] Expose BitPolynom in `globals()`
|
||||
- [#765][765] Added `-d` option for hex-escaped output for `shellcraft` command-line tool
|
||||
- [#772][772] Fixed bash completion regressions
|
||||
- [30c34b7][30c34b7] Fix `ROP.call()` with `Function` objects from `ELF.functions`
|
||||
- [fa402ce][fa402ce] Add `adb.uptime` and `adb.boot_time`
|
||||
- [82312ba][82312ba] Add `cyclic_metasploit` and `cyclic_metasploit_find`
|
||||
|
||||
[757]: https://github.com/Gallopsled/pwntools/pull/757
|
||||
[765]: https://github.com/Gallopsled/pwntools/pull/765
|
||||
[772]: https://github.com/Gallopsled/pwntools/pull/772
|
||||
[b198ec8]: https://github.com/Gallopsled/pwntools/commit/b198ec8
|
||||
[aec3fa6]: https://github.com/Gallopsled/pwntools/commit/aec3fa6
|
||||
[f9133b1]: https://github.com/Gallopsled/pwntools/commit/f9133b1
|
||||
[67e11a9]: https://github.com/Gallopsled/pwntools/commit/67e11a9
|
||||
[5fda658]: https://github.com/Gallopsled/pwntools/commit/5fda658
|
||||
[30c34b7]: https://github.com/Gallopsled/pwntools/commit/30c34b7
|
||||
[fa402ce]: https://github.com/Gallopsled/pwntools/commit/fa402ce
|
||||
[82312ba]: https://github.com/Gallopsled/pwntools/commit/82312ba
|
||||
|
||||
## 3.2.1
|
||||
|
||||
@@ -87,7 +174,7 @@ Multiple bug fixes.
|
||||
- [1e414af][1e414af] Added `connect()` alias for `remote()`
|
||||
+ For example, `io=connect('google.com', 80)`
|
||||
+ This also works with `tcp(...)` and `udp(...)` aliases
|
||||
- [869ec42][869ec42] Added `ssh.read()` and `ssh.write()` aiases
|
||||
- [869ec42][869ec42] Added `ssh.read()` and `ssh.write()` aliases
|
||||
- [2af55c9][2af55c9] `AdbDevice` objects exposed via e.g. `adb.devices()` now offer scoped access to all `adb` module properties
|
||||
+ It is now possible to e.g. `map(lambda d: d.process(['id']).recvall(), adb.devices())`
|
||||
|
||||
@@ -174,7 +261,7 @@ Android support via a new `adb` module, `context.device`, `context.adb_host`, an
|
||||
- Added `context.log_file` setting for sending logs to a file. This can be set with the `LOG_FILE` magic command-line option.
|
||||
- Added `context.noptrace` setting for disabling actions which require `ptrace` support. This is useful for turning all `gdb.debug` and `gdb.attach` options into no-ops, and can be set via the `NOPTRACE` magic command-line option.
|
||||
- Added `context.proxy` which hooks all connections and sends them to a SOCKS4/SOCKS5. This can be set via the `PROXY` magic command-line option.
|
||||
- Added `context.randomize` to control randommization of settings like XOR keys and register ordering (default off).
|
||||
- Added `context.randomize` to control randomization of settings like XOR keys and register ordering (default off).
|
||||
- Added `context.terminal` for setting how to launch commands in a new terminal.
|
||||
|
||||
#### DynELF and MemLeak Module
|
||||
@@ -187,7 +274,7 @@ Android support via a new `adb` module, `context.device`, `context.adb_host`, an
|
||||
#### Encoders Module
|
||||
|
||||
- Added a `pwnlib.encoders` module for assembled-shellcode encoders/decoders
|
||||
- Includes position-indepentent basic XOR encoders
|
||||
- Includes position-independent basic XOR encoders
|
||||
- Includes position-independent delta encoders
|
||||
- Includes non-position-independent alphanumeric encoders for Intel
|
||||
- Includes position-independent alphanumeric encoders for ARM/Thumb
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||

|
||||
|
||||
[](https://docs.pwntools.com/)
|
||||
[](https://pypi.python.org/pypi/pwntools/)
|
||||
[](https://pypi.python.org/pypi/pwntools/)
|
||||
[](https://travis-ci.org/Gallopsled/pwntools)
|
||||
[](https://coveralls.io/github/Gallopsled/pwntools?branch=dev)
|
||||
[](https://twitter.com/pwntools)
|
||||
@@ -38,7 +38,7 @@ Most of the functionality of pwntools is self-contained and Python-only. You sh
|
||||
|
||||
```sh
|
||||
apt-get update
|
||||
apt-get install python2.7 python-pip python-dev git libssl-dev
|
||||
apt-get install python2.7 python-pip python-dev git libssl-dev libffi-dev
|
||||
pip install --upgrade pwntools
|
||||
```
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ Pwntools makes extensive use of unit tests and integration tests to ensure every
|
||||
## Test Suite
|
||||
|
||||
|
||||
To run the test suite, it is beste to use Ubuntu 12.04 or 14.04, and run the following commands. **Be aware** that this will add a user to the machine, and create a public key for SSH login!
|
||||
To run the test suite, it is best to use Ubuntu 12.04 or 14.04, and run the following commands. **Be aware** that this will add a user to the machine, and create a public key for SSH login!
|
||||
|
||||
```sh
|
||||
bash travis/install.sh
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
|
||||
:mod:`pwnlib.args` --- Magic Command-Line Arguments
|
||||
=====================================================
|
||||
|
||||
.. automodule:: pwnlib.args
|
||||
:members:
|
||||
@@ -55,6 +55,16 @@ pwnlib.context.ContextType.defaults['randomize'] = False
|
||||
pwnlib.term.text.when = 'never'
|
||||
pwnlib.log.install_default_handler()
|
||||
pwnlib.log.rootlogger.setLevel(1)
|
||||
|
||||
# Sphinx modifies sys.stdout, and context.log_terminal has
|
||||
# a reference to the original instance. We need to update
|
||||
# it for logging to be captured.
|
||||
class stdout(object):
|
||||
def __getattr__(self, name):
|
||||
return getattr(sys.stdout, name)
|
||||
def __setattr__(self, name, value):
|
||||
return setattr(sys.stdout, name, value)
|
||||
pwnlib.context.ContextType.defaults['log_console'] = stdout()
|
||||
'''
|
||||
|
||||
autodoc_member_order = 'alphabetical'
|
||||
|
||||
@@ -43,6 +43,7 @@ Each of the ``pwntools`` modules is documented here.
|
||||
:glob:
|
||||
|
||||
adb
|
||||
args
|
||||
asm
|
||||
atexception
|
||||
atexit
|
||||
|
||||
@@ -24,7 +24,8 @@ pwntools is available as a ``pip`` package.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ apt-get install python2.7 python2.7-dev python-pip
|
||||
$ apt-get update
|
||||
$ apt-get install python2.7 python-pip python-dev git libssl-dev libffi-dev
|
||||
$ pip install --upgrade pwntools
|
||||
|
||||
Development
|
||||
|
||||
+2
-1
@@ -13,4 +13,5 @@ if not platform.architecture()[0].startswith('64'):
|
||||
See Gallopsled/pwntools#518 for more information."""
|
||||
log.warn_once('Pwntools does not support 32-bit Python. Use a 64-bit release.')
|
||||
|
||||
pwnlib.update.check_automatically()
|
||||
with context.local(log_console=sys.stderr):
|
||||
pwnlib.update.check_automatically()
|
||||
@@ -51,6 +51,7 @@ from pwnlib.util import iters
|
||||
from pwnlib.util import net
|
||||
from pwnlib.util import proc
|
||||
from pwnlib.util import safeeval
|
||||
from pwnlib.util.crc import BitPolynom
|
||||
from pwnlib.util.cyclic import *
|
||||
from pwnlib.util.fiddling import *
|
||||
from pwnlib.util.getdents import *
|
||||
|
||||
+199
-8
@@ -10,12 +10,38 @@ If you have multiple devices, you have a handful of options to select one, or it
|
||||
over the devices.
|
||||
|
||||
First and most important is the ``context.device`` property, which declares the "currently"
|
||||
seelcted device in any scope. It can be set manually to a serial number, or to a ``Device``
|
||||
selected device in any scope. It can be set manually to a serial number, or to a ``Device``
|
||||
instance.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> context.device = ''
|
||||
# Take the first available device
|
||||
context.device = adb.wait_for_device()
|
||||
|
||||
# Set a device by serial number
|
||||
context.device = 'ZX1G22LH8S'
|
||||
|
||||
# Set a device by its product name
|
||||
for device in adb.devices():
|
||||
if device.product == 'shamu':
|
||||
break
|
||||
else:
|
||||
error("Could not find any shamus!")
|
||||
|
||||
Once a device is selected, you can operate on it with any of the functions in
|
||||
the ``pwnlib.adb`` module.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Get a process listing
|
||||
print adb.process(['ps']).recvall()
|
||||
|
||||
# Fetch properties
|
||||
print adb.properties.ro.build.fingerprint
|
||||
|
||||
# Read and write files
|
||||
print adb.read('/proc/version')
|
||||
adb.write('/data/local/tmp/foo', 'my data')
|
||||
|
||||
"""
|
||||
import functools
|
||||
@@ -162,6 +188,29 @@ def reboot_bootloader():
|
||||
with Client() as c:
|
||||
c.reboot_bootloader()
|
||||
|
||||
@with_device
|
||||
def uptime():
|
||||
"""uptime() -> float
|
||||
|
||||
Returns:
|
||||
Uptime of the device, in seconds
|
||||
"""
|
||||
up, idle = map(float, read('/proc/uptime').split())
|
||||
return up
|
||||
|
||||
@with_device
|
||||
def boot_time():
|
||||
"""boot_time() -> int
|
||||
|
||||
Returns:
|
||||
Boot time of the device, in Unix time, rounded to the
|
||||
nearest second.
|
||||
"""
|
||||
for line in read('/proc/stat').splitlines():
|
||||
name, value = line.split(None, 1)
|
||||
if name == 'btime':
|
||||
return int(value)
|
||||
|
||||
class AdbDevice(Device):
|
||||
"""Encapsulates information about a connected device.
|
||||
|
||||
@@ -550,6 +599,150 @@ def write(path, data=''):
|
||||
misc.write(temp.name, data)
|
||||
push(temp.name, path)
|
||||
|
||||
@context.quiet
|
||||
@with_device
|
||||
def mkdir(path):
|
||||
"""Create a directory on the target device.
|
||||
|
||||
Note:
|
||||
Silently succeeds if the directory already exists.
|
||||
|
||||
Arguments:
|
||||
path(str): Directory to create.
|
||||
|
||||
Examples:
|
||||
|
||||
>>> adb.mkdir('/')
|
||||
|
||||
>>> path = '/data/local/tmp/mkdir_test'
|
||||
>>> adb.exists(path)
|
||||
False
|
||||
>>> adb.mkdir(path)
|
||||
>>> adb.exists(path)
|
||||
True
|
||||
|
||||
>>> adb.mkdir('/init')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
PwnlibException: mkdir failed for /init, File exists
|
||||
"""
|
||||
if not path.startswith('/'):
|
||||
log.error("Must provide an absolute path: %r" % path)
|
||||
|
||||
with Client() as c:
|
||||
st = c.stat(path)
|
||||
|
||||
# Don't re-create existing directories
|
||||
if st and stat.S_ISDIR(st['mode']):
|
||||
return
|
||||
|
||||
result = process(['mkdir', path]).recvall()
|
||||
|
||||
# Any output at all is an error
|
||||
if result:
|
||||
log.error(result)
|
||||
|
||||
@context.quiet
|
||||
@with_device
|
||||
def makedirs(path):
|
||||
"""Create a directory and all parent directories on the target device.
|
||||
|
||||
Note:
|
||||
Silently succeeds if the directory already exists.
|
||||
|
||||
Examples:
|
||||
|
||||
>>> adb.makedirs('/data/local/tmp/this/is/a/directory/heirarchy')
|
||||
>>> adb.listdir('/data/local/tmp/this/is/a/directory')
|
||||
['heirarchy']
|
||||
"""
|
||||
if path != '/':
|
||||
makedirs(os.path.dirname(path))
|
||||
|
||||
mkdir(path)
|
||||
|
||||
@context.quiet
|
||||
@with_device
|
||||
def exists(path):
|
||||
"""Return ``True`` if ``path`` exists on the target device.
|
||||
|
||||
Examples:
|
||||
|
||||
>>> adb.exists('/')
|
||||
True
|
||||
>>> adb.exists('/init')
|
||||
True
|
||||
>>> adb.exists('/does/not/exist')
|
||||
False
|
||||
"""
|
||||
with Client() as c:
|
||||
return bool(c.stat(path))
|
||||
|
||||
@context.quiet
|
||||
@with_device
|
||||
def isdir(path):
|
||||
"""Return ``True`` if ``path`` is a on the target device.
|
||||
|
||||
Examples:
|
||||
|
||||
>>> adb.isdir('/')
|
||||
True
|
||||
>>> adb.isdir('/init')
|
||||
False
|
||||
>>> adb.isdir('/does/not/exist')
|
||||
False
|
||||
"""
|
||||
with Client() as c:
|
||||
st = c.stat(path)
|
||||
return bool(st and stat.S_ISDIR(st['mode']))
|
||||
|
||||
@context.quiet
|
||||
@with_device
|
||||
def unlink(path, recursive=False):
|
||||
"""Unlinks a file or directory on the target device.
|
||||
|
||||
Examples:
|
||||
|
||||
>>> adb.unlink("/does/not/exist")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
PwnlibException: Could not unlink '/does/not/exist': Does not exist
|
||||
|
||||
>>> filename = '/data/local/tmp/unlink-test'
|
||||
>>> adb.write(filename, 'hello')
|
||||
>>> adb.exists(filename)
|
||||
True
|
||||
>>> adb.unlink(filename)
|
||||
>>> adb.exists(filename)
|
||||
False
|
||||
|
||||
>>> adb.mkdir(filename)
|
||||
>>> adb.write(filename + '/contents', 'hello')
|
||||
>>> adb.unlink(filename)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
PwnlibException: Cannot delete non-empty directory '/data/local/tmp/unlink-test' without recursive=True
|
||||
|
||||
>>> adb.unlink(filename, recursive=True)
|
||||
>>> adb.exists(filename)
|
||||
False
|
||||
"""
|
||||
with Client() as c:
|
||||
st = c.stat(path)
|
||||
if not st:
|
||||
log.error("Could not unlink %r: Does not exist" % path)
|
||||
|
||||
# If the directory is not empty, do not delete it
|
||||
if isdir(path) and c.list(path) and not recursive:
|
||||
log.error("Cannot delete non-empty directory %r without recursive=True" % path)
|
||||
|
||||
flags = '-rf' if recursive else '-r'
|
||||
|
||||
output = c.execute(['rm', flags, path]).recvall()
|
||||
|
||||
if output:
|
||||
log.error(output)
|
||||
|
||||
@with_device
|
||||
def process(argv, *a, **kw):
|
||||
"""Execute a process on the device.
|
||||
@@ -711,16 +904,15 @@ def listdir(directory='/'):
|
||||
"""
|
||||
return list(sorted(Client().list(directory)))
|
||||
|
||||
@with_device
|
||||
def fastboot(args, *a, **kw):
|
||||
"""Executes a fastboot command.
|
||||
|
||||
Returns:
|
||||
The command output.
|
||||
"""
|
||||
serial = context.device
|
||||
if not serial:
|
||||
log.error("Unknown device")
|
||||
return tubes.process.process(['fastboot', '-s', serial] + list(args), **kw).recvall()
|
||||
argv = ['fastboot', '-s', str(context.device)] + list(args)
|
||||
return tubes.process.process(argv, *a, **kw).recvall()
|
||||
|
||||
@with_device
|
||||
def fingerprint():
|
||||
@@ -1128,7 +1320,7 @@ def uninstall(package, *arguments):
|
||||
package(str): Name of the package to uninstall (e.g. ``'com.foo.MyPackage'``)
|
||||
arguments: Supplementary arguments to ``'pm install'``, e.g. ``'-k'``.
|
||||
"""
|
||||
with log.progress("Installing package {}".format(package)):
|
||||
with log.progress("Uninstalling package {}".format(package)):
|
||||
with context.quiet:
|
||||
return process(['pm','uninstall',package] + list(arguments)).recvall()
|
||||
|
||||
@@ -1137,4 +1329,3 @@ def packages():
|
||||
"""Returns a list of packages installed on the system"""
|
||||
packages = process(['pm', 'list', 'packages']).recvall()
|
||||
return [line.split('package:', 1)[-1] for line in packages.splitlines()]
|
||||
|
||||
+27
-9
@@ -43,14 +43,7 @@ class Message(object):
|
||||
class Connection(remote):
|
||||
"""Connection to the ADB server"""
|
||||
def __init__(self, host, port, level=None, *a, **kw):
|
||||
# Try to make sure ADB is running if it's on the default host and port.
|
||||
if host == context.defaults['adb_host'] \
|
||||
and port == context.defaults['adb_port']:
|
||||
with context.quiet:
|
||||
process(context.adb + ['start-server']).recvall()
|
||||
|
||||
with context.quiet:
|
||||
super(Connection, self).__init__(host, port, level=level, *a, **kw)
|
||||
super(Connection, self).__init__(host, port, level=level, *a, **kw)
|
||||
|
||||
self._executable = None
|
||||
self._argv = None
|
||||
@@ -91,6 +84,20 @@ class Client(Logger):
|
||||
@property
|
||||
def c(self):
|
||||
"""Client's connection to the ADB server"""
|
||||
if not self._c:
|
||||
try:
|
||||
self._c = Connection(self.host, self.port, level=self.level)
|
||||
except Exception:
|
||||
# If the connection fails, try starting a server on that port
|
||||
# as long as it's the *default* port.
|
||||
if self.host == context.defaults['adb_host'] \
|
||||
and self.port == context.defaults['adb_port']:
|
||||
log.warn("Could not connect to ADB server, trying to start it")
|
||||
process(context.adb + ['start-server']).recvall()
|
||||
else:
|
||||
log.exception('Could not connect to ADB server')
|
||||
|
||||
# Final attempt...
|
||||
if not self._c:
|
||||
self._c = Connection(self.host, self.port, level=self.level)
|
||||
return self._c
|
||||
@@ -135,12 +142,23 @@ class Client(Logger):
|
||||
|
||||
@_autoclose
|
||||
def kill(self):
|
||||
"""Kills the remote ADB server"""
|
||||
"""Kills the remote ADB server"
|
||||
|
||||
>>> c=adb.protocol.Client()
|
||||
>>> c.kill()
|
||||
|
||||
The server is automatically re-started on the next request,
|
||||
if the default host/port are used.
|
||||
|
||||
>>> c.version() > (4,0)
|
||||
True
|
||||
"""
|
||||
try:
|
||||
self.send('host:kill')
|
||||
except EOFError:
|
||||
pass
|
||||
|
||||
@_autoclose
|
||||
def version(self):
|
||||
"""
|
||||
Returns:
|
||||
|
||||
+79
-20
@@ -1,5 +1,43 @@
|
||||
#!/usr/bin/env python2
|
||||
"""
|
||||
Pwntools exposes several magic command-line arguments and environment
|
||||
variables when operating in `from pwn import *` mode.
|
||||
|
||||
The arguments extracted from the command-line and removed from ``sys.argv``.
|
||||
|
||||
Arguments can be set by appending them to the command-line, or setting
|
||||
them in the environment prefixed by ``PWNLIB_``.
|
||||
|
||||
The easiest example is to enable more verbose debugging. Just set ``DEBUG``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ PWNLIB_DEBUG=1 python exploit.py
|
||||
$ python exploit.py DEBUG
|
||||
|
||||
These arguments are automatically extracted, regardless of their name, and
|
||||
exposed via ``pwnlib.args.args``, which is exposed as the global variable
|
||||
``args``. Arguments which ``pwntools`` reserves internally are not exposed
|
||||
this way.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python -c 'from pwn import *; print args' A=1 B=Hello HOST=1.2.3.4 DEBUG
|
||||
defaultdict(<type 'str'>, {'A': '1', 'HOST': '1.2.3.4', 'B': 'Hello'})
|
||||
|
||||
This is very useful for conditional code, for example determining whether to
|
||||
run an exploit locally or to connect to a remote server. Arguments which are
|
||||
not specified evaluate to an empty string.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
if args['REMOTE']:
|
||||
io = remote('exploitme.com', 4141)
|
||||
else:
|
||||
io = process('./pwnable')
|
||||
|
||||
The full list of supported "magic arguments" and their effects are listed
|
||||
below.
|
||||
"""
|
||||
import collections
|
||||
import logging
|
||||
@@ -42,46 +80,67 @@ def asbool(s):
|
||||
else:
|
||||
raise ValueError('must be integer or boolean: %r' % s)
|
||||
|
||||
def set_log_level(x):
|
||||
def LOG_LEVEL(x):
|
||||
"""Sets the logging verbosity used via ``context.log_level``,
|
||||
e.g. ``LOG_LEVEL=debug``.
|
||||
"""
|
||||
with context.local(log_level=x):
|
||||
context.defaults['log_level']=context.log_level
|
||||
|
||||
def set_log_file(x):
|
||||
def LOG_FILE(x):
|
||||
"""Sets a log file to be used via ``context.log_file``, e.g.
|
||||
``LOG_FILE=./log.txt``"""
|
||||
context.log_file=x
|
||||
|
||||
def set_log_level_error(x):
|
||||
set_log_level('error')
|
||||
def SILENT(x):
|
||||
"""Sets the logging verbosity to ``error`` which silences most
|
||||
output."""
|
||||
LOG_LEVEL('error')
|
||||
|
||||
def set_log_level_debug(x):
|
||||
set_log_level('debug')
|
||||
def DEBUG(x):
|
||||
"""Sets the logging verbosity to ``debug`` which displays much
|
||||
more information, including logging each byte sent by tubes."""
|
||||
LOG_LEVEL('debug')
|
||||
|
||||
def set_noterm(v):
|
||||
def NOTERM(v):
|
||||
"""Disables pretty terminal settings and animations."""
|
||||
if asbool(v):
|
||||
global term_mode
|
||||
term_mode = False
|
||||
|
||||
def set_timeout(v):
|
||||
def TIMEOUT(v):
|
||||
"""Sets a timeout for tube operations (in seconds) via
|
||||
``context.timeout``, e.g. ``TIMEOUT=30``"""
|
||||
context.defaults['timeout'] = int(v)
|
||||
|
||||
def set_randomize(v):
|
||||
def RANDOMIZE(v):
|
||||
"""Enables randomization of various pieces via ``context.randomize``"""
|
||||
context.defaults['randomize'] = asbool(v)
|
||||
|
||||
def set_aslr(v):
|
||||
def NOASLR(v):
|
||||
"""Disables ASLR via ``context.aslr``"""
|
||||
context.defaults['aslr'] = not asbool(v)
|
||||
|
||||
def set_noptrace(v):
|
||||
def NOPTRACE(v):
|
||||
"""Disables facilities which require ``ptrace`` such as ``gdb.attach()``
|
||||
statements, via ``context.noptrace``."""
|
||||
context.defaults['noptrace'] = asbool(v)
|
||||
|
||||
def STDERR(v):
|
||||
"""Sends logging to ``stderr`` by default, instead of ``stdout``"""
|
||||
context.log_console = sys.stderr
|
||||
|
||||
hooks = {
|
||||
'LOG_LEVEL': set_log_level,
|
||||
'LOG_FILE': set_log_file,
|
||||
'DEBUG': set_log_level_debug,
|
||||
'NOTERM': set_noterm,
|
||||
'SILENT': set_log_level_error,
|
||||
'RANDOMIZE': set_randomize,
|
||||
'TIMEOUT': set_timeout,
|
||||
'NOASLR': set_aslr,
|
||||
'NOPTRACE': set_noptrace,
|
||||
'LOG_LEVEL': LOG_LEVEL,
|
||||
'LOG_FILE': LOG_FILE,
|
||||
'DEBUG': DEBUG,
|
||||
'NOTERM': NOTERM,
|
||||
'SILENT': SILENT,
|
||||
'RANDOMIZE': RANDOMIZE,
|
||||
'TIMEOUT': TIMEOUT,
|
||||
'NOASLR': NOASLR,
|
||||
'NOPTRACE': NOPTRACE,
|
||||
'STDERR': STDERR,
|
||||
}
|
||||
|
||||
def initialize():
|
||||
|
||||
@@ -5,8 +5,6 @@ import sys
|
||||
import pwnlib
|
||||
from pwnlib.context import context
|
||||
|
||||
pwnlib.log.console.stream = sys.stderr
|
||||
|
||||
choices = map(str, [16,32,64])
|
||||
choices += list(context.oses)
|
||||
choices += list(context.architectures)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import sys
|
||||
|
||||
from . import asm
|
||||
from . import checksec
|
||||
from . import common
|
||||
@@ -14,6 +16,7 @@ from . import scramble
|
||||
from . import shellcraft
|
||||
from . import unhex
|
||||
from . import update
|
||||
from ..context import context
|
||||
from .common import parser
|
||||
|
||||
commands = {
|
||||
@@ -36,7 +39,8 @@ commands = {
|
||||
|
||||
def main():
|
||||
args = parser.parse_args()
|
||||
commands[args.command](args)
|
||||
with context.local(log_console = sys.stderr):
|
||||
commands[args.command](args)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -57,9 +57,10 @@ p.add_argument(
|
||||
'p',
|
||||
'i', 'hexii',
|
||||
'e', 'elf',
|
||||
'd', 'escaped',
|
||||
'default'],
|
||||
default = 'default',
|
||||
help = 'Output format (default: hex), choose from {r}aw, {s}tring, {c}-style array, {h}ex string, hex{i}i, {a}ssembly code, {p}reprocssed code',
|
||||
help = 'Output format (default: hex), choose from {e}lf, {r}aw, {s}tring, {c}-style array, {h}ex string, hex{i}i, {a}ssembly code, {p}reprocssed code, escape{d} hex string',
|
||||
)
|
||||
|
||||
p.add_argument(
|
||||
@@ -329,7 +330,8 @@ def main(args):
|
||||
code = pwnlib.util.fiddling.enhex(code) + '\n'
|
||||
elif args.format in ['i', 'hexii']:
|
||||
code = hexii(code) + '\n'
|
||||
|
||||
elif args.format in ['d', 'escaped']:
|
||||
code = ''.join('\\x%02x' % ord(c) for c in code) + '\n'
|
||||
if not sys.stdin.isatty():
|
||||
args.out.write(sys.stdin.read())
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ p.add_argument('--pre', action='store_true', help='''
|
||||
def main(a):
|
||||
result = pwnlib.update.perform_check(prerelease=a.pre)
|
||||
if a.install:
|
||||
subprocess.check_call(result, shell=True)
|
||||
subprocess.check_call(result, shell=False)
|
||||
|
||||
if __name__ == '__main__':
|
||||
pwnlib.common.main(__file__)
|
||||
@@ -330,11 +330,13 @@ class ContextType(object):
|
||||
'aslr': True,
|
||||
'binary': None,
|
||||
'bits': 32,
|
||||
'buffer_size': 4096,
|
||||
'device': os.getenv('ANDROID_SERIAL', None) or None,
|
||||
'endian': 'little',
|
||||
'kernel': None,
|
||||
'log_level': logging.INFO,
|
||||
'log_file': _devnull(),
|
||||
'log_console': sys.stdout,
|
||||
'randomize': False,
|
||||
'newline': '\n',
|
||||
'noptrace': False,
|
||||
@@ -923,6 +925,24 @@ class ContextType(object):
|
||||
value.flush()
|
||||
return value
|
||||
|
||||
@_validator
|
||||
def log_console(self, stream):
|
||||
"""
|
||||
Sets the default logging console target.
|
||||
|
||||
Examples:
|
||||
|
||||
>>> context.log_level = 'warn'
|
||||
>>> log.warn("Hello")
|
||||
[!] Hello
|
||||
>>> context.log_console=open('/dev/null', 'w')
|
||||
>>> log.warn("Hello")
|
||||
>>> context.clear()
|
||||
"""
|
||||
if isinstance(stream, str):
|
||||
stream = open(stream, 'wt')
|
||||
return stream
|
||||
|
||||
@property
|
||||
def mask(self):
|
||||
return (1 << self.bits) - 1
|
||||
@@ -1127,6 +1147,15 @@ class ContextType(object):
|
||||
|
||||
return command
|
||||
|
||||
@_validator
|
||||
def buffer_size(self, size):
|
||||
"""Internal buffer size to use for ``tube`` objects.
|
||||
|
||||
This is not the maximum size of the buffer, but this is the amount of data
|
||||
which is passed to each raw ``read`` syscall (or equivalent).
|
||||
"""
|
||||
return int(size)
|
||||
|
||||
@property
|
||||
def cache_dir(self):
|
||||
"""Directory used for caching data.
|
||||
@@ -1166,7 +1195,6 @@ class ContextType(object):
|
||||
|
||||
return cache
|
||||
|
||||
|
||||
#*************************************************************************
|
||||
# ALIASES
|
||||
#*************************************************************************
|
||||
|
||||
@@ -6,6 +6,7 @@ from elftools.common.py3compat import bytes2str
|
||||
from elftools.common.utils import roundup
|
||||
from elftools.common.utils import struct_parse
|
||||
from elftools.construct import CString
|
||||
|
||||
from ..context import context
|
||||
from ..log import getLogger
|
||||
from ..tubes.tube import tube
|
||||
|
||||
+18
-2
@@ -1,5 +1,6 @@
|
||||
"""Exposes functionality for manipulating ELF files
|
||||
"""
|
||||
import codecs
|
||||
import mmap
|
||||
import os
|
||||
import subprocess
|
||||
@@ -30,7 +31,18 @@ log = getLogger(__name__)
|
||||
|
||||
__all__ = ['load', 'ELF']
|
||||
|
||||
Function = namedtuple('Function', 'address size')
|
||||
class Function(object):
|
||||
def __init__(self, name, address, size):
|
||||
self.name = name
|
||||
self.address = address
|
||||
self.size = size
|
||||
def __repr__(self):
|
||||
return '%s(name=%r, address=%#x, size=%#x)' % (
|
||||
self.__class__.__name__,
|
||||
self.name,
|
||||
self.address,
|
||||
self.size
|
||||
)
|
||||
|
||||
def load(*args, **kwargs):
|
||||
"""Compatibility wrapper for pwntools v1"""
|
||||
@@ -348,11 +360,15 @@ class ELF(ELFFile):
|
||||
continue
|
||||
if sym.entry.st_info['type'] == 'STT_FUNC' and sym.entry.st_size != 0:
|
||||
name = sym.name
|
||||
try:
|
||||
name = codecs.encode(name, 'latin-1')
|
||||
except Exception:
|
||||
pass
|
||||
if name not in self.symbols:
|
||||
continue
|
||||
addr = self.symbols[name]
|
||||
size = sym.entry.st_size
|
||||
self.functions[name] = Function(addr, size)
|
||||
self.functions[name] = Function(name, addr, size)
|
||||
|
||||
def _populate_symbols(self):
|
||||
"""
|
||||
|
||||
+1
-1
@@ -3,8 +3,8 @@
|
||||
import os
|
||||
|
||||
from ..args import args
|
||||
from ..tubes.remote import remote
|
||||
from ..log import getLogger
|
||||
from ..tubes.remote import remote
|
||||
|
||||
env_server = args.get('FLAG_HOST', 'flag-submission-server').strip()
|
||||
env_port = args.get('FLAG_PORT', '31337').strip()
|
||||
|
||||
+8
-6
@@ -113,7 +113,7 @@ from .term import spinners
|
||||
from .term import text
|
||||
|
||||
# list of prefixes to use for the different message types. note that the `text`
|
||||
# module won't add any escape codes if `sys.stderr.isatty()` is `False`
|
||||
# module won't add any escape codes if `pwnlib.context.log_console.isatty()` is `False`
|
||||
_msgtype_prefixes = {
|
||||
'status' : [text.magenta, 'x'],
|
||||
'success' : [text.bold_green, '+'],
|
||||
@@ -489,10 +489,14 @@ class Handler(logging.StreamHandler):
|
||||
logger will not be emitted but rather an animated progress line will be
|
||||
created.
|
||||
|
||||
This handler outputs to ``sys.stderr``.
|
||||
|
||||
An instance of this handler is added to the ``'pwnlib'`` logger.
|
||||
"""
|
||||
@property
|
||||
def stream(self):
|
||||
return context.log_console
|
||||
@stream.setter
|
||||
def stream(self, value):
|
||||
pass
|
||||
def emit(self, record):
|
||||
"""
|
||||
Emit a log record or create/update an animated progress logger
|
||||
@@ -651,7 +655,7 @@ log_file.setFormatter(logging.Formatter(fmt, iso_8601))
|
||||
# logger.addHandler(myCoolPitchingHandler)
|
||||
#
|
||||
rootlogger = getLogger('pwnlib')
|
||||
console = Handler(sys.stdout)
|
||||
console = Handler()
|
||||
formatter = Formatter()
|
||||
console.setFormatter(formatter)
|
||||
|
||||
@@ -662,8 +666,6 @@ def install_default_handler():
|
||||
the ``pwnlib`` root logger. This function is automatically called from when
|
||||
importing :mod:`pwn`.
|
||||
'''
|
||||
console.stream = sys.stdout
|
||||
|
||||
logger = logging.getLogger('pwnlib')
|
||||
|
||||
if console not in logger.handlers:
|
||||
|
||||
@@ -606,3 +606,14 @@ class MemLeak(object):
|
||||
return result
|
||||
|
||||
return MemLeak(string_wrapper)
|
||||
|
||||
# Aliases for convenience
|
||||
u64 = q
|
||||
u32 = d
|
||||
u16 = w
|
||||
u8 = b
|
||||
|
||||
p64 = setq
|
||||
p32 = setd
|
||||
p16 = setw
|
||||
p8 = setb
|
||||
+5
-1
@@ -224,6 +224,8 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
|
||||
('mov', 'b', 'c'),
|
||||
('mov', 'c', 'x'),
|
||||
('mov', 'x', '1')]
|
||||
>>> regsort({'a': 'b', 'b': 'c'}, ['a','b','c'], xchg=0)
|
||||
[('mov', 'a', 'b'), ('mov', 'b', 'c')]
|
||||
"""
|
||||
if randomize is None:
|
||||
randomize = context.randomize
|
||||
@@ -333,7 +335,9 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
|
||||
# If XCHG is expressly disabled, and there is no temporary register,
|
||||
# try to see if there is any register which can be used as a temp
|
||||
# register instead.
|
||||
if not (xchg or tmp):
|
||||
#
|
||||
# If there are no cycles, there's no need for a temporary register.
|
||||
if in_cycle and not (xchg or tmp):
|
||||
for reg in in_out:
|
||||
if not depends_on_cycle(reg, in_out, in_cycle):
|
||||
tmp = reg
|
||||
|
||||
@@ -700,6 +700,9 @@ class ROP(object):
|
||||
# If we can find a function with that name, just call it
|
||||
if isinstance(resolvable, str):
|
||||
addr = self.resolve(resolvable)
|
||||
elif hasattr(resolvable, 'name') and hasattr(resolvable, 'address'):
|
||||
addr = resolvable.address
|
||||
resolvable = str(resolvable.name)
|
||||
else:
|
||||
addr = resolvable
|
||||
resolvable = ''
|
||||
|
||||
@@ -61,17 +61,26 @@ Example:
|
||||
mov rax, 0x1010110dfac01fe
|
||||
xor [rsp], rax
|
||||
pop rax
|
||||
>>> with context.local(os = 'linux'):
|
||||
... print shellcraft.amd64.mov('eax', 'SYS_read').rstrip()
|
||||
xor eax, eax /* (SYS_read) */
|
||||
>>> with context.local(os = 'freebsd'):
|
||||
... print shellcraft.amd64.mov('eax', 'SYS_read').rstrip()
|
||||
push (SYS_read) /* 3 */
|
||||
pop rax
|
||||
>>> with context.local(os = 'linux'):
|
||||
... print shellcraft.amd64.mov('eax', 'PROT_READ | PROT_WRITE | PROT_EXEC').rstrip()
|
||||
push (PROT_READ | PROT_WRITE | PROT_EXEC) /* 7 */
|
||||
pop rax
|
||||
>>> print shellcraft.amd64.mov('rax', 0xffffffff).rstrip()
|
||||
mov eax, 0xffffffff
|
||||
>>> print shellcraft.amd64.mov('rax', 0x7fffffff).rstrip()
|
||||
mov eax, 0x7fffffff
|
||||
>>> print shellcraft.amd64.mov('rax', 0x80010101).rstrip()
|
||||
mov eax, 0x80010101
|
||||
>>> print shellcraft.amd64.mov('rax', 0x80000000).rstrip()
|
||||
mov eax, 0x1010101 /* 2147483648 == 0x80000000 */
|
||||
xor eax, 0x81010101
|
||||
>>> with context.local(os = 'linux'):
|
||||
... print shellcraft.amd64.mov('eax', 'SYS_read').rstrip()
|
||||
xor eax, eax /* (SYS_read) */
|
||||
>>> with context.local(os = 'freebsd'):
|
||||
... print shellcraft.amd64.mov('eax', 'SYS_read').rstrip()
|
||||
push (SYS_read) /* 3 */
|
||||
pop rax
|
||||
>>> with context.local(os = 'linux'):
|
||||
... print shellcraft.amd64.mov('eax', 'PROT_READ | PROT_WRITE | PROT_EXEC').rstrip()
|
||||
push (PROT_READ | PROT_WRITE | PROT_EXEC) /* 7 */
|
||||
pop rax
|
||||
|
||||
Args:
|
||||
dest (str): The destination register.
|
||||
@@ -99,7 +108,6 @@ if get_register(src):
|
||||
if dest.size == 64 and src.size <= 32:
|
||||
dest = get_register(dest.native32)
|
||||
|
||||
src_size = src.size
|
||||
else:
|
||||
with ctx.local(arch = 'amd64'):
|
||||
src = eval(src)
|
||||
@@ -107,9 +115,9 @@ else:
|
||||
if not dest.fits(src):
|
||||
log.error("cannot mov %s, %r: dest is smaller than src" % (dest, src))
|
||||
|
||||
src_size = bits_required(src)
|
||||
orig_dest = dest
|
||||
|
||||
if dest.size == 64 and src_size <= 32:
|
||||
if dest.size == 64 and bits_required(src) <= 32:
|
||||
dest = get_register(dest.native32)
|
||||
|
||||
# Calculate the packed version
|
||||
@@ -117,7 +125,15 @@ else:
|
||||
|
||||
# Calculate the unsigned and signed versions
|
||||
srcu = packing.unpack(srcp, dest.size, sign=False)
|
||||
srcs = packing.unpack(srcp, dest.size, sign=True)
|
||||
|
||||
# N.B.: We may have downsized the register for e.g. mov('rax', 0xffffffff)
|
||||
# In this case, srcp is now a 4-byte packed value, which will expand
|
||||
# to "-1", which isn't correct.
|
||||
if orig_dest.size != dest.size:
|
||||
srcs = src
|
||||
else:
|
||||
srcs = packing.unpack(srcp, dest.size, sign=True)
|
||||
|
||||
%>\
|
||||
% if is_register(src):
|
||||
% if src == dest:
|
||||
|
||||
@@ -6,8 +6,8 @@ in the same order.
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rbp
|
||||
pop rsp
|
||||
pop rbp
|
||||
pop rbx /* add rsp, 8 */
|
||||
pop rbx
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rax
|
||||
@@ -22,6 +22,7 @@ import threading
|
||||
import traceback
|
||||
|
||||
from . import termcap
|
||||
from ..context import ContextType
|
||||
|
||||
settings = None
|
||||
_graphics_mode = False
|
||||
@@ -127,6 +128,11 @@ def init():
|
||||
sys.stdout = Wrapper(sys.stdout)
|
||||
if sys.stderr.isatty():
|
||||
sys.stderr = Wrapper(sys.stderr)
|
||||
|
||||
console = ContextType.defaults['log_console']
|
||||
if console.isatty():
|
||||
ContextType.defaults['log_console'] = Wrapper(console)
|
||||
|
||||
# freeze all cells if an exception is thrown
|
||||
orig_hook = sys.excepthook
|
||||
def hook(*args):
|
||||
|
||||
+21
-2
@@ -1,5 +1,8 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
from ..context import context
|
||||
|
||||
|
||||
class Buffer(Exception):
|
||||
"""
|
||||
List of strings with some helper routines.
|
||||
@@ -28,10 +31,10 @@ class Buffer(Exception):
|
||||
The ``0th`` item in the buffer is the oldest item, and
|
||||
will be received first.
|
||||
"""
|
||||
def __init__(self):
|
||||
def __init__(self, buffer_fill_size = None):
|
||||
self.data = [] # Buffer
|
||||
self.size = 0 # Length
|
||||
|
||||
self.buffer_fill_size = buffer_fill_size
|
||||
|
||||
def __len__(self):
|
||||
"""
|
||||
@@ -169,3 +172,19 @@ class Buffer(Exception):
|
||||
self.size -= len(data)
|
||||
|
||||
return data
|
||||
|
||||
def get_fill_size(self, size=None):
|
||||
"""
|
||||
Retrieves the default fill size for this buffer class.
|
||||
|
||||
Arguments:
|
||||
size (int): (Optional) If set and not None, returns the size variable back.
|
||||
|
||||
Returns:
|
||||
Fill size as integer if size == None, else size.
|
||||
"""
|
||||
if size is None:
|
||||
size = self.buffer_fill_size
|
||||
|
||||
with context.local(buffer_size=size):
|
||||
return context.buffer_size
|
||||
@@ -20,13 +20,11 @@ class listen(sock):
|
||||
bindaddr(str): The address to bind to.
|
||||
fam: The string "any", "ipv4" or "ipv6" or an integer to pass to :func:`socket.getaddrinfo`.
|
||||
typ: The string "tcp" or "udp" or an integer to pass to :func:`socket.getaddrinfo`.
|
||||
timeout: A positive number, None
|
||||
"""
|
||||
|
||||
def __init__(self, port=0, bindaddr = "0.0.0.0",
|
||||
fam = "any", typ = "tcp",
|
||||
timeout = Timeout.default, level = None):
|
||||
super(listen, self).__init__(timeout, level = level)
|
||||
fam = "any", typ = "tcp", *args, **kwargs):
|
||||
super(listen, self).__init__(*args, **kwargs)
|
||||
|
||||
port = int(port)
|
||||
fam = {socket.AF_INET: 'ipv4',
|
||||
|
||||
+15
-8
@@ -44,8 +44,6 @@ class process(tube):
|
||||
Working directory. Uses the current working directory by default.
|
||||
env(dict):
|
||||
Environment variables. By default, inherits from Python's environment.
|
||||
timeout(int):
|
||||
Timeout to use on ``tube`` ``recv`` operations.
|
||||
stdin(int):
|
||||
File object or file descriptor number to use for ``stdin``.
|
||||
By default, a pipe is used. A pty can be used instead by setting
|
||||
@@ -201,16 +199,14 @@ class process(tube):
|
||||
#: Have we seen the process stop?
|
||||
_stop_noticed = False
|
||||
|
||||
def __init__(self, argv,
|
||||
def __init__(self, argv = None,
|
||||
shell = False,
|
||||
executable = None,
|
||||
cwd = None,
|
||||
env = None,
|
||||
timeout = Timeout.default,
|
||||
stdin = PIPE,
|
||||
stdout = PTY,
|
||||
stderr = STDOUT,
|
||||
level = None,
|
||||
close_fds = True,
|
||||
preexec_fn = lambda: None,
|
||||
raw = True,
|
||||
@@ -218,8 +214,19 @@ class process(tube):
|
||||
setuid = None,
|
||||
where = 'local',
|
||||
display = None,
|
||||
alarm = None):
|
||||
super(process, self).__init__(timeout, level = level)
|
||||
alarm = None,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
super(process, self).__init__(*args,**kwargs)
|
||||
|
||||
# Permit using context.binary
|
||||
if argv is None:
|
||||
if context.binary:
|
||||
argv = [context.binary.path]
|
||||
else:
|
||||
raise TypeError('Must provide argv or set context.binary')
|
||||
|
||||
|
||||
#: `subprocess.Popen` object
|
||||
self.proc = None
|
||||
@@ -786,7 +793,7 @@ class process(tube):
|
||||
import pwnlib.elf.corefile
|
||||
return pwnlib.elf.corefile.Core(filename)
|
||||
|
||||
def leak(self, address, count=0):
|
||||
def leak(self, address, count=1):
|
||||
"""Leaks memory within the process at the specified address.
|
||||
|
||||
Arguments:
|
||||
|
||||
+6
-10
@@ -45,8 +45,8 @@ class remote(sock):
|
||||
|
||||
def __init__(self, host, port,
|
||||
fam = "any", typ = "tcp",
|
||||
timeout = Timeout.default, ssl=False, sock=None, level = None):
|
||||
super(remote, self).__init__(timeout, level = level)
|
||||
ssl=False, sock=None, *args, **kwargs):
|
||||
super(remote, self).__init__(*args, **kwargs)
|
||||
|
||||
self.rport = int(port)
|
||||
self.rhost = host
|
||||
@@ -150,17 +150,13 @@ class remote(sock):
|
||||
|
||||
class tcp(remote):
|
||||
__doc__ = remote.__doc__
|
||||
def __init__(self, host, port,
|
||||
fam = "any", typ = "tcp",
|
||||
timeout = Timeout.default, ssl=False, sock=None, level = None):
|
||||
return super(tcp, self).__init__(host, port, fam, typ, timeout, ssl, sock, level)
|
||||
def __init__(self, host, port, *a, **kw):
|
||||
return super(tcp, self).__init__(host, port, typ="tcp", *a, **kw)
|
||||
|
||||
class udp(remote):
|
||||
__doc__ = remote.__doc__
|
||||
def __init__(self, host, port,
|
||||
fam = "any", typ = "udp",
|
||||
timeout = Timeout.default, ssl=False, sock=None, level = None):
|
||||
return super(udp, self).__init__(host, port, fam, typ, timeout, ssl, sock, level)
|
||||
def __init__(self, host, port, *a, **kw):
|
||||
return super(udp, self).__init__(host, port, typ="udp", *a, **kw)
|
||||
|
||||
class connect(remote):
|
||||
__doc__ = remote.__doc__
|
||||
+14
-23
@@ -9,7 +9,6 @@ from . import tube
|
||||
from .. import context
|
||||
from .. import term
|
||||
from ..log import getLogger
|
||||
from ..timeout import Timeout
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
@@ -18,10 +17,8 @@ class serialtube(tube.tube):
|
||||
self, port = None, baudrate = 115200,
|
||||
convert_newlines = True,
|
||||
bytesize = 8, parity='N', stopbits=1, xonxoff = False,
|
||||
rtscts = False, dsrdtr = False,
|
||||
timeout = Timeout.default,
|
||||
level = None):
|
||||
super(serialtube, self).__init__(timeout, level = level)
|
||||
rtscts = False, dsrdtr = False, *a, **kw):
|
||||
super(serialtube, self).__init__(*a, **kw)
|
||||
|
||||
if port is None:
|
||||
if platform.system() == 'Darwin':
|
||||
@@ -49,21 +46,14 @@ class serialtube(tube.tube):
|
||||
if not self.conn:
|
||||
raise EOFError
|
||||
|
||||
if self.timeout == None:
|
||||
end = float('inf')
|
||||
else:
|
||||
end = time.time() + self.timeout
|
||||
with self.countdown():
|
||||
while self.conn and self.countdown_active():
|
||||
data = self.conn.read(numb)
|
||||
|
||||
while self.conn:
|
||||
data = self.conn.read(numb)
|
||||
if data:
|
||||
return data
|
||||
if data:
|
||||
return data
|
||||
|
||||
delta = end - time.time()
|
||||
if delta <= 0:
|
||||
break
|
||||
else:
|
||||
time.sleep(min(delta, 0.1))
|
||||
time.sleep(min(self.timeout, 0.1))
|
||||
|
||||
return None
|
||||
|
||||
@@ -83,10 +73,11 @@ class serialtube(tube.tube):
|
||||
pass
|
||||
|
||||
def can_recv_raw(self, timeout):
|
||||
end = time.time()
|
||||
while time.time() < end:
|
||||
if self.conn.inWaiting():
|
||||
return True
|
||||
with self.countdown(timeout):
|
||||
while self.conn and self.countdown_active():
|
||||
if self.conn.inWaiting():
|
||||
return True
|
||||
time.sleep(min(self.timeout, 0.1))
|
||||
return False
|
||||
|
||||
def connected_raw(self, direction):
|
||||
@@ -99,7 +90,7 @@ class serialtube(tube.tube):
|
||||
|
||||
def fileno(self):
|
||||
if not self.connected():
|
||||
self.error("A stopped program does not have a file number")
|
||||
self.error("A closed serialtube does not have a file number")
|
||||
|
||||
return self.conn.fileno()
|
||||
|
||||
|
||||
+79
-11
@@ -10,8 +10,8 @@ log = getLogger(__name__)
|
||||
class sock(tube):
|
||||
"""Methods available exclusively to sockets."""
|
||||
|
||||
def __init__(self, timeout, level = None):
|
||||
super(sock, self).__init__(timeout, level = level)
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(sock, self).__init__(*args, **kwargs)
|
||||
self.closed = {"recv": False, "send": False}
|
||||
|
||||
# Overwritten for better usability
|
||||
@@ -26,13 +26,13 @@ class sock(tube):
|
||||
else:
|
||||
return super(sock, self).recvall(timeout)
|
||||
|
||||
def recv_raw(self, numb):
|
||||
def recv_raw(self, numb, *a):
|
||||
if self.closed["recv"]:
|
||||
raise EOFError
|
||||
|
||||
while True:
|
||||
try:
|
||||
data = self.sock.recv(numb)
|
||||
data = self.sock.recv(numb, *a)
|
||||
break
|
||||
except socket.timeout:
|
||||
return None
|
||||
@@ -72,21 +72,89 @@ class sock(tube):
|
||||
self.sock.settimeout(timeout)
|
||||
|
||||
def can_recv_raw(self, timeout):
|
||||
"""
|
||||
Tests:
|
||||
|
||||
>>> l = listen()
|
||||
>>> r = remote('localhost', l.lport)
|
||||
>>> r.can_recv_raw(timeout=0)
|
||||
False
|
||||
>>> l.send('a')
|
||||
>>> r.can_recv_raw(timeout=1)
|
||||
True
|
||||
>>> r.recv()
|
||||
'a'
|
||||
>>> r.can_recv_raw(timeout=0)
|
||||
False
|
||||
>>> l.close()
|
||||
>>> r.can_recv_raw(timeout=1)
|
||||
False
|
||||
>>> r.closed['recv']
|
||||
True
|
||||
"""
|
||||
if not self.sock or self.closed["recv"]:
|
||||
return False
|
||||
|
||||
return select.select([self.sock], [], [], timeout) == ([self.sock], [], [])
|
||||
# select() will tell us data is available at EOF
|
||||
can_recv = select.select([self.sock], [], [], timeout) == ([self.sock], [], [])
|
||||
|
||||
if not can_recv:
|
||||
return False
|
||||
|
||||
# Ensure there's actually data, not just EOF
|
||||
try:
|
||||
self.recv_raw(1, socket.MSG_PEEK)
|
||||
except EOFError:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def connected_raw(self, direction):
|
||||
"""
|
||||
Tests:
|
||||
|
||||
>>> l = listen()
|
||||
>>> r = remote('localhost', l.lport)
|
||||
>>> r.connected()
|
||||
True
|
||||
>>> l.close()
|
||||
>>> time.sleep(1) # Avoid race condition
|
||||
>>> r.connected()
|
||||
False
|
||||
"""
|
||||
# If there's no socket, it's definitely closed
|
||||
if not self.sock:
|
||||
return False
|
||||
|
||||
if direction == 'any':
|
||||
return True
|
||||
elif direction == 'recv':
|
||||
return not self.closed['recv']
|
||||
elif direction == 'send':
|
||||
return not self.closed['send']
|
||||
# If we have noticed a connection close in a given direction before,
|
||||
# return fast.
|
||||
if self.closed.get(direction, False):
|
||||
return False
|
||||
|
||||
# If a connection is closed in all manners, return fast
|
||||
if all(self.closed.values()):
|
||||
return False
|
||||
|
||||
# Use poll() to determine the connection state
|
||||
want = {
|
||||
'recv': select.POLLIN,
|
||||
'send': select.POLLOUT,
|
||||
'any': select.POLLIN | select.POLLOUT,
|
||||
}[direction]
|
||||
|
||||
poll = select.poll()
|
||||
poll.register(self, want | select.POLLHUP | select.POLLERR)
|
||||
|
||||
for fd, event in poll.poll(0):
|
||||
if event & select.POLLHUP:
|
||||
self.close()
|
||||
return False
|
||||
if event & select.POLLIN:
|
||||
return True
|
||||
if event & select.POLLOUT:
|
||||
return True
|
||||
|
||||
return True
|
||||
|
||||
def close(self):
|
||||
if not getattr(self, 'sock', None):
|
||||
|
||||
+38
-18
@@ -59,7 +59,7 @@ class ssh_channel(sock):
|
||||
#: Only valid when instantiated through :meth:`ssh.process`
|
||||
pid = None
|
||||
|
||||
#: Executable of the process
|
||||
#: Executable of the procesks
|
||||
#: Only valid when instantiated through :meth:`ssh.process`
|
||||
executable = None
|
||||
|
||||
@@ -67,8 +67,8 @@ class ssh_channel(sock):
|
||||
#: Only valid when instantiated through :meth:`ssh.process`
|
||||
argv = None
|
||||
|
||||
def __init__(self, parent, process = None, tty = False, wd = None, env = None, timeout = Timeout.default, level = 0, raw = True):
|
||||
super(ssh_channel, self).__init__(timeout, level=level)
|
||||
def __init__(self, parent, process = None, tty = False, wd = None, env = None, raw = True, *args, **kwargs):
|
||||
super(ssh_channel, self).__init__(*args, **kwargs)
|
||||
|
||||
# keep the parent from being garbage collected in some cases
|
||||
self.parent = parent
|
||||
@@ -191,11 +191,11 @@ class ssh_channel(sock):
|
||||
return self.returncode
|
||||
|
||||
def can_recv_raw(self, timeout):
|
||||
end = time.time() + timeout
|
||||
while time.time() < end:
|
||||
if self.sock.recv_ready():
|
||||
return True
|
||||
time.sleep(0.05)
|
||||
with self.countdown(timeout):
|
||||
while self.countdown_active():
|
||||
if self.sock.recv_ready():
|
||||
return True
|
||||
time.sleep(min(self.timeout, 0.05))
|
||||
return False
|
||||
|
||||
def interactive(self, prompt = term.text.bold_red('$') + ' '):
|
||||
@@ -366,8 +366,8 @@ class ssh_channel(sock):
|
||||
return e
|
||||
|
||||
class ssh_connecter(sock):
|
||||
def __init__(self, parent, host, port, timeout = Timeout.default, level = None):
|
||||
super(ssh_connecter, self).__init__(timeout, level = level)
|
||||
def __init__(self, parent, host, port, *a, **kw):
|
||||
super(ssh_connecter, self).__init__(*a, **kw)
|
||||
|
||||
# keep the parent from being garbage collected in some cases
|
||||
self.parent = parent
|
||||
@@ -398,8 +398,8 @@ class ssh_connecter(sock):
|
||||
|
||||
|
||||
class ssh_listener(sock):
|
||||
def __init__(self, parent, bind_address, port, timeout = Timeout.default, level = None):
|
||||
super(ssh_listener, self).__init__(timeout, level = level)
|
||||
def __init__(self, parent, bind_address, port, *a, **kw):
|
||||
super(ssh_listener, self).__init__(*a, **kw)
|
||||
|
||||
# keep the parent from being garbage collected in some cases
|
||||
self.parent = parent
|
||||
@@ -478,8 +478,7 @@ class ssh(Timeout, Logger):
|
||||
|
||||
def __init__(self, user, host, port = 22, password = None, key = None,
|
||||
keyfile = None, proxy_command = None, proxy_sock = None,
|
||||
timeout = Timeout.default, level = None, cache = True,
|
||||
ssh_agent = False):
|
||||
level = None, cache = True, ssh_agent = False, *a, **kw):
|
||||
"""Creates a new ssh connection.
|
||||
|
||||
Arguments:
|
||||
@@ -498,7 +497,7 @@ class ssh(Timeout, Logger):
|
||||
|
||||
NOTE: The proxy_command and proxy_sock arguments is only available if a
|
||||
fairly new version of paramiko is used."""
|
||||
super(ssh, self).__init__(timeout)
|
||||
super(ssh, self).__init__(*a, **kw)
|
||||
|
||||
Logger.__init__(self)
|
||||
if level is not None:
|
||||
@@ -623,7 +622,8 @@ class ssh(Timeout, Logger):
|
||||
return self.run(shell, tty, timeout = timeout)
|
||||
|
||||
def process(self, argv=None, executable=None, tty=True, cwd=None, env=None, timeout=Timeout.default, run=True,
|
||||
stdin=0, stdout=1, stderr=2, preexec_fn=None, preexec_args=[], raw=True, aslr=None, setuid=None):
|
||||
stdin=0, stdout=1, stderr=2, preexec_fn=None, preexec_args=[], raw=True, aslr=None, setuid=None,
|
||||
shell=False):
|
||||
r"""
|
||||
Executes a process on the remote server, in the same fashion
|
||||
as pwnlib.tubes.process.process.
|
||||
@@ -680,6 +680,8 @@ class ssh(Timeout, Logger):
|
||||
See ``pwnlib.tubes.process.process`` for more information.
|
||||
setuid(bool):
|
||||
See ``pwnlib.tubes.process.process`` for more information.
|
||||
shell(bool):
|
||||
Pass the command-line arguments to the shell.
|
||||
|
||||
Returns:
|
||||
A new SSH channel, or a path to a script if ``run=False``.
|
||||
@@ -737,6 +739,9 @@ class ssh(Timeout, Logger):
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
NameError: global name 'bar' is not defined
|
||||
|
||||
>>> s.process('echo hello', shell=True).recvall()
|
||||
'hello\n'
|
||||
"""
|
||||
if not argv and not executable:
|
||||
self.error("Must specify argv or executable")
|
||||
@@ -750,6 +755,11 @@ class ssh(Timeout, Logger):
|
||||
if not isinstance(argv, (list, tuple)):
|
||||
self.error('argv must be a list or tuple')
|
||||
|
||||
if shell:
|
||||
if len(argv) != 1:
|
||||
self.error('Cannot provide more than 1 argument if shell=True')
|
||||
argv = ['/bin/sh', '-c'] + argv
|
||||
|
||||
# Python doesn't like when an arg in argv contains '\x00'
|
||||
# -> execve() arg 2 must contain only strings
|
||||
for i, arg in enumerate(argv):
|
||||
@@ -862,6 +872,13 @@ if not %(aslr)r:
|
||||
|
||||
resource.setrlimit(resource.RLIMIT_STACK, (-1, -1))
|
||||
|
||||
# Attempt to dump ALL core file regions
|
||||
try:
|
||||
with open('/proc/self/coredump_filter', 'w') as core_filter:
|
||||
core_filter.write('0x3f\n')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Assume that the user would prefer to have core dumps.
|
||||
resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
|
||||
|
||||
@@ -941,7 +958,7 @@ os.execve(exe, argv, os.environ)
|
||||
|
||||
return result
|
||||
|
||||
def system(self, process, tty = True, wd = None, env = None, timeout = Timeout.default, raw = True):
|
||||
def system(self, process, tty = True, wd = None, env = None, timeout = None, raw = True):
|
||||
r"""system(process, tty = True, wd = None, env = None, timeout = Timeout.default, raw = True) -> ssh_channel
|
||||
|
||||
Open a new channel with a specific process inside. If `tty` is True,
|
||||
@@ -967,7 +984,10 @@ os.execve(exe, argv, os.environ)
|
||||
if wd is None:
|
||||
wd = self.cwd
|
||||
|
||||
return ssh_channel(self, process, tty, wd, env, timeout, level = self.level, raw = raw)
|
||||
if timeout is None:
|
||||
timeout = self.timeout
|
||||
|
||||
return ssh_channel(self, process, tty, wd, env, timeout = timeout, level = self.level, raw = raw)
|
||||
|
||||
#: Backward compatibility. Use :meth:`system`
|
||||
run = system
|
||||
|
||||
+36
-5
@@ -30,18 +30,18 @@ class tube(Timeout, Logger):
|
||||
#: and related functions.
|
||||
newline = '\n'
|
||||
|
||||
def __init__(self, timeout = default, level = None):
|
||||
def __init__(self, timeout = default, level = None, *a, **kw):
|
||||
super(tube, self).__init__(timeout)
|
||||
|
||||
Logger.__init__(self, None)
|
||||
if level is not None:
|
||||
self.setLevel(level)
|
||||
|
||||
self.buffer = Buffer()
|
||||
self.buffer = Buffer(*a, **kw)
|
||||
atexit.register(self.close)
|
||||
|
||||
# Functions based on functions from subclasses
|
||||
def recv(self, numb = 4096, timeout = default):
|
||||
def recv(self, numb = None, timeout = default):
|
||||
r"""recv(numb = 4096, timeout = default) -> str
|
||||
|
||||
Receives up to `numb` bytes of data from the tube, and returns
|
||||
@@ -72,6 +72,7 @@ class tube(Timeout, Logger):
|
||||
[...] Received 0xc bytes:
|
||||
'Hello, world'
|
||||
"""
|
||||
numb = self.buffer.get_fill_size(numb)
|
||||
return self._recv(numb, timeout) or ''
|
||||
|
||||
def unrecv(self, data):
|
||||
@@ -122,7 +123,7 @@ class tube(Timeout, Logger):
|
||||
data = ''
|
||||
|
||||
with self.local(timeout):
|
||||
data = self.recv_raw(4096)
|
||||
data = self.recv_raw(self.buffer.get_fill_size())
|
||||
|
||||
if data and self.isEnabledFor(logging.DEBUG):
|
||||
self.debug('Received %#x bytes:' % len(data))
|
||||
@@ -141,12 +142,13 @@ class tube(Timeout, Logger):
|
||||
return data
|
||||
|
||||
|
||||
def _recv(self, numb = 4096, timeout = default):
|
||||
def _recv(self, numb = None, timeout = default):
|
||||
"""_recv(numb = 4096, timeout = default) -> str
|
||||
|
||||
Receives one chunk of from the internal buffer or from the OS if the
|
||||
buffer is empty.
|
||||
"""
|
||||
numb = self.buffer.get_fill_size(numb)
|
||||
data = ''
|
||||
|
||||
# No buffered data, could not put anything in the buffer
|
||||
@@ -826,6 +828,35 @@ class tube(Timeout, Logger):
|
||||
while t.is_alive():
|
||||
t.join(timeout = 0.1)
|
||||
|
||||
def stream(self, line_mode=True):
|
||||
"""stream()
|
||||
|
||||
Receive data until the tube exits, and print it to stdout.
|
||||
|
||||
Similar to :func:`interactive`, except that no input is sent.
|
||||
|
||||
Similar to ``print tube.recvall()`` except that data is printed
|
||||
as it is received, rather than after all data is received.
|
||||
|
||||
Arguments:
|
||||
line_mode(bool): Whether to receive line-by-line or raw data.
|
||||
|
||||
Returns:
|
||||
All data printed.
|
||||
"""
|
||||
buf = Buffer()
|
||||
function = self.recvline if line_mode else self.recv
|
||||
try:
|
||||
while True:
|
||||
buf.add(function())
|
||||
sys.stdout.write(buf.data[-1])
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
except EOFError:
|
||||
pass
|
||||
|
||||
return buf.get()
|
||||
|
||||
def clean(self, timeout = 0.05):
|
||||
"""clean(timeout = 0.05)
|
||||
|
||||
|
||||
+92
-11
@@ -1,10 +1,10 @@
|
||||
"""Module for calculating CRC-sums.
|
||||
|
||||
Contains all crc implementations know on the interwebz. For most implementations it
|
||||
contains only the core crc algorithm and not e.g. padding schemes.
|
||||
Contains all crc implementations know on the interwebz. For most implementations
|
||||
it contains only the core crc algorithm and not e.g. padding schemes.
|
||||
|
||||
It is horribly slow, as implements a naive algorithm working direclty on
|
||||
bit polynomials.
|
||||
bit polynomials. This class is exposed as `BitPolynom`.
|
||||
|
||||
The current algorithm is super-linear and takes about 4 seconds to calculate
|
||||
the crc32-sum of ``'A'*40000``.
|
||||
@@ -18,15 +18,70 @@ import types
|
||||
from . import known
|
||||
from .. import fiddling
|
||||
from .. import packing
|
||||
from .. import safeeval
|
||||
|
||||
|
||||
class BitPolynom(object):
|
||||
"""Class for representing GF(2)[X], i.e. the field of polynomials over
|
||||
GF(2).
|
||||
|
||||
In practice the polynomials are represented as numbers such that `x**n`
|
||||
corresponds to `1 << n`. In this representation calculations are easy: Just
|
||||
do everything as normal, but forget about everything the carries.
|
||||
|
||||
Addition becomes xor and multiplication becomes carry-less multiplication.
|
||||
|
||||
Examples:
|
||||
|
||||
>>> p1 = BitPolynom("x**3 + x + 1")
|
||||
>>> p1
|
||||
BitPolynom('x**3 + x + 1')
|
||||
>>> int(p1)
|
||||
11
|
||||
>>> p1 == BitPolynom(11)
|
||||
True
|
||||
>>> p2 = BitPolynom("x**2 + x + 1")
|
||||
>>> p1 + p2
|
||||
BitPolynom('x**3 + x**2')
|
||||
>>> p1 * p2
|
||||
BitPolynom('x**5 + x**4 + 1')
|
||||
>>> p1 / p2
|
||||
BitPolynom('x + 1')
|
||||
>>> p1 % p2
|
||||
BitPolynom('x')
|
||||
>>> d, r = divmod(p1, p2)
|
||||
>>> d * p2 + r == p1
|
||||
True
|
||||
>>> BitPolynom(-1)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Polynomials cannot be negative: -1
|
||||
>>> BitPolynom('y')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Not a valid polynomial: y
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, n):
|
||||
if not isinstance(n, (int, long)):
|
||||
raise TypeError("Polynomial must be called with an integer or a list")
|
||||
if n < 0:
|
||||
raise ValueError("Polynomials cannot be negative: %d" % n)
|
||||
self.n = n
|
||||
if isinstance(n, (str, unicode)):
|
||||
self.n = 0
|
||||
x = BitPolynom(2)
|
||||
try:
|
||||
for p in n.split('+'):
|
||||
k = safeeval.values(p.strip(), {'x': x, 'X': x})
|
||||
assert isinstance(k, (BitPolynom, int, long))
|
||||
assert k >= 0
|
||||
self.n ^= int(k)
|
||||
except (ValueError, NameError, AssertionError):
|
||||
raise ValueError("Not a valid polynomial: %s" % n)
|
||||
elif isinstance(n, (int, long)):
|
||||
if n >= 0:
|
||||
self.n = n
|
||||
else:
|
||||
raise ValueError("Polynomials cannot be negative: %d" % n)
|
||||
else:
|
||||
raise TypeError("Polynomial must be called with a string or integer")
|
||||
|
||||
def __int__(self):
|
||||
return self.n
|
||||
@@ -126,7 +181,30 @@ class BitPolynom(object):
|
||||
def __rrshift__(self, other):
|
||||
return BitPolynom(int(other) >> int(self))
|
||||
|
||||
def __pow__(self, other):
|
||||
r = BitPolynom(1)
|
||||
for _ in range(other):
|
||||
r *= self
|
||||
return r
|
||||
|
||||
def degree(self):
|
||||
"""Returns the degree of the polynomial.
|
||||
|
||||
Examples:
|
||||
|
||||
>>> BitPolynom(0).degree()
|
||||
0
|
||||
>>> BitPolynom(1).degree()
|
||||
0
|
||||
>>> BitPolynom(2).degree()
|
||||
1
|
||||
>>> BitPolynom(7).degree()
|
||||
2
|
||||
>>> BitPolynom((1 << 10) - 1).degree()
|
||||
9
|
||||
>>> BitPolynom(1 << 10).degree()
|
||||
10
|
||||
"""
|
||||
return max(0, int(self).bit_length()-1)
|
||||
|
||||
def __repr__(self):
|
||||
@@ -134,17 +212,20 @@ class BitPolynom(object):
|
||||
return '0'
|
||||
|
||||
out = []
|
||||
for n in range(self.degree(), 0, -1):
|
||||
for n in range(self.degree(), 1, -1):
|
||||
if int(self) & (1 << n):
|
||||
out.append("x**%d" % n)
|
||||
if int(self) & 2:
|
||||
out.append("x")
|
||||
if int(self) & 1:
|
||||
out.append("1")
|
||||
return ' + '.join(out)
|
||||
return 'BitPolynom(%r)' % ' + '.join(out)
|
||||
|
||||
class Module(types.ModuleType):
|
||||
def __init__(self):
|
||||
super(Module, self).__init__(__name__)
|
||||
self._cached_crcs = None
|
||||
self.BitPolynom = BitPolynom
|
||||
self.__dict__.update({
|
||||
'__file__' : __file__,
|
||||
'__package__' : __package__,
|
||||
@@ -154,7 +235,7 @@ class Module(types.ModuleType):
|
||||
crcs = known.all_crcs
|
||||
|
||||
if attr == '__all__':
|
||||
return ['generic_crc', 'cksum', 'find_crc_function'] + sorted(crcs.keys())
|
||||
return ['BitPolynom', 'generic_crc', 'cksum', 'find_crc_function'] + sorted(crcs.keys())
|
||||
|
||||
info = crcs.get(attr, None)
|
||||
if not info:
|
||||
|
||||
+99
-5
@@ -43,8 +43,8 @@ def de_bruijn(alphabet = string.ascii_lowercase, n = None):
|
||||
def cyclic(length = None, alphabet = string.ascii_lowercase, n = None):
|
||||
"""cyclic(length = None, alphabet = string.ascii_lowercase, n = 4) -> list/str
|
||||
|
||||
A simple wrapper over :func:`de_bruijn`. This function returns a
|
||||
at most `length` elements.
|
||||
A simple wrapper over :func:`de_bruijn`. This function returns at most
|
||||
`length` elements.
|
||||
|
||||
If the given alphabet is a string, a string is returned from this function. Otherwise
|
||||
a list is returned.
|
||||
@@ -66,6 +66,10 @@ def cyclic(length = None, alphabet = string.ascii_lowercase, n = None):
|
||||
if n is None:
|
||||
n = 4
|
||||
|
||||
if len(alphabet) ** n < length:
|
||||
log.error("Can't create a pattern length=%i with len(alphabet)==%i and n==%i" \
|
||||
% (length, len(alphabet), n))
|
||||
|
||||
out = []
|
||||
for ndx, c in enumerate(de_bruijn(alphabet, n)):
|
||||
if length != None and ndx >= length:
|
||||
@@ -93,8 +97,8 @@ def cyclic_find(subseq, alphabet = string.ascii_lowercase, n = None):
|
||||
https://www.sciencedirect.com/science/article/pii/S0012365X00001175
|
||||
|
||||
Arguments:
|
||||
subseq: The subsequence to look for. This can either be a string, a list
|
||||
or an integer. If an integer is provided it will be packed as a
|
||||
subseq: The subsequence to look for. This can be a string, a list or an
|
||||
integer. If an integer is provided it will be packed as a
|
||||
little endian integer.
|
||||
alphabet: List or string to generate the sequence over.
|
||||
n(int): The length of subsequences that should be unique.
|
||||
@@ -124,8 +128,98 @@ def cyclic_find(subseq, alphabet = string.ascii_lowercase, n = None):
|
||||
|
||||
return _gen_find(subseq, de_bruijn(alphabet, n))
|
||||
|
||||
def metasploit_pattern(sets = None):
|
||||
"""metasploit_pattern(sets = [ string.ascii_uppercase, string.ascii_lowercase, string.digits ]) -> generator
|
||||
|
||||
Generator for a sequence of characters as per Metasploit Framework's
|
||||
`Rex::Text.pattern_create` (aka `pattern_create.rb`).
|
||||
|
||||
The returned generator will yield up to
|
||||
``len(sets) * reduce(lambda x,y: x*y, map(len, sets))`` elements.
|
||||
|
||||
Arguments:
|
||||
sets: List of strings to generate the sequence over.
|
||||
"""
|
||||
sets = sets or [ string.ascii_uppercase, string.ascii_lowercase, string.digits ]
|
||||
offsets = [ 0 ] * len(sets)
|
||||
offsets_indexes_reversed = list(reversed(range(len(offsets))))
|
||||
|
||||
while True:
|
||||
for i, j in zip(sets, offsets):
|
||||
yield i[j]
|
||||
# increment offsets with cascade
|
||||
for i in offsets_indexes_reversed:
|
||||
offsets[i] = (offsets[i] + 1) % len(sets[i])
|
||||
if offsets[i] != 0:
|
||||
break
|
||||
# finish up if we've exhausted the sequence
|
||||
if offsets == [ 0 ] * len(sets):
|
||||
return
|
||||
|
||||
def cyclic_metasploit(length = None, sets = None):
|
||||
"""cyclic_metasploit(length = None, sets = [ string.ascii_uppercase, string.ascii_lowercase, string.digits ]) -> str
|
||||
|
||||
A simple wrapper over :func:`metasploit_pattern`. This function returns a
|
||||
string of length `length`.
|
||||
|
||||
Arguments:
|
||||
length: The desired length of the string or None if the entire sequence is desired.
|
||||
sets: List of strings to generate the sequence over.
|
||||
|
||||
Example:
|
||||
>>> cyclic_metasploit(32)
|
||||
'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab'
|
||||
>>> cyclic_metasploit(sets = ["AB","ab","12"])
|
||||
'Aa1Aa2Ab1Ab2Ba1Ba2Bb1Bb2'
|
||||
>>> cyclic_metasploit()[1337:1341]
|
||||
'5Bs6'
|
||||
>>> len(cyclic_metasploit())
|
||||
20280
|
||||
"""
|
||||
sets = sets or [ string.ascii_uppercase, string.ascii_lowercase, string.digits ]
|
||||
out = []
|
||||
|
||||
for ndx, c in enumerate(metasploit_pattern(sets)):
|
||||
if length != None and ndx >= length:
|
||||
break
|
||||
else:
|
||||
out.append(c)
|
||||
|
||||
out = ''.join(out)
|
||||
|
||||
if len(out) < length:
|
||||
log.error("Can't create a pattern of length %i with sets of lengths %s. Maximum pattern length is %i." \
|
||||
% (length, map(len, sets), len(out)))
|
||||
|
||||
return ''.join(out)
|
||||
|
||||
def cyclic_metasploit_find(subseq, sets = None):
|
||||
"""cyclic_metasploit_find(subseq, sets = [ string.ascii_uppercase, string.ascii_lowercase, string.digits ]) -> int
|
||||
|
||||
Calculates the position of a substring into a Metasploit Pattern sequence.
|
||||
|
||||
Arguments:
|
||||
subseq: The subsequence to look for. This can be a string or an
|
||||
integer. If an integer is provided it will be packed as a
|
||||
little endian integer.
|
||||
sets: List of strings to generate the sequence over.
|
||||
|
||||
Examples:
|
||||
|
||||
>>> cyclic_metasploit_find(cyclic_metasploit(1000)[514:518])
|
||||
514
|
||||
>>> cyclic_metasploit_find(0x61413161)
|
||||
4
|
||||
"""
|
||||
sets = sets or [ string.ascii_uppercase, string.ascii_lowercase, string.digits ]
|
||||
|
||||
if isinstance(subseq, (int, long)):
|
||||
subseq = packing.pack(subseq, 'all', 'little', False)
|
||||
|
||||
return _gen_find(subseq, metasploit_pattern(sets))
|
||||
|
||||
def _gen_find(subseq, generator):
|
||||
"""Returns the first position of subseq in the generator or -1 if there is no such position."""
|
||||
"""Returns the first position of `subseq` in the generator or -1 if there is no such position."""
|
||||
subseq = list(subseq)
|
||||
pos = 0
|
||||
saved = []
|
||||
|
||||
+37
-15
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import base64
|
||||
import random
|
||||
import os
|
||||
import re
|
||||
import string
|
||||
import StringIO
|
||||
@@ -10,7 +11,7 @@ from . import packing
|
||||
from ..context import context
|
||||
from ..log import getLogger
|
||||
from ..term import text
|
||||
from .cyclic import cyclic
|
||||
from .cyclic import de_bruijn
|
||||
from .cyclic import cyclic_find
|
||||
|
||||
log = getLogger(__name__)
|
||||
@@ -559,13 +560,15 @@ default_style = {
|
||||
}
|
||||
|
||||
cyclic_pregen = ''
|
||||
de_bruijn_gen = de_bruijn()
|
||||
|
||||
def sequential_lines(a,b):
|
||||
return (a+b) in cyclic_pregen
|
||||
|
||||
def update_cyclic_pregenerated(size):
|
||||
global cyclic_pregen
|
||||
cyclic_pregen = cyclic(size)
|
||||
while size > len(cyclic_pregen):
|
||||
cyclic_pregen += de_bruijn_gen.next()
|
||||
|
||||
def hexdump_iter(fd, width=16, skip=True, hexii=False, begin=0, style=None,
|
||||
highlight=None, cyclic=False):
|
||||
@@ -627,30 +630,49 @@ def hexdump_iter(fd, width=16, skip=True, hexii=False, begin=0, style=None,
|
||||
return hbyte, abyte
|
||||
cache = [style_byte(chr(b)) for b in range(256)]
|
||||
|
||||
if cyclic:
|
||||
update_cyclic_pregenerated(len(s))
|
||||
|
||||
numb = 0
|
||||
while True:
|
||||
offset = begin + numb
|
||||
chunk = fd.read(width)
|
||||
|
||||
# If a tube is passed in as fd, it will raise EOFError when it runs
|
||||
# out of data, unlike a file or StringIO object, which return an empty
|
||||
# string.
|
||||
try:
|
||||
chunk = fd.read(width)
|
||||
except EOFError:
|
||||
chunk = ''
|
||||
|
||||
# We have run out of data, exit the loop
|
||||
if chunk == '':
|
||||
break
|
||||
|
||||
# Advance the cursor by the number of bytes we actually read
|
||||
numb += len(chunk)
|
||||
|
||||
# Update the cyclic pattern in case
|
||||
if cyclic:
|
||||
update_cyclic_pregenerated(numb)
|
||||
|
||||
# If this chunk is the same as the last unique chunk,
|
||||
# use a '*' instead.
|
||||
if skip and \
|
||||
(last_unique == chunk or \
|
||||
(cyclic and sequential_lines(last_unique, chunk))):
|
||||
if skip and last_unique:
|
||||
same_as_last_line = (last_unique == chunk)
|
||||
lines_are_sequential = (cyclic and sequential_lines(last_unique, chunk))
|
||||
last_unique = chunk
|
||||
if not skipping:
|
||||
yield '*'
|
||||
skipping = True
|
||||
continue
|
||||
|
||||
# Chunk is unique, save for next iteration
|
||||
last_unique = chunk
|
||||
if same_as_last_line or lines_are_sequential:
|
||||
|
||||
# If we have not already printed a "*", do so
|
||||
if not skipping:
|
||||
yield '*'
|
||||
skipping = True
|
||||
|
||||
# Move on to the next chunk
|
||||
continue
|
||||
|
||||
# Chunk is unique, no longer skipping
|
||||
skipping = False
|
||||
last_unique = chunk
|
||||
|
||||
# Generate contents for line
|
||||
hexbytes = ''
|
||||
|
||||
+3
-61
@@ -2,19 +2,14 @@ import errno
|
||||
import socket
|
||||
import time
|
||||
|
||||
import psutil
|
||||
|
||||
from .. import tubes
|
||||
from ..log import getLogger
|
||||
|
||||
try:
|
||||
import psutil
|
||||
_ok_import = True
|
||||
except ImportError:
|
||||
_ok_import = False
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
if _ok_import:
|
||||
all_pids = psutil.pids
|
||||
all_pids = psutil.pids
|
||||
|
||||
def pidof(target):
|
||||
"""pidof(target) -> int list
|
||||
@@ -305,56 +300,3 @@ def wait_for_debugger(pid):
|
||||
while tracer(pid) is None:
|
||||
time.sleep(0.01)
|
||||
l.success()
|
||||
|
||||
if not _ok_import:
|
||||
def _make_stub(func):
|
||||
func.__doc__ = 'Stubbed out function, because psutil is not available.'
|
||||
return func
|
||||
|
||||
@_make_stub
|
||||
def all_pids():
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def pidof(target):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def pid_by_name(name):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def name(pid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def parent(pid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def children(ppid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def ancestors(pid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def descendants(pid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def exe(pid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def cwd(pid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def cmdline(pid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def starttime(pid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
+1
-1
@@ -1 +1 @@
|
||||
__version__ = '3.2.1'
|
||||
__version__ = '3.4.0'
|
||||
@@ -54,11 +54,8 @@ install_requires = ['paramiko>=1.15.2',
|
||||
'pysocks',
|
||||
'python-dateutil',
|
||||
'pypandoc',
|
||||
'packaging']
|
||||
|
||||
# This is a hack until somebody ports psutil to OpenBSD
|
||||
if platform.system() != 'OpenBSD':
|
||||
install_requires.append('psutil>=2.1.3')
|
||||
'packaging',
|
||||
'psutil>=3.3.0']
|
||||
|
||||
# Check that the user has installed the Python development headers
|
||||
PythonH = os.path.join(get_python_inc(), 'Python.h')
|
||||
@@ -83,7 +80,7 @@ except ImportError:
|
||||
setup(
|
||||
name = 'pwntools',
|
||||
packages = find_packages(),
|
||||
version = '3.2.1',
|
||||
version = '3.4.0',
|
||||
data_files = [('',
|
||||
glob.glob('*.md') + glob.glob('*.txt')),
|
||||
],
|
||||
|
||||
+47
-37
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env bash -e
|
||||
set -e
|
||||
|
||||
local_deb_extract()
|
||||
{
|
||||
wget $1
|
||||
@@ -8,52 +9,54 @@ local_deb_extract()
|
||||
rm -f *.tar.* *deb*
|
||||
}
|
||||
|
||||
get_binutils()
|
||||
install_deb()
|
||||
{
|
||||
BINUTILS_PREFIX='https://launchpad.net/~pwntools/+archive/ubuntu/binutils/+files/binutils-'
|
||||
BINUTILS_SUFFIX='-linux-gnu_2.22-6ubuntu1.1cross0.11pwntools12~precise_amd64.deb'
|
||||
local_deb_extract "${BINUTILS_PREFIX}${1}${BINUTILS_SUFFIX}"
|
||||
}
|
||||
|
||||
get_qemu()
|
||||
{
|
||||
echo "Installing qemu"
|
||||
QEMU_INDEX='http://packages.ubuntu.com/en/yakkety/amd64/qemu-user-static/download'
|
||||
QEMU_URL=$(curl "$QEMU_INDEX" | grep kernel.org | grep -Eo 'http.*\.deb')
|
||||
local_deb_extract "$QEMU_URL"
|
||||
version=${2:-zesty}
|
||||
package=$1
|
||||
echo "Installing $package"
|
||||
INDEX="http://packages.ubuntu.com/en/$version/amd64/$package/download"
|
||||
URL=$(curl "$INDEX" | grep -Eo "https?://.*$package.*\.deb" | head -1)
|
||||
local_deb_extract "$URL"
|
||||
}
|
||||
|
||||
setup_travis()
|
||||
{
|
||||
export PATH=$PWD/usr/bin:$PATH
|
||||
export LD_LIBRARY_PATH=$PWD/usr/lib
|
||||
export LD_LIBRARY_PATH=$PWD/usr/lib:$LD_LIBRARY_PATH
|
||||
export LD_LIBRARY_PATH=$PWD/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH
|
||||
|
||||
# Install libbfd-multiarch and libopcodes-multiarch if not found in the cache
|
||||
if [ ! -f usr/lib/libbfd-2.22-multiarch.so ];
|
||||
then
|
||||
# Install the multiarch binutils
|
||||
local_deb_extract http://mirrors.mit.edu/ubuntu/pool/universe/b/binutils/binutils-multiarch_2.22-6ubuntu1_amd64.deb
|
||||
pushd usr/lib
|
||||
ln -sf libbfd-2.22-multiarch.so libbfd-2.22.so
|
||||
ln -sf libopcodes-2.22-multiarch.so libopcodes-2.22.so
|
||||
popd
|
||||
fi
|
||||
# Install a more modern binutils, which is required for some of the tests
|
||||
[[ -f usr/bin/objcopy ]] || install_deb binutils
|
||||
|
||||
# Install/upgrade qemu
|
||||
if ! (which qemu-arm-static && qemu-arm-static -version | grep 2.6.1); then
|
||||
get_qemu
|
||||
fi
|
||||
[[ -f usr/bin/qemu-arm-static ]] || install_deb qemu-user-static xenial
|
||||
|
||||
# Install our custom binutils
|
||||
which arm-linux-gnu-as || get_binutils arm
|
||||
which mips-linux-gnu-as || get_binutils mips
|
||||
which powerpc-linux-gnu-as || get_binutils powerpc
|
||||
# Install cross-binutils
|
||||
[[ -f usr/bin/x86_64-linux-gnu-ar ]] || install_deb binutils-multiarch
|
||||
[[ -f usr/bin/aarch64-linux-gnu-as ]] || install_deb binutils-aarch64-linux-gnu
|
||||
[[ -f usr/bin/arm-linux-gnueabihf-as ]] || install_deb binutils-arm-linux-gnueabihf
|
||||
[[ -f usr/bin/mips-linux-gnu-as ]] || install_deb binutils-mips-linux-gnu
|
||||
[[ -f usr/bin/powerpc-linux-gnu-as ]] || install_deb binutils-powerpc-linux-gnu
|
||||
|
||||
# Test that the installs worked
|
||||
which arm-linux-gnu-as
|
||||
which mips-linux-gnu-as
|
||||
which powerpc-linux-gnu-as
|
||||
which qemu-arm-static
|
||||
as --version
|
||||
x86_64-linux-gnu-ar --version
|
||||
aarch64-linux-gnu-as --version
|
||||
arm-linux-gnueabihf-as --version
|
||||
mips-linux-gnu-as --version
|
||||
powerpc-linux-gnu-as --version
|
||||
qemu-arm-static --version
|
||||
|
||||
# Force-install capstone because it's broken somehow
|
||||
[[ -f usr/lib/libcapstone.so.3 ]] || install_deb libcapstone3
|
||||
|
||||
# Install a newer copy of GDB
|
||||
if [[ ! -f usr/bin/gdb ]]; then
|
||||
git clone --depth=1 https://github.com/zachriggle/pwntools-gdb-travis-ci.git
|
||||
tar xf pwntools-gdb-travis-ci/gdb.tar.xz
|
||||
which gdb
|
||||
usr/bin/gdb --version
|
||||
fi
|
||||
|
||||
# Get rid of files we don't want cached
|
||||
rm -rf usr/share
|
||||
@@ -74,8 +77,14 @@ setup_android_emulator()
|
||||
if [ -n "$TRAVIS" ]; then
|
||||
if [ -z "$TRAVIS_COMMIT_RANGE" ]; then
|
||||
echo "TRAVIS_COMMIT_RANGE is empty, forcing Android Emulator installation"
|
||||
elif ! git show "$TRAVIS_COMMIT_RANGE" ; then
|
||||
elif ! (git show "$TRAVIS_COMMIT_RANGE" >/dev/null) ; then
|
||||
echo "TRAVIS_COMMIT_RANGE is invalid, forcing Android Emulator installation"
|
||||
elif [[ "$TRAVIS_BRANCH" =~ "staging" ]]; then
|
||||
echo "TRAVIS_BRANCH ($TRAVIS_BRANCH) indicates a branch we care about"
|
||||
echo "Forcing Android Emulator installation"
|
||||
elif [[ -n "$TRAVIS_TAG" ]]; then
|
||||
echo "TRAVIS_TAG ($TRAVIS_TAG) indicates a new relase"
|
||||
echo "Forcing Android Emulator installation"
|
||||
elif (git log --stat "$TRAVIS_COMMIT_RANGE" | grep -iE "android|adb"); then
|
||||
echo "Found Android-related commits, forcing Android Emulator installation"
|
||||
else
|
||||
@@ -83,9 +92,11 @@ setup_android_emulator()
|
||||
# emulator, while still leaving the code intact, we remove the
|
||||
# RST file that Sphinx searches.
|
||||
rm -f 'docs/source/adb.rst'
|
||||
rm -f 'docs/source/protocols/adb.rst'
|
||||
|
||||
# However, the file needs to be present or else things break.
|
||||
touch 'docs/source/adb.rst'
|
||||
touch 'docs/source/protocols/adb.rst'
|
||||
|
||||
echo "Skipping Android emulator install, Android tests disabled."
|
||||
return
|
||||
@@ -182,5 +193,4 @@ elif [[ "$(uname)" == "Linux" ]]; then
|
||||
setup_android_emulator
|
||||
fi
|
||||
|
||||
|
||||
dpkg -l
|
||||
set +e
|
||||
@@ -54,3 +54,5 @@ Host example.pwnme
|
||||
EOF
|
||||
|
||||
ssh -o "StrictHostKeyChecking no" -vvvv [email protected] id
|
||||
|
||||
set +e
|
||||
Reference in new issue
Block a user