mirror of
https://github.com/Gallopsled/pwntools.git
synced 2026-11-09 10:09:36 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74f475170d | ||
|
|
0dc0a9acc0 | ||
|
|
774ed3b85e | ||
|
|
292b81af17 | ||
|
|
90056fbeca | ||
|
|
60df8107c0 | ||
|
|
7467402ecf | ||
|
|
80e12c7031 | ||
|
|
f4159bdad4 | ||
|
|
26e6bce81a | ||
|
|
6af09645e7 | ||
|
|
146348f514 | ||
|
|
fe6619b336 | ||
|
|
5ae13e8c8c | ||
|
|
67473560c7 | ||
|
|
1cb0502157 | ||
|
|
9604f7847e |
No files matched your search
+2
-1
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
@@ -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'], {})}
|
||||
@@ -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
@@ -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()
|
||||
|
||||
|
||||
@@ -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
@@ -1 +1 @@
|
||||
__version__ = '3.12.0'
|
||||
__version__ = '3.12.2'
|
||||
@@ -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
@@ -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"
|
||||
|
||||
Reference in new issue
Block a user