diff options
| author | Malfurious <m@lfurio.us> | 2022-03-14 00:43:15 -0400 | 
|---|---|---|
| committer | Malfurious <m@lfurio.us> | 2022-03-14 00:43:15 -0400 | 
| commit | 616c8b8eadbde6fbb2fe16a6a2167e04f9d16382 (patch) | |
| tree | 6560d8b5fea2b40d041f52683cd7accc61ce67a5 | |
| parent | dcba5f2b3d13f5142e4e552bdd717286f953bf1a (diff) | |
| parent | c493a8f8073702bcdccdbc40bf09931e201c9013 (diff) | |
| download | nsploit-616c8b8eadbde6fbb2fe16a6a2167e04f9d16382.tar.gz nsploit-616c8b8eadbde6fbb2fe16a6a2167e04f9d16382.zip | |
Merge tag 'pull-sploit-rev' of https://github.com/Dusoleil/lib-des-gnux
Add rev for basic reverse engineering
* tag 'pull-sploit-rev' of https://github.com/Dusoleil/lib-des-gnux:
  sploit: Move __attr_filter__ to a general place in util
  sploit: Filter all magic python members by default in mem module
  sploit: add stack base pointer to locals symtbl
  sploit: print hex of addresses in rev logs
  sploit: add status logging to rev module
  sploit: lazy load libs for ELF
  sploit: cache results of external commands
  sploit: add the rest of r2 functions through elf
  sploit: typo fix in rev.r2
  sploit: cache ELF loads
  sploit: add ELF helper class to rev
  sploit: consolidate r2 symbol search calls
  sploit: fix r2 module syntax error
  sploit: reverse direction of r2 get_locals offsets
  sploit: add r2 funcionality to rev module
  sploit: add ldd ability to rev module
  sploit: add rev module to sploit
| -rw-r--r-- | setup.py | 4 | ||||
| -rw-r--r-- | sploit/__init__.py | 2 | ||||
| -rw-r--r-- | sploit/mem.py | 9 | ||||
| -rw-r--r-- | sploit/rev/__init__.py | 6 | ||||
| -rw-r--r-- | sploit/rev/elf.py | 56 | ||||
| -rw-r--r-- | sploit/rev/ldd.py | 13 | ||||
| -rw-r--r-- | sploit/rev/r2.py | 94 | ||||
| -rw-r--r-- | sploit/util.py | 22 | 
8 files changed, 201 insertions, 5 deletions
| @@ -1,7 +1,7 @@ -from setuptools import setup +from setuptools import setup, find_packages  setup(          name='sploit',          version='0', -        packages=['sploit'], +        packages=find_packages(),          entry_points={"console_scripts":["sploit=sploit.main:main"]}       ) diff --git a/sploit/__init__.py b/sploit/__init__.py index 9e637df..f5a82fc 100644 --- a/sploit/__init__.py +++ b/sploit/__init__.py @@ -5,4 +5,6 @@ from sploit import (          mem,          payload,          until, +        util, +        rev,  ) diff --git a/sploit/mem.py b/sploit/mem.py index 3ad0c50..ac2bbb1 100644 --- a/sploit/mem.py +++ b/sploit/mem.py @@ -1,3 +1,5 @@ +from sploit.util import __attr_filter__ +  class Symtbl:      __subs__ = {}      def __init__(self, **kwargs): @@ -12,7 +14,7 @@ class Symtbl:              self.off = off              self.tbl = tbl          def __getattribute__(self,sym): -            if(sym in ['off','tbl','__class__']): +            if(sym in (['off','tbl'] + __attr_filter__)):                  return object.__getattribute__(self,sym)              addr = getattr(self.tbl,sym)              if(type(addr)==int): @@ -30,7 +32,8 @@ class Symtbl:      def __getattribute__(self, sym):          addr = object.__getattribute__(self,sym) -        if(sym == '__subs__'):return addr +        if(sym in (['__subs__'] + __attr_filter__)): +            return addr          if(sym == 'base'):return 0          if(sym in self.__subs__):              return self.__InnerTable__(addr,self.__subs__[sym]) @@ -51,7 +54,7 @@ class Memmap:          self.base = addr - sym      def __getattribute__(self, sym): -        if(sym in ['__tbl__','base']): +        if(sym in (['__tbl__','base'] + __attr_filter__)):              return object.__getattribute__(self, sym)          addr = getattr(self.__tbl__, sym)          if(type(addr)==Symtbl.__InnerTable__): diff --git a/sploit/rev/__init__.py b/sploit/rev/__init__.py new file mode 100644 index 0000000..43cee7b --- /dev/null +++ b/sploit/rev/__init__.py @@ -0,0 +1,6 @@ +from . import ( +        ldd, +        r2, +        elf, +) + diff --git a/sploit/rev/elf.py b/sploit/rev/elf.py new file mode 100644 index 0000000..7bfd31f --- /dev/null +++ b/sploit/rev/elf.py @@ -0,0 +1,56 @@ +from sploit.rev import ldd, r2 +from sploit.util import __attr_filter__ + +class ELF: +    def __init__(self, path): +        self.path = path +        self.sym = r2.get_elf_symbols(self.path) +        libs = ldd.get_libraries(self.path) +        self.libs = self.__LIBS__(libs) +        self.locals = self.__LOCALS__(self) + +    def __str__(self): +        s = 'ELF: ' +        s += self.path +        s += '\nSymbol Table' +        s += '\n------------' +        s += '\n' +        s += str(self.sym) +        s += '\n------------' +        s += '\nLibararies' +        s += '\n------------' +        s += str(self.libs) +        return s + +    class __LIBS__(dict): +        def __init__(self, libs): +            super().__init__({lib.name:lib.path for lib in libs.values() if lib.path}) +        def __getitem__(self, lib): +            get = super().__getitem__ +            if(type(get(lib))==str):self[lib] = ELF(get(lib)) +            return get(lib) +        def __str__(self): +            s = '' +            for name,lib in self.items(): +                s += '\n' + str(name) + ' => ' + lib if(type(lib)==str) else str(lib.path) +            return s + +    class __LOCALS__: +        def __init__(self, elf): +            self.elf = elf +        def __getattribute__(self, sym): +            if(sym in (['elf'] + __attr_filter__)): +                return object.__getattribute__(self,sym) +            return r2.get_locals(self.elf.path, getattr(self.elf.sym, sym)) + +    def retaddr(self, caller, callee): +        return [c.ret_addr for c in r2.get_call_returns(self.path, caller, callee)] + +    def retgad(self): +        return r2.ret_gadget(self.path) + +    def gad(self, gad): +        return [g.addr for g in r2.rop_gadget(self.path, gad)] + +    def egad(self, gad): +        return r2.rop_gadget_exact(self.path, gad).addr diff --git a/sploit/rev/ldd.py b/sploit/rev/ldd.py new file mode 100644 index 0000000..1a28c7c --- /dev/null +++ b/sploit/rev/ldd.py @@ -0,0 +1,13 @@ +from sploit.util import run_cmd_cached +from sploit.log import ilog + +import re +from collections import namedtuple as nt + +def get_libraries(elf): +    ilog(f'Retrieving linked libraries of {elf} with ldd...') +    out = run_cmd_cached(['ldd',elf]) +    out = [re.split(r'\s+',lib)[1:] for lib in out] +    Lib = nt("Lib", "name path addr") +    out = {l[0]:Lib(l[0],l[0] if l[0][0]=='/' else l[2] if l[1]=='=>' else None,l[-1]) for l in out} +    return out diff --git a/sploit/rev/r2.py b/sploit/rev/r2.py new file mode 100644 index 0000000..bb3edb3 --- /dev/null +++ b/sploit/rev/r2.py @@ -0,0 +1,94 @@ +from sploit.mem import Symtbl +from sploit.arch import arch +from sploit.util import run_cmd_cached +from sploit.log import ilog + +import re +from collections import namedtuple as nt + +def run_cmd(binary,cmd): +    return run_cmd_cached(['r2','-q','-c',cmd,'-e','scr.color=false',binary]) + +def get_elf_symbols(elf): +    ilog(f'Retrieving symbols of {elf} with r2...') +    out = {} + +    cmd_syms = 'is' +    out_syms = run_cmd(elf,cmd_syms) +    out_syms = [re.split(r'\s+',sym) for sym in out_syms][4:] +    out_syms = [sym for sym in out_syms if sym[6].find('.')<0] +    out_syms = [sym for sym in out_syms if sym[4]=='FUNC' or sym[4]=='LOOS' or sym[4]=='TLS'] +    out_syms = {sym[6]:int(sym[2],0) for sym in out_syms} +    out.update(out_syms) + +    cmd_syms = 'ii~ FUNC ' +    out_syms = run_cmd(elf,cmd_syms) +    out_syms = [re.split(r'\s+',sym) for sym in out_syms] +    out_syms = {"_PLT_"+sym[4]:int(sym[1],0) for sym in out_syms} +    out.update(out_syms) + +    cmd_syms = 'fs relocs;f' +    out_syms = run_cmd(elf,cmd_syms) +    out_syms = [re.split(r'\s+',sym) for sym in out_syms] +    out_syms = {"_GOT_"+sym[2][sym[2].rfind('.')+1:]:int(sym[0],0) for sym in out_syms} +    out.update(out_syms) + +    cmd_strs = 'fs strings;f' +    out_strs = run_cmd(elf,cmd_strs) +    out_strs = [re.split(r'\s+',sym) for sym in out_strs] +    out_strs = {sym[2][sym[2].rfind('.')+1:]:int(sym[0],0) for sym in out_strs} +    out.update(out_strs) + +    return Symtbl(**out) + +def get_locals(binary,func): +    ilog(f'Retrieving local stack frame of {hex(func)} in {binary} with r2...') + +    addr = hex(func) +    cmd_locals = f's {func};af;aafr;aaft;afvf' +    out = run_cmd(binary,cmd_locals) +    out = [re.split(r':?\s+',var) for var in out] +    out = {var[1]:-(int(var[0],0)-arch.wordsize) for var in out} +    out = Symtbl(**out) +    out.sbp = 0 +    return out + +def ret_gadget(binary): +    ilog(f'Searching for a ret gadget in {binary} with r2...') + +    cmd_ret = '/R/ ret~ret' +    out = run_cmd(binary,cmd_ret) +    out = out[0] +    out = re.split(r'\s+',out) +    out = out[1] +    return int(out,0) + +def rop_gadget(binary,gad): +    ilog(f'Searching for "{gad}" gadgets in {binary} with r2...') + +    cmd_gad = f'"/R/q {gad}"' +    out = run_cmd(binary,cmd_gad) +    Gad = nt("Gad", "addr asm") +    out = [Gad(int(gad[:gad.find(':')],0),gad[gad.find(':')+2:]) for gad in out] +    return out + +def rop_gadget_exact(binary,gad): +    gads = rop_gadget(binary,gad) +    for g in gads: +        if g.asm[:-1].replace('; ',';') == gad: +            return g + +def get_call_returns(binary,xref_from,xref_to): +    ilog(f'Getting return addresses of calls from {hex(xref_from)} to {hex(xref_to)} in {binary} with r2...') + +    cmd_xrefs = f's {hex(xref_from)};af;axq' +    xrefs = run_cmd(binary,cmd_xrefs) +    xrefs = [re.split(r'\s+',x) for x in xrefs] +    xrefs = [x for x in xrefs if int(x[2],0)==xref_to] +    rets = [] +    CallRet = nt("CallRet", "xref_from xref_to call_addr ret_addr") +    for x in xrefs: +        cmd_ret = f's {x[0]};so;s' +        ret = run_cmd(binary,cmd_ret) +        rets.append(CallRet(xref_from,xref_to,int(x[0],0),int(ret[0],0))) +    return rets diff --git a/sploit/util.py b/sploit/util.py new file mode 100644 index 0000000..8a259c4 --- /dev/null +++ b/sploit/util.py @@ -0,0 +1,22 @@ +from subprocess import run + +def run_cmd(cmd): +    return run(cmd,capture_output=True).stdout.decode('utf-8').split('\n')[:-1] + +__RUN_CACHE__ = {} +def run_cmd_cached(cmd): +    key = ''.join(cmd) +    if key in __RUN_CACHE__: +        return __RUN_CACHE__[key] +    else: +        result = run_cmd(cmd) +        __RUN_CACHE__[key] = result +        return result + +__attr_filter__ = ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', +        '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', +        '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', +        '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', +        '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', +        '__weakref__'] + | 
