├── README.md ├── bin └── template.py ├── img ├── 1.png ├── 2.png └── 3.png └── ropdump.py /README.md: -------------------------------------------------------------------------------- 1 | # ROPDump 2 | 3 | ROPDump is a tool for analyzing binary executables to identify potential Return-Oriented Programming (ROP) gadgets, as well as detecting potential buffer overflow and memory leak vulnerabilities. 4 | 5 | ## Features 6 | 7 | - Identifies potential ROP gadgets in binary executables. 8 | - Detects potential buffer overflow vulnerabilities by analyzing vulnerable functions. 9 | - Generates exploit templates to make the exploit process faster 10 | - Identifies potential memory leak vulnerabilities by analyzing memory allocation functions. 11 | - Can print function names and addresses for further analysis. 12 | - Supports searching for specific instruction patterns. 13 | 14 | ## Usage 15 | 16 | - ``: Path to the binary file for analysis. 17 | - `-s, --search SEARCH`: Optional. Search for specific instruction patterns. 18 | - `-f, --functions`: Optional. Print function names and addresses. 19 | 20 | ## Examples 21 | 22 | - Analyze a binary without searching for specific instructions: 23 | 24 | python3 ropdump.py /path/to/binary 25 | 26 | 27 | - Analyze a binary and search for specific instructions: 28 | 29 | python3 ropdump.py /path/to/binary -s "pop eax" 30 | 31 | - Analyze a binary and print function names and addresses: 32 | 33 | python3 ropdump.py /path/to/binary -f 34 | 35 | ![](img/1.png) 36 | ![](img/2.png) 37 | ![](img/3.png) 38 | -------------------------------------------------------------------------------- /bin/template.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys 5 | import argparse 6 | import io 7 | from pwn import * 8 | 9 | exe = context.binary = ELF(args.EXE or './BINNAME') 10 | 11 | def start_local(args, argv=[], *a, **kw): 12 | if args.GDB: 13 | return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw) 14 | else: 15 | return process([exe.path] + argv, *a, **kw) 16 | 17 | def start_remote(host, port, argv=[], *a, **kw): 18 | return remote(host, port) 19 | 20 | gdbscript = ''' 21 | tbreak main 22 | continue 23 | '''.format(**locals()) 24 | 25 | parser = argparse.ArgumentParser(description='Exploit script') 26 | parser.add_argument('mode', choices=['local', 'remote'], help='Mode: local or remote') 27 | parser.add_argument('--GDB', action='store_true', help='Enable GDB debugging') 28 | parser.add_argument('host', nargs='?', default='localhost', help='Remote host') 29 | parser.add_argument('port', nargs='?', type=int, default=1337, help='Remote port') 30 | args = parser.parse_args() 31 | 32 | if args.mode == 'local': 33 | start_func = lambda: start_local(args) 34 | else: 35 | start_func = lambda: start_remote(args.host, args.port) 36 | 37 | io = start_func() 38 | # 39 | # 40 | # Exploit goes here 41 | # 42 | # 43 | 44 | io.interactive() 45 | -------------------------------------------------------------------------------- /img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rizer0/Ropdump/e8ad8aaae6070749087471646002f339b804fb06/img/1.png -------------------------------------------------------------------------------- /img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rizer0/Ropdump/e8ad8aaae6070749087471646002f339b804fb06/img/2.png -------------------------------------------------------------------------------- /img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rizer0/Ropdump/e8ad8aaae6070749087471646002f339b804fb06/img/3.png -------------------------------------------------------------------------------- /ropdump.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import sys 4 | import re 5 | from pwn import * 6 | 7 | context.log_level = 'error' 8 | print(''' 9 | ____ ___ ____ ____ _ _ __ __ ____ 10 | | _ \ / _ \| _ \| _ \| | | | \/ | _ \ 11 | | |_) | | | | |_) | | | | | | | |\/| | |_) | 12 | | _ <| |_| | __/| |_| | |_| | | | | __/ 13 | |_| \_\ ___/|_| |____/ \___/|_| |_|_| 14 | By @Nullbyte0x\n''') 15 | 16 | 17 | def check_buffer_overflow(file_path): 18 | with open(file_path, 'rb') as f: 19 | binary_content = f.read() 20 | 21 | vulnerable_functions = { 22 | b'strcpy': 'strcpy', 23 | b'strcat': 'strcat', 24 | b'gets': 'gets', 25 | b'fscanf': 'fscanf', 26 | b'scanf': 'scanf', 27 | } 28 | 29 | found_vulnerabilities = [] 30 | 31 | for func, func_name in vulnerable_functions.items(): 32 | indices = [m.start() for m in re.finditer(func, binary_content)] 33 | for idx in indices: 34 | start_idx = max(0, idx - 20) 35 | end_idx = min(len(binary_content), idx + 20) 36 | context = binary_content[start_idx:end_idx].decode(errors='ignore') 37 | found_vulnerabilities.append((func_name, idx, context)) 38 | 39 | if found_vulnerabilities: 40 | print("\033[31mPotential Buffer Overflow Vulnerabilities Detected:\033[0m") 41 | for func_name, idx, context in found_vulnerabilities: 42 | print(f" \033[33mFunction:\033[0m {func_name}, \033[33mOffset:\033[0m {idx}") 43 | print(f" \033[33mContext:\033[0m {context}") 44 | 45 | 46 | def check_memory_leaks(file_path): 47 | with open(file_path, 'rb') as f: 48 | binary_content = f.read() 49 | 50 | memory_allocation_functions = { 51 | b'malloc': 'malloc', 52 | b'calloc': 'calloc', 53 | b'realloc': 'realloc', 54 | b'free': 'free', 55 | } 56 | 57 | found_memory_leaks = [] 58 | 59 | for func, func_name in memory_allocation_functions.items(): 60 | indices = [m.start() for m in re.finditer(func, binary_content)] 61 | for idx in indices: 62 | start_idx = max(0, idx - 20) 63 | end_idx = min(len(binary_content), idx + 20) 64 | context = binary_content[start_idx:end_idx].decode(errors='ignore') 65 | found_memory_leaks.append((func_name, idx, context)) 66 | 67 | if found_memory_leaks: 68 | print("\033[31mPotential Memory Leak Vulnerabilities Detected:\033[0m") 69 | for func_name, idx, context in found_memory_leaks: 70 | print(f" \033[33mFunction:\033[0m {func_name}, \033[33mOffset:\033[0m {idx}") 71 | print(f" \033[33mContext:\033[0m {context}") 72 | 73 | 74 | def disassemble_binary(file_path, search_string=None, print_functions=False): 75 | 76 | try: 77 | binary = ELF(file_path) 78 | except Exception as e: 79 | print(f"Error: {e}") 80 | return 81 | arch = binary.arch 82 | 83 | print("\n\033[1mBinary Information:\033[0m") 84 | print(f" \033[32mArch:\033[0m {arch}") 85 | print(f" \033[32mEntry Point:\033[0m {hex(binary.entry)}") 86 | print(f" \033[32mRELRO:\033[0m {binary.relro}") 87 | print(f" \033[32mStack:\033[0m {binary.canary}") 88 | print(f" \033[32mNX:\033[0m {binary.nx}") 89 | print(f" \033[32mPIE:\033[0m {binary.pie}") 90 | print(f" \033[32mLibc used:\033[0m {binary.libc.path}") 91 | 92 | nx = str(binary.nx) 93 | 94 | with open(file_path, 'rb') as f: 95 | binary_content = f.read() 96 | disassembly = disasm(binary_content, arch=arch, vma=binary.address) 97 | instructions = disassembly.split('\n') 98 | rop_addresses = set() 99 | 100 | if print_functions: 101 | print("\n\033[1mFunctions:\033[0m") 102 | ignored_functions = {'printf', 'gets', '_IO_stdin_used', '_IO_stdin_getc', '_IO_stdout_used', 103 | '_IO_file_doallocate', '_IO_file_attach', '_DYNAMIC', 'libc', '__', '_GLOBAL_', 104 | 'stdout', 'stderr', 'stdin', '_ITM_', 'plt.', 'got.', 'register_tm'} 105 | for symbol, address in binary.symbols.items(): 106 | if not any(ignore_func in symbol for ignore_func in ignored_functions): 107 | print(f" \033[33m{symbol}\033[0m : {hex(address)}") 108 | 109 | print("\n\033[1mPotential ROP gadgets:\033[0m") 110 | print(" Gadget : Address:\t Hex representation:\t Instruction:") 111 | if search_string: 112 | search_words = search_string.split() 113 | for idx, instruction in enumerate(instructions): 114 | addr_idx = instruction.find(":") 115 | if addr_idx != -1: 116 | hex_address = instruction[:addr_idx].strip() 117 | try: 118 | gadget_address = int(hex_address, 16) 119 | if all(word in instruction for word in search_words): 120 | if gadget_address not in rop_addresses: 121 | rop_addresses.add(gadget_address) 122 | print(f" \033[33m0x{gadget_address:x}:\033[31m {instruction}") 123 | reg = instruction.split(":")[0] 124 | fmt = "0x"+reg.strip() 125 | if binary.arch == 'i386': 126 | print(f" \033[33mFormatted:\033[0m {p32(int(fmt, 16))}") 127 | if nx == "None" or nx == "False": 128 | shellcode = asm(shellcraft.i386.linux.sh()) 129 | print(f" \033[33mShellcode:\033[0m{shellcode}") 130 | elif binary.arch == 'amd64': 131 | print(f" \033[33mFormatted:\033[0m {p64(int(fmt, 16))}") 132 | if nx == "None" or nx == "False": 133 | try: 134 | shellcode = asm(shellcraft.amd64.linux.sh()) 135 | print(f" \033[33mShellcode:\033[0m{shellcode}") 136 | except NameError: 137 | print("Couldn't make a shellcode!") 138 | except ValueError: 139 | continue 140 | else: 141 | for idx, instruction in enumerate(instructions): 142 | if 'ret' in instruction or 'jmp' in instruction or 'pop' in instruction or 'test' in instruction or 'mov' in instruction: 143 | addr_idx = instruction.find(":") 144 | if addr_idx != -1: 145 | hex_address = instruction[:addr_idx].strip() 146 | try: 147 | gadget_address = int(hex_address, 16) 148 | if gadget_address not in rop_addresses: 149 | rop_addresses.add(gadget_address) 150 | print(f" \033[33m0x{gadget_address:x}:\033[31m {instruction}") 151 | except ValueError: 152 | continue 153 | 154 | 155 | def main(): 156 | sys.stderr = open(os.devnull, 'w') 157 | 158 | parser = argparse.ArgumentParser(description="Disassemble binary and find potential ROP gadgets") 159 | parser.add_argument("binary", help="Path to the binary file") 160 | parser.add_argument("-s", "--search", help="Search string") 161 | parser.add_argument("-f", "--functions", action="store_true", help="Print function names and addresses") 162 | args = parser.parse_args() 163 | 164 | check_buffer_overflow(args.binary) 165 | check_memory_leaks(args.binary) 166 | disassemble_binary(args.binary, args.search, args.functions) 167 | SkGen = input("Create exploit skeleton (Y/N) :") 168 | if SkGen == "y" or SkGen == "Y": 169 | pwd = os.getcwd() 170 | path = pwd + "/bin/template.py" 171 | print(path) 172 | with open(path, "r") as skeleton: 173 | template_content = skeleton.read().replace("BINNAME",args.binary) 174 | with open("skeleton.py","w") as tgen: 175 | tgen.write(template_content) 176 | print("Skeleton exploit file generated successfully as 'skeleton.py'") 177 | 178 | else: 179 | print("Not Ok") 180 | 181 | 182 | if __name__ == "__main__": 183 | main() 184 | --------------------------------------------------------------------------------