fastbin dup 来获取libc地址

当我在做0ctf2017 babyheap的时候遇到利用fastbin dup 来泄露mainarena的地址来获取libc的地址,其他大佬给的wp没有讲如果通过泄露的smallbin的地址获取mainarena和获取libc的地址。

获取mainarena地址

首先我们要知道

  • bin是由struct chunk结构体组成的链表。
  • 不同的chunk更据特点的不同分为不同的chunk,为了将这些chunk进行分类管理,glibc采用了bin链这种方式管理不同的chunk。
  • 不同的bin链是由arena管理的
  • bin链中的chunk均为free chunk。
  • 主线程的main_arena保存在libc.so的数据段里面,其他线程的arena则保存在该arena分配的heap里面。

bin链的保存依赖struct malloc_state结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
typedef struct malloc_chunk* mchunkptr;
typedef struct malloc_chunk *mfastbinptr;
struct malloc_state {
/* Serialize access. */
mutex_t mutex;
/* Statistics for locking. Only used if THREAD_STATS is defined. */
long stat_lock_direct, stat_lock_loop, stat_lock_wait;
long pad0_[1]; /* try to give the mutex its own cacheline */
/* The maximum chunk size to be eligible for fastbin */
INTERNAL_SIZE_T max_fast; /* low 2 bits used as flags */
/* Fastbins */
mfastbinptr fastbins[NFASTBINS];
/* Base of the topmost chunk -- not otherwise kept in a bin */
mchunkptr top;
/* The remainder from the most recent split of a small request */
mchunkptr last_remainder;
/* Normal bins packed as described above */
mchunkptr bins[NBINS * 2];
/* Bitmap of bins */
unsigned int binmap[BINMAPSIZE];
/* Linked list */
struct malloc_state *next;
/* Memory allocated from the system in this arena. */
INTERNAL_SIZE_T system_mem;
INTERNAL_SIZE_T max_system_mem;
};

但是不同版本也有不同的malloc_state结构体,于是需要具体问题具体分析。

于是更据malloc_state结构体我们可以知道mainarena的地址。

获取libc地址

获取libc的地址,我们需要先获取mainarena在libc中的偏移,于是我们需要去源代码中找那些函数用了mainarena,再去libc中寻找对应mainarena中找即可,于是我们找到了__malloc_trim函数调用了main_arena,并且函数流程比较少,就算libc去除了符号,我们也能根据有符号表的libc来找到mainarena的地址。

为什么我说一定能在libc中找到main_arena呢,因为main_arena是静态的,本身就是存储在libc的数据区的。

1
static struct malloc_state main_arena;

下面是__malloc_trim的函数定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __malloc_trim (size_t s)
{
int result = 0;

if (__malloc_initialized < 0)
ptmalloc_init ();

mstate ar_ptr = &main_arena;
do
{
(void) mutex_lock (&ar_ptr->mutex);
result |= mtrim (ar_ptr, s);
(void) mutex_unlock (&ar_ptr->mutex);

ar_ptr = ar_ptr->next;
}
while (ar_ptr != &main_arena);

return result;
}

当然__malloc_trim函数不是唯一的函数,也可以用其他包含main_arena的函数,比如malloc_info更加简单易读。