#!/usr/bin/env python2.7 # Copyright (c) 2016-2018 Angelo Moura # # This file is part of the program pythem # # pythem is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA import os import fcntl import signal import sys import struct import resource import time import termcolor import threading from utils import * from netaddr import IPAddress, AddrFormatError import subprocess from subprocess import * from socket import * from ropper import RopperService import termcolor from time import sleep from completer import Completer class Exploit(object): name = "Exploit development interactive shell." desc = "use gdb plus ROPgadget + offset generator and memaddresses to create exploits." def __init__(self, target, mode): self.version = '0.0.5' self.target = target self.mode = mode self.xtype = 'bufferoverflow' self.offset = 1 self.nops = 0 self.shellcode = '' self.lenght = 0 self.addr1 = None self.addr2 = None self.arch = 'x86' self.port = 0 if self.target: self.p1 = Popen(['gdb', "--silent", "{}".format(self.target)], stdin=PIPE, stdout=PIPE, bufsize=1) gdbout = self.p1.stdout.readline() else: self.p1 = Popen(['gdb', '--silent'], stdin=PIPE, stdout=PIPE, bufsize=1) # gdbout = self.p1.stdout.readline() completer = Completer(".gdb_history", "xploit") def gdb(self, cmd): def signal_handler(signum, frame): print 1 + "that's ugly" signal.signal(signal.SIGALRM, signal_handler) signal.alarm(1) try: print >> self.p1.stdin, cmd for line in iter(self.p1.stdout.readline, b''): print line except KeyboardInterrupt: pass except Exception as e: # print "[!] Exception caught: {}".format(e) pass def getshellcode(self, file): os.system("for i in $(objdump -d {} |grep '^ ' |cut -f2); do echo -n '\\x'$i; done; echo".format(file)) def search(self, file, search, find): options = {'color': True, 'detailed': True} rs = RopperService(options) ls = file rs.addFile(ls) rs.setArchitectureFor(name=ls, arch=self.arch) if search == "instructions": os.system('ropper --file {} --search "{}"'.format(self.target, find)) elif search == "opcode": os.system('ropper --file {} --opcode "{}"'.format(self.target, find)) else: print "[!] Select a valid search (instructions/opcode)." return def pattern(self, size=1024): return "\x41" * size def nops(self, size=1024): return "\x90" * size def int2hexstr(self, num, intsize=4): if intsize == 8: if num < 0: result = strct.pack("<q", num) else: result = struct.pack("<Q", num) else: if num < 0: result = struct.pack("<l", num) else: result = struct.pack("<L", num) return result def list2hexstr(self, intlist, intsize=4): result = "" for value in intlist: if isinstance(value, str): result += value else: result += self.int2hexstr(value, intsize) return result def run(self): padding = self.pattern(self.offset) payload = [padding] if self.xtype == "bufferoverflow": if self.arch == "x86": if self.addr1 is not None: payload += [self.addr1] if self.addr2 is not None: payload += [self.addr2] if self.nops > 0: payload += ["{}".format(self.nops(self.nops))] payload += [self.shellcode] total = len(payload) - self.lenght fill = self.pattern(total) payload += [fill] payload = self.list2hexstr(payload) print "[+] Writing payload into buffer.txt" f = open("buffer.txt", "w") f.write(payload) elif self.arch == "x64": if self.addr1 is not None: payload += struct.pack("<Q", int(self.addr1)) if self.addr2 is not None: payload += struct.pack("<Q", int(self.addr2)) if self.nops > 0: payload += ["{}".format(self.nops(self.nops))] payload += [self.shellcode] total = len(payload) - self.lenght fill = self.pattern(total) payload += [fill] payload = self.list2hexstr(payload, 8) print "\n[+] Writing payload into buffer.txt\n" f = open("buffer.txt", "w") f.write(payload) else: print "[!] Select a valid processor architecture." return if self.mode == "tcp": self.port = input("[+] Enter the tcp port to fuzz: ") self.tcppwn(payload) elif self.mode == "stdin": self.stdinpwn(payload) else: print "[!] Select a valid mode (stdin or tcp)." def stdinpwn(self, payload): resource.setrlimit(resource.RLIMIT_STACK, (-1, -1)) resource.setrlimit(resource.RLIMIT_CORE, (-1, -1)) P = Popen(self.target, stdin=PIPE) print "[*] Sending buffer with lenght: " + str(len(payload)) P.stdin.write(payload) while True: line = sys.stdin.readline() P.poll() ret = P.returncode if ret is None: P.stdin.write(line) else: if ret == -11: print "[*] Child program crashed with SIGSEGV" else: print "[-] Child program exited with code %d" % ret break print "\n If it does not work automatically, run on terminal: (cat buffer.txt ; cat) | {}".format(self.target) def tcppwn(self, payload): try: self.target = str(IPAddress(self.target)) except AddrFormatError as e: try: self.target = gethostbyname(self.target) except Exception as e: print "[-] Select a valid IP address or domain name as target." print "[!] Exception caught: {}".format(e) return try: self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.settimeout(4) self.socket.connect((self.target, self.port)) self.socket.send(payload) while True: self.socket.recv(1024) except KeyboardInterrupt: return except Exception as e: if 'Connection refused' in e: print "[-] Connection refused." return def start(self): while True: try: console = termcolor.colored("xploit>", "blue", attrs=["bold"]) self.command = raw_input("{} ".format(console)) os.system("echo {} >> .gdb_history".format(self.command)) self.argv = self.command.split() self.input_list = [str(a) for a in self.argv] try: if self.input_list[0] == 'exit' or self.input_list[0] == 'quit': break elif self.input_list[0] == 'help': self.printHelp() elif self.input_list[0] == 'clear': os.system("clear") elif self.input_list[0] == 'cat' or self.input_list[0] == '(cat': os.system("cat {}".format(str(self.input_list[1]))) elif self.input_list[0] == 'python': os.system("python {}".format(" ".join(self.input_list[1:]))) elif self.input_list[0] == 'echo': os.system("echo {}".format(" ".join(self.input_list[1:]))) elif self.input_list[0] == 'ping': os.system("ping {}".format(" ".join(self.input_list[1:]))) elif self.input_list[0] == 'nc': os.system("nc {}".format(" ".join(self.input_list[1:]))) elif self.input_list[0] == 'search': try: file = self.target.replace("./", "") try: search = self.input_list[1] except IndexError: try: search = raw_input("[+] Search (instructions/opcode): ") except KeyboardInterrupt: pass try: find = raw_input("[+] Find: ") except KeyboardInterrupt: pass self.search(file, search, find) except Exception as e: print "[!] Exception caught: {}".format(e) elif self.input_list[0] == 'fuzz': try: from fuzzer import SimpleFuzz self.fuzz = SimpleFuzz(self.target, self.mode, self.offset) except KeyboardInterrupt: pass except Exception as e: print "[!] Exception caught: {}".format(e) pass elif self.input_list[0] == 'shellcode': self.getshellcode(self.input_list[1]) elif self.input_list[0] == 'cheatsheet': self.gdbCheatSheet() elif self.input_list[0] == 'xploit': self.run() elif self.input_list[0] == "decode": try: print decode(self.input_list[1]) except KeyboardInterrupt: pass except: type = raw_input("[+] Type of decoding: ") print decode(type) elif self.input_list[0] == "encode": try: print encode(self.input_list[1]) except KeyboardInterrupt: pass except: type = raw_input("[+] Type of encoding: ") print decode(type) elif self.input_list[0] == "encoder": try: if self.input_list[1]: string = " ".join(self.input_list[1:]) except: string = raw_input("[+] String to encode: ") try: opt = raw_input("[?] Output, [A]Address/[S]Shellcode/[L]LittleEndian (A/S/L): ") rev_string_hex = string[::-1].encode('hex') if opt.lower() == "a": if len(string) > 8: print "[-] String overflow the 64bit address space." else: print "0x" + rev_string_hex elif opt.lower() == "s": array = [] for i in rev_string_hex: array.append(i) result = zip(*[array[x::2] for x in (0, 1)]) buf = "" for x, y in result: buf += "\\x{}{}".format(x, y) print buf elif opt.lower() == "l": print rev_string_hex else: print "[!] Invalid option" except KeyboardInterrupt: pass elif self.input_list[0] == "decoder": try: if self.input_list[1]: string = " ".join(self.input_list[1:]) except: string = raw_input("[+] Shellcode/Address/LittleEndian String to decode: ") try: string = string.strip("\\x") except: pass try: string = string.strip("0x") except: pass try: array = [] for i in string: array.append(i) result = zip(*[array[x::2] for x in (0, 1)]) result = result[::-1] buf = "" for x, y in result: buf += "{}{}".format(x, y) print buf.decode("hex") except Exception as e: print "[!] Exception caught: {}".format(e) elif self.input_list[0] == "print": if self.input_list[1] == "offset": print "[+] Offset " print "[+] lenght: {}".format(self.offset) elif self.input_list[1] == "nops": print "[+] Nops " print "[+] lenght: {}".format(self.nops) elif self.input_list[1] == "shellcode": print "[+] Shellcode " print "[+] lenght: {}".format(self.shellcode) elif self.input_list[1] == "lenght": print "[+] Total payload lenght " print "[+] lenght: {}".format(self.lenght) elif self.input_list[1] == "addr1": print "[+] First address to overwrite" print "[+] memory address 1: {}".format(self.addr1) elif self.input_list[1] == "addr2": print "[+] Second address to overwrite" print "[+] memory address 2: {}".format(self.addr2) elif self.input_list[1] == "arch": print "[+] Target system arch" print "[+] Architecture: {}".format(self.arch) else: cmd = ' '.join(self.input_list[0:]) data = self.gdb(cmd) if data: print color("{}".format(data), "blue") elif self.input_list[0] == "set" or self.input_list[0] == "SET": if self.input_list[1] == "offset": try: self.offset = int(self.input_list[2]) except IndexError: try: self.offset = input("[+] Enter the offset (number of 'A's): ") except KeyboardInterrupt: pass elif self.input_list[1] == "nops": try: self.nops = int(self.input_list[2]) except IndexError: try: self.nops = input("[+] Enter the NOPsled (number of NOPs): ") except KeyboardInterrupt: pass elif self.input_list[1] == "shellcode": try: self.shellcode = input("[+] Enter the shellcode: ") except KeyboardInterrupt: pass elif self.input_list[1] == "lenght": try: self.lenght = int(self.input_list[2]) except IndexError: try: self.lenght = input("[+] Enter the payload total lenght: ") except KeyboardInterrupt: pass elif self.input_list[1] == "addr1": try: self.addr1 = input("[+] First address to overwrite: ") except KeyboardInterrupt: pass elif self.input_list[1] == "addr2": try: self.addr2 = input("[+] Second address to overwrite: ") except KeyboardInterrupt: pass elif self.input_list[1] == "arch": try: self.arch = self.input_list[2] except IndexError: try: self.arch = raw_input("[+] Target system arch: ") except KeyboardInterrupt: pass else: cmd = ' '.join(self.input_list[0:]) data = self.gdb(cmd) if data: print color("{}".format(data), "blue") else: try: cmd = ' '.join(self.input_list[0:]) data = self.gdb(cmd) if data: print color("{}".format(data), "blue") except Exception as e: # DEBUG # print "[!] Select a valid option, type help to check sintax." # print e continue except IndexError: pass except Exception as e: print "[!] Exception caught: {}".format(e) except KeyboardInterrupt: break def printHelp(self): print print color(" [XPLOIT v{}]".format(self.version), "grey") print print print color(" TARGET - [ {} ]".format(self.target), "red") print print print color("[*] help: Print this help message.", "blue") print print print color("[*] clear: Clean the screen, same as GNU/Linux OS 'clear'.", "blue") print print print color("[*] exit/quit: Return to pythem.", "blue") print print print color("[*] set Set the variables values.", "blue") print print color(" parameters:", "red") print print color(" - offset | Number os 'A's to overwrite the instruction pointer.", "yellow") print print color( " - addr1 | (Optional) Hexa(0xaddress) First address to overwrite after the offset.", "yellow") print print color( " - addr2 | (Optional) Hexa(0xaddress) Second address to overwrite after the offset.", "yellow") print print color( " - nops | (Optional) Number of NOPs after IP overwrite or after the addr1 and addr2 if they are set.", "yellow") print print color( " - shellcode | (Optional) Shellcode (could be generated by msfvenom or any other).", "yellow") print print color(" - lenght | Total lenght of the payload.", "yellow") print print color(" - arch | Target system processor architecture.", "yellow") print print print color("[*] print Print a variable's value.", "blue") print print color(" examples:", "red") print print color(" xploit> ", "blue") + "print offset" print print print color("[*] decode/encode Decode or encode a string with a chosen pattern.", "blue") print print color(" examples:", "red") print print color(" xploit> ", "blue") + "decode hex" print color(" xploit> ", "blue") + "encode hex" print print print color("[*] encoder Encode string as address / shellcode / little endian", "blue") print print color(" examples:", "red") print print color(" xploit> ", "blue") + "encoder abcd" print " [?] Output, [A]Address/[S]Shellcode/[L]LittleEndian (A/S/L): s" print "\x64\x63\x62\x61" print print print color("[*] decoder Decode address / shellcode / little endian into ASCII", "blue") print print color(" examples:", "red") print print color(" xploit> ", "blue") + "decoder 0x636261" print " abc" print print print color("[*] shellcode Get the shellcode of executable file", "blue") print print color(" examples:", "red") print print color(" xploit> ", "blue") + "shellcode compiled_program" print print print color("[*] search Automatically search for instructions or opcode in the binary executable.", "blue") print print color(" parameters:", "red") print print color(" - instructions", "yellow") print print color(" - opcode", "yellow") print print color(" examples:", "red") print print color(" xploit> ", "blue") + "search" print " [+] Search (instructions/opcode):" print " or" print color(" xploit> ", "blue") + "search instructions" + color(" ? - any character", "green") print " [+] Find: pop ?di" + color(" % - any character", "green") print print color(" xploit>", "blue") + "search opcode" print " [+] Find: ffe4" print print print color("[*] xploit Run the exploit after all the settings.", "blue") print print color(" examples:", "red") print print color(" xploit> ", "blue") + "xploit" print print print color("[*] cheatsheet Display a GDB cheatsheet ;).", "blue") print print color(" examples:", "red") print print color(" xploit> ", "blue") + "cheatsheet" print print print color("[*] fuzz Start fuzzing on subject.", "blue") print print "If file is passed to xploit will fuzz stdin" print "If target is passed to xploit will fuzz tcp" print print "The offset's value will be the number of 'A's to send." print print "[Default = 1]" print "will be increased in 1 by 1." print "example:" print "[offset = 10]" print "will be increased in 10 by 10." print print color(" examples:", "green") print print color(" xploit> ", "blue") + "fuzz" print print print color("* Anything else will be executed in GNU debugger shell with {} as file *".format(self.target), "red") print def gdbCheatSheet(self): print " ____________________________________________________________________________________ " print "|<where>: |<what>: |" print "|---------------------------------------|--------------------------------------------|" print "|function_name |expression |" print "|*function_name+<point> (disas function |address |" print "|line_number to get <point>) |$register |" print "|file:line_number |filename::variable_name |" print "| |function::variable_name |" print "|_______________________________________|____________________________________________|" print " ____________________________________________________________________________________ " print "|Registers: |Formats: |" print "|---------------------------------------|--------------------------------------------|" print "|General Purpose Registers: | |" print "|ax - Accumulator register |a Pointer |" print "|bx - Base register |c Read as integer,print as char |" print "|cx - Counter register |d Integer |" print "|dx - Data register (I/O) |f Float |" print "| |o Integer as octal |" print "|Index Registers: |s String |" print "|si - Source index (string) |t Integer as binary |" print "|di - Destination index (string) |u Integer, unsigned decimal |" print "|ip - Instruction pointer |x Integer, as hexadecimal |" print "| | |" print "|Stack Registers: | |" print "|bp - Base pointer | |" print "|sp - Stack pointer | |" print "|_______________________________________|____________________________________________|" print " ____________________________________________________________________________________ " print "|Conditions: |Signals: |" print "|---------------------------------------|--------------------------------------------|" print "|break/watch <where> if <condition> |handle <signal> <options> |" print "|condition <breakpoint#> <condition> |<options>: |" print "| |(no)print |" print "| |(no)stop |" print "| |(no)pass |" print "|_______________________________________|____________________________________________|" print " ____________________________________________________________________________________ " print "|Manipulating the program: |Running: |" print "|---------------------------------------|--------------------------------------------|" print "|set var <variable_name>=<value> |run / r |" print "|return <expression> |kill / k |" print "|jump <where> | |" print "|_______________________________________|____________________________________________|" print " ____________________________________________________________________________________ " print "|Variables and memory: |Informations: |" print "|---------------------------------------|--------------------------------------------|" print "|print/format <what> |disassemble / disas |" print "|display/format <what> |disassemble / disas <where> |" print "|undisplay <display#> |info args |" print "|enable display <display#> |info breakpoints |" print "|disable display <display#> |info display |" print "|x/nf <address/variable/register> |info locals |" print "|n:how many units to print |info sharedlibrary |" print "|f: format character |info threads |" print "| |info directories |" print "| |info registers |" print "| |whatis variable_name |" print "|_______________________________________|____________________________________________|" print " ____________________________________________________________________________________ " print "|Watchpoints: |Stepping: |" print "|---------------------------------------|--------------------------------------------|" print "|watch <where> |step / s |" print "|delete/enable/disable <watchpoint#> |next / n |" print "| |finish / f |" print "| |continue / c |" print "|_______________________________________|____________________________________________|" print " ____________________________________________________________________________________ " print "|Breakpoints: | Examining the stack: |" print "|---------------------------------------|--------------------------------------------|" print "| break / br <where> | backtrace / bt |" print "| delete <breakpoint#> | where |" print "| clear | backtrace full |" print "| enable <breakpoint#> | where full |" print "| disable <breakpoint#> | frame <frame#> |" print "|_______________________________________|____________________________________________|" if __name__ == "__main__": try: if sys.argv[1]: xploit = Exploit(sys.argv[1], "stdin") xploit.start() except: xploit = Exploit(None, "stdin") xploit.start()