clinuxgdbheap-memorybuffer-overflow

How is a heap overflow attack implemented?


I am learning about heap overflow attacks, but I am encountering a problem. Based on the knowledge I found online and my own guesses, I believe that a heap overflow attack involves overwriting metadata in the heap, such as a pointer to a function, to execute the code that the attacker wants to run. However, when I use GDB to inspect memory allocated by malloc, I find that the header of the heap only contains the size allocated by malloc, And the footer only contains the remaining available size. Why???

Here is the process I followed to inspect the memory: source c:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char const *argv[])
{
    char *buf,*buf2;
    buf=(char*)malloc(1024);
    buf2=(char*)malloc(1024*2);

    free(buf2);
    strcpy(buf,argv[1]);
    printf("Done.");
    return 0;
}
  1. compile:

gcc heap2.c -o heap2 -g

  1. Start gdb:
┌──(kali㉿kali)-[~/Desktop/book_c]
└─$ gdb heap2              
GNU gdb (Debian 15.2-1+b1) 15.2
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from heap2...
(gdb) 
  1. Setting a breakpoint in main:
(gdb) b main
Breakpoint 1 at 0x1178: file heap2.c, line 8.
(gdb)
  1. run:
(gdb) run AAAAAAAA
Starting program: /home/kali/Desktop/book_c/heap2 AAAAAAAA
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main (argc=2, argv=0x7fffffffdd88) at heap2.c:8
8           buf=(char*)malloc(1024);
(gdb)
  1. Executing the n command to let malloc allocate memory
(gdb) n
9           buf2=(char*)malloc(1024*2);
(gdb)
  1. View memory
(gdb) x/32wx buf-32
0x555555559280: 0x00000000      0x00000000      0x00000000      0x00000000
0x555555559290: 0x00000000      0x00000000      0x00000411      0x00000000
0x5555555592a0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555592b0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555592c0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555592d0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555592e0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555592f0: 0x00000000      0x00000000      0x00000000      0x00000000
(gdb)

Why only one size? I guess that the metadata might be at the end, so I inspected the memory at the end of the allocated block.

(gdb) x/32wx buf-32+0x00000411-1
0x555555559690: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596a0: 0x00000000      0x00000000      0x00020961      0x00000000
0x5555555596b0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596c0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596d0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596e0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596f0: 0x00000000      0x00000000      0x00000000      0x00000000
0x555555559700: 0x00000000      0x00000000      0x00000000      0x00000000
(gdb) 

There are no pointers at all!!!! Why????

So, I guessed that the first allocated block might be special. I continued to inspect the next allocated block.

Execute the n command

(gdb) n
11          free(buf2);
(gdb)

Inspect the header of the block.

(gdb) x/32wx buf-32+0x00000411-1
0x555555559690: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596a0: 0x00000000      0x00000000      0x00000811      0x00000000
0x5555555596b0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596c0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596d0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596e0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596f0: 0x00000000      0x00000000      0x00000000      0x00000000
0x555555559700: 0x00000000      0x00000000      0x00000000      0x00000000
(gdb) x/32wx buf2-32
0x555555559690: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596a0: 0x00000000      0x00000000      0x00000811      0x00000000
0x5555555596b0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596c0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596d0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596e0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596f0: 0x00000000      0x00000000      0x00000000      0x00000000
0x555555559700: 0x00000000      0x00000000      0x00000000      0x00000000
(gdb)

There are still no pointers at all!!!! Why????

So, I made another guess and executed free(buf2). I hope this will give me some clues.

(gdb) n
12          strcpy(buf,argv[1]);
(gdb)

head:

(gdb) x/32wx buf2-32
0x555555559690: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596a0: 0x00000000      0x00000000      0x00020961      0x00000000
0x5555555596b0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596c0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596d0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596e0: 0x00000000      0x00000000      0x00000000      0x00000000
0x5555555596f0: 0x00000000      0x00000000      0x00000000      0x00000000
0x555555559700: 0x00000000      0x00000000      0x00000000      0x00000000
(gdb) 

end:

(gdb) x/32wx buf2-32+0x00000811-1
0x555555559ea0: 0x00000000      0x00000000      0x00000000      0x00000000
0x555555559eb0: 0x00000000      0x00000000      0x00020151      0x00000000
0x555555559ec0: 0x00000000      0x00000000      0x00000000      0x00000000
0x555555559ed0: 0x00000000      0x00000000      0x00000000      0x00000000
0x555555559ee0: 0x00000000      0x00000000      0x00000000      0x00000000
0x555555559ef0: 0x00000000      0x00000000      0x00000000      0x00000000
0x555555559f00: 0x00000000      0x00000000      0x00000000      0x00000000
0x555555559f10: 0x00000000      0x00000000      0x00000000      0x00000000
(gdb) 

I have no clues....

Is this because GDB has some limitation? Or is there another reason?

Of course, the most important thing is how heap overflow attacks are implemented? How can I reproduce this attack?


Solution

  • The behavior you're encountering is not due to GDB limitations, but rather how modern memory allocators like glibc's ptmalloc or jemalloc manage memory.

    Here a exemple of heap overflow:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main() {
        char *buf1 = (char *)malloc(32);  // Allocate 32 bytes
        char *buf2 = (char *)malloc(32);  // Allocate another 32 bytes
    
        printf("buf1: %p\n", buf1);
        printf("buf2: %p\n", buf2);
    
        // Overflow buf1 to overwrite buf2's metadata
        memset(buf1, 'A', 60);
    
        printf("buf1: %s\n", buf1);
        printf("buf2: %s\n", buf2);
        // Trigger corruption
        free(buf2);
    
        return 0;
    }
    

    Compiling your program:

    $ gcc heap_overflow.c -o heap_overflow -g
    

    And run it:

    $ $ ./heap_overflow
    buf1: 0x55cf8911a2a0
    buf2: 0x55cf8911a2d0
    buf1: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    buf2: AAAAAAAAAAAA
    double free or corruption (out)
    Aborted (core dumped)
    

    buf2 got some values of buf1.

    I learned pwn heap overflow with this sources:

    Try to do some CTF about this, or read some "CTF write ups about heap overflow"