Skip to content

Commit

Permalink
This contains a large merge from the Samurai internal repo.
Browse files Browse the repository at this point in the history
Changes:

- `pwn/init` initialization code simplified, and some was moved to `pwnlib/args`
- `scramble` script added to `pwnlib.commandline`; support for encoders added to relevant scripts
- Added shellcode encoders for several architectures
- Added CGC architecture shellcode and constants
- Added Shellcraft templates for every syscall
- Added `xor_key` helper for generating a 4-byte XOR key for a data stream
- Added `getdents` for use with the relevant shellcraft scripts
- Add ELF loaders for all architectures
- Lots of MIPS and AArch64 shellcode
  • Loading branch information
zachriggle committed Oct 12, 2015
1 parent 768b24e commit 11fa0d8
Show file tree
Hide file tree
Showing 1,656 changed files with 27,374 additions and 858 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ addons:
apt:
packages:
- gcc-multilib
- gcc-4.6-arm-linux-gnueabihf
cache:
- pip
- directories:
Expand Down
2 changes: 2 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@
doctest_global_setup = '''
import sys, os
os.environ['PWNLIB_NOTERM'] = '1'
os.environ['PWNLIB_RANDOMIZE'] = '0'
import pwnlib
pwnlib.context.context.reset_local()
pwnlib.context.ContextType.defaults['log_level'] = 'ERROR'
pwnlib.context.ContextType.defaults['randomize'] = False
pwnlib.term.text.when = 'never'
pwnlib.log.install_default_handler()
pwnlib.log.rootlogger.setLevel(1)
Expand Down
2 changes: 1 addition & 1 deletion docs/source/shellcraft/thumb.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.. testsetup:: *

from pwn import *
context.clear(arch='arm')
context.clear(arch='thumb')

:mod:`pwnlib.shellcraft.thumb` --- Shellcode for Thumb Mode
===========================================================
Expand Down
81 changes: 4 additions & 77 deletions pwn/__init__.py
Original file line number Diff line number Diff line change
@@ -1,81 +1,8 @@
# Promote useful stuff to toplevel
from .toplevel import *

log = getLogger('pwnlib.exploit')
pwnlib.args.initialize()
pwnlib.log.install_default_handler()

# look for special args in argv
def closure():
term_mode = True
import sys
if not hasattr(sys, 'argv'):
return
import string, collections
global args
args = collections.defaultdict(str)
def isident(s):
first = string.uppercase + '_'
body = string.digits + first
if not s:
return False
if s[0] not in first:
return False
if not all(c in body for c in s[1:]):
return False
return True
def asbool(s):
if s.lower() == 'true':
return True
elif s.lower() == 'false':
return False
elif s.isdigit():
return bool(int(s))
else:
raise ValueError('must be integer or boolean')
# parse environtment variables
for k, v in os.environ.items():
if not k.startswith('PWNLIB_'):
continue
k = k[7:]
if k == 'DEBUG':
if asbool(v):
context.log_level = 'DEBUG'
elif k == 'SILENT':
if asbool(v):
context.log_level = 'ERROR'
elif k == 'NOTERM':
if asbool(v):
term_mode = False
elif isident(k):
args[k] = v
# parse command line
# save a copy of argv for the log file header (see below)
argv = sys.argv[:]
for arg in argv:
if arg == 'DEBUG':
sys.argv.remove(arg)
context.log_level = 'DEBUG'
elif arg == 'SILENT':
sys.argv.remove(arg)
context.log_level = 'ERROR'
elif arg == 'NOTERM':
term_mode = False
elif arg.find('=') > 0:
k, v = arg.split('=', 1)
if not isident(k):
continue
sys.argv.remove(arg)
args[k] = v
if 'LOG_LEVEL' in args:
context.log_level = args['LOG_LEVEL']
if 'LOG_FILE' in args:
context.log_file = args['LOG_FILE']
# put the terminal in rawmode unless NOTERM was specified
if term_mode:
term.init()
# install a log handler and turn logging all the way up
import pwnlib.log as log
import logging
log.install_default_handler()

closure()
del closure
log = pwnlib.log.getLogger('pwnlib.exploit')
args = pwnlib.args.args
2 changes: 2 additions & 0 deletions pwn/toplevel.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from pwnlib.encoders import *
from pwnlib.elf import ELF
from pwnlib.elf import load
from pwnlib.encoders import *
from pwnlib.exception import PwnlibException
from pwnlib.fmtstr import FmtStr, fmtstr_payload
from pwnlib.log import getLogger
Expand All @@ -44,6 +45,7 @@
from pwnlib.util import safeeval
from pwnlib.util.cyclic import *
from pwnlib.util.fiddling import *
from pwnlib.util.getdents import *
from pwnlib.util.hashes import *
from pwnlib.util.lists import *
from pwnlib.util.misc import *
Expand Down
1 change: 1 addition & 0 deletions pwnlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
version = __version__

__all__ = [
'args',
'asm',
'atexception',
'atexit',
Expand Down
107 changes: 9 additions & 98 deletions pwnlib/abi.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ def default():
(32, 'i386', 'linux'): linux_i386,
(64, 'amd64', 'linux'): linux_amd64,
(32, 'arm', 'linux'): linux_arm,
(32, 'thumb', 'linux'): linux_arm,
(32, 'mips', 'linux'): linux_mips,
(32, 'i386', 'windows'): windows_i386,
(64, 'amd64', 'windows'): windows_amd64,
}[(context.bits, context.arch, context.os)]
Expand All @@ -45,6 +47,8 @@ def syscall():
(32, 'i386', 'linux'): linux_i386_syscall,
(64, 'amd64', 'linux'): linux_amd64_syscall,
(32, 'arm', 'linux'): linux_arm_syscall,
(32, 'thumb', 'linux'): linux_arm_syscall,
(32, 'mips', 'linux'): linux_mips_syscall,
}[(context.bits, context.arch, context.os)]

@staticmethod
Expand All @@ -54,6 +58,7 @@ def sigreturn():
(32, 'i386', 'linux'): linux_i386_sigreturn,
(64, 'amd64', 'linux'): linux_amd64_sigreturn,
(32, 'arm', 'linux'): linux_arm_sigreturn,
(32, 'thumb', 'linux'): linux_arm_sigreturn,
}[(context.bits, context.arch, context.os)]

class SyscallABI(ABI):
Expand All @@ -77,10 +82,14 @@ class SigreturnABI(SyscallABI):
linux_i386 = ABI([], 4, 0)
linux_amd64 = ABI(['rdi','rsi','rdx','rcx','r8','r9'], 8, 0)
linux_arm = ABI(['r0', 'r1', 'r2', 'r3'], 8, 0)
linux_aarch64 = ABI(['x0', 'x1', 'x2', 'x3'], 16, 0)
linux_mips = ABI(['$a0','$a1','$a2','$a3'], 4, 0)

linux_i386_syscall = SyscallABI(['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp'], 4, 0)
linux_amd64_syscall = SyscallABI(['rax','rdi', 'rsi', 'rdx', 'r10', 'r8', 'r9'], 8, 0)
linux_arm_syscall = SyscallABI(['r7', 'r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6'], 4, 0)
linux_aarch64_syscall = SyscallABI(['x8', 'x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6'], 16, 0)
linux_mips_syscall = ABI(['$v0', '$a0','$a1','$a2','$a3'], 4, 0)

linux_i386_sigreturn = SigreturnABI(['eax'], 4, 0)
linux_amd64_sigreturn = SigreturnABI(['rax'], 4, 0)
Expand All @@ -93,101 +102,3 @@ class SigreturnABI(SyscallABI):
linux_i386_srop = ABI(['eax'], 4, 0)
linux_amd64_srop = ABI(['rax'], 4, 0)
linux_arm_srop = ABI(['r7'], 4, 0)


''' === OLD CODE ===
class AbiCall(Call):
"""
Encapsulates ABI-specific information about a function call, which is
to be executed with ROP.
"""
#: Mapping of registers to the values to which they should be set, before
#: $pc is set to ``addr``.
registers = {}
#: List of values which must appear in-order on the stack, including all
#: padding required by the ABI (e.g. Windows x64 requires a minimum of 32 bytes)
stack = []
def __new__(cls, *a, **kw):
# Allow explicit creation of subclasses
if cls != AbiCall:
return super(AbiCall, cls).__new__(cls, *a, **kw)
# Do not allow explicit creation of AbiCall.
# Default to the best choice.
abis = {
('i386',32,'linux'): x86LinuxAbiCall,
('amd64',64,'linux'): amd64LinuxAbiCall,
('arm',32,'linux'): armLinuxAbiCall
}
key = (context.arch, context.bits, context.os)
if key not in abis:
log.error("Don't know how to make ROP calls for %r" % (key,))
return super(AbiCall, cls).__new__(abis[key], *a, **kw)
def __init__(self, name, target, args):
super(AbiCall, self).__init__(name, target, args)
self.registers = {}
self.stack = []
self.build()
class StackAdjustingAbiCall(AbiCall):
"""
Encapsulates information about a calling convention which
may capture arguments on the stack, and as such the stack
pointer must be adjusted in order to continue ROP execution.
This functionality is separated out from the normal ABI call
so that optimizations can be performed on the last call in
the stack if there are no arguments.
"""
def build(self, addr = None):
self.stack.append(StackAdjustment())
class x86LinuxAbiCall(StackAdjustingAbiCall):
def build(self, addr = None):
super(x86LinuxAbiCall, self).build()
self.stack.extend(self.args)
class amd64LinuxAbiCall(StackAdjustingAbiCall):
def build(self, addr = None):
super(amd64LinuxAbiCall, self).build()
registers = ['rdi','rsi','rdx','rcx','r8','r9']
for reg, arg in zip(registers, self.args):
self.registers[reg] = arg
self.stack.extend(self.args[len(registers):])
class armLinuxAbiCall(StackAdjustingAbiCall):
def build(self, addr = None):
super(armLinuxAbiCall, self).build()
registers = ['r0','r1','r2','r3']
args = list(self.args)
for reg, arg in zip(registers, args):
self.registers[reg] = arg
self.stack.extend(self.args[len(registers):])
class x86SysretCall(x86LinuxAbiCall):
def build(self, addr = None):
super(x86SysretCall, self).build()
self.stack = list(self.args)
self.regs = {'eax': constants.i386.SYS_sigreturn}
class x64SysretCall(AbiCall):
def build(self, addr = None):
super(x64SysretCall, self).build()
self.stack = list(self.args)
self.regs = {'rax': constants.amd64.SYS_sigreturn}
'''
112 changes: 112 additions & 0 deletions pwnlib/args.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/usr/bin/env python2
"""
"""
import collections
import logging
import os
import string
import sys
from .context import context
from . import term

term_mode = False
args = collections.defaultdict(str)
env_prefix = 'PWNLIB_'

def isident(s):
"""
Helper function to check whether a string is a valid identifier,
as passed in on the command-line.
"""
first = string.uppercase + '_'
body = string.digits + first
if not s:
return False
if s[0] not in first:
return False
if not all(c in body for c in s[1:]):
return False
return True

def asbool(s):
"""
Convert a string to its boolean value
"""
if s.lower() == 'true':
return True
elif s.lower() == 'false':
return False
elif s.isdigit():
return bool(int(s))
else:
raise ValueError('must be integer or boolean: %r' % s)

def set_log_level(x):
with context.local(log_level=x):
context.defaults['log_level']=context.log_level

def set_log_file(x):
context.log_file=x

def set_log_level_error(x):
set_log_level('error')

def set_log_level_debug(x):
set_log_level('debug')

def set_noterm(v):
if asbool(v):
global term_mode
term_mode = False

def set_timeout(v):
context.defaults['timeout'] = int(v)

def set_randomize(v):
context.defaults['randomize'] = asbool(v)

def set_multiply(v):
context.defaults['multiply'] = int(v, 0)

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,
'MULTIPLY': set_multiply,
'TIMEOUT': set_timeout
}

def initialize():
global args, term_mode

for k, v in os.environ.items():
if not k.startswith(env_prefix):
continue
k = k[len(env_prefix):]

if k in hooks:
hooks[k](v)
elif isident(k):
args[k] = v

argv = sys.argv[:]
for arg in sys.argv[:]:
orig = arg
value = 'True'

if '=' in arg:
arg, value = arg.split('=')

if arg in hooks:
sys.argv.remove(orig)
hooks[arg](value)

elif isident(arg):
sys.argv.remove(orig)
args[arg] = value

if term_mode:
term.init()
Loading

0 comments on commit 11fa0d8

Please sign in to comment.