Commit 5fe97b51 authored by Sophie Brun's avatar Sophie Brun

New upstream version 1.1~20180207

parents
*.py[co]
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
http://creativecommons.org/licenses/by-nc-sa/3.0/
PEDA - Python Exploit Development Assistance for GDB
Version: 1.0
Release: special public release, Black Hat USA 2012
0. Credits
- Huy Phan (pdah) for reviewing code
1. Introduction
PEDA is a Python GDB script with many handy commands to help speed up
exploit development process on Linux/Unix. It is also a framework for
writing custom interactive Python GDB commands.
2. Requirements
- PEDA 1.0 is only support Linux
- GDB 7.x
- Python 2.6+
- Utilities: nasm, readelf, objdump
3. Installation
- Download
$ wget http://ropshell.com/peda/peda.tar.gz
- Unpack to HOME directory
$ tar zxvf peda.tar.gz
- Append a line to ~/.gdbinit to load PEDA when GDB starts
$ echo "source ~/peda/peda.py" >> ~/.gdbinit
4. Usage
- List of available commands:
gdb-peda$ peda help
- Search for some commands:
gdb-peda$ apropos <keyword>
gdb-peda$ help <keyword>
- Get usage manual of specific command:
gdb-peda$ phelp <command>
gdb-peda$ help <command>
- Get/set config option:
gdb-peda$ pshow option
gdb-peda$ pset option <name> <value>
peda
====
PEDA - Python Exploit Development Assistance for GDB
## Key Features:
* Enhance the display of gdb: colorize and display disassembly codes, registers, memory information during debugging.
* Add commands to support debugging and exploit development (for a full list of commands use `peda help`):
* `aslr` -- Show/set ASLR setting of GDB
* `checksec` -- Check for various security options of binary
* `dumpargs` -- Display arguments passed to a function when stopped at a call instruction
* `dumprop` -- Dump all ROP gadgets in specific memory range
* `elfheader` -- Get headers information from debugged ELF file
* `elfsymbol` -- Get non-debugging symbol information from an ELF file
* `lookup` -- Search for all addresses/references to addresses which belong to a memory range
* `patch` -- Patch memory start at an address with string/hexstring/int
* `pattern` -- Generate, search, or write a cyclic pattern to memory
* `procinfo` -- Display various info from /proc/pid/
* `pshow` -- Show various PEDA options and other settings
* `pset` -- Set various PEDA options and other settings
* `readelf` -- Get headers information from an ELF file
* `ropgadget` -- Get common ROP gadgets of binary or library
* `ropsearch` -- Search for ROP gadgets in memory
* `searchmem|find` -- Search for a pattern in memory; support regex search
* `shellcode` -- Generate or download common shellcodes.
* `skeleton` -- Generate python exploit code template
* `vmmap` -- Get virtual mapping address ranges of section(s) in debugged process
* `xormem` -- XOR a memory region with a key
## Installation
git clone https://github.com/longld/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinit
echo "DONE! debug your program with gdb and enjoy"
## Screenshot
![start](http://i.imgur.com/P1BF5mp.png)
![pattern arg](http://i.imgur.com/W97OWRC.png)
![patts](http://i.imgur.com/Br24IpC.png)
#
# PEDA - Python Exploit Development Assistance for GDB
#
# Copyright (C) 2012 Long Le Dinh <longld at vnsecurity.net>
#
# License: see LICENSE file for details
#
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
# change below settings to match your needs
## BEGIN OF SETTINGS ##
# external binaries, required for some commands
READELF = "/usr/bin/readelf"
OBJDUMP = "/usr/bin/objdump"
NASM = "/usr/bin/nasm"
NDISASM = "/usr/bin/ndisasm"
# PEDA global options
OPTIONS = {
"badchars" : ("", "bad characters to be filtered in payload/output, e.g: '\\x0a\\x00'"),
"pattern" : (1, "pattern type, 0 = basic, 1 = extended, 2 = maximum"),
"p_charset" : ("", "custom charset for pattern_create"),
"indent" : (4, "number of ident spaces for output python payload, e.g: 0|4|8"),
"ansicolor" : ("on", "enable/disable colorized output, e.g: on|off"),
"pagesize" : (25, "number of lines to display per page, 0 = disable paging"),
"session" : ("peda-session-#FILENAME#.txt", "target file to save peda session"),
"tracedepth": (0, "max depth for calls/instructions tracing, 0 means no limit"),
"tracelog" : ("peda-trace-#FILENAME#.txt", "target file to save tracecall output"),
"crashlog" : ("peda-crashdump-#FILENAME#.txt", "target file to save crash dump of fuzzing"),
"snapshot" : ("peda-snapshot-#FILENAME#.raw", "target file to save crash dump of fuzzing"),
"autosave" : ("on", "auto saving peda session, e.g: on|off"),
"payload" : ("peda-payload-#FILENAME#.txt", "target file to save output of payload command"),
"context" : ("register,code,stack", "context display setting, e.g: register, code, stack, all"),
"clearscr" : ("on", "clear screen for each context display"),
"verbose" : ("off", "show detail execution of commands, e.g: on|off"),
"debug" : ("off", "show detail error of peda commands, e.g: on|off"),
"_teefd" : ("", "internal use only for tracelog/crashlog writing")
}
## END OF SETTINGS ##
class Option(object):
"""
Class to access global options of PEDA commands and functions
TODO: save/load option to/from file
"""
options = OPTIONS.copy()
def __init__(self):
"""option format: name = (value, 'help message')"""
pass
@staticmethod
def reset():
"""reset to default options"""
Option.options = OPTIONS.copy()
return True
@staticmethod
def show(name=""):
"""display options"""
result = {}
for opt in Option.options:
if name in opt and not opt.startswith("_"):
result[opt] = Option.options[opt][0]
return result
@staticmethod
def get(name):
"""get option"""
if name in Option.options:
return Option.options[name][0]
else:
return None
@staticmethod
def set(name, value):
"""set option"""
if name in Option.options:
Option.options[name] = (value, Option.options[name][1])
return True
else:
return False
@staticmethod
def help(name=""):
"""display help info of options"""
result = {}
for opt in Option.options:
if name in opt and not opt.startswith("_"):
result[opt] = Option.options[opt][1]
return result
#
# PEDA - Python Exploit Development Assistance for GDB
#
# Copyright (C) 2012 Long Le Dinh <longld at vnsecurity.net>
#
# License: see LICENSE file for details
#
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
from utils import *
import config
class Nasm(object):
"""
Wrapper class for assemble/disassemble using nasm/ndisassm
"""
def __init__(self):
pass
@staticmethod
def assemble(asmcode, mode=32):
"""
Assemble ASM instructions using NASM
- asmcode: input ASM instructions, multiple instructions are separated by ";" (String)
- mode: 16/32/64 bits assembly
Returns:
- bin code (raw bytes)
"""
if not os.path.exists(config.NASM):
error_msg("%s binary not found, please install NASM for asm/rop functions" % config.NASM)
raise UserWarning("missing requirement")
asmcode = asmcode.strip('"').strip("'")
asmcode = asmcode.replace(";", "\n")
asmcode = ("BITS %d\n" % mode) + asmcode
asmcode = decode_string_escape(asmcode)
asmcode = re.sub("PTR|ptr|ds:|DS:", "", asmcode)
infd = tmpfile()
outfd = tmpfile(is_binary_file=True)
infd.write(asmcode)
infd.flush()
execute_external_command("%s -f bin -o %s %s" % (config.NASM, outfd.name, infd.name))
infd.close()
if os.path.exists(outfd.name):
bincode = outfd.read()
outfd.close()
return bincode
# reopen it so tempfile will not complain
open(outfd.name,'w').write('B00B')
return None
@staticmethod
def disassemble(buf, mode=32):
"""
Disassemble binary to ASM instructions using NASM
- buf: input binary (raw bytes)
- mode: 16/32/64 bits assembly
Returns:
- ASM code (String)
"""
out = execute_external_command("%s -b %d -" % (config.NDISASM, mode), buf)
return out
@staticmethod
def format_shellcode(buf, mode=32):
"""
Format raw shellcode to ndisasm output display
"\x6a\x01" # 0x00000000: push byte +0x1
"\x5b" # 0x00000002: pop ebx
TODO: understand syscall numbers, socket call
"""
def nasm2shellcode(asmcode):
if not asmcode:
return ""
shellcode = []
pattern = re.compile("([0-9A-F]{8})\s*([^\s]*)\s*(.*)")
matches = pattern.findall(asmcode)
for line in asmcode.splitlines():
m = pattern.match(line)
if m:
(addr, bytes, code) = m.groups()
sc = '"%s"' % to_hexstr(codecs.decode(bytes, 'hex'))
shellcode += [(sc, "0x"+addr, code)]
maxlen = max([len(x[0]) for x in shellcode])
text = ""
for (sc, addr, code) in shellcode:
text += "%s # %s: %s\n" % (sc.ljust(maxlen+1), addr, code)
return text
out = execute_external_command("%s -b %d -" % (config.NDISASM, mode), buf)
return nasm2shellcode(out)
This diff is collapsed.
This diff is collapsed.
#
# PEDA - Python Exploit Development Assistance for GDB
#
# Copyright (C) 2012 Long Le Dinh <longld at vnsecurity.net>
#
# License: see LICENSE file for details
#
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
class ExploitSkeleton(object):
"""
Wrapper for exploit skeleton codes
"""
def __init__(self):
self.skeleton_basic = """
#!/usr/bin/env python
#
# Template for #TYPE# exploit code, generated by PEDA
#
import os
import sys
import struct
import resource
import time
def usage():
print "Usage: %s #USAGE#" % sys.argv[0]
return
def pattern(size=1024, start=0):
try:
bytes = open("pattern.txt").read(size+start)
return bytes[start:]
except:
return "A"*size
def nops(size=1024):
return "\\x90"*size
def int2hexstr(num, intsize=4):
if intsize == 8:
if num < 0:
result = struct.pack("<q", num)
else:
result = struct.pack("<Q", num)
else:
if num < 0:
result = struct.pack("<l", num)
else:
result = struct.pack("<L", num)
return result
i2hs = int2hexstr
def list2hexstr(intlist, intsize=4):
result = ""
for value in intlist:
if isinstance(value, str):
result += value
else:
result += int2hexstr(value, intsize)
return result
l2hs = list2hexstr
"""
self.skeleton_local_argv = self.skeleton_basic
self.skeleton_local_argv = self.skeleton_local_argv.replace("#TYPE#", "local argv")
self.skeleton_local_argv = self.skeleton_local_argv.replace("#USAGE#", "target_program")
self.skeleton_local_argv += """
def exploit(vuln):
padding = pattern(0)
payload = [padding]
payload += ["PAYLOAD"] # put your payload here
payload = list2hexstr(payload)
args = [vuln, payload]
env = {"PEDA":nops()}
resource.setrlimit(resource.RLIMIT_STACK, (-1, -1))
resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
os.execve(vuln, args, env)
if __name__ == "__main__":
if len(sys.argv) < 2:
usage()
else:
exploit(sys.argv[1])
"""
self.skeleton_local_env = self.skeleton_basic
self.skeleton_local_env = self.skeleton_local_env.replace("#TYPE#", "local env")
self.skeleton_local_env = self.skeleton_local_env.replace("#USAGE#", "target_program")
self.skeleton_local_env += """
from ctypes import *
from ctypes.util import find_library
def exploit(vuln):
libc = cdll.LoadLibrary(find_library("c"))
execve = libc.execve
padding = pattern(0)
payload = [padding]
payload += ["PAYLOAD"] # put your payload here
payload = list2hexstr(payload)
args = sys.argv[1:] + [None]
# create custom env with NULL value
env = [
"EGG",
"A","","", # 0x00000041
"B"*2,"", # 0x00004242
"C"*3, # 0x00434343
"D"*4, # 0x44444444
payload,
"X", # padding
None ]
l = len(env)
envp = (c_char_p*l)()
for i in range(l):
envp[i] = cast(env[i], c_char_p)
# create custom argv with null: A "" "" BB "" CCC DDDD
l = len(args)
argp = (c_char_p*l)()
for i in range(l):
argp[i] = cast(args[i], c_char_p)
resource.setrlimit(resource.RLIMIT_STACK, (-1, -1))
resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
execve(vuln, argp, envp)
if __name__ == "__main__":
if len(sys.argv) < 2:
usage()
else:
exploit(sys.argv[1])
"""
self.skeleton_local_stdin = self.skeleton_basic
self.skeleton_local_stdin = self.skeleton_local_stdin.replace("#TYPE#", "local stdin")
self.skeleton_local_stdin = self.skeleton_local_stdin.replace("#USAGE#", "target_program")
self.skeleton_local_stdin += """
from subprocess import *
def exploit(vuln):
padding = pattern(0)
payload = [padding]
payload += ["PAYLOAD"] # put your payload here
payload = list2hexstr(payload)
env = {"PEDA":nops()}
args = sys.argv[1:]
resource.setrlimit(resource.RLIMIT_STACK, (-1, -1))
resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
P = Popen(args, stdin=PIPE)
P.stdin.write(payload + "\\n")
while True:
line = sys.stdin.readline()
P.poll()
ret = P.returncode
if ret is None:
P.stdin.write(line)
else:
if ret == -11:
print "Child program crashed with SIGSEGV"
else:
print "Child program exited with code %d" % ret
break
if __name__ == "__main__":
if len(sys.argv) < 2:
usage()
else:
exploit(sys.argv[1])
"""
self.skeleton_remote_tcp = self.skeleton_basic
self.skeleton_remote_tcp = self.skeleton_remote_tcp.replace("#TYPE#", "remote TCP")
self.skeleton_remote_tcp = self.skeleton_remote_tcp.replace("#USAGE#", "host port")
self.skeleton_remote_tcp += """
from socket import *
import telnetlib
class TCPClient():
def __init__(self, host, port, debug=0):
self.debug = debug
self.sock = socket(AF_INET, SOCK_STREAM)
self.sock.connect((host, port))
def debug_log(self, size, data, cmd):
if self.debug != 0:
print "%s(%d): %s" % (cmd, size, repr(data))
def send(self, data, delay=0):
if delay:
time.sleep(delay)
nsend = self.sock.send(data)
if self.debug > 1:
self.debug_log(nsend, data, "send")
return nsend
def sendline(self, data, delay=0):
nsend = self.send(data + "\\n", delay)
return nsend
def recv(self, size=1024, delay=0):
if delay:
time.sleep(delay)
buf = self.sock.recv(size)
if self.debug > 0:
self.debug_log(len(buf), buf, "recv")
return buf
def recv_until(self, delim):
buf = ""
while True:
c = self.sock.recv(1)
buf += c
if delim in buf:
break
self.debug_log(len(buf), buf, "recv")
return buf
def recvline(self):
buf = self.recv_until("\\n")
return buf
def close(self):
self.sock.close()
def exploit(host, port):
port = int(port)
client = TCPClient(host, port, debug=1)
padding = pattern(0)
payload = [padding]
payload += ["PAYLOAD"] # put your payload here
payload = list2hexstr(payload)
raw_input("Enter to continue")
client.send(payload)
try:
t = telnetlib.Telnet()
t.sock = client.sock
t.interact()
t.close()
except KeyboardInterrupt:
pass
if __name__ == "__main__":
if len(sys.argv) < 3:
usage()
else:
exploit(sys.argv[1], sys.argv[2])
"""
This diff is collapsed.
This diff is collapsed.
# Overview
PEDA supports Python 2 and Python 3 using the
[six](https://pypi.python.org/pypi/six) library. To make sure code runs on both
Python 2 and Python 3, make sure to keep the following in mind.
## Division
For integer division, use the `//` operator instead of `/`. In Python 3, the `/` operator returns a `float`.
In Python 3:
```python
>>> 5 / 2
2.5
>>> type(5 / 2)
<class 'float'>
```
## Type checking
To check if something is a string:
```python
isinstance(obj, six.string_types)
```
To check if something is an integer type:
```python
isinstance(x, six.integer_types)
```
## Strings
In Python 2, `bytes` is an alias for `str`. In Python 3, `str` is a unicode
type and `bytes` is used for a sequece of arbitrary bytes. Use a leading 'b' to
signify that a string is a `bytes` object.
```python
>>> 'Normal string'
'Normal string'
>>> b'arbitrary bytes \x90\x90'
b'arbitrary bytes \x90\x90'
```
To convert between `str` to `bytes`:
```python
>>> 'hi there'.encode('utf-8')
b'hi there'
>>> b'some string'.decode('utf-8')
'some string'
```
Do not mix `bytes` and `str` with each other with basic string functions. The
following is okay:
```python
>>> "abc".replace("a", "f")
'fbc'
>>> b"abc".replace(b"a", b"f")
b'fbc'
```
Mixing types in Python 3 will throw an exception:
```python
>>> b"abc".replace("a", "f")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: expected bytes, bytearray or buffer compatible object
```
In Python 2, indexing into a `str` returns a `str` of length 1. In Python 3, indexing into a `bytes` returns an `int`. This causes a problem when iterating. To solve this, use the `bytes_iterator` from `utils.py`.
```python
# In Python 2:
>>> s = b'hello'
>>> s
'hello'
>>> s[0]
'h'
# In Python 3:
>>> s = b'hello'
>>> s
b'hello'
>>> s[0]
104
# Solution:
>>> for c in bytes_iterator(b'hi'): print(c)
...
b'h'
b'i'
```
## Encodings
Encode (and decode) strings into hex:
```python
>>> codecs.encode(b'abcdef', 'hex')
b'616263646566'
>>> codecs.decode('616263646566', 'hex')
b'abcdef'
```
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment