0

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?

4
  • 3
    Re “Based on the knowledge I found online…”: Nobody can tell you why the information you found is wrong or does not apply unless you identify that information. Whenever you refer to information in a question, you should include a bibliographic citation for that information, including a URL, the title, the author’s name, and more. (Well known sources, such as the C standard, can be abbreviated.) Commented Jan 23 at 14:36
  • 2
    Re “… and my own guesses…”: You have shown evidence that your guesses are wrong, and that is largely the answer to your question. Without stating what your guesses are or what led you to them, nobody can tell you why they are wrong other than that they are. Commented Jan 23 at 14:36
  • 2
    Re “… the header of the heap only contains the size allocated by malloc…”: There are many ways to implement malloc. One is to record the size of each allocation in the bytes preceding the allocation, and then free can easily find that size and link the allocation back into the database. This method does not require there be any pointers in or near the allocated memory. Another way to implement malloc is to keep a bitmap of fixed-size blocks that have been allocated within a region, using different regions for different sizes of allocations… Commented Jan 23 at 14:38
  • 1
    … And another way would be to keep a database of addresses that have been allocated, so free can look them up. Which of these implementations of malloc are you using? You should identify the specific implementation of the C standard library you are using. And be aware that any sort of exploit on one is not likely to work the same way on another. Commented Jan 23 at 14:39

1 Answer 1

0

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"

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.