Buffer Overflow

En seguridad informática y programación, un desbordamiento de buffer (del inglés buffer overflow o buffer overrun) es un error de software que se produce cuando se copia una cantidad de datos sobre un área que no es lo suficientemente grande para contenerlos, sobrescribiendo de esta manera otras zonas de memoria. Esto se debe en general a un fallo de programación. La consecuencia de escribir en una zona de memoria imprevista puede resultar impredecibles. Existen zonas de memoria protegidas por el sistema operativo. Si se produce la escritura fuera de una zona de memoria protegida se producirá una excepción del sistema de acceso a memoria seguido de la terminación del programa. Bajo ciertas condiciones, un usuario obrando con malas intenciones puede aprovecharse de este mal funcionamiento para ejecutar código malicioso.

Ejemplo de un buffer overflow para Linux

En este ejemplo tenemos un programa con una funcion main que llama a una funcion f y esta como como cualquier función normal luego de ejecutarse devuelve el control a quien la llamo.

main -> f -> main

También tenemos una funcion g que nunca es llamada, pero usando un bo(buffer overflow) podemos hacer que lo sea aun cuando esto no se ha hecho explicitamente en el codigo fuente, para ello en f cambiamos la dirección de memoria a la que deberia retornar normalmente la dirección de la funcion main por la de la funcion g

main -> f -> g

overflow.c para 32 bits

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

void f(char *str)
{
  char foo[16];
  strcpy(foo, str);
}

void g(){
  printf("Esto nunca se imprime\n");
}

int main()
{
  char large_one[19];

  large_one[0]='A';
  large_one[1]='A';
  large_one[2]='A';
  large_one[3]='A';
  large_one[4]='A';
  large_one[5]='A';
  large_one[6]='A';
  large_one[7]='A';
  large_one[8]='A';
  large_one[9]='A';
  large_one[10]='A';
  large_one[11]='A';
  large_one[12]='A';
  large_one[13]='A';
  large_one[14]='A';
  large_one[15]='A';  
  large_one[16]='A';
  large_one[17]='A';
  large_one[18]='A';
  large_one[19]='A';
  large_one[20]='A';
  large_one[21]='A';
  large_one[22]='A';
  large_one[23]='A';
  large_one[24]='A';
  large_one[25]='A';
  large_one[26]='A';
  large_one[27]='A';

  //Direccion de memoria: 0x ** 41 41 41
  large_one[28]='A';
  large_one[29]='A';
  large_one[30]='A';

  //Direccion de memoria funcion g: 0x 08 04 84 2e
  /*
  large_one[28]=0x2e;
  large_one[29]=0x84;
  large_one[30]=0x04;
  large_one[31]=0x08;
  */

  f(large_one);
  return 0;
}

Ejecucion

Kernel

Linux tiene una debil implementacion de ASLR habilitada por defecto desde el kernel version 2.6.12 para desactivarla use el comando:

El conjunto de parches ExecShield provee una implementacion mas completa y en caso de tenerlo puede deshabilitarlo con:

Compilacion y ejecucion

$ gcc -fno-stack-protector -g overflow.c -o overflow
$ ulimit -c unlimited
$ ./overflow
Segmentation fault
$ gdb -q overflow core
Leyendo símbolos desde /tmp/overflow...hecho.
[Nuevo Thread 2535]

El núcleo se generó por «./overflow».
El programa terminó con la señal 11, Segmentation fault.
#0  0xd6414141 in ?? ()

(gdb) disas g
Dump of assembler code for function g:
   0x0804842e <+0>:     push   %ebp

$ gcc -g overflow.c -o overflow
$ ./overflow
Esto nunca se imprime
Violación de segmento (`core' generado)

64 bits

En una computadora de 64 bits debe buscar una dirección del tipo: 0x ** 41 41 41 41 41 41 41

Documentacion

Seguridad/BufferOverflow (last edited 2011-11-28 12:50:22 by kmilo)