Compare commits

...
17 Commits
Author SHA1 Message Date
Zach Riggle 74f475170d Bump version to 3.12.2 2019-01-07 15:21:39 -06:00
Kyle Zeng 0dc0a9acc0 check qemu_path correctly and give out a reasonable error msg (#1243) 2019-01-07 14:42:24 -06:00
Zach Riggle 774ed3b85e Do not use intervaltree 3.xx (#1242)
In the future, we may want to update Pwntools to use the newer version.

In the meantime, pin to 2.xx
2018-12-28 23:19:54 -06:00
joesixpack666 292b81af17 close ssh_channel properly in download() (#1208) (#1209)
* close ssh_channel properly in download() (#1208)

* Update ssh.py
2018-10-17 13:14:20 -05:00
Zach Riggle 90056fbeca Version bump to 3.12.1 2018-09-17 17:11:45 -05:00
Zach Riggle 60df8107c0 corefile: Update NT_XXX type names for pyelftools==0.25 (#1198)
* corefile: Update NT_XXX type names for pyelftools==0.25

* travis: Do not use Sphinx version 1.8.0, it fails with recursive errors

* corefile: Fix stack detection and Mapping.__contains__ logic

* corefile: Better detection of AT_EXECFN when NT_AUXV does not have it

* corefile: Avoid trying to parse corrupt stacks

* Fix doctests for new warning

* log: Fix warning_once caching
2018-09-17 17:04:40 -05:00
Ricky Zhou 7467402ecf Work around renamed ENUM_P_TYPE variables in elftools 0.25 and up. 2018-09-17 14:07:24 -05:00
Zach Riggle 80e12c7031 Switch FTP servers to ftp.ubuntu.com
Fixes Gallopsled/pwntools#1172
2018-07-02 16:57:16 -05:00
pwn f4159bdad4 check if ":" exists before index(':') (#1159)
* check if ":" exists before index(':')

* Update proc.py
2018-06-04 11:13:03 -05:00
Zach Riggle 26e6bce81a Fix broken versions of package dependencies (#1162)
Fixes Gallopsled/pwntools#971
Fixes Gallopsled/pwntools#1154
Fixes Gallopsled/pwntools#1160
2018-05-31 15:22:45 -05:00
Inndy 6af09645e7 Prevent crash from not existed cache file in ssh.checksec() (#1150)
* Prevent crash from not existed cache file in ssh.checksec()

* Use path.exists instead of exception handling

* Fix space

* Update ssh.py
2018-05-30 14:35:23 -05:00
Bruce Chen 146348f514 fix wrong gadget selection in setRegisters() (#1118) (#1156)
* fix wrong gadget selection in setRegisters() (#1118)

* Fix detection logic

* Update rop.py

* add test cases for filtering out the bad instructions in rop.py
2018-05-30 13:31:33 -05:00
Michael Rodler fe6619b336 fixed called to qemu.ld_prefix passing env dict as target (#1152) 2018-05-25 16:21:57 -05:00
Bruce Chen 5ae13e8c8c switch to trusty build in travis ci and fix some test cases (#1155) 2018-05-25 14:38:06 -05:00
Alexey Vishnyakov 67473560c7 Check libc- as well (#1131) 2018-04-02 14:03:38 -05:00
Tyler Lambert 1cb0502157 Replace string format char (#1125)
* replace string format char

* add parentheses
2018-03-19 16:26:03 -05:00
Zach Riggle 9604f7847e Fix tests relying on broken autocontrib version (#1121) 2018-02-28 15:09:35 -06:00
20 changed files with 105 additions and 73 deletions

No files matched your search

+2 -1
View File
@@ -1,4 +1,4 @@
dist: precise
dist: trusty
language: python
addons:
apt:
@@ -19,6 +19,7 @@ cache:
- usr
- /home/travis/virtualenv/python2.7.13/lib/python2.7/site-packages/
- /home/travis/virtualenv/python2.7.13/bin/
sudo: required
python:
- "2.7"
before_install:
+1 -1
View File
@@ -2,7 +2,7 @@
![pwntools logo](https://github.com/Gallopsled/pwntools/blob/stable/docs/source/logo.png?raw=true)
[![Docs](https://readthedocs.org/projects/pwntools/badge/?version=stable)](https://docs.pwntools.com/)
[![PyPI](https://img.shields.io/badge/pypi-v3.12.0-green.svg?style=flat)](https://pypi.python.org/pypi/pwntools/)
[![PyPI](https://img.shields.io/badge/pypi-v3.12.1-green.svg?style=flat)](https://pypi.python.org/pypi/pwntools/)
[![Travis](https://travis-ci.org/Gallopsled/pwntools.svg)](https://travis-ci.org/Gallopsled/pwntools)
[![Coveralls](https://img.shields.io/coveralls/Gallopsled/pwntools/dev.svg)](https://coveralls.io/github/Gallopsled/pwntools?branch=dev)
[![Twitter](https://img.shields.io/badge/twitter-pwntools-4099FF.svg?style=flat)](https://twitter.com/pwntools)
+2 -1
View File
@@ -1,5 +1,5 @@
sphinxcontrib-napoleon
sphinxcontrib-autoprogram==0.1.2
sphinxcontrib-autoprogram==0.1.4
isort
paramiko>=1.15.2
mako>=1.0.0
@@ -14,3 +14,4 @@ pygments>=2.0
sphinx_rtd_theme
doc2dash
coveralls
sphinx<1.8.0
-23
View File
@@ -24,29 +24,6 @@ sys.path.insert(0, os.path.abspath('../..'))
import pwnlib
# -- WORK-AROUNDS FOR DEPRECATION ----------------------------------------------
# Deprecated
# 1.6b1
# sphinx.util.compat.Directive class is now deprecated.
# Please use instead docutils.parsers.rst.Directive
#
# Pwntools Note:
# Can't just "do the right thing" since we have dependencies that
# are also affected by this, specifically sphinxcontrib.autoprogram
try:
import sphinx.util.compat
except ImportError:
import sys
import types
import sphinx.util
import docutils.parsers.rst
class compat(types.ModuleType):
Directive = docutils.parsers.rst.Directive
sphinx.util.compat = compat('sphinx.util.compat')
sys.modules['sphinx.util.compat'] = sphinx.util.compat
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
+1 -1
View File
@@ -27,7 +27,7 @@ This exposes a standard interface to talk to processes, sockets, serial ports,
and all manner of things, along with some nifty helpers for common tasks.
For example, remote connections via :mod:`pwnlib.tubes.remote`.
>>> conn = remote('ftp.ubuntu.org',21)
>>> conn = remote('ftp.ubuntu.com',21)
>>> conn.recvline() # doctest: +ELLIPSIS
'220 ...'
>>> conn.send('USER anonymous\r\n')
+32 -23
View File
@@ -87,6 +87,7 @@ from pwnlib.tubes.process import process
from pwnlib.tubes.ssh import ssh_channel
from pwnlib.tubes.tube import tube
from pwnlib.util.fiddling import b64d
from pwnlib.util.fiddling import enhex
from pwnlib.util.fiddling import unhex
from pwnlib.util.misc import read
from pwnlib.util.misc import write
@@ -223,6 +224,8 @@ class Mapping(object):
return self._core.read(item, 1)
def __contains__(self, item):
if isinstance(item, Mapping):
return (self.start <= item.start) and (item.stop <= self.stop)
return self.start <= item < self.stop
def find(self, sub, start=None, end=None):
@@ -472,6 +475,7 @@ class Corefile(ELF):
>>> io = elf.process()
>>> io.wait()
>>> core = io.corefile
[!] End of the stack is corrupted, skipping stack parsing (got: 4141414141414141)
>>> core.argc, core.argv, core.env
(0, [], {})
>>> core.stack.data.endswith('AAAA')
@@ -545,36 +549,40 @@ class Corefile(ELF):
for segment in self.segments:
if not isinstance(segment, elftools.elf.segments.NoteSegment):
continue
# Note that older versions of pyelftools (<=0.24) are missing enum values
# for NT_PRSTATUS, NT_PRPSINFO, NT_AUXV, etc.
# For this reason, we have to check if note.n_type is any of several values.
for note in iter_notes(segment):
# Try to find NT_PRSTATUS. Note that pyelftools currently
# mis-identifies the enum name as 'NT_GNU_ABI_TAG'.
# Try to find NT_PRSTATUS.
if prstatus_type and \
note.n_descsz == ctypes.sizeof(prstatus_type) and \
note.n_type == 'NT_GNU_ABI_TAG':
note.n_type in ('NT_GNU_ABI_TAG', 'NT_PRSTATUS'):
self.NT_PRSTATUS = note
self.prstatus = prstatus_type.from_buffer_copy(note.n_desc)
# Try to find NT_PRPSINFO
# Note that pyelftools currently mis-identifies the enum name
# as 'NT_GNU_BUILD_ID'
if note.n_descsz == ctypes.sizeof(prpsinfo_type) and \
note.n_type == 'NT_GNU_BUILD_ID':
if prpsinfo_type and \
note.n_descsz == ctypes.sizeof(prpsinfo_type) and \
note.n_type in ('NT_GNU_ABI_TAG', 'NT_PRPSINFO'):
self.NT_PRPSINFO = note
self.prpsinfo = prpsinfo_type.from_buffer_copy(note.n_desc)
# Try to find NT_SIGINFO so we can see the fault
if note.n_type == 0x53494749:
if note.n_type in (0x53494749, 'NT_SIGINFO'):
self.NT_SIGINFO = note
self.siginfo = siginfo_type.from_buffer_copy(note.n_desc)
# Try to find the list of mapped files
if note.n_type == constants.NT_FILE:
if note.n_type in (constants.NT_FILE, 'NT_FILE'):
with context.local(bytes=self.bytes):
self._parse_nt_file(note)
# Try to find the auxiliary vector, which will tell us
# where the top of the stack is.
if note.n_type == constants.NT_AUXV:
if note.n_type in (constants.NT_AUXV, 'NT_AUXV'):
self.NT_AUXV = note
with context.local(bytes=self.bytes):
self._parse_auxv(note)
@@ -583,19 +591,13 @@ class Corefile(ELF):
if self.stack and self.mappings:
for mapping in self.mappings:
if mapping.stop == self.stack:
if self.stack in mapping or self.stack == mapping.stop:
mapping.name = '[stack]'
self.stack = mapping
break
else:
for mapping in self.mappings:
if self.stack in mapping:
mapping.name = '[stack]'
self.stack = mapping
break
else:
log.warn('Could not find the stack!')
self.stack = None
log.warn('Could not find the stack!')
self.stack = None
with context.local(bytes=self.bytes, log_level='warn'):
try:
@@ -895,18 +897,25 @@ class Corefile(ELF):
if not stack:
return
# If the stack does not end with zeroes, something is very wrong.
if not stack.data.endswith('\x00' * 8):
log.warn_once("End of the stack is corrupted, skipping stack parsing (got: %s)",
enhex(self.data[-8:]))
return
# AT_EXECFN is the start of the filename, e.g. '/bin/sh'
# Immediately preceding is a NULL-terminated environment variable string.
# We want to find the beginning of it
if self.at_execfn:
address = self.at_execfn-1
else:
log.debug('No AT_EXECFN')
if not self.at_execfn:
address = stack.stop
address -= 2*self.bytes
address -= 1
address = stack.rfind('\x00', None, address)
address += 1
self.at_execfn = address
address = self.at_execfn-1
# Sanity check!
try:
+6 -2
View File
@@ -51,12 +51,17 @@ from elftools.elf.constants import P_FLAGS
from elftools.elf.constants import SHN_INDICES
from elftools.elf.descriptions import describe_e_type
from elftools.elf.elffile import ELFFile
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
# See https://github.com/Gallopsled/pwntools/issues/1189
try:
from elftools.elf.enums import ENUM_P_TYPE
except ImportError:
from elftools.elf.enums import ENUM_P_TYPE_BASE as ENUM_P_TYPE
import intervaltree
from pwnlib import adb
@@ -1767,4 +1772,3 @@ class ELF(ELFFile):
return
log.error("Could not find PT_GNU_STACK, stack should already be executable")
+1 -1
View File
@@ -423,7 +423,7 @@ def debug(args, gdbscript=None, exe=None, ssh=None, env=None, sysroot=None, **kw
else:
qemu_port = random.randint(1024, 65535)
qemu_user = qemu.user_path()
sysroot = sysroot or qemu.ld_prefix(env)
sysroot = sysroot or qemu.ld_prefix(env=env)
if not qemu_user:
log.error("Cannot debug %s binaries without appropriate QEMU binaries" % context.arch)
args = [qemu_user, '-g', str(qemu_port)] + args
+1 -1
View File
@@ -3,7 +3,7 @@ from os.path import basename
from docutils import nodes
from docutils import statemachine
from sphinx.util.compat import Directive
from docutils.parsers.rst import Directive
try:
from StringIO import StringIO
+1 -1
View File
@@ -363,7 +363,7 @@ class Logger(object):
"""
m = message % args
if m not in self._one_time_warnings:
if self.isEnabledFor(logging.INFO):
if self.isEnabledFor(logging.WARNING):
self._one_time_warnings.add(m)
self._log(logging.WARNING, message, args, kwargs, 'warning_once')
+1 -1
View File
@@ -234,7 +234,7 @@ class Call(object):
else:
args.append(arg)
name = self.name or fmt & self.target
name = self.name or (fmt % self.target)
arg_str = []
for arg in args:
if isinstance(arg, (int,long)) and arg > 0x100:
+27 -3
View File
@@ -168,6 +168,21 @@ requirements so that everything "just works".
0x0078: 'faabgaab' <pad 0x8>
0x0080: 0x10000008 target
Pwntools will also filter out some bad instructions while setting the registers
( e.g. syscall, int 0x80... )
>>> assembly = 'syscall; pop rdx; pop rsi; ret ; pop rdi ; int 0x80; pop rsi; pop rdx; ret ; pop rdi ; ret'
>>> binary = ELF.from_assembly(assembly)
>>> rop = ROP(binary)
>>> rop.call(0xdeadbeef, [1, 2, 3])
>>> print rop.dump()
0x0000: 0x1000000b pop rdi; ret
0x0008: 0x1 [arg0] rdi = 1
0x0010: 0x10000008 pop rsi; pop rdx; ret
0x0018: 0x2 [arg1] rsi = 2
0x0020: 0x3 [arg2] rdx = 3
0x0028: 0xdeadbeef
ROP + Sigreturn
-----------------------
@@ -495,15 +510,20 @@ class ROP(object):
regset = set(registers)
bad_instructions = set(('syscall', 'sysenter', 'int 0x80'))
# Collect all gadgets which use these registers
# Also collect the "best" gadget for each combination of registers
gadgets = []
best_gadgets = {}
for gadget in self.gadgets.values():
# Do not use gadgets which end in e.g. "int 0x80"
# Do not use gadgets which doesn't end with 'ret'
if gadget.insns[-1] != 'ret':
continue
# Do not use gadgets which contain 'syscall' or 'int'
if set(gadget.insns) & bad_instructions:
continue
touched = tuple(regset & set(gadget.regs))
@@ -512,10 +532,14 @@ class ROP(object):
old = best_gadgets.get(touched, gadget)
if old is gadget or old.move > gadget.move:
# if we have a new gadget for the touched registers, choose it
# if the new gadget requires less stack space, choose it
# if both gadgets require same stack space, choose the one with less instructions
if (old is gadget) \
or (old.move > gadget.move) \
or (old.move == gadget.move and len(old.insns) > len(gadget.insns)):
best_gadgets[touched] = gadget
winner = None
budget = 999999999
+3 -1
View File
@@ -40,6 +40,8 @@ mips = {
'$31': 31, '$ra': 31,
}
mips_list = list(mips)
arm = map('r{}'.format, range(13))
arm += ["sp", "lr", "pc", "cpsr"]
@@ -211,7 +213,7 @@ def current():
'arm': arm,
'thumb': arm,
'aarch64': aarch64,
'mips': mips,
'mips': mips_list,
'powerpc': powerpc
}[context.arch]
+10 -1
View File
@@ -1,4 +1,13 @@
<% from pwnlib.shellcraft import mips %>
<%docstring>Execute /bin/sh</%docstring>
<%docstring>Execute /bin/sh
Example:
>>> p = run_assembly(shellcraft.mips.linux.sh())
>>> p.sendline('echo Hello')
>>> p.recv()
'Hello\n'
</%docstring>
${mips.execve('//bin/sh', ['sh'], {})}
+4 -4
View File
@@ -434,11 +434,11 @@ class process(tube):
# appropriate qemu binary to run it.
qemu_path = qemu.user_path(arch=binary.arch)
if not qemu:
if not qemu_path:
raise exception
qemu_path = which(qemu_path)
if qemu:
if qemu_path:
self._qemu = qemu_path
args = [qemu_path]
@@ -875,7 +875,7 @@ class process(tube):
from pwnlib.elf import ELF
for lib, address in self.libs().items():
if 'libc.so' in lib:
if 'libc.so' in lib or 'libc-' in lib:
e = ELF(lib)
e.address = address
return e
@@ -931,7 +931,7 @@ class process(tube):
Example:
>>> e = ELF('/bin/sh')
>>> e = ELF('/bin/bash')
>>> p = process(e.path)
In order to make sure there's not a race condition against
+5 -3
View File
@@ -1619,7 +1619,6 @@ from ctypes import *; libc = CDLL('libc.so.6'); print(libc.getenv(%r))
self.error('%r does not exist' % file_or_directory)
def download(self, file_or_directory, local=None):
"""download(file_or_directory, local=None)
@@ -1633,7 +1632,10 @@ from ctypes import *; libc = CDLL('libc.so.6'); print(libc.getenv(%r))
if not self.sftp:
self.error("Cannot determine remote file type without SFTP")
if 0 == self.system('test -d ' + sh_string(file_or_directory)).wait():
with self.system('test -d ' + sh_string(file_or_directory)) as io:
is_dir = io.wait()
if 0 == is_dir:
self.download_dir(file_or_directory, local)
else:
self.download_file(file_or_directory, local)
@@ -1994,7 +1996,7 @@ from ctypes import *; libc = CDLL('libc.so.6'); print(libc.getenv(%r))
if value is not None:
with open(path, 'w+') as f:
f.write(value)
else:
elif os.path.exists(path):
with open(path, 'r+') as f:
return f.read()
+2
View File
@@ -245,6 +245,8 @@ def status(pid):
try:
with open('/proc/%d/status' % pid) as fd:
for line in fd:
if ':' not in line:
continue
i = line.index(':')
key = line[:i]
val = line[i + 2:-1] # initial :\t and trailing \n
+1 -1
View File
@@ -1 +1 @@
__version__ = '3.12.0'
__version__ = '3.12.2'
+4 -3
View File
@@ -45,7 +45,7 @@ for filename in glob.glob('pwnlib/commandline/*'):
install_requires = ['paramiko>=1.15.2',
'mako>=1.0.0',
'pyelftools>=0.2.4',
'capstone',
'capstone>=3.0.5rc2', # See Gallopsled/pwntools#971, Gallopsled/pwntools#1160
'ropgadget>=5.3',
'pyserial>=2.7',
'requests>=2.0',
@@ -57,7 +57,8 @@ install_requires = ['paramiko>=1.15.2',
'pypandoc',
'packaging',
'psutil>=3.3.0',
'intervaltree',
'intervaltree<3.0', # See Gallopsled/pwntools#1238
'sortedcontainers<2.0', # See Gallopsled/pwntools#1154
'unicorn']
# Check that the user has installed the Python development headers
@@ -86,7 +87,7 @@ except Exception as e:
setup(
name = 'pwntools',
packages = find_packages(),
version = '3.12.0',
version = '3.12.2',
data_files = [('',
glob.glob('*.md') + glob.glob('*.txt')),
],
+1 -1
View File
@@ -11,7 +11,7 @@ local_deb_extract()
install_deb()
{
version=${2:-zesty}
version=${2:-artful}
package=$1
echo "Installing $package"
INDEX="http://packages.ubuntu.com/en/$version/amd64/$package/download"