diff --git a/dotfiles/lldb/lisa.py b/dotfiles/lldb/lisa.py new file mode 100644 index 0000000..245f187 --- /dev/null +++ b/dotfiles/lldb/lisa.py @@ -0,0 +1,2982 @@ +#!/usr/bin/env python + +# Copyright 2015 ant4g0nist + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import re +import cmd +import sys +import time +import shlex +import random +import string +import struct +import commands +import datetime +import optparse +import argparse +import platform +import httplib +from struct import * +from sys import version_info +from struct import pack +from binascii import * +from ctypes import * +import subprocess + + +#install package +def install(name): + subprocess.call(['sudo','pip', 'install', name]) + +try: + from capstone import * +except: + print "[+]\tGonna try installing capstone." + install('capstone') + from capstone import * + +PYROPGADGET_VERSION = 'ich' + +if sys.version_info.major == 3: + xrange = range + +import lldb + +#global vars# +lisaversion = 'v-ni' +PAGE_SIZE=4096 +MAX_DISTANCE=PAGE_SIZE*10 +g_ignore_frame_pointer= False +reportexploitable="" +################### + +REGISTERS = { + 8 : ["al", "ah", "bl", "bh", "cl", "ch", "dl", "dh"], + 16: ["ax", "bx", "cx", "dx"], + 32: ["eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp", "eip"], + 64: ["rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "rsp", "rip", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"] +} + +#################################### +# Misc Utils # +#################################### +def banner(debugger,command,result,dict): + + lisa2=""" + + lllllll iiii + l:::::l i::::i + l:::::l iiii + l:::::l + l::::l iiiiiii ssssssssss aaaaaaaaaaaaa + l::::l i:::::i ss::::::::::s a::::::::::::a + l::::l i::::i ss:::::::::::::s aaaaaaaaa:::::a + l::::l i::::i s::::::ssss:::::s a::::a + l::::l i::::i s:::::s ssssss aaaaaaa:::::a + l::::l i::::i s::::::s aa::::::::::::a + l::::l i::::i s::::::s a::::aaaa::::::a + l::::l i::::i ssssss s:::::s a::::a a:::::a + l::::::li::::::is:::::ssss::::::sa::::a a:::::a + l::::::li::::::is::::::::::::::s a:::::aaaa::::::a + l::::::li::::::i s:::::::::::ss a::::::::::aa:::a + lllllllliiiiiiii sssssssssss aaaaaaaaaa aaaa + """ + print tty_colors.green()+random.choice([lisa2])+tty_colors.default() + print tty_colors.red()+"\t-An Exploit Dev Swiss Army Knife. Version: "+lisaversion+tty_colors.default() + +#convert to hex +def to_hex(var): + """ + converts given value to hex + """ + return hex(var) + +#hextoascii +def hex2ascii(debugger,hex,result,dict): + """ + converts Hex to ascii + ex: h2a 0x41414141 prints AAAA + """ + print hex.replace('0x','').decode('hex') + +#generate random hex of length between n - m +def urandom(debugger,n,result,dict): + """ + Generates random hex of given length + """ + if not n: + print 'rand command an argument: example: rand 23' + return + print open('/dev/urandom','r').read(random.randint(int(n)/2,int(n)/2)).encode('hex') + +# run os commands +def shell(debugger,command,result,dict): + """ + runs shell command and prints output + """ + try: + if command: + os.system(command) + else: + print 'Please enter a proper shell command.Eg: shell ls' + return + except: + print 'Please enter a proper shell command.Eg: shell ls' + return + +#term colors +class TerminalColors: + '''Simple terminal colors class''' + def __init__(self, enabled = True): + # TODO: discover terminal type from "file" and disable if + # it can't handle the color codes + self.enabled = enabled + + def reset(self): + '''Reset all terminal colors and formatting.''' + if self.enabled: + return "\x1b[0m"; + return '' + + def bold(self, on = True): + '''Enable or disable bold depending on the "on" parameter.''' + if self.enabled: + if on: + return "\x1b[1m"; + else: + return "\x1b[22m"; + return '' + + def italics(self, on = True): + '''Enable or disable italics depending on the "on" parameter.''' + if self.enabled: + if on: + return "\x1b[3m"; + else: + return "\x1b[23m"; + return '' + + def underline(self, on = True): + '''Enable or disable underline depending on the "on" parameter.''' + if self.enabled: + if on: + return "\x1b[4m"; + else: + return "\x1b[24m"; + return '' + + def inverse(self, on = True): + '''Enable or disable inverse depending on the "on" parameter.''' + if self.enabled: + if on: + return "\x1b[7m"; + else: + return "\x1b[27m"; + return '' + + def strike(self, on = True): + '''Enable or disable strike through depending on the "on" parameter.''' + if self.enabled: + if on: + return "\x1b[9m"; + else: + return "\x1b[29m"; + return '' + + def black(self, fg = True): + '''Set the foreground or background color to black. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[30m"; + else: + return "\x1b[40m"; + return '' + + def red(self, fg = True): + '''Set the foreground or background color to red. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[31m"; + else: + return "\x1b[41m"; + return '' + + def green(self, fg = True): + '''Set the foreground or background color to green. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[32m"; + else: + return "\x1b[42m"; + return '' + + def yellow(self, fg = True): + '''Set the foreground or background color to yellow. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[43m"; + else: + return "\x1b[33m"; + return '' + + def blue(self, fg = True): + '''Set the foreground or background color to blue. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[34m"; + else: + return "\x1b[44m"; + return '' + + def magenta(self, fg = True): + '''Set the foreground or background color to magenta. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[35m"; + else: + return "\x1b[45m"; + return '' + + def cyan(self, fg = True): + '''Set the foreground or background color to cyan. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[36m"; + else: + return "\x1b[46m"; + return '' + + def white(self, fg = True): + '''Set the foreground or background color to white. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[37m"; + else: + return "\x1b[47m"; + return '' + + def default(self, fg = True): + '''Set the foreground or background color to the default. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[39m"; + else: + return "\x1b[49m"; + return '' + +#################################### +# LLDB # +#################################### + +#set malloc debugging features +def setMallocDebug(debugger,c,result,dict): + """sets DYLD_INSERT_LIBRARIES to /usr/lib/libgmalloc.dylib""" + execute(debugger,'settings set target.env-vars DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib',result,dict) + return True + +#execute given LLDB command +def execute(debugger,lldb_command,result,dict): + """ + Execute given command and print the outout to stdout + """ + debugger.HandleCommand(lldb_command) + +#execute command and return output +def executeReturnOutput(debugger,lldb_command,result,dict): + """Execute given command and returns the outout""" + ci = debugger.GetCommandInterpreter() + res=lldb.SBCommandReturnObject() + ci.HandleCommand(lldb_command,res) + output= res.GetOutput() + error = res.GetError() + return (output,error) + +def s(debugger,command,result,dict): + """step command""" + executeReturnOutput(debugger,"thread step-in",result,dict) + context(debugger,command,result,dict) + +def si(debugger,command,result,dict): + """step into command""" + executeReturnOutput(debugger,"thread step-inst",result,dict) + context(debugger,command,result,dict) + +def so(debugger,command,result,dict): + """step over""" + executeReturnOutput(debugger,"thread step-over",result,dict) + context(debugger,command,result,dict) + +def stepnInstructions(debugger,count,result,dict): + """step-in n time""" + c=0 + + while c [set a] [set b] [set c]" + seta="ABCDEFGHIJKLMNOPQRSTUVWXYZ" + setb="abcdefghijklmnopqrstuvwxyz" + setc="0123456789" + + string="" ; a=0 ; b=0 ; c=0 + + while len(string) < length: + string += seta[a] + setb[b] + setc[c] + c+=1 + if c == len(setc):c=0;b+=1 + if b == len(setb):b=0;a+=1 + if a == len(seta):a=0 + + print tty_colors.red()+ string[:length]+tty_colors.default() + + return string[:length] + +#check if given pattern is in cyclic pattern +def check_if_cyclic(debugger,pat,result,dict): + """check if given pattern is in cyclic pattern""" + + seta="ABCDEFGHIJKLMNOPQRSTUVWXYZ" + setb="abcdefghijklmnopqrstuvwxyz" + setc="0123456789" + + if not pat: + print '[+] Usage: check_if_cyclic ' + return + + string=pat ; a=0 ; b=0 ; c=0 + length=len(string) + i=0 + while i<(length-2): + if string[i].isalpha(): + if string[i].islower(): + if string[i+1].isupper(): + if string[i+2].isdigit(): + pass + else: + print tty_colors.red()+"Not a cyclic pattern"+tty_colors.default() + return False + else: + print tty_colors.red()+"Not a cyclic pattern"+tty_colors.default() + return False + + elif string[i].isupper(): + if string[i+1].islower(): + if string[i+2].isdigit(): + pass + else: + print tty_colors.red()+"Not a cyclic pattern"+tty_colors.default() + return False + else: + print tty_colors.red()+"Not a cyclic pattern"+tty_colors.default() + return False + + elif string[i].isdigit(): + if string[i+1].isalpha(): + if string[i+1].isupper(): + if string[i+2].islower(): + pass + else: + print tty_colors.red()+"Not a cyclic pattern"+tty_colors.default() + return False + else: + print tty_colors.red()+"Not a cyclic pattern"+tty_colors.default() + return False + + + i+=3 + print "seems to be a valid pattern" + return True + +#pattern search +def pattern_offset(debugger,sizepat,result,dict): + """search offset of pattern.""" + + if len(sizepat.split(' '))==2: + try: + size=int(sizepat.split(' ')[0]) + pat=sizepat.split(' ')[1] + pattern=pattern_create(debugger,size,result,dict) + if "0x" in pat: + pat=pat.replace("0x","") + pat=pat.decode("hex")[::-1] + try: + p=int(pat) + pat=pat.decode('hex') + except: + pass + found=[m.start() for m in re.finditer(pat, pattern)] + if found!=-1: + print 'offsets:',found + except: + print "please check the syntax" + print "pattern_offset 250 Aa2A" + + elif len(sizepat.split(' '))==1: + try: + size=10000 + pat=sizepat.split(' ')[1] + pattern=pattern_create(debugger,size,result,dict,True) + if "0x" in pat: + pat=pat.replace("0x","") + pat=pat.decode("hex")[::-1] + try: + p=int(pat) + pat=pat.decode('hex') + except: + pass + found=[m.start() for m in re.finditer(pat, pattern)] + # found=pattern.find(pat) + if found!=-1: + print found + except: + print "please check the syntax" + print "pattern_offset 250 Aa2A" + +#return address in register +def getregvalue(debugger,reg,result,dict): + output,error=executeReturnOutput(debugger,'register read '+reg,result,dict) + return output.split("= ")[-1].split(" ")[0] + +lldb_stop_reasons = { 'eStateCrashed' : 8, 'eStateDetached' : 9, 'eStateExited' : 10, 'eStateInvalid' : 0, + 'eStateLaunching' : 4, 'eStateRunning' : 6, 'eStateStepping' : 7,'eStateStopped' : 5, + 'eStateSuspended' : 11, 'eStopReasonBreakpoint' : 3, 'eStopReasonException' : 6, + 'eStopReasonExec' : 7, 'eStopReasonInvalid' : 0, 'eStopReasonNone' : 1, 'eStopReasonSignal' : 5, + 'eStopReasonThreadExiting' : 9, 'eStopReasonTrace' : 2, 'eStopReasonWatchpoint' : 4 + } + +def getexception(exception_description): + type1 = exception_description + try: + exception = re.search("EXC_(.+?) ",type1).group().strip(' ') + except: + exception = None + try: + code = re.search("\(code(.+?),",type1).group().split('=')[1].strip(',') + except: + try: + code = re.search("\(code(.+?)\)",type1).group().split('=')[1].strip(')') + except: + code = None + try: + address = re.search(", address(.+?)\)",type1).group().split('=')[1].strip(')') + except: + address = None + + return exception,code,address + +def getsignal(signal_description): + return signal_description.split(' ')[1] + + +def type_for_two_memory(access_address, disassembly): + first_reg_val = value_for_first_register(disassembly) + if first_reg_val != access_address: + return "read" + else: + return "write" + +def stack_access_crash(access_address, sp_val): + access_address=int(access_address,0) + sp_val = int(sp_val,0) + if ((sp_val - access_address) <= PAGE_SIZE): + return True + return False + +def getexceptiontype(access_address, disassembly, registers): + if disassembly!=None: + last_comma = disassembly.find(',') + right_paren = disassembly.find(']') + + sp = registers['sp'] + + if disassembly[right_paren+1:].find(']')!=-1: + type_=type_for_two_memory(access_address, disassembly) + return type_ + + elif disassembly.find('call')!=-1: + if not right_paren or last_comma: + type_ = "recursion" + elif stack_access_crash(access_address,sp): + print 'ohhh' + type_ = "recursion" + else: + type_ = "exec" + return type_ + + elif disassembly.find("cmp")!=-1 or disassembly.find("test")!=-1 or disassembly.find("fld")!=-1: + type_ = "read" + return type_ + + elif disassembly.find("fst")!=-1: + type_ = "write" + return type_ + + elif disassembly.find("mov")!=-1: + if last_comma>right_paren: + type_ = "read" + else: + type_ = "write" + return type_ + + elif disassembly.find('jmp')!=-1: + type_ = "exec" + return type_ + + elif disassembly.find('push')!=-1: + if right_paren: + type_ = "read" + else: + type_ = "recursion" + return type_ + + elif disassembly.find('inc')!=-1 or disassembly.find('dec')!=-1: + type_ = "write" + return type_ + + elif disassembly.find("stos")!=-1: + type_ = "write" + return type_ + + elif disassembly.find("lods")!=-1: + type_ = "read" + return type_ + + else: + type_ = "unknown" + return type_ + + if disassembly.find("st") == 2: + type_ = "write" + return type_ + + elif disassembly.find("ld") == 2: + type_ = "read" + return type_ + + elif disassembly.find("push") == 2: + type_ = "recursion" + return type_ + + else: + type_ = "unknown" + return type_ + + else: + type_ = "unknown" + return type_ + +def is_stack_suspicious(exc_address, exception, backtrace): + global reportexploitable + global is_exploitable + + suspicious_functions = [ + "__chk_fail", "__stack_chk_fail", "szone_error", "CFRelease", "CFRetain", "_CFRelease", "_CFRetain", + "malloc", "calloc", "realloc", "objc_msgSend", + "szone_free", "free_small", "tiny_free_list_add_ptr", "tiny_free_list_remove_ptr", + "small_free_list_add_ptr", "small_free_list_remove_ptr", "large_entries_free_no_lock", + "large_free_no_lock", "szone_batch_free", "szone_destroy", "free", + "CSMemDisposeHandle", "CSMemDisposePtr", + "append_int", "release_file_streams_for_task", "__guard_setup", + "_CFStringAppendFormatAndArgumentsAux", "WTF::fastFree", "WTF::fastMalloc", + "WTF::FastCalloc", "WTF::FastRealloc", " WTF::tryFastCalloc", "WTF::tryFastMalloc", + "WTF::tryFastRealloc", "WTF::TCMalloc_Central_FreeList", "GMfree", "GMmalloc_zone_free", + "GMrealloc", "GMmalloc_zone_realloc"] + + if exc_address=="0xbbadbeef": + # WebCore functions call CRASH() in various assertions or if the amount to allocate was too big. CRASH writes a null byte to 0xbbadbeef. + is_exploitable=False + print tty_colors.red()+"Exploitable = %s"%is_exploitable+tty_colors.default() + reportexploitable = "Not exploitable. Seems to be a safe crash. Calls to CRASH() function writes a null byte to 0xbbadbeef" + print tty_colors.red()+"Not exploitable. Seems to be a safe crash. Calls to CRASH() function writes a null byte to 0xbbadbeef"+tty_colors.default() + + return + + if "0 ???" in backtrace: + is_exploitable = True + print tty_colors.red()+"Exploitable = %s"%is_exploitable+tty_colors.default() + print tty_colors.red()+"This crash is suspected to be exploitable because the crashing instruction is outside of a known function, i.e. in dynamically generated code"+tty_colors.default() + reportexploitable="This crash is suspected to be exploitable because the crashing instruction is outside of a known function, i.e. in dynamically generated code" + return + + for i in suspicious_functions: + if i in backtrace: + if exception == "EXC_BREAKPOINT" and (i=="CFRelease" or i=="CFRetain"): + is_exploitable = "no" + return + elif i=="_CFRelease" or i=="CFRelease" and "CGContextDelegateFinalize" in backtrace: + return + elif i=="objc_msgSend" and exc_address< sp_val since bp_val - sp_val may have underflowed. + + if (int(bp_val,0) - int(sp_val,0)) > MAX_DISTANCE: + return True + return False + +class Lisa: + def __init__(self, debugger,result,dict): + + self.debugger = debugger + self.target = self.debugger.GetSelectedTarget() + self.process = self.target.process + self.thread = self.process.selected_thread + self.frame = self.thread.GetFrameAtIndex(0) + self.pc = hex(self.frame.pc) + self.sp = hex(self.frame.sp) + self.bp = hex(self.frame.fp) + + disas,disas_error = executeReturnOutput(debugger,"disassemble -c 1 -s $pc",result,dict) + + if disas_error: + self.pc_disas = None + else: + self.pc_disas = re.search("->(.+?)\n",disas).group().split(':')[1] + + self.backtrace, self.backtrace_error = executeReturnOutput(debugger,"bt",result,dict) + + self.crash_reason = self.thread.GetStopReason() + + if self.crash_reason == lldb_stop_reasons['eStopReasonException']: + self.exception = self.thread.GetStopDescription(80) + self.exception,self.exc_code,self.exc_address = getexception(self.exception) + self.signal = None + + print tty_colors.red()+"Exception : "+self.exception+tty_colors.default() + + elif self.crash_reason == lldb_stop_reasons['eStopReasonSignal']: + self.signal = self.thread.GetStopDescription(80) + self.signal = getsignal(self.signal) + self.exc_address = None + self.exception = None + + print tty_colors.red()+"Signal : "+self.signal+tty_colors.default() + + else: + return + + self.gen_registers = list(self.frame.registers)[0] + self.registers = {} + + for i in self.gen_registers.__iter__(): + self.registers[i.name]=i.value + + max_offset = 1024 + if self.exception: + if self.exception=="EXC_BAD_ACCESS": + # check pc == access_address + + if self.exc_address and int(self.exc_address,0)==int(self.pc,0): + # IP over write + is_exploitable = True + print tty_colors.red()+"Exploitable = %s"%is_exploitable+tty_colors.default() + print tty_colors.red()+"Trying to execute a bad address, this is a potentially exploitable issue"+tty_colors.default() + reportexploitable="Trying to execute a bad address, this is a potentially exploitable issue" + + else: + self.access_type = getexceptiontype(self.exc_address, self.pc_disas, self.registers) + + if self.exc_address and int(self.exc_address,16)MINIMUM_RECURSION_LENGTH: + print tty_colors.red()+"Exploitable = %s"%is_exploitable+tty_colors.default() + print tty_colors.red()+"The crash is suspected to be not exploitable due to unbounded recursion since there were %d stack frames."%stack_length+tty_colors.default() + reportexploitable="The crash is suspected to be not exploitable due to unbounded recursion since there were %d stack frames."%stack_length + return + else: + is_exploitable=True + + if self.access_type == "exec": + is_exploitable = True + + addr = self.exc_address + max_offset = 1024 + + if (addr > 0x55555555 - max_offset and addr < 0x55555555 + max_offset): + print tty_colors.red()+"Exploitable = %s"%is_exploitable+tty_colors.default() + print tty_colors.red()+"The access address indicates the use of freed memory if MallocScribble was used, or uninitialized memory if libgmalloc and MALLOC_FILL_SPACE was used."+tty_colors.default() + reportexploitable="The access address indicates the use of freed memory if MallocScribble was used, or uninitialized memory if libgmalloc and MALLOC_FILL_SPACE was used." + + elif (addr > 0xaaaaaaaa - max_offset and addr < 0xaaaaaaaa + max_offset): + print tty_colors.red()+"Exploitable = %s"%is_exploitable+tty_colors.default() + print tty_colors.red()+"The access address indicates that uninitialized memory was being used if MallocScribble was used."+tty_colors.default() + reportexploitable="The access address indicates that uninitialized memory was being used if MallocScribble was used." + + elif "EXC_I386_GPFLT" == self.exc_code: + print tty_colors.red()+"Exploitable = %s"%is_exploitable+tty_colors.default() + print tty_colors.red()+"The exception code indicates that the access address was invalid in the 64-bit ABI (it was > 0x0000800000000000)."+tty_colors.default() + reportexploitable="The exception code indicates that the access address was invalid in the 64-bit ABI (it was > 0x0000800000000000)." + + elif not g_ignore_frame_pointer and bp_inconsistent_with_sp(self.bp,self.sp): + is_exploitable = True + print tty_colors.red()+"Exploitable = %s"%is_exploitable+tty_colors.default() + print tty_colors.red()+"Presumed exploitable based on the discrepancy between the stack pointer and base pointer registers. "+tty_colors.default() + reportexploitable="Presumed exploitable based on the discrepancy between the stack pointer and base pointer registers." + + else: + print tty_colors.red()+"Exploitable = %s"%is_exploitable+tty_colors.default() + + if self.access_type=="read" or self.access_type=="write": + print tty_colors.red()+"Crash "+self.access_type+"'g invalid address."+tty_colors.default() + reportexploitable= "Crash "+self.access_type+"'g invalid address." + else: + print tty_colors.red()+"Crash accessing invalid address."+tty_colors.default() + reportexploitable= "Crash accessing invalid address." + + elif self.exception=="EXC_BAD_INSTRUCTION": + is_exploitable = True + print tty_colors.red()+"Exploitable = %s"%is_exploitable+tty_colors.default() + print tty_colors.blue()+"Illegal instruction at %s, probably a exploitable issue unless the crash was in libdispatch/xpc."%self.pc+tty_colors.default() + reportexploitable="Illegal instruction at %s, probably a exploitable issue unless the crash was in libdispatch/xpc."%self.pc + + elif self.exception=="EXC_ARITHMETIC": + is_exploitable = False + print tty_colors.red()+"Exploitable = %s"%is_exploitable+tty_colors.default() + print tty_colors.blue()+"Arithmetic exception at %s, probably not exploitable."%self.pc+tty_colors.default() + reportexploitable="Arithmetic exception at %s, probably not exploitable."%self.pc + + elif self.exception=="EXC_SOFTWARE": + is_exploitable=False + print tty_colors.red()+"Exploitable = %s"%is_exploitable+tty_colors.default() + print tty_colors.blue()+"Software exception, probably not exploitable."+tty_colors.default() + reportexploitable="Software exception, probably not exploitable." + + elif self.exception=="EXC_BREAKPOINT": + is_exploitable=False + print tty_colors.red()+"Exploitable = %s"%is_exploitable+tty_colors.default() + print tty_colors.blue()+"Software breakpoint, probably not exploitable."+tty_colors.default() + reportexploitable="Software breakpoint, probably not exploitable." + + elif self.exc_address=="EXC_CRASH": + is_exploitable= False + print tty_colors.red()+"Exploitable = %s"%is_exploitable+tty_colors.default() + + elif self.signal: + is_stack_suspicious(self.exc_address, self.exception, self.backtrace) + + +def exploitable(debugger,cmd,res,dict): + """checks if the crash is exploitable""" + lisa_=Lisa(debugger,res,dict) + +class ShellStorm: + def __init__(self): + pass + + def searchShellcode(self, keyword): + try: + print "Connecting to shell-storm.org..." + s = httplib.HTTPConnection("shell-storm.org") + s.request("GET", "/api/?s="+str(keyword)) + res = s.getresponse() + data_l = res.read().split('\n') + except: + print "Cannot connect to shell-storm.org" + return None + + data_dl = [] + for data in data_l: + try: + desc = data.split("::::") + try: + dico = { + 'ScAuthor': desc[0], + 'ScArch': desc[1], + 'ScTitle': desc[2], + 'ScId': desc[3], + 'ScUrl': desc[4], + 'ScSize': int(''.join(x for x in desc[2][-10:-5] if x.isdigit())) + } + except Exception: + dico = { + 'ScAuthor': desc[0], + 'ScArch': desc[1], + 'ScTitle': desc[2], + 'ScId': desc[3], + 'ScUrl': desc[4], + 'ScSize': 0 + } + + + data_dl.append(dico) + except: + pass + + try: + return sorted(data_dl, key=lambda x: x['ScSize'], reverse=True) + except Exception: + print("Could not sort by size") + + return data_dl + + def displayShellcode(self, shellcodeId): + if shellcodeId is None: + return None + + try: + print "Connecting to shell-storm.org..." + s = httplib.HTTPConnection("shell-storm.org") + except: + print "Cannot connect to shell-storm.org" + return None + + try: + s.request("GET", "/shellcode/files/shellcode-"+str(shellcodeId)+".php") + res = s.getresponse() + data = res.read().split("
")[1].split("")[0]
+        except:
+            print "Failed to download shellcode from shell-storm.org"
+            return None
+
+        data = data.replace(""", "\"")
+        data = data.replace("&", "&")
+        data = data.replace("<", "<")
+        data = data.replace(">", ">")
+
+        return data
+
+    @staticmethod
+    def version():
+        print "shell-storm API - v0.1"
+        print "Search and display all shellcodes in shell-storm database"
+        print "Jonathan Salwan - @JonathanSalwan - 2012"
+        print "http://shell-storm.org"
+        return
+
+def extract_from_universal_binary(debugger,command,result,dict):
+    """Uses lipo to extract a given architecture from a Universal binary
+        Syntax: extract x86_64  
+        Ex: extract x86_64 /usr/lib/system/libsystem_kernel.dylib ./libsystem_kernel.dylib
+
+    """
+    args = shlex.split(command)
+    if len(args)==3:
+        architecture = args[0]
+        intputfile = args[1]
+        outputfile = args[2]
+
+        commands.getoutput('lipo '+intputfile+' -extract '+architecture+' -output '+outputfile)
+    else:
+        print "Syntax: extract x86_64 /usr/lib/system/libsystem_kernel.dylib ./libsystem_kernel.dylib"
+
+
+
+def shellcode(debugger, command, result, dict):
+    """Searches shell-storm for shellcode
+       Syntax:shellcode"""
+    mod = shlex.split(command)
+    if len(mod)!=2:
+        print "Syntax:   shellcode