登录后台

页面导航

本文编写于 425 天前,最后修改于 124 天前,其中某些信息可能已经过时。

此文字暂时搁浅.....有点难

pwn堆入门系列教程2:https://xz.aliyun.com/t/6169#toc-9

程序分析

题目来源:plaidctf 2015 plaiddb

    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    FORTIFY:  Enabled
INFO: Welcome to the PlaidDB data storage service.
INFO: Valid commands are GET, PUT, DUMP, DEL, EXIT
PROMPT: Enter command:

这个太难受,输入命令

ida分析程序,有点复杂......看解析说是红黑树

数据结构

struct Node {
    char *key;
    long data_size;
    char *data;
    struct Node *left;
    struct Node *right;
    long dummy;
    long dummy1;
}
char *__fastcall sub_1040(__int64 a1, signed __int64 a2)
{
  char *v2; // r12
  char *v3; // rbx
  size_t v4; // r14
  char v5; // al
  char v6; // bp
  signed __int64 v7; // r13
  char *v8; // rax

  v2 = (char *)malloc(8uLL);
  v3 = v2;
  v4 = malloc_usable_size(v2);
  while ( 1 )
  {
    v5 = _IO_getc(stdin);
    v6 = v5;
    if ( v5 == -1 )
      sub_1020();
    if ( v5 == 10 )
      break;
    v7 = v3 - v2;
    if ( v4 <= v3 - v2 )
    {
      v8 = (char *)realloc(v2, 2 * v4);
      v2 = v8;
      if ( !v8 )
      {
        puts("FATAL: Out of memory");
        exit(-1);
      }
      v3 = &v8[v7];
      v4 = malloc_usable_size(v8);
    }
    *v3++ = v6;
  }
  *v3 = 0;    //存在off-by-one
  return v2;
}

GET:分配放key 的空间,输入key , 可获得db 的内容,最后再把刚分配的空间free 掉

PUT;一开使会先分配0x38 byte 放置row ,再分配8 byte 放key,再依据所输入的size 大小,分配相对应的空间给你,而在输入key 时会检查所输入key 的空间够不够用,一旦不够用就会重新realloc 两倍的空间给你

DUMP:会将所有key 的资讯dump 出来

DEL:分配放key的空间,输入key之后,会先比对是否key是否有在tree中,若有,则将相对应的key、c​​ontent、row及用来比对key依序free掉, 若无则返回menu选单(并没有将刚刚用来比对的key free掉),这部分在后续排heap的阶段颇好用

EXIT:离开程式

漏洞利用

chunk重叠:http://4ngelboy.blogspot.com/2016/10/span-display-block-overflow-hidden_10.html

利用堆块的重叠进行泄露地址,然后覆盖fd指针,然后fastbin attack

1.先删掉初始存在的堆块 th3fl4g,方便后续堆的布置及对齐
效果如下

pwndbg> heap
0x55d06fef0000 FASTBIN {
  prev_size = 0, 
  size = 65, 
  fd = 0x0, 
  bk = 0x8, 
  fd_nextsize = 0x55d06fef0070, 
  bk_nextsize = 0x0
}
0x55d06fef0040 FASTBIN {
  prev_size = 0, 
  size = 33, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x21
}
0x55d06fef0060 FASTBIN {
  prev_size = 0, 
  size = 33, 
  fd = 0x55d06fef0040, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x21
}
0x55d06fef0080 FASTBIN {
  prev_size = 0, 
  size = 33, 
  fd = 0x55d06fef0060, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x20f61
}
0x55d06fef00a0 PREV_INUSE {
  prev_size = 0, 
  size = 135009, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}
pwndbg> bins
fastbins
0x20: 0x55d06fef0080 —▸ 0x55d06fef0060 —▸ 0x55d06fef0040 ◂— 0x0
0x30: 0x0
0x40: 0x55d06fef0000 ◂— 0x0

2.创建堆块,为后续做准备在创建同key堆块的时候,会删去上一个同key堆块

add一个chunk时的效果:

0x55e0fa005000 FASTBIN {
  prev_size = 0, 
  size = 65, 
  fd = 0x55e0fa005090, 
  bk = 0x80, 
  fd_nextsize = 0x55e0fa0050b0, 
  bk_nextsize = 0x0
}
0x55e0fa005080 FASTBIN {
  prev_size = 0, 
  size = 33, 
  fd = 0x3131313131313131, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x91
}
0x55e0fa0050a0 PREV_INUSE {
  prev_size = 0, 
  size = 145, 
  fd = 0x4141414141414141, 
  bk = 0x4141414141414141, 
  fd_nextsize = 0x4141414141414141, 
  bk_nextsize = 0x4141414141414141
}

3.利用off-by-one覆盖下个chunk的pre_size,这里必须是0x18,0x38,0x78这种递增的,他realloc是按倍数递增的,如果我们用了0x18大小的key的话,会将下一个chunk的pre_size部分当数据块来用,在加上off-by-one覆盖掉size的insue位,

4.先free掉第一块,为后续大堆块做准备,然后free第三块,这时候会向后合并堆块,根据pre_size合并成大堆块造成堆块重叠,这时候可以泄露地址了

5.申请堆块填充空间至chunk2

6.chunk2上为main_arena,泄露libc地址

7.现在堆块是重叠的,chunk3在我们free后的大堆块里,然后修改chunk3的fd指针指向realloc_hook
不破坏现场(不容易)

8.malloc一次,在malloc一次,这里有个点要注意,需要错位伪造size,因为fastbin有个checksize,我们这里将前面的0x7f错位,后面偏移也要补上

9.最后改掉后,在调用一次getshell