From 729c5598b3fcb85e52c62bf19d28a7db2647659d 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 --- sploit/rev/r2.py | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 sploit/rev/r2.py (limited to 'sploit/rev/r2.py') diff --git a/sploit/rev/r2.py b/sploit/rev/r2.py new file mode 100644 index 0000000..cd4684f --- /dev/null +++ b/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 8e2b4fab035279f18b015374121933b2f937a8fc 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 --- sploit/rev/r2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sploit/rev/r2.py') diff --git a/sploit/rev/r2.py b/sploit/rev/r2.py index cd4684f..c133c33 100644 --- a/sploit/rev/r2.py +++ b/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 f3b278a1da4bd80c57d54188c270f780fac32c27 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 --- sploit/rev/r2.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'sploit/rev/r2.py') diff --git a/sploit/rev/r2.py b/sploit/rev/r2.py index c133c33..306e026 100644 --- a/sploit/rev/r2.py +++ b/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 63b9139833b847000fe6cc76fad07f6f6866e416 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 --- sploit/rev/r2.py | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'sploit/rev/r2.py') diff --git a/sploit/rev/r2.py b/sploit/rev/r2.py index 306e026..6fde112 100644 --- a/sploit/rev/r2.py +++ b/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 19fc4694e7f825b1fee0cce05c4a34f3ae717679 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 --- sploit/rev/r2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sploit/rev/r2.py') diff --git a/sploit/rev/r2.py b/sploit/rev/r2.py index 6fde112..af0fe24 100644 --- a/sploit/rev/r2.py +++ b/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 509a8cfcadcca94d336fe08be897f62a721079d2 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 --- sploit/rev/r2.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sploit/rev/r2.py') diff --git a/sploit/rev/r2.py b/sploit/rev/r2.py index af0fe24..c7a8a65 100644 --- a/sploit/rev/r2.py +++ b/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 = {} -- cgit v1.2.3 From 6bc9c69c534447ecec79ae551d8f6b3e50c71eba 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 --- sploit/rev/r2.py | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sploit/rev/r2.py') diff --git a/sploit/rev/r2.py b/sploit/rev/r2.py index c7a8a65..ffa6dd4 100644 --- a/sploit/rev/r2.py +++ b/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 22771b12afcc50e3281e48301cedfd0599624b6e 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 --- sploit/rev/r2.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sploit/rev/r2.py') diff --git a/sploit/rev/r2.py b/sploit/rev/r2.py index ffa6dd4..97eeadd 100644 --- a/sploit/rev/r2.py +++ b/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 0ddf210c257cd27bb78743b5548d4c26fe1521df 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 --- sploit/rev/r2.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sploit/rev/r2.py') diff --git a/sploit/rev/r2.py b/sploit/rev/r2.py index 97eeadd..bb3edb3 100644 --- a/sploit/rev/r2.py +++ b/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