Explorando el heap

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

int main() {

  char *buffer = malloc(16);
  char *filename = malloc(23);
  strcpy(filename, "/tmp/heap-overflow.txt");

  gets(buffer);
  printf("%s\n" ,buffer);
  printf("%s\n" ,filename);

  FILE *fd = fopen(filename, "w");
  if (fd != NULL) {
      fputs(buffer, fd);
      fclose(fd);
  }

  return 0;
}

En C9.io lo compilamos usando la opción de debug:

gcc  -g  ho.c

Notamos que los espacios reservados viven a 0x20 bytes de distancia.

(gdb) p buffer
$2 = 0x602010 ""
(gdb) p filename
$3 = 0x602030 ""

Si inspeccionamos varios bytes antes del primero, vemos su contenido.

(gdb) x/10wx buffer-8
0x602008:       0x00000021      0x00000000      0x00000000      0x00000000
0x602018:       0x00000000      0x00000000      0x00000000      0x00000000

Si huberamos reservado 64 bytes para el filename, el contenido sería 0x00000051. De modo los 4 bytes antes del comienzo del espacio reservado para data contienen el largo del espacio reservado y un bit adicional para qué?

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

int main() {

  char *buf1 = malloc(16);
  char *buf2 = malloc(16);
  char *buf3 = malloc(16);
  char *buf4 = malloc(16);


  free(buf3);
  free(buf2);
  gets(buf1);

  buf3=malloc(16);
   gets(buf3);
  return 0;
}
(gdb) p buf1
$1 = 0x602010 ""
(gdb) p buf2
$2 = 0x602030 ""
(gdb) p buf3
$3 = 0x602080 ""
(gdb) p buf4
$4 = 0x6020d0 ""

El contenido del heap luego de los mallocs pero antes del free:

(gdb) x/100x buf1-8
0x602008:       0x00000021      0x00000000      0x00000000      0x00000000
0x602018:       0x00000000      0x00000000      0x00000000      0x00000000
0x602028:       0x00000051      0x00000000      0x00000000      0x00000000
...
0x602078:       0x00000051      0x00000000      0x00000000      0x00000000
...
0x6020c8:       0x00000051      0x00000000      0x00000000      0x00000000
...
0x602118:       0x00020ef1      0x00000000      0x00000000      0x00000000

Segun borramos pedazos (usando free)

0x602078:       0x00000051      0x00000000      0x00602020      0x00000000

Envenenamos el prev o next de uno de los chunks vacíos. Al tratar de reservar con malloc un nuevo espacio:

*** Error in `/home/ubuntu/workspace/a.out': malloc(): memory corruption (fast): 0x0000000000602030 ***

Program received signal SIGABRT, Aborted.
0x00007ffff7a4af89 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56      ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.

0x0000000000602030 es la dirección que habíamos modificado. Bajo condiciones normales ¿Será que malloc valida el contenido de los punteros?

Si apagamos las verificaciones:

export MALLOC_CHECK_=0

Al correr el programa y pasar un string envenenado al buf1, logramos que el buf3 apunte a otra dirección muy lejos del heap:

(gdb) p buf3
0x7ffff00008c0

Referencias

*