mirror of
https://github.com/Gallopsled/pwntools.git
synced 2026-11-08 08:06:05 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df7c1fef9d | ||
|
|
b234b319df | ||
|
|
91768424ba | ||
|
|
af2f8b4bf4 | ||
|
|
ab0ac00c73 | ||
|
|
d87ab3ac65 | ||
|
|
23cd5cb819 | ||
|
|
bb25140807 | ||
|
|
92ad1a4933 | ||
|
|
3e163e9cf2 | ||
|
|
267c6cc15a | ||
|
|
c438893d7e | ||
|
|
1a94acab67 | ||
|
|
6263a347bd | ||
|
|
a344047348 | ||
|
|
4aa96b48ba | ||
|
|
6f2598aee0 | ||
|
|
3f42ce8636 | ||
|
|
901f3eddb1 | ||
|
|
5180230f04 | ||
|
|
1ab07de033 | ||
|
|
5936d0f565 | ||
|
|
e3fd03458a | ||
|
|
55016fb416 | ||
|
|
08b316098b | ||
|
|
a27cb1c168 | ||
|
|
d923729dfb | ||
|
|
db75ecb897 | ||
|
|
0dc2949790 | ||
|
|
89a848b51f | ||
|
|
672b4dd090 | ||
|
|
094e44fd65 | ||
|
|
b83db46c34 | ||
|
|
40c1796fc4 | ||
|
|
984d54d9b2 | ||
|
|
3cbc527deb | ||
|
|
1482fb7545 | ||
|
|
7ed6f5fe6b | ||
|
|
fd5a7fea68 | ||
|
|
fda1821fd9 | ||
|
|
f7568b47b3 | ||
|
|
2ccd36ca7f | ||
|
|
9062360041 | ||
|
|
3f9c192a5e | ||
|
|
b8e902b611 | ||
|
|
8055ec98ce |
No files matched your search
@@ -4,6 +4,11 @@ Thanks for contributing to Pwntools!
|
||||
|
||||
When reporting an issue, be sure that you are running the latest released version of pwntools (`pip install --upgrade pwntools`).
|
||||
|
||||
Please verify that your issue occurs on 64-bit Ubuntu 14.04. You can use the Dockerfile in `extra/docker/Dockerfile` to save time.
|
||||
Please verify that your issue occurs on 64-bit Ubuntu 14.04. You can use the Dockerfile on `docker.io` for quick testing.
|
||||
|
||||
```
|
||||
$ docker pull pwntools/pwntools:stable
|
||||
$ docker run -it pwntools/pwntools:stable
|
||||
```
|
||||
|
||||
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`.
|
||||
+3
-4
@@ -1,10 +1,9 @@
|
||||
sudo: false
|
||||
dist: precise
|
||||
language: python
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- gcc-4.6-arm-linux-gnueabihf
|
||||
- lib32stdc++6
|
||||
- ash
|
||||
- bash
|
||||
@@ -18,8 +17,8 @@ cache:
|
||||
- pip
|
||||
- directories:
|
||||
- usr
|
||||
- /home/travis/virtualenv/python2.7.9/lib/python2.7/site-packages/
|
||||
- /home/travis/virtualenv/python2.7.9/bin/
|
||||
- /home/travis/virtualenv/python2.7.13/lib/python2.7/site-packages/
|
||||
- /home/travis/virtualenv/python2.7.13/bin/
|
||||
python:
|
||||
- "2.7"
|
||||
before_install:
|
||||
|
||||
+51
-10
@@ -9,9 +9,14 @@ The table below shows which release corresponds to each branch, and what date th
|
||||
|
||||
| Version | Branch | Release Date |
|
||||
| ---------------- | -------- | ---------------------- |
|
||||
| [3.9.0](#390) | `dev` | Sep 8, 2017 (planned)
|
||||
| [3.8.0](#380) | `beta` | Jul 28, 2017 (planned)
|
||||
| [3.7.0](#370) | `stable` | Jun 19, 2017
|
||||
| [3.11.0](#3110) | `dev` | Dec 2, 2017 (planned)
|
||||
| [3.10.0](#3100) | `beta` | Oct 21, 2017 (planned)
|
||||
| [3.9.2](#392) | `stable` | Oct 5, 2017
|
||||
| [3.9.1](#391) | | Sep 28, 2017
|
||||
| [3.9.0](#390) | | Sep 11, 2017
|
||||
| [3.8.0](#380) | | Jul 29, 2017
|
||||
| [3.7.1](#371) | | Jul 14, 2017
|
||||
| [3.7.0](#370) | | Jun 19, 2017
|
||||
| [3.6.1](#361) | | May 12, 2017
|
||||
| [3.6.0](#360) | | May 8, 2017
|
||||
| [3.5.1](#351) | | Apr 15, 2017
|
||||
@@ -34,19 +39,55 @@ 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.11.0
|
||||
|
||||
To be released on Dec 2, 2017.
|
||||
|
||||
## 3.10.0
|
||||
|
||||
To be released on Oct 21, 2017.
|
||||
|
||||
## 3.9.2
|
||||
|
||||
- [#1043][1043] Do not attempt to populate the libraries used by statically-linked binaries
|
||||
|
||||
[1043]: https://github.com/Gallopsled/pwntools/pull/1043
|
||||
|
||||
## 3.9.1
|
||||
|
||||
- [#1038][1038] Fix an issue with `process()` where glibc would buffer data internally, causing a hang on `select()`
|
||||
- [#1036][1036] Fix Travis CI logging verbosity
|
||||
- [#1029][1029] Fix some `unicode` issues when using the `readline` command history in `tube.interactive()`
|
||||
|
||||
[1038]: https://github.com/Gallopsled/pwntools/pull/1038
|
||||
[1036]: https://github.com/Gallopsled/pwntools/pull/1036
|
||||
[1029]: https://github.com/Gallopsled/pwntools/pull/1029
|
||||
|
||||
## 3.9.0
|
||||
|
||||
To be released on Sep 8, 2017.
|
||||
- [#1003][1003] Make `concat_all` faster while also simplifying it's logic
|
||||
- [#1014][1014] Fix for overwritten env when parsing core file
|
||||
- [#1023][1023] Fixes to Travis CI
|
||||
|
||||
[1003]: https://github.com/Gallopsled/pwntools/pull/1003
|
||||
[1014]: https://github.com/Gallopsled/pwntools/pull/1014
|
||||
[1023]: https://github.com/Gallopsled/pwntools/pull/1023
|
||||
|
||||
## 3.8.0
|
||||
|
||||
To be released on Jul 28, 2017.
|
||||
|
||||
- [#981][981] Fixed RELRO detection logic
|
||||
- [#986][986] Enhancements to DynELF for controlling usage of LibcDB
|
||||
- A few documentation fixes
|
||||
- A few fixes for the Docker image
|
||||
|
||||
[981]: https://github.com/Gallopsled/pwntools/issues/981
|
||||
[986]: https://github.com/Gallopsled/pwntools/issues/986
|
||||
[981]: https://github.com/Gallopsled/pwntools/pull/981
|
||||
[986]: https://github.com/Gallopsled/pwntools/pull/986
|
||||
|
||||
## 3.7.1
|
||||
|
||||
- [#998][998] Fix a bug where integer values could not be set in `.pwn.conf`.
|
||||
|
||||
[998]: https://github.com/Gallopsled/pwntools/pull/998
|
||||
|
||||
## 3.7.0
|
||||
|
||||
@@ -54,8 +95,8 @@ To be released on Jul 28, 2017.
|
||||
- [#952][952] A few small fixes were made to `pwn template`, and the CRC database was updated.
|
||||
- [5c72d62c][5c72d62c] Updated the CRC database
|
||||
|
||||
[933]: https://github.com/Gallopsled/pwntools/issues/933
|
||||
[952]: https://github.com/Gallopsled/pwntools/issues/952
|
||||
[933]: https://github.com/Gallopsled/pwntools/pull/933
|
||||
[952]: https://github.com/Gallopsled/pwntools/pull/952
|
||||
[5c72d62c]: https://github.com/Gallopsled/pwntools/commit/5c72d62c
|
||||
|
||||
## 3.6.1
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||

|
||||
|
||||
[](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)
|
||||
[](http://choosealicense.com/licenses/mit/)
|
||||
|
||||
pwntools is a CTF framework and exploit development library. Written in Python, it is designed for rapid prototyping and development, and intended to make exploit writing as simple as possible.
|
||||
Pwntools is a CTF framework and exploit development library. Written in Python, it is designed for rapid prototyping and development, and intended to make exploit writing as simple as possible.
|
||||
|
||||
```python
|
||||
from pwn import *
|
||||
@@ -32,7 +32,7 @@ To get you started, we've provided some example solutions for past CTF challenge
|
||||
|
||||
# Installation
|
||||
|
||||
pwntools is best supported on 64-bit Ubuntu 12.04 and 14.04, but most functionality should work on any Posix-like distribution (Debian, Arch, FreeBSD, OSX, etc.). Python 2.7 is required.
|
||||
Pwntools is best supported on 64-bit Ubuntu LTE releases (12.04, 14.04, and 16.04). Most functionality should work on any Posix-like distribution (Debian, Arch, FreeBSD, OSX, etc.). Python 2.7 is required.
|
||||
|
||||
Most of the functionality of pwntools is self-contained and Python-only. You should be able to get running quickly with
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
:members:
|
||||
|
||||
Internal Functions
|
||||
=========================================
|
||||
-----------------------------------------
|
||||
|
||||
These are only included so that their tests are run.
|
||||
|
||||
|
||||
@@ -44,6 +44,23 @@ extensions = [
|
||||
'sphinxcontrib.napoleon'
|
||||
]
|
||||
|
||||
# Disable "info" logging directly to stdout by Sphinx
|
||||
import logging
|
||||
|
||||
class SphinxPwnlibFilter(logging.Filter):
|
||||
def filter(self, record):
|
||||
if record.name.startswith('pwn'):
|
||||
return False
|
||||
if record.name.startswith('paramiko'):
|
||||
return False
|
||||
return True
|
||||
|
||||
log_filter = SphinxPwnlibFilter()
|
||||
|
||||
for i, handler in enumerate(logging.root.handlers):
|
||||
print("Filtering Sphinx handler", handler)
|
||||
handler.addFilter(log_filter)
|
||||
|
||||
# Napoleon settings
|
||||
napoleon_use_ivar = True
|
||||
napoleon_use_rtype = False
|
||||
|
||||
@@ -57,6 +57,7 @@ Each of the ``pwntools`` modules is documented here.
|
||||
flag
|
||||
fmtstr
|
||||
gdb
|
||||
libcdb
|
||||
log
|
||||
memleak
|
||||
protocols
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.libcdb import *
|
||||
|
||||
:mod:`pwnlib.libcdb` --- Libc Database
|
||||
===========================================
|
||||
|
||||
.. automodule:: pwnlib.libcdb
|
||||
:members:
|
||||
@@ -1,6 +1,6 @@
|
||||
subdirs=xenial stable $(wildcard */)
|
||||
makefiles=$(wildcard */Makefile)
|
||||
tags=stable beta dev
|
||||
tags=base stable beta dev
|
||||
|
||||
all: $(makefiles) $(subdirs)
|
||||
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
xenial
|
||||
@@ -1,6 +1,6 @@
|
||||
all: Dockerfile
|
||||
|
||||
Dockerfile: ../stable/Dockerfile FORCE
|
||||
Dockerfile: ../xenial/Dockerfile FORCE
|
||||
sed "s|ubuntu:xenial|kalilinux/kali-linux-docker|" < "$<" > "$@"
|
||||
|
||||
FORCE:
|
||||
|
||||
@@ -1,26 +1,6 @@
|
||||
############################################################
|
||||
# Dockerfile to build Pwntools container
|
||||
# Based on Ubuntu
|
||||
############################################################
|
||||
FROM pwntools/pwntools:base
|
||||
|
||||
FROM ubuntu:xenial
|
||||
MAINTAINER Maintainer Gallopsled et al.
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential
|
||||
RUN apt-get install -y git
|
||||
RUN apt-get install -y libssl-dev
|
||||
RUN apt-get install -y libffi-dev
|
||||
RUN apt-get install -y python2.7
|
||||
RUN apt-get install -y python-pip
|
||||
RUN apt-get install -y python-dev
|
||||
RUN pip install --upgrade pip
|
||||
RUN python -m pip install --upgrade pwntools
|
||||
USER root
|
||||
RUN pip install --upgrade git+https://github.com/Gallopsled/pwntools@stable
|
||||
RUN PWNLIB_NOTERM=1 pwn update
|
||||
|
||||
RUN apt-get install -y sudo
|
||||
RUN useradd -m pwntools
|
||||
RUN passwd --delete --unlock pwntools
|
||||
RUN echo "pwntools ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/pwntools
|
||||
USER pwntools
|
||||
WORKDIR /home/pwntools
|
||||
@@ -1,8 +0,0 @@
|
||||
all: Dockerfile
|
||||
|
||||
Dockerfile: ../xenial/Dockerfile FORCE
|
||||
cp "$<" "$@"
|
||||
|
||||
FORCE:
|
||||
|
||||
.PHONY: all
|
||||
+1
-1
@@ -328,7 +328,7 @@ class AdbDevice(Device):
|
||||
kwargs['port'] = 'emulator'
|
||||
|
||||
for field in fields[2:]:
|
||||
k,v = field.split(':')
|
||||
k,v = field.split(':', 1)
|
||||
kwargs[k] = v
|
||||
|
||||
return AdbDevice(serial, type, **kwargs)
|
||||
|
||||
@@ -37,8 +37,18 @@ not specified evaluate to an empty string.
|
||||
else:
|
||||
io = process('./pwnable')
|
||||
|
||||
Arguments can also be accessed directly with the dot operator, e.g.:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
if args.REMOTE:
|
||||
...
|
||||
|
||||
Any undefined arguments evaluate to an empty string, ``''``.
|
||||
|
||||
The full list of supported "magic arguments" and their effects are listed
|
||||
below.
|
||||
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
@@ -1359,9 +1359,14 @@ def update_context_defaults(section):
|
||||
if key not in ContextType.defaults:
|
||||
log.warn("Unknown configuration option %r in section %r" % (key, 'context'))
|
||||
continue
|
||||
if isinstance(ContextType.defaults[key], (str, unicode, tuple)):
|
||||
value = safeeval.expr(value)
|
||||
|
||||
ContextType.defaults[key] = value
|
||||
default = ContextType.defaults[key]
|
||||
|
||||
if isinstance(default, (str, unicode, tuple, int, long, list, dict)):
|
||||
value = safeeval.expr(value)
|
||||
else:
|
||||
log.warn("Unsupported configuration option %r in section %r" % (key, 'context'))
|
||||
|
||||
ContextType.defaults[key] = type(default)(value)
|
||||
|
||||
register_config('context', update_context_defaults)
|
||||
@@ -1,3 +1,6 @@
|
||||
from __future__ import absolute_import
|
||||
from pwnlib.data.elf import relro
|
||||
|
||||
import os
|
||||
path = os.path.dirname(__file__)
|
||||
|
||||
|
||||
@@ -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.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
+22
-18
@@ -145,7 +145,7 @@ class DynELF(object):
|
||||
.. _DT_PLTGOT: http://refspecs.linuxfoundation.org/ELF/zSeries/lzsabi0_zSeries/x2251.html
|
||||
'''
|
||||
|
||||
def __init__(self, leak, pointer=None, elf=None):
|
||||
def __init__(self, leak, pointer=None, elf=None, libcdb=True):
|
||||
'''
|
||||
Instantiates an object which can resolve symbols in a running binary
|
||||
given a :class:`pwnlib.memleak.MemLeak` leaker and a pointer inside
|
||||
@@ -155,7 +155,9 @@ class DynELF(object):
|
||||
leak(MemLeak): Instance of pwnlib.memleak.MemLeak for leaking memory
|
||||
pointer(int): A pointer into a loaded ELF file
|
||||
elf(str,ELF): Path to the ELF file on disk, or a loaded :class:`pwnlib.elf.ELF`.
|
||||
libcdb(bool): Attempt to use libcdb to speed up libc lookups
|
||||
'''
|
||||
self.libcdb = libcdb
|
||||
self._elfclass = None
|
||||
self._elftype = None
|
||||
self._link_map = None
|
||||
@@ -415,7 +417,7 @@ class DynELF(object):
|
||||
def _find_linkmap(self, pltgot=None, debug=None):
|
||||
"""
|
||||
The linkmap is a chained structure created by the loader at runtime
|
||||
which contains information on the names and load addresses osf all
|
||||
which contains information on the names and load addresses of all
|
||||
libraries.
|
||||
|
||||
For non-RELRO binaries, a pointer to this is stored in the .got.plt
|
||||
@@ -429,7 +431,7 @@ class DynELF(object):
|
||||
Got = {32: elf.Elf_i386_GOT, 64: elf.Elf_x86_64_GOT}[self.elfclass]
|
||||
r_debug = {32: elf.Elf32_r_debug, 64: elf.Elf64_r_debug}[self.elfclass]
|
||||
|
||||
result = None
|
||||
linkmap = None
|
||||
|
||||
if not pltgot:
|
||||
w.status("Finding linkmap: DT_PLTGOT")
|
||||
@@ -437,24 +439,24 @@ class DynELF(object):
|
||||
|
||||
if pltgot:
|
||||
w.status("GOT.linkmap")
|
||||
result = self.leak.field(pltgot, Got.linkmap)
|
||||
w.status("GOT.linkmap %#x" % result)
|
||||
linkmap = self.leak.field(pltgot, Got.linkmap)
|
||||
w.status("GOT.linkmap %#x" % linkmap)
|
||||
|
||||
if not result:
|
||||
if not linkmap:
|
||||
debug = debug or self._find_dt(constants.DT_DEBUG)
|
||||
if debug:
|
||||
w.status("r_debug.linkmap")
|
||||
result = self.leak.field(debug, r_debug.r_map)
|
||||
linkmap = self.leak.field(debug, r_debug.r_map)
|
||||
w.status("r_debug.linkmap %#x" % result)
|
||||
|
||||
if not (pltgot or debug):
|
||||
if not linkmap:
|
||||
w.failure("Could not find DT_PLTGOT or DT_DEBUG")
|
||||
return None
|
||||
|
||||
result = self._make_absolute_ptr(result)
|
||||
linkmap = self._make_absolute_ptr(linkmap)
|
||||
|
||||
w.success('%#x' % result)
|
||||
return result
|
||||
w.success('%#x' % linkmap)
|
||||
return linkmap
|
||||
|
||||
def waitfor(self, msg):
|
||||
if not self._waitfor:
|
||||
@@ -521,6 +523,7 @@ class DynELF(object):
|
||||
|
||||
Arguments:
|
||||
symb(str): Named routine to look up
|
||||
If omitted, the base address of the library will be returned.
|
||||
lib(str): Substring to match for the library name.
|
||||
If omitted, the current library is searched.
|
||||
If set to ``'libc'``, ``'libc.so'`` is assumed.
|
||||
@@ -560,11 +563,10 @@ class DynELF(object):
|
||||
#
|
||||
# If we are resolving a symbol in the library, find it.
|
||||
#
|
||||
if symb:
|
||||
if symb and self.libcdb:
|
||||
# Try a quick lookup by build ID
|
||||
self.status("Trying lookup based on Build ID")
|
||||
build_id = dynlib._lookup_build_id(lib=lib)
|
||||
result = None
|
||||
if build_id:
|
||||
log.info("Trying lookup based on Build ID: %s" % build_id)
|
||||
path = libcdb.search_by_build_id(build_id)
|
||||
@@ -573,11 +575,10 @@ class DynELF(object):
|
||||
e = ELF(path)
|
||||
e.address = dynlib.libbase
|
||||
result = e.symbols[symb]
|
||||
|
||||
if not result:
|
||||
self.status("Trying remote lookup")
|
||||
result = dynlib._lookup(symb)
|
||||
else:
|
||||
if symb and not result:
|
||||
self.status("Trying remote lookup")
|
||||
result = dynlib._lookup(symb)
|
||||
if not symb:
|
||||
result = dynlib.libbase
|
||||
|
||||
#
|
||||
@@ -837,6 +838,9 @@ class DynELF(object):
|
||||
def _lookup_build_id(self, lib = None):
|
||||
|
||||
libbase = self.libbase
|
||||
if not self.link_map:
|
||||
self.status("No linkmap found")
|
||||
return None
|
||||
|
||||
if lib is not None:
|
||||
libbase = self.lookup(symb = None, lib = lib)
|
||||
|
||||
@@ -545,7 +545,7 @@ class Corefile(ELF):
|
||||
log.warn('Could not find the stack!')
|
||||
self.stack = None
|
||||
|
||||
with context.local(bytes=self.bytes, log_level='error'):
|
||||
with context.local(bytes=self.bytes, log_level='warn'):
|
||||
try:
|
||||
self._parse_stack()
|
||||
except ValueError:
|
||||
@@ -826,6 +826,10 @@ class Corefile(ELF):
|
||||
# find a pointer to this address, followed by a NULL.
|
||||
last_env_addr = address + 1
|
||||
p_last_env_addr = stack.find(pack(last_env_addr), None, last_env_addr)
|
||||
if p_last_env_addr < 0:
|
||||
# Something weird is happening. Just don't touch it.
|
||||
log.warn_once("Found bad environment at %#x", last_env_addr)
|
||||
return
|
||||
|
||||
# Sanity check that we did correctly find the envp NULL terminator.
|
||||
envp_nullterm = p_last_env_addr+context.bytes
|
||||
|
||||
@@ -252,6 +252,40 @@ class constants:
|
||||
AT_L2_CACHESHAPE = 36
|
||||
AT_L3_CACHESHAPE = 37
|
||||
|
||||
# Legal flags used in the d_val field of the DT_FLAGS dynamic entry.
|
||||
DF_ORIGIN = 0x01
|
||||
DF_SYMBOLIC = 0x02
|
||||
DF_TEXTREL = 0x04
|
||||
DF_BIND_NOW = 0x08
|
||||
DF_STATIC_TLS = 0x10
|
||||
|
||||
# Legal flags used in the d_val field of the DT_FLAGS_1 dynamic entry.
|
||||
DF_1_NOW = 0x00000001
|
||||
DF_1_GLOBAL = 0x00000002
|
||||
DF_1_GROUP = 0x00000004
|
||||
DF_1_NODELETE = 0x00000008
|
||||
DF_1_LOADFLTR = 0x00000010
|
||||
DF_1_INITFIRST = 0x00000020
|
||||
DF_1_NOOPEN = 0x00000040
|
||||
DF_1_ORIGIN = 0x00000080
|
||||
DF_1_DIRECT = 0x00000100
|
||||
DF_1_TRANS = 0x00000200
|
||||
DF_1_INTERPOSE = 0x00000400
|
||||
DF_1_NODEFLIB = 0x00000800
|
||||
DF_1_NODUMP = 0x00001000
|
||||
DF_1_CONFALT = 0x00002000
|
||||
DF_1_ENDFILTEE = 0x00004000
|
||||
DF_1_DISPRELDNE = 0x00008000
|
||||
DF_1_DISPRELPND = 0x00010000
|
||||
DF_1_NODIRECT = 0x00020000
|
||||
DF_1_IGNMULDEF = 0x00040000
|
||||
DF_1_NOKSYMS = 0x00080000
|
||||
DF_1_NOHDR = 0x00100000
|
||||
DF_1_EDITED = 0x00200000
|
||||
DF_1_NORELOC = 0x00400000
|
||||
DF_1_SYMINTPOSE = 0x00800000
|
||||
DF_1_GLOBAUDIT = 0x01000000
|
||||
DF_1_SINGLETON = 0x02000000
|
||||
|
||||
|
||||
class Elf32_Ehdr(ctypes.Structure):
|
||||
|
||||
+30
-4
@@ -55,6 +55,7 @@ from elftools.elf.enums import ENUM_P_TYPE
|
||||
from elftools.elf.gnuversions import GNUVerDefSection
|
||||
from elftools.elf.relocation import RelocationSection
|
||||
from elftools.elf.sections import SymbolTableSection
|
||||
from elftools.elf.segments import InterpSegment
|
||||
|
||||
import intervaltree
|
||||
|
||||
@@ -64,6 +65,7 @@ from pwnlib.context import LocalContext
|
||||
from pwnlib.context import context
|
||||
from pwnlib.elf.config import kernel_configuration
|
||||
from pwnlib.elf.config import parse_kconfig
|
||||
from pwnlib.elf.datatypes import constants
|
||||
from pwnlib.elf.plt import emulate_plt_instructions
|
||||
from pwnlib.log import getLogger
|
||||
from pwnlib.qemu import get_qemu_arch
|
||||
@@ -604,10 +606,20 @@ class ELF(ELFFile):
|
||||
>>> any(map(lambda x: 'libc' in x, bash.libs.keys()))
|
||||
True
|
||||
"""
|
||||
if not self.get_section_by_name('.dynamic'):
|
||||
|
||||
# We need a .dynamic section for dynamically linked libraries
|
||||
if not self.get_section_by_name('.dynamic') or self.statically_linked:
|
||||
self.libs= {}
|
||||
return
|
||||
|
||||
# We must also specify a 'PT_INTERP', otherwise it's a 'statically-linked'
|
||||
# binary which is also position-independent (and as such has a .dynamic).
|
||||
for segment in self.iter_segments_by_type('PT_INTERP'):
|
||||
break
|
||||
else:
|
||||
self.libs = {}
|
||||
return
|
||||
|
||||
try:
|
||||
cmd = 'ulimit -s unlimited; LD_TRACE_LOADED_OBJECTS=1 LD_WARN=1 LD_BIND_NOW=1 %s 2>/dev/null' % sh_string(self.path)
|
||||
|
||||
@@ -1327,14 +1339,28 @@ class ELF(ELFFile):
|
||||
.. _PT_GNU_RELRO: https://refspecs.linuxbase.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic.html#PROGHEADER
|
||||
.. _DF_BIND_NOW: http://refspecs.linuxbase.org/elf/gabi4+/ch5.dynamic.html#df_bind_now
|
||||
|
||||
>>> path = pwnlib.data.elf.relro.path
|
||||
>>> for test in glob(os.path.join(path, 'test-*')):
|
||||
... e = ELF(test)
|
||||
... expected = os.path.basename(test).split('-')[2]
|
||||
... actual = str(e.relro).lower()
|
||||
... assert actual == expected
|
||||
"""
|
||||
if not any('GNU_RELRO' in str(s.header.p_type) for s in self.segments):
|
||||
return None
|
||||
|
||||
if self.dynamic_by_tag('DT_BIND_NOW'):
|
||||
return "Full"
|
||||
|
||||
if any('GNU_RELRO' in str(s.header.p_type) for s in self.segments):
|
||||
return "Partial"
|
||||
flags = self.dynamic_value_by_tag('DT_FLAGS')
|
||||
if flags and flags & constants.DF_BIND_NOW:
|
||||
return "Full"
|
||||
|
||||
return None
|
||||
flags_1 = self.dynamic_value_by_tag('DT_FLAGS_1')
|
||||
if flags_1 and flags_1 & constants.DF_1_NOW:
|
||||
return "Full"
|
||||
|
||||
return "Partial"
|
||||
|
||||
@property
|
||||
def nx(self):
|
||||
|
||||
+120
-23
@@ -21,14 +21,63 @@ from pwnlib.util.web import wget
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
cache_dir = os.path.join(tempfile.gettempdir(), 'pwn')
|
||||
HASHES = ['build_id', 'sha1', 'sha256', 'md5']
|
||||
|
||||
def search_by_hash(hex_encoded_id, hash_type='build_id'):
|
||||
assert hash_type in HASHES, hash_type
|
||||
|
||||
# Ensure that the libcdb cache directory exists
|
||||
cache_dir = os.path.join(context.cache_dir, 'libcdb', hash_type)
|
||||
|
||||
if not os.path.isdir(cache_dir):
|
||||
os.makedirs(cache_dir)
|
||||
|
||||
# If we already downloaded the file, and it looks even passingly like
|
||||
# a valid ELF file, return it.
|
||||
cache = os.path.join(cache_dir, hex_encoded_id)
|
||||
|
||||
if os.path.exists(cache):
|
||||
log.debug("Found existing cached libc at %r", cache)
|
||||
|
||||
data = read(cache)
|
||||
if data.startswith('\x7FELF'):
|
||||
log.info_once("Using cached data from %r", cache)
|
||||
return cache
|
||||
else:
|
||||
log.info_once("Skipping unavialable libc %s", hex_encoded_id)
|
||||
return None
|
||||
|
||||
# Build the URL using the requested hash type
|
||||
url_base = "https://gitlab.com/libcdb/libcdb/raw/master/hashes/%s/" % hash_type
|
||||
url = urlparse.urljoin(url_base, hex_encoded_id)
|
||||
|
||||
data = ""
|
||||
while not data.startswith('\x7fELF'):
|
||||
log.debug("Downloading data from LibcDB: %s", url)
|
||||
data = wget(url)
|
||||
|
||||
if not data:
|
||||
log.warn_once("Could not fetch libc for build_id %s", hex_encoded_id)
|
||||
break
|
||||
|
||||
# GitLab serves up symlinks with
|
||||
if data.startswith('..'):
|
||||
url = os.path.dirname(url) + '/'
|
||||
url = urlparse.urljoin(url, data)
|
||||
|
||||
# Save whatever we got to the cache
|
||||
write(cache, data or '')
|
||||
|
||||
# Return ``None`` if we did not get a valid ELF file
|
||||
if not data or not data.startswith('\x7FELF'):
|
||||
return None
|
||||
|
||||
return cache
|
||||
|
||||
|
||||
def search_by_build_id(hex_encoded_id):
|
||||
"""
|
||||
Given a hex-encoded Build ID, return the path to an ELF with that Build ID
|
||||
only the local system.
|
||||
|
||||
If it can't be found, return None.
|
||||
Given a hex-encoded Build ID, attempt to download a matching libc from libcdb.
|
||||
|
||||
Arguments:
|
||||
hex_encoded_id(str):
|
||||
@@ -36,31 +85,79 @@ def search_by_build_id(hex_encoded_id):
|
||||
|
||||
Returns:
|
||||
Path to the downloaded library on disk, or :const:`None`.
|
||||
|
||||
Examples:
|
||||
>>> filename = search_by_build_id('fe136e485814fee2268cf19e5c124ed0f73f4400')
|
||||
>>> hex(ELF(filename).symbols.read)
|
||||
'0xda260'
|
||||
>>> None == search_by_build_id('XX')
|
||||
True
|
||||
"""
|
||||
cache = cache_dir + '-libc.so.' + hex_encoded_id
|
||||
return search_by_hash(hex_encoded_id, 'build_id')
|
||||
|
||||
if os.path.exists(cache) and read(cache).startswith('\x7FELF'):
|
||||
log.info_once("Using cached data from %r" % cache)
|
||||
return cache
|
||||
def search_by_md5(hex_encoded_id):
|
||||
"""
|
||||
Given a hex-encoded md5sum, attempt to download a matching libc from libcdb.
|
||||
|
||||
log.info("Downloading data from GitHub")
|
||||
Arguments:
|
||||
hex_encoded_id(str):
|
||||
Hex-encoded Build ID (e.g. 'ABCDEF...') of the library
|
||||
|
||||
url_base = "https://gitlab.com/libcdb/libcdb/raw/master/hashes/build_id/"
|
||||
url = urlparse.urljoin(url_base, hex_encoded_id)
|
||||
Returns:
|
||||
Path to the downloaded library on disk, or :const:`None`.
|
||||
|
||||
data = ""
|
||||
while not data.startswith('\x7fELF'):
|
||||
data = wget(url)
|
||||
Examples:
|
||||
>>> filename = search_by_md5('7a71dafb87606f360043dcd638e411bd')
|
||||
>>> hex(ELF(filename).symbols.read)
|
||||
'0xda260'
|
||||
>>> None == search_by_build_id('XX')
|
||||
True
|
||||
"""
|
||||
return search_by_hash(hex_encoded_id, 'md5')
|
||||
|
||||
def search_by_sha1(hex_encoded_id):
|
||||
"""
|
||||
Given a hex-encoded sha1, attempt to download a matching libc from libcdb.
|
||||
|
||||
Arguments:
|
||||
hex_encoded_id(str):
|
||||
Hex-encoded Build ID (e.g. 'ABCDEF...') of the library
|
||||
|
||||
Returns:
|
||||
Path to the downloaded library on disk, or :const:`None`.
|
||||
|
||||
Examples:
|
||||
>>> filename = search_by_sha1('34471e355a5e71400b9d65e78d2cd6ce7fc49de5')
|
||||
>>> hex(ELF(filename).symbols.read)
|
||||
'0xda260'
|
||||
>>> None == search_by_sha1('XX')
|
||||
True
|
||||
"""
|
||||
return search_by_hash(hex_encoded_id, 'sha1')
|
||||
|
||||
|
||||
def search_by_sha256(hex_encoded_id):
|
||||
"""
|
||||
Given a hex-encoded sha256, attempt to download a matching libc from libcdb.
|
||||
|
||||
Arguments:
|
||||
hex_encoded_id(str):
|
||||
Hex-encoded Build ID (e.g. 'ABCDEF...') of the library
|
||||
|
||||
Returns:
|
||||
Path to the downloaded library on disk, or :const:`None`.
|
||||
|
||||
Examples:
|
||||
>>> filename = search_by_sha256('5e877a8272da934812d2d1f9ee94f73c77c790cbc5d8251f5322389fc9667f21')
|
||||
>>> hex(ELF(filename).symbols.read)
|
||||
'0xda260'
|
||||
>>> None == search_by_sha256('XX')
|
||||
True
|
||||
"""
|
||||
return search_by_hash(hex_encoded_id, 'sha256')
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
if data.startswith('..'):
|
||||
url = os.path.dirname(url) + '/'
|
||||
url = urlparse.urljoin(url, data)
|
||||
|
||||
write(cache, data)
|
||||
return cache
|
||||
|
||||
def get_build_id_offsets():
|
||||
"""
|
||||
@@ -114,4 +211,4 @@ def get_build_id_offsets():
|
||||
}.get(context.arch, [])
|
||||
|
||||
|
||||
__all__ = ['get_build_id_offsets', 'search_by_build_id']
|
||||
__all__ = ['get_build_id_offsets', 'search_by_build_id', 'search_by_sha1', 'search_by_sha256', 'search_by_md5']
|
||||
@@ -1,8 +1,2 @@
|
||||
<%docstring>A trap instruction.</%docstring>
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
mov r0, 12
|
||||
mov r1, sp
|
||||
BKPT 0xab
|
||||
B .
|
||||
BKPT
|
||||
@@ -24,7 +24,7 @@ Examples:
|
||||
'Hello'
|
||||
|
||||
>>> l = listen(fam='ipv6', timeout=5)
|
||||
>>> assembly = shellcraft.i386.linux.connect('ip6-localhost', l.lport, 'ipv6')
|
||||
>>> assembly = shellcraft.i386.linux.connect('::1', l.lport, 'ipv6')
|
||||
>>> p = run_assembly(assembly)
|
||||
>>> assert l.wait_for_connection()
|
||||
|
||||
|
||||
+20
-10
@@ -1,3 +1,5 @@
|
||||
#!/usr/bin/env python2
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import
|
||||
|
||||
from pwnlib.term import keyconsts as kc
|
||||
@@ -7,7 +9,7 @@ from pwnlib.term import text
|
||||
|
||||
cursor = text.reverse
|
||||
|
||||
buffer_left, buffer_right = u'', u''
|
||||
buffer_left, buffer_right = '', ''
|
||||
saved_buffer = None
|
||||
history = []
|
||||
history_idx = None
|
||||
@@ -29,6 +31,14 @@ suggest_hook = None
|
||||
|
||||
tabs = 0
|
||||
|
||||
def force_to_bytes(data):
|
||||
if isinstance(data, bytes):
|
||||
return data
|
||||
try:
|
||||
return data.encode('utf-8')
|
||||
except Exception:
|
||||
return data.encode('latin-1')
|
||||
|
||||
def set_completer(completer):
|
||||
global complete_hook, suggest_hook
|
||||
if completer is None:
|
||||
@@ -80,7 +90,7 @@ def handle_keypress(trace):
|
||||
|
||||
def clear():
|
||||
global buffer_left, buffer_right, history_idx, search_idx
|
||||
buffer_left, buffer_right = u'', u''
|
||||
buffer_left, buffer_right = '', ''
|
||||
history_idx = None
|
||||
search_idx = None
|
||||
redisplay()
|
||||
@@ -141,7 +151,7 @@ def cancel_search(*_):
|
||||
def commit_search():
|
||||
global search_idx
|
||||
if search_idx is not None and search_results:
|
||||
set_buffer(history[search_results[search_idx][0]], u'')
|
||||
set_buffer(history[search_results[search_idx][0]], '')
|
||||
search_idx = None
|
||||
redisplay()
|
||||
|
||||
@@ -169,7 +179,7 @@ def update_search_results():
|
||||
def search_history(*_):
|
||||
global buffer_left, buffer_right, history_idx, search_idx
|
||||
if search_idx is None:
|
||||
buffer_left, buffer_right = buffer_left + buffer_right, u''
|
||||
buffer_left, buffer_right = buffer_left + buffer_right, ''
|
||||
history_idx = None
|
||||
search_idx = 0
|
||||
update_search_results()
|
||||
@@ -187,7 +197,7 @@ def history_prev(*_):
|
||||
history_idx = -1
|
||||
if history_idx < len(history) - 1:
|
||||
history_idx += 1
|
||||
set_buffer(history[history_idx], u'')
|
||||
set_buffer(history[history_idx], '')
|
||||
|
||||
def history_next(*_):
|
||||
global history_idx, saved_buffer
|
||||
@@ -200,7 +210,7 @@ def history_next(*_):
|
||||
saved_buffer = None
|
||||
else:
|
||||
history_idx -= 1
|
||||
set_buffer(history[history_idx], u'')
|
||||
set_buffer(history[history_idx], '')
|
||||
|
||||
def backward_char(*_):
|
||||
global buffer_left, buffer_right
|
||||
@@ -319,11 +329,11 @@ def forward_word(*_):
|
||||
|
||||
def go_beginning(*_):
|
||||
commit_search()
|
||||
set_buffer(u'', buffer_left + buffer_right)
|
||||
set_buffer('', buffer_left + buffer_right)
|
||||
|
||||
def go_end(*_):
|
||||
commit_search()
|
||||
set_buffer(buffer_left + buffer_right, u'')
|
||||
set_buffer(buffer_left + buffer_right, '')
|
||||
|
||||
keymap = km.Keymap({
|
||||
'<nomatch>' : self_insert,
|
||||
@@ -382,10 +392,10 @@ def readline(_size = None, prompt = '', float = True, priority = 10):
|
||||
if eof:
|
||||
return ''
|
||||
else:
|
||||
buffer = (buffer_left + buffer_right).encode('utf-8')
|
||||
buffer = (buffer_left + buffer_right)
|
||||
if buffer:
|
||||
history.insert(0, buffer)
|
||||
return buffer + '\n'
|
||||
return force_to_bytes(buffer) + '\n'
|
||||
except KeyboardInterrupt:
|
||||
control_c()
|
||||
finally:
|
||||
|
||||
@@ -336,11 +336,11 @@ class process(tube):
|
||||
|
||||
if self.pty is not None:
|
||||
if stdin is slave:
|
||||
self.proc.stdin = os.fdopen(os.dup(master), 'r+')
|
||||
self.proc.stdin = os.fdopen(os.dup(master), 'r+', 0)
|
||||
if stdout is slave:
|
||||
self.proc.stdout = os.fdopen(os.dup(master), 'r+')
|
||||
self.proc.stdout = os.fdopen(os.dup(master), 'r+', 0)
|
||||
if stderr is slave:
|
||||
self.proc.stderr = os.fdopen(os.dup(master), 'r+')
|
||||
self.proc.stderr = os.fdopen(os.dup(master), 'r+', 0)
|
||||
|
||||
os.close(master)
|
||||
os.close(slave)
|
||||
|
||||
@@ -622,7 +622,7 @@ class tube(Timeout, Logger):
|
||||
return self.recvline_pred(pred, keepends = keepends, timeout = timeout)
|
||||
|
||||
def recvrepeat(self, timeout = default):
|
||||
"""recvrepeat()
|
||||
"""recvrepeat(timeout = default) -> str
|
||||
|
||||
Receives data until a timeout or EOF is reached.
|
||||
|
||||
|
||||
+8
-10
@@ -114,17 +114,15 @@ def concat_all(*args):
|
||||
[0, 1, 2, 3, 4, 5, 6]
|
||||
"""
|
||||
|
||||
if len(args) != 1:
|
||||
return concat_all(list(args))
|
||||
def go(arg, output):
|
||||
if isinstance(arg, (tuple, list)):
|
||||
for e in arg:
|
||||
go(e, output)
|
||||
else:
|
||||
output.append(arg)
|
||||
return output
|
||||
|
||||
if not isinstance(args[0], (tuple, list)):
|
||||
return [args[0]]
|
||||
|
||||
res = []
|
||||
for k in args[0]:
|
||||
res.extend(concat_all(k))
|
||||
|
||||
return res
|
||||
return go(args, [])
|
||||
|
||||
def ordlist(s):
|
||||
"""ordlist(s) -> list
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
__version__ = '3.7.0'
|
||||
__version__ = '3.9.2'
|
||||
@@ -86,7 +86,7 @@ except Exception as e:
|
||||
setup(
|
||||
name = 'pwntools',
|
||||
packages = find_packages(),
|
||||
version = '3.7.0',
|
||||
version = '3.9.2',
|
||||
data_files = [('',
|
||||
glob.glob('*.md') + glob.glob('*.txt')),
|
||||
],
|
||||
@@ -105,7 +105,7 @@ setup(
|
||||
description = "Pwntools CTF framework and exploit development library.",
|
||||
long_description = long_description,
|
||||
author = "Gallopsled et al.",
|
||||
author_email = "#pwntools @ freenode.net",
|
||||
author_email = "pwntools[email protected]",
|
||||
url = 'https://pwntools.com',
|
||||
download_url = "https://github.com/Gallopsled/pwntools/releases",
|
||||
install_requires = install_requires,
|
||||
|
||||
@@ -8,7 +8,10 @@ MAINTAINER Maintainer Gallopsled et al.
|
||||
|
||||
USER root
|
||||
|
||||
RUN apt-get update
|
||||
|
||||
# Use UTF-8
|
||||
RUN apt-get install -y locales
|
||||
RUN locale-gen en_US.UTF-8
|
||||
ENV LANG en_US.UTF-8
|
||||
ENV LANGUAGE en_US:en
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash -e
|
||||
set -e
|
||||
set -ex
|
||||
|
||||
local_deb_extract()
|
||||
{
|
||||
@@ -15,7 +15,7 @@ install_deb()
|
||||
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)
|
||||
URL=$(curl -L "$INDEX" | grep -Eo "https?://.*$package.*\.deb" | head -1)
|
||||
local_deb_extract "$URL"
|
||||
}
|
||||
|
||||
@@ -198,4 +198,4 @@ elif [[ "$(uname)" == "Linux" ]]; then
|
||||
setup_android_emulator
|
||||
fi
|
||||
|
||||
set +e
|
||||
set +ex
|
||||
+2
-2
@@ -4,7 +4,7 @@
|
||||
#
|
||||
# All of the "conditional sudo" is to do container-based builds on
|
||||
# Travis which are much, much faster.
|
||||
set -e
|
||||
set -ex
|
||||
|
||||
U=travis
|
||||
H=/home/$U
|
||||
@@ -55,4 +55,4 @@ EOF
|
||||
|
||||
ssh -o "StrictHostKeyChecking no" -vvvv [email protected] id
|
||||
|
||||
set +e
|
||||
set +ex
|
||||
Reference in new issue
Block a user