From cdd6180dacf2fbd380b8a1c2fea38959a2953dbb Mon Sep 17 00:00:00 2001 From: dusoleil Date: Fri, 11 Mar 2022 09:01:18 -0500 Subject: sploit: add rev module to sploit Signed-off-by: dusoleil --- tools/sploit/setup.py | 4 ++-- tools/sploit/sploit/__init__.py | 1 + tools/sploit/sploit/rev/__init__.py | 0 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 tools/sploit/sploit/rev/__init__.py diff --git a/tools/sploit/setup.py b/tools/sploit/setup.py index eb1b299..5afa958 100644 --- a/tools/sploit/setup.py +++ b/tools/sploit/setup.py @@ -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/tools/sploit/sploit/__init__.py b/tools/sploit/sploit/__init__.py index 9e637df..137cd35 100644 --- a/tools/sploit/sploit/__init__.py +++ b/tools/sploit/sploit/__init__.py @@ -5,4 +5,5 @@ from sploit import ( mem, payload, until, + rev, ) diff --git a/tools/sploit/sploit/rev/__init__.py b/tools/sploit/sploit/rev/__init__.py new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3 From 30004f849d2cbb91432cb2700379e17765eccb03 Mon Sep 17 00:00:00 2001 From: dusoleil Date: Fri, 11 Mar 2022 09:04:32 -0500 Subject: sploit: add ldd ability to rev module add helper function to invoke ldd to get a list of libraries that will be linked to a given ELF Signed-off-by: dusoleil --- tools/sploit/sploit/rev/__init__.py | 4 ++++ tools/sploit/sploit/rev/ldd.py | 10 ++++++++++ 2 files changed, 14 insertions(+) create mode 100644 tools/sploit/sploit/rev/ldd.py diff --git a/tools/sploit/sploit/rev/__init__.py b/tools/sploit/sploit/rev/__init__.py index e69de29..c489b98 100644 --- a/tools/sploit/sploit/rev/__init__.py +++ b/tools/sploit/sploit/rev/__init__.py @@ -0,0 +1,4 @@ +from . import ( + ldd +) + diff --git a/tools/sploit/sploit/rev/ldd.py b/tools/sploit/sploit/rev/ldd.py new file mode 100644 index 0000000..60306f1 --- /dev/null +++ b/tools/sploit/sploit/rev/ldd.py @@ -0,0 +1,10 @@ +import re +from subprocess import run +from collections import namedtuple as nt + +def get_libraries(elf): + out = run(['ldd',elf],capture_output=True).stdout.decode('utf-8').split('\n')[:-1] + 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 -- cgit v1.2.3 From 461df183a551566c4a24f6f075ebabdd7a59f32f Mon Sep 17 00:00:00 2001 From: dusoleil Date: Fri, 11 Mar 2022 09:15:31 -0500 Subject: sploit: add r2 funcionality to rev module Add an r2 module with several helper functions that do a number of simple reverse engineering tasks to aid in writing simple sploit scripts. The functions in this module invoke radare2 to accomplish their tasks. Signed-off-by: dusoleil --- tools/sploit/sploit/rev/__init__.py | 3 +- tools/sploit/sploit/rev/r2.py | 92 +++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 tools/sploit/sploit/rev/r2.py diff --git a/tools/sploit/sploit/rev/__init__.py b/tools/sploit/sploit/rev/__init__.py index c489b98..b6a73a2 100644 --- a/tools/sploit/sploit/rev/__init__.py +++ b/tools/sploit/sploit/rev/__init__.py @@ -1,4 +1,5 @@ from . import ( - ldd + ldd, + r2, ) diff --git a/tools/sploit/sploit/rev/r2.py b/tools/sploit/sploit/rev/r2.py new file mode 100644 index 0000000..cd4684f --- /dev/null +++ b/tools/sploit/sploit/rev/r2.py @@ -0,0 +1,92 @@ +from sploit.mem import Symtbl +from sploit.arch import arch + +import re +from subprocess import run +from collections import namedtuple as nt + +def run_cmd(binary,cmd): + return run(['r2','-q','-c',cmd,'-e','scr.color=false',binary],capture_output=True).stdout.decode('utf-8').split('\n')[:-1] + +def get_elf_symbols(elf): + out = {} + + cmd_syms = 'is~ FUNC ' + out_syms = r2.run_cmd(elf,cmd_syms) + out_syms = [re.split(r'\s+',sym) for sym in out_syms] + out_syms = {sym[6]:int(sym[2],0) for sym in out_syms if sym[6].find('.')<0} + out.update(out_syms) + + cmd_syms = 'is~ LOOS ' + out_syms = r2.run_cmd(elf,cmd_syms) + out_syms = [re.split(r'\s+',sym) for sym in out_syms] + out_syms = {sym[6]:int(sym[2],0) for sym in out_syms if sym[6].find('.')<0} + out.update(out_syms) + + cmd_syms = 'is~ TLS ' + out_syms = r2.run_cmd(elf,cmd_syms) + out_syms = [re.split(r'\s+',sym) for sym in out_syms] + out_syms = {sym[6]:int(sym[2],0) for sym in out_syms if sym[6].find('.')<0} + out.update(out_syms) + + cmd_syms = 'ii~ FUNC ' + out_syms = r2.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 = r2.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 = r2.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): + addr = hex(func) + cmd_locals = f's {func};af;aafr;aaft;afvf' + out = r2.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} + return Symtbl(**out) + +def ret_gadget(binary): + cmd_ret = '/R/ ret~ret' + out = r2.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): + cmd_gad = f'"/R/q {gad}"' + out = r2.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 = r2.rop_gadget(gad,elf) + for g in gads: + if g.asm[:-1].replace('; ',';') == gad: + return g + +def get_call_returns(binary,xref_from,xref_to): + cmd_xrefs = f's {hex(xref_from)};af;axq' + xrefs = r2.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 = r2.run_cmd(binary,cmd_ret) + rets.append(CallRet(xref_from,xref_to,int(x[0],0),int(ret[0],0))) + return rets -- cgit v1.2.3 From 435890fec3cc62d67a154f5f6f4c04e21f81d7a5 Mon Sep 17 00:00:00 2001 From: dusoleil Date: Fri, 11 Mar 2022 09:19:25 -0500 Subject: sploit: reverse direction of r2 get_locals offsets rev.r2's get_locals() function returns a Symtbl of offsets representing the local variables on in a stack frame of a particular function. The offsets returned by r2 are based around the base of the stack, but they are increasing in value as they grow from the stack. To properly model memory, they should decrease in value as they grow from the stack. Signed-off-by: dusoleil --- tools/sploit/sploit/rev/r2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/sploit/sploit/rev/r2.py b/tools/sploit/sploit/rev/r2.py index cd4684f..c133c33 100644 --- a/tools/sploit/sploit/rev/r2.py +++ b/tools/sploit/sploit/rev/r2.py @@ -54,7 +54,7 @@ def get_locals(binary,func): cmd_locals = f's {func};af;aafr;aaft;afvf' out = r2.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 = {var[1]:-(int(var[0],0)-arch.wordsize) for var in out} return Symtbl(**out) def ret_gadget(binary): -- cgit v1.2.3 From f239dd6d622a6c2a18cfee07aa2e2e120eef2deb Mon Sep 17 00:00:00 2001 From: dusoleil Date: Fri, 11 Mar 2022 09:27:00 -0500 Subject: sploit: fix r2 module syntax error forgot to remove the r2 namespace from the calls from back when it was implemented differently Signed-off-by: dusoleil --- tools/sploit/sploit/rev/r2.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/sploit/sploit/rev/r2.py b/tools/sploit/sploit/rev/r2.py index c133c33..306e026 100644 --- a/tools/sploit/sploit/rev/r2.py +++ b/tools/sploit/sploit/rev/r2.py @@ -12,37 +12,37 @@ def get_elf_symbols(elf): out = {} cmd_syms = 'is~ FUNC ' - out_syms = r2.run_cmd(elf,cmd_syms) + out_syms = run_cmd(elf,cmd_syms) out_syms = [re.split(r'\s+',sym) for sym in out_syms] out_syms = {sym[6]:int(sym[2],0) for sym in out_syms if sym[6].find('.')<0} out.update(out_syms) cmd_syms = 'is~ LOOS ' - out_syms = r2.run_cmd(elf,cmd_syms) + out_syms = run_cmd(elf,cmd_syms) out_syms = [re.split(r'\s+',sym) for sym in out_syms] out_syms = {sym[6]:int(sym[2],0) for sym in out_syms if sym[6].find('.')<0} out.update(out_syms) cmd_syms = 'is~ TLS ' - out_syms = r2.run_cmd(elf,cmd_syms) + out_syms = run_cmd(elf,cmd_syms) out_syms = [re.split(r'\s+',sym) for sym in out_syms] out_syms = {sym[6]:int(sym[2],0) for sym in out_syms if sym[6].find('.')<0} out.update(out_syms) cmd_syms = 'ii~ FUNC ' - out_syms = r2.run_cmd(elf,cmd_syms) + 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 = r2.run_cmd(elf,cmd_syms) + 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 = r2.run_cmd(elf,cmd_strs) + 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) @@ -52,14 +52,14 @@ def get_elf_symbols(elf): def get_locals(binary,func): addr = hex(func) cmd_locals = f's {func};af;aafr;aaft;afvf' - out = r2.run_cmd(binary,cmd_locals) + 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} return Symtbl(**out) def ret_gadget(binary): cmd_ret = '/R/ ret~ret' - out = r2.run_cmd(binary,cmd_ret) + out = run_cmd(binary,cmd_ret) out = out[0] out = re.split(r'\s+',out) out = out[1] @@ -67,26 +67,26 @@ def ret_gadget(binary): def rop_gadget(binary,gad): cmd_gad = f'"/R/q {gad}"' - out = r2.run_cmd(binary,cmd_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 = r2.rop_gadget(gad,elf) + gads = rop_gadget(gad,elf) for g in gads: if g.asm[:-1].replace('; ',';') == gad: return g def get_call_returns(binary,xref_from,xref_to): cmd_xrefs = f's {hex(xref_from)};af;axq' - xrefs = r2.run_cmd(binary,cmd_xrefs) + 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 = r2.run_cmd(binary,cmd_ret) + ret = run_cmd(binary,cmd_ret) rets.append(CallRet(xref_from,xref_to,int(x[0],0),int(ret[0],0))) return rets -- cgit v1.2.3 From 2340245d685ec19e6517f95c1ff8dc8b9249e873 Mon Sep 17 00:00:00 2001 From: dusoleil Date: Fri, 11 Mar 2022 09:48:42 -0500 Subject: sploit: consolidate r2 symbol search calls Consolidate some of the r2 calls that get combined to create the symbol list. Instead of doing multiple calls with different greps within radare2, just do a single call and search it in the python side. This gives us a slight, but noticeable performance increase. Signed-off-by: dusoleil --- tools/sploit/sploit/rev/r2.py | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/tools/sploit/sploit/rev/r2.py b/tools/sploit/sploit/rev/r2.py index 306e026..6fde112 100644 --- a/tools/sploit/sploit/rev/r2.py +++ b/tools/sploit/sploit/rev/r2.py @@ -10,23 +10,12 @@ def run_cmd(binary,cmd): def get_elf_symbols(elf): out = {} - - cmd_syms = 'is~ FUNC ' - out_syms = run_cmd(elf,cmd_syms) - out_syms = [re.split(r'\s+',sym) for sym in out_syms] - out_syms = {sym[6]:int(sym[2],0) for sym in out_syms if sym[6].find('.')<0} - out.update(out_syms) - - cmd_syms = 'is~ LOOS ' + cmd_syms = 'is' out_syms = run_cmd(elf,cmd_syms) - out_syms = [re.split(r'\s+',sym) for sym in out_syms] - out_syms = {sym[6]:int(sym[2],0) for sym in out_syms if sym[6].find('.')<0} - out.update(out_syms) - - cmd_syms = 'is~ TLS ' - out_syms = run_cmd(elf,cmd_syms) - out_syms = [re.split(r'\s+',sym) for sym in out_syms] - out_syms = {sym[6]:int(sym[2],0) for sym in out_syms if sym[6].find('.')<0} + 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 ' -- cgit v1.2.3 From 352fe42c6e5e4f5996289bc0d9479c1be19c1117 Mon Sep 17 00:00:00 2001 From: dusoleil Date: Fri, 11 Mar 2022 10:15:35 -0500 Subject: sploit: add ELF helper class to rev Create a class which encapsulates some basic information about an ELF file and provides a convenient interface for basic reverse engineering. In particular, ELF automatically loads the symbol table of the given elf file and recursively creates ELF objects for any linked libraries. Signed-off-by: dusoleil --- tools/sploit/sploit/rev/__init__.py | 1 + tools/sploit/sploit/rev/elf.py | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 tools/sploit/sploit/rev/elf.py diff --git a/tools/sploit/sploit/rev/__init__.py b/tools/sploit/sploit/rev/__init__.py index b6a73a2..43cee7b 100644 --- a/tools/sploit/sploit/rev/__init__.py +++ b/tools/sploit/sploit/rev/__init__.py @@ -1,5 +1,6 @@ from . import ( ldd, r2, + elf, ) diff --git a/tools/sploit/sploit/rev/elf.py b/tools/sploit/sploit/rev/elf.py new file mode 100644 index 0000000..a748f10 --- /dev/null +++ b/tools/sploit/sploit/rev/elf.py @@ -0,0 +1,22 @@ +from sploit.rev import ldd, r2 + +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 = {lib.name:ELF(lib.path) for lib in libs.values() if lib.path} + + 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------------' + for name,lib in self.libs.items(): + s += '\n' + str(name) + ' => ' + str(lib.path) + return s -- cgit v1.2.3 From 84aae4be53028e543fa9b00f1bc53d6c2420cc51 Mon Sep 17 00:00:00 2001 From: dusoleil Date: Fri, 11 Mar 2022 10:27:58 -0500 Subject: sploit: cache ELF loads With recursive ELF loads, there is the possibility of loading in a heavy ELF (like libc) multiple times. Hiding instantiation of the class behind a factory method and caching instances should eliminate this problem. Signed-off-by: dusoleil --- tools/sploit/sploit/rev/elf.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tools/sploit/sploit/rev/elf.py b/tools/sploit/sploit/rev/elf.py index a748f10..bdced0a 100644 --- a/tools/sploit/sploit/rev/elf.py +++ b/tools/sploit/sploit/rev/elf.py @@ -1,6 +1,16 @@ from sploit.rev import ldd, r2 -class ELF: +__ELF_CACHE__ = {} + +def ELF(path): + if path in __ELF_CACHE__: + return __ELF_CACHE__[path] + else: + elf = __ELF__(path) + __ELF_CACHE__[path] = elf + return elf + +class __ELF__: def __init__(self, path): self.path = path self.sym = r2.get_elf_symbols(self.path) -- cgit v1.2.3 From ae2b8e94ec5da005fd28233971a7b31256cdcf61 Mon Sep 17 00:00:00 2001 From: dusoleil Date: Fri, 11 Mar 2022 11:21:34 -0500 Subject: sploit: typo fix in rev.r2 accidentally left the argument as "elf" instead of "binary" and had the arguments in the wrong order Signed-off-by: dusoleil --- tools/sploit/sploit/rev/r2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/sploit/sploit/rev/r2.py b/tools/sploit/sploit/rev/r2.py index 6fde112..af0fe24 100644 --- a/tools/sploit/sploit/rev/r2.py +++ b/tools/sploit/sploit/rev/r2.py @@ -62,7 +62,7 @@ def rop_gadget(binary,gad): return out def rop_gadget_exact(binary,gad): - gads = rop_gadget(gad,elf) + gads = rop_gadget(binary,gad) for g in gads: if g.asm[:-1].replace('; ',';') == gad: return g -- cgit v1.2.3 From 083ed374269e8a6be53d33eeddb396442205d925 Mon Sep 17 00:00:00 2001 From: dusoleil Date: Fri, 11 Mar 2022 11:36:59 -0500 Subject: sploit: add the rest of r2 functions through elf expose the rest of the rev.r2 capabilities through rev.elf Signed-off-by: dusoleil --- tools/sploit/sploit/rev/elf.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tools/sploit/sploit/rev/elf.py b/tools/sploit/sploit/rev/elf.py index bdced0a..d9edd40 100644 --- a/tools/sploit/sploit/rev/elf.py +++ b/tools/sploit/sploit/rev/elf.py @@ -16,6 +16,7 @@ class __ELF__: self.sym = r2.get_elf_symbols(self.path) libs = ldd.get_libraries(self.path) self.libs = {lib.name:ELF(lib.path) for lib in libs.values() if lib.path} + self.locals = self.__LOCALS__(self) def __str__(self): s = 'ELF: ' @@ -30,3 +31,22 @@ class __ELF__: for name,lib in self.libs.items(): s += '\n' + str(name) + ' => ' + str(lib.path) return s + + class __LOCALS__: + def __init__(self,elf): + self.elf = elf + def __getattribute__(self, sym): + if(sym=='elf'):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 -- cgit v1.2.3 From bb5575987ff7237af8011928304ed2db2a457720 Mon Sep 17 00:00:00 2001 From: dusoleil Date: Sat, 12 Mar 2022 19:18:28 -0500 Subject: sploit: cache results of external commands rather than cacheing ELF instantiations, just cache the results of external commands Signed-off-by: dusoleil --- tools/sploit/sploit/__init__.py | 1 + tools/sploit/sploit/rev/elf.py | 12 +----------- tools/sploit/sploit/rev/ldd.py | 5 +++-- tools/sploit/sploit/rev/r2.py | 4 ++-- tools/sploit/sploit/util.py | 18 ++++++++++++++++++ 5 files changed, 25 insertions(+), 15 deletions(-) create mode 100644 tools/sploit/sploit/util.py diff --git a/tools/sploit/sploit/__init__.py b/tools/sploit/sploit/__init__.py index 137cd35..f5a82fc 100644 --- a/tools/sploit/sploit/__init__.py +++ b/tools/sploit/sploit/__init__.py @@ -5,5 +5,6 @@ from sploit import ( mem, payload, until, + util, rev, ) diff --git a/tools/sploit/sploit/rev/elf.py b/tools/sploit/sploit/rev/elf.py index d9edd40..1957c15 100644 --- a/tools/sploit/sploit/rev/elf.py +++ b/tools/sploit/sploit/rev/elf.py @@ -1,16 +1,6 @@ from sploit.rev import ldd, r2 -__ELF_CACHE__ = {} - -def ELF(path): - if path in __ELF_CACHE__: - return __ELF_CACHE__[path] - else: - elf = __ELF__(path) - __ELF_CACHE__[path] = elf - return elf - -class __ELF__: +class ELF: def __init__(self, path): self.path = path self.sym = r2.get_elf_symbols(self.path) diff --git a/tools/sploit/sploit/rev/ldd.py b/tools/sploit/sploit/rev/ldd.py index 60306f1..d162207 100644 --- a/tools/sploit/sploit/rev/ldd.py +++ b/tools/sploit/sploit/rev/ldd.py @@ -1,9 +1,10 @@ +from sploit.util import run_cmd_cached + import re -from subprocess import run from collections import namedtuple as nt def get_libraries(elf): - out = run(['ldd',elf],capture_output=True).stdout.decode('utf-8').split('\n')[:-1] + 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} diff --git a/tools/sploit/sploit/rev/r2.py b/tools/sploit/sploit/rev/r2.py index af0fe24..c7a8a65 100644 --- a/tools/sploit/sploit/rev/r2.py +++ b/tools/sploit/sploit/rev/r2.py @@ -1,12 +1,12 @@ from sploit.mem import Symtbl from sploit.arch import arch +from sploit.util import run_cmd_cached import re -from subprocess import run from collections import namedtuple as nt def run_cmd(binary,cmd): - return run(['r2','-q','-c',cmd,'-e','scr.color=false',binary],capture_output=True).stdout.decode('utf-8').split('\n')[:-1] + return run_cmd_cached(['r2','-q','-c',cmd,'-e','scr.color=false',binary]) def get_elf_symbols(elf): out = {} diff --git a/tools/sploit/sploit/util.py b/tools/sploit/sploit/util.py new file mode 100644 index 0000000..b0572a0 --- /dev/null +++ b/tools/sploit/sploit/util.py @@ -0,0 +1,18 @@ +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__: + print('cache hit') + return __RUN_CACHE__[key] + else: + print('cache miss') + result = run_cmd(cmd) + __RUN_CACHE__[key] = result + return result + + -- cgit v1.2.3 From 3ddf898a5e664ed84d1b30dbfdd34bb977f15ce4 Mon Sep 17 00:00:00 2001 From: dusoleil Date: Sat, 12 Mar 2022 20:36:30 -0500 Subject: sploit: lazy load libs for ELF Signed-off-by: dusoleil --- tools/sploit/sploit/rev/elf.py | 20 ++++++++++++++++---- tools/sploit/sploit/util.py | 2 -- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/tools/sploit/sploit/rev/elf.py b/tools/sploit/sploit/rev/elf.py index 1957c15..acfe73b 100644 --- a/tools/sploit/sploit/rev/elf.py +++ b/tools/sploit/sploit/rev/elf.py @@ -5,7 +5,7 @@ class ELF: self.path = path self.sym = r2.get_elf_symbols(self.path) libs = ldd.get_libraries(self.path) - self.libs = {lib.name:ELF(lib.path) for lib in libs.values() if lib.path} + self.libs = self.__LIBS__(libs) self.locals = self.__LOCALS__(self) def __str__(self): @@ -18,12 +18,24 @@ class ELF: s += '\n------------' s += '\nLibararies' s += '\n------------' - for name,lib in self.libs.items(): - s += '\n' + str(name) + ' => ' + str(lib.path) + 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): + def __init__(self, elf): self.elf = elf def __getattribute__(self, sym): if(sym=='elf'):return object.__getattribute__(self,sym) diff --git a/tools/sploit/sploit/util.py b/tools/sploit/sploit/util.py index b0572a0..610ab31 100644 --- a/tools/sploit/sploit/util.py +++ b/tools/sploit/sploit/util.py @@ -7,10 +7,8 @@ __RUN_CACHE__ = {} def run_cmd_cached(cmd): key = ''.join(cmd) if key in __RUN_CACHE__: - print('cache hit') return __RUN_CACHE__[key] else: - print('cache miss') result = run_cmd(cmd) __RUN_CACHE__[key] = result return result -- cgit v1.2.3 From 9ab54facd5005879e68a1ff83166de5dd576a524 Mon Sep 17 00:00:00 2001 From: dusoleil Date: Sat, 12 Mar 2022 21:22:36 -0500 Subject: sploit: add status logging to rev module Signed-off-by: dusoleil --- tools/sploit/sploit/rev/ldd.py | 2 ++ tools/sploit/sploit/rev/r2.py | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/tools/sploit/sploit/rev/ldd.py b/tools/sploit/sploit/rev/ldd.py index d162207..1a28c7c 100644 --- a/tools/sploit/sploit/rev/ldd.py +++ b/tools/sploit/sploit/rev/ldd.py @@ -1,9 +1,11 @@ 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") diff --git a/tools/sploit/sploit/rev/r2.py b/tools/sploit/sploit/rev/r2.py index c7a8a65..ffa6dd4 100644 --- a/tools/sploit/sploit/rev/r2.py +++ b/tools/sploit/sploit/rev/r2.py @@ -1,6 +1,7 @@ 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 @@ -9,7 +10,9 @@ 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:] @@ -39,6 +42,8 @@ def get_elf_symbols(elf): return Symtbl(**out) def get_locals(binary,func): + ilog(f'Retrieving local stack frame of {func} in {binary} with r2...') + addr = hex(func) cmd_locals = f's {func};af;aafr;aaft;afvf' out = run_cmd(binary,cmd_locals) @@ -47,6 +52,8 @@ def get_locals(binary,func): return Symtbl(**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] @@ -55,6 +62,8 @@ def ret_gadget(binary): 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") @@ -68,6 +77,8 @@ def rop_gadget_exact(binary,gad): return g def get_call_returns(binary,xref_from,xref_to): + ilog(f'Getting return addresses of calls from {xref_from} to {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] -- cgit v1.2.3 From 11b9ed39ac694932461b03b132e1a01e11658322 Mon Sep 17 00:00:00 2001 From: dusoleil Date: Sun, 13 Mar 2022 00:27:21 -0500 Subject: sploit: print hex of addresses in rev logs Signed-off-by: dusoleil --- tools/sploit/sploit/rev/r2.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/sploit/sploit/rev/r2.py b/tools/sploit/sploit/rev/r2.py index ffa6dd4..97eeadd 100644 --- a/tools/sploit/sploit/rev/r2.py +++ b/tools/sploit/sploit/rev/r2.py @@ -42,7 +42,7 @@ def get_elf_symbols(elf): return Symtbl(**out) def get_locals(binary,func): - ilog(f'Retrieving local stack frame of {func} in {binary} with r2...') + 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' @@ -77,7 +77,7 @@ def rop_gadget_exact(binary,gad): return g def get_call_returns(binary,xref_from,xref_to): - ilog(f'Getting return addresses of calls from {xref_from} to {xref_to} in {binary} with r2...') + 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) -- cgit v1.2.3 From 4bf40b9d27dbb471b7b18be502deacfb12540120 Mon Sep 17 00:00:00 2001 From: dusoleil Date: Sun, 13 Mar 2022 04:33:58 -0400 Subject: sploit: add stack base pointer to locals symtbl Signed-off-by: dusoleil --- tools/sploit/sploit/rev/r2.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/sploit/sploit/rev/r2.py b/tools/sploit/sploit/rev/r2.py index 97eeadd..bb3edb3 100644 --- a/tools/sploit/sploit/rev/r2.py +++ b/tools/sploit/sploit/rev/r2.py @@ -49,7 +49,9 @@ def get_locals(binary,func): 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} - return Symtbl(**out) + out = Symtbl(**out) + out.sbp = 0 + return out def ret_gadget(binary): ilog(f'Searching for a ret gadget in {binary} with r2...') -- cgit v1.2.3 From afdc128959004fc630382debf29d47f367463d7e Mon Sep 17 00:00:00 2001 From: dusoleil Date: Sun, 13 Mar 2022 23:15:42 -0400 Subject: sploit: Filter all magic python members by default in mem module In the various __getattribute__() overloads in the mem module, we should filter all of the built-in magic members to do the default object.__getattribute__() behavior. This is opposed to the earlier stance of just caring about the ones that I saw as realistically being called. Signed-off-by: dusoleil --- tools/sploit/sploit/mem.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/sploit/sploit/mem.py b/tools/sploit/sploit/mem.py index 3ad0c50..c953fce 100644 --- a/tools/sploit/sploit/mem.py +++ b/tools/sploit/sploit/mem.py @@ -12,7 +12,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 +30,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 +52,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__): @@ -83,3 +84,5 @@ def __str__(self,tbl): else: s += __tbl_format__.format(hex(addr),sym) return s + +__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__'] -- cgit v1.2.3 From cd12c17a6a41102f55ef034fb819a2ee093df356 Mon Sep 17 00:00:00 2001 From: dusoleil Date: Sun, 13 Mar 2022 23:34:23 -0400 Subject: sploit: Move __attr_filter__ to a general place in util Found a spot to use __attr_filter__ in the rev module, so moving it out of mem and into a shared place (util). Signed-off-by: dusoleil --- tools/sploit/sploit/mem.py | 4 ++-- tools/sploit/sploit/rev/elf.py | 4 +++- tools/sploit/sploit/util.py | 6 ++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tools/sploit/sploit/mem.py b/tools/sploit/sploit/mem.py index c953fce..ac2bbb1 100644 --- a/tools/sploit/sploit/mem.py +++ b/tools/sploit/sploit/mem.py @@ -1,3 +1,5 @@ +from sploit.util import __attr_filter__ + class Symtbl: __subs__ = {} def __init__(self, **kwargs): @@ -84,5 +86,3 @@ def __str__(self,tbl): else: s += __tbl_format__.format(hex(addr),sym) return s - -__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__'] diff --git a/tools/sploit/sploit/rev/elf.py b/tools/sploit/sploit/rev/elf.py index acfe73b..7bfd31f 100644 --- a/tools/sploit/sploit/rev/elf.py +++ b/tools/sploit/sploit/rev/elf.py @@ -1,4 +1,5 @@ from sploit.rev import ldd, r2 +from sploit.util import __attr_filter__ class ELF: def __init__(self, path): @@ -38,7 +39,8 @@ class ELF: def __init__(self, elf): self.elf = elf def __getattribute__(self, sym): - if(sym=='elf'):return object.__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): diff --git a/tools/sploit/sploit/util.py b/tools/sploit/sploit/util.py index 610ab31..8a259c4 100644 --- a/tools/sploit/sploit/util.py +++ b/tools/sploit/sploit/util.py @@ -13,4 +13,10 @@ def run_cmd_cached(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__'] -- cgit v1.2.3