Program code (with Pseudo code part):

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

int main(int argc, char** argv)

int controlled1=10;
int controlled2=20;
int controlled3=300;
//test.bin file is also controlled

unsigned char   * pData;
unsigned char   * pTemp;
FILE * f1;

if ((f1 = fopen("test.bin", "rb")) == 0)
    printf("Error: can't open file\n");

pTemp   = (unsigned char  *)malloc(controlled1);

pData = (unsigned char  *)malloc(controlled2);


fread(pData, 1, controlled3, f1);

//pseudo code part:
//here pData can be used or not by other internal function (based on parameters in pData)



Variables named controlled* are controlled and can be adjusted to what is needed.

Below gdb output:

root@laptop:~/security/testprog# gdb testprog 
        GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
        Copyright (C) 2016 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:
        Find the GDB manual and other documentation resources online at:
        For help, type "help".
        Type "apropos word" to search for commands related to "word"...
        Reading symbols from testprog...(no debugging symbols found)...done.
        (gdb) r
        Starting program: /home/user/security/testprog/testprog 
        *** Error in `/home/user/security/testprog/testprog': free(): invalid next size (fast): 0x0000000000602260 ***
        ======= Backtrace: =========
        ======= Memory map: ========
        00400000-00401000 r-xp 00000000 fc:00 4616045                            /home/user/security/testprog/testprog
        00600000-00601000 r--p 00000000 fc:00 4616045                            /home/user/security/testprog/testprog
        00601000-00602000 rw-p 00001000 fc:00 4616045                            /home/user/security/testprog/testprog
        00602000-00623000 rw-p 00000000 00:00 0                                  [heap]
        7ffff0000000-7ffff0021000 rw-p 00000000 00:00 0 
        7ffff0021000-7ffff4000000 ---p 00000000 00:00 0 
        7ffff77f8000-7ffff780e000 r-xp 00000000 fc:00 11801003                   /lib/x86_64-linux-gnu/libgcc_s.so.1
        7ffff780e000-7ffff7a0d000 ---p 00016000 fc:00 11801003                   /lib/x86_64-linux-gnu/libgcc_s.so.1
        7ffff7a0d000-7ffff7a0e000 rw-p 00015000 fc:00 11801003                   /lib/x86_64-linux-gnu/libgcc_s.so.1
        7ffff7a0e000-7ffff7bcd000 r-xp 00000000 fc:00 11801086                   /lib/x86_64-linux-gnu/libc-2.23.so
        7ffff7bcd000-7ffff7dcd000 ---p 001bf000 fc:00 11801086                   /lib/x86_64-linux-gnu/libc-2.23.so
        7ffff7dcd000-7ffff7dd1000 r--p 001bf000 fc:00 11801086                   /lib/x86_64-linux-gnu/libc-2.23.so
        7ffff7dd1000-7ffff7dd3000 rw-p 001c3000 fc:00 11801086                   /lib/x86_64-linux-gnu/libc-2.23.so
        7ffff7dd3000-7ffff7dd7000 rw-p 00000000 00:00 0 
        7ffff7dd7000-7ffff7dfd000 r-xp 00000000 fc:00 11796505                   /lib/x86_64-linux-gnu/ld-2.23.so
        7ffff7fd4000-7ffff7fd7000 rw-p 00000000 00:00 0 
        7ffff7ff5000-7ffff7ff8000 rw-p 00000000 00:00 0 
        7ffff7ff8000-7ffff7ffa000 r--p 00000000 00:00 0                          [vvar]
        7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0                          [vdso]
        7ffff7ffc000-7ffff7ffd000 r--p 00025000 fc:00 11796505                   /lib/x86_64-linux-gnu/ld-2.23.so
        7ffff7ffd000-7ffff7ffe000 rw-p 00026000 fc:00 11796505                   /lib/x86_64-linux-gnu/ld-2.23.so
        7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
        7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
        ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

        Program received signal SIGABRT, Aborted.
        0x00007ffff7a43428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
        54  ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
        (gdb) bt
        #0  0x00007ffff7a43428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
        #1  0x00007ffff7a4502a in __GI_abort () at abort.c:89
        #2  0x00007ffff7a857ea in __libc_message (do_abort=do_abort@entry=2, fmt=fmt@entry=0x7ffff7b9e2e0 "*** Error in `%s': %s: 0x%s ***\n")
            at ../sysdeps/posix/libc_fatal.c:175
        #3  0x00007ffff7a8de0a in malloc_printerr (ar_ptr=<optimized out>, ptr=<optimized out>, 
            str=0x7ffff7b9e358 "free(): invalid next size (fast)", action=3) at malloc.c:5004
        #4  _int_free (av=<optimized out>, p=<optimized out>, have_lock=0) at malloc.c:3865
        #5  0x00007ffff7a9198c in __GI___libc_free (mem=<optimized out>) at malloc.c:2966
        #6  0x0000000000400811 in main ()

I noticed that I can controll malloc structure and here it is overwritten to nonsense that's why free complaints:

free(): invalid next size (fast)

Is there a way to exploit this program? What technique should be used?


Yes, this program contains a simple buffer overflow error, and is exploitable. fread() reads up to 300 bytes and writes them to pData, which has only 20 allocated bytes. The memory space immediately following pData, which will be overwritten, is in use by other parts of the code, just not your application's code.

The part of the code that will be impacted is dependent on how it was linked, which C-Runtime libraries are loaded and in use and what they may have stored in that memory, compiler options, optimizations, etc. What you have to do is figure out the layout of the memory immediately following pData, and then figure out what values to put in test.bin in order to overwrite that memory with usefully malicious data. For example, you might be able to overwrite the memory table pointer so that when free() runs, it frees up something other than what it originally allocated. Can you figure out a way to structure a fake memory table to get free() to jump to some shellcode hidden in the 300 bytes of test.bin?

| improve this answer | |
  • Thanks! Found this win.tue.nl/~aeb/linux/hh/hh.html#toc11.2 - see section "Exploit free()", but I think it won't work with current glibc since there are so many security checks/improvements now. Hence my questions.... can I somehow abuse free() here to execute shellcode in modern/recent glibc? How to exploit this in more detail? – dev Feb 18 '17 at 10:50
  • I tried sample bug program and exploit from win.tue.nl/~aeb/linux/hh/hh.html#toc11.2 tutorial and on Ubuntu 16.04.02 LTS it doesn't work :( – dev Feb 18 '17 at 11:11
  • Found this .... github.com/shellphish/how2heap/blob/master/unsafe_unlink.c .... can I use it in this case? – dev Feb 18 '17 at 13:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.