Вы находитесь на странице: 1из 7

SMASHING THE STACK FOR

FUN AND PROFIT


Rompiendo la pila por diversin

Descripcin breve
Explicacin de que es una pila en conceptos de informtica. Y como aprovechar una
vulnerabilidad en ella para explotarla.

QUIROGA JULIO
Julio.quiroga@davinci.edu.ar
Rompiendo la pila por diversin y
ganancias

Qu es una pila?
Pilas: Las pilas son estructuras de datos que tienes dos operaciones bsicas: push (para insertar
un elemento) y pop (para extraer un elemento). Su caracterstica fundamental es que al extraer
se obtiene siempre el ltimo elemento que acaba de insertarse. Por esta razn tambin se
conocen como estructuras de datos LIFO (del ingls Last In First Out). Una posible
implementacin mediante listas enlazadas sera insertando y extrayendo siempre por el
principio de la lista. Gracias a las pilas es posible el uso de la recursividad. La variable que llama
al mismo procedimiento en el q est, habr que guardarla, as como el resto de variables de la
nueva llamada, para a la vuelta de la recursividad ir sacndolas, esto es posible a la
implementacin de pilas.

Buffer overflows
Un buffer overflow (o desborde de memoria) se lleva a cabo cuando un programa informtico
excede el uso de cantidad de memoria asignado por el sistema operativo, escribiendo en el
bloque de memoria contiguo.
En verdad, un buffer overflow se produce en una aplicacin informtica cuando no cuenta con
los controles de seguridad necesarios en su cdigo de programacin. Cabe destacar que para
poder llevar a cabo un desborde de memoria, se debe contar con conocimientos de
programacin, como tambin nociones bsicas de arquitectura de Sistemas Operativos.

ESTRUCTURA DE LA MEMORIA
Cuando un programa es ejecutado, el sistema operativo reserva una zona de memoria para que
la aplicacin realice correctamente sus instrucciones, este espacio se divide en zonas de acuerdo
a los distintos tipos de datos. Primero es necesario cargar el cdigo ejecutable del programa, es
decir, las instrucciones. La zona etiquetada como data es utilizada por lenguajes de
programacin que permiten la creacin de variables globales y variables estticas.

Asimismo, se reservan por lo menos dos espacios para los datos requeridos en la ejecucin,
estos espacios son stack y heap.

El stack almacena los argumentos de las


funciones, las variables locales y las
direcciones de retorno de las llamadas a
funciones.

El heap se encarga de gestionar la memoria


dinmica, es decir la memoria solicitada
durante el tiempo de ejecucin.

Figura 1. Estructura de la memoria.

Existen regiones reservadas para datos de


entrada del programa, pueden ser localizadas
tanto en el stack como en
el heap dependiendo del tipo de datos que van
a almacenar. Estas regiones son
llamadas buffer, por lo que se puede definir
el buffer como un espacio en memoria que
sirve como almacenamiento temporal de
datos de entrada en un programa.

TIPOS DE BUFFER OVERFLOW


Bsicamente pueden distinguirse dos tipos primarios de buffer overflow que se ligan
directamente con la explicacin previa sobre las regiones de memoria ya que su nombre se
deriva del espacio en memoria sobre el cual es localizada la vulnerabilidad:

Stack overflow

Heap overflow
CONSECUENCIAS DEL STACK OVERFLOW
Qu pasa s se sobrescribe la direccin de retorno? Se debe recordar que la direccin de retorno
indica qu es lo que se debe ejecutar una vez que termina la ejecucin de una funcin o
procedimiento, en este caso, pueden ocurrir las siguientes opciones:

S se llena con caracteres que no representen una direccin vlida de memoria, generar
un error de tipo segmentation fault. Por ejemplo, AAAAAA no es una direccin
reconocible de memoria.

Se puede apuntar a una direccin dentro del programa, provocando que se ejecute de
forma incorrecta, por ejemplo, ir al inicio del programa o al final de ste, ir a una
instruccin de impresin en pantalla, etc.

Y el peor escenario y por el cual esta vulnerabilidad es muy explotada, es posible


ejecutar cdigo arbitrario:

Escrito por un individuo malicioso apuntando a una direccin en memoria donde inicie
el cdigo malicioso.

Cdigo que ya se encuentra en el espacio de direcciones del sistema, haciendo


referencia a la direccin donde se encuentre localizado, por ejemplo la ejecucin de un
Shell (/bin/sh).

Ejemplo de STACK OVERFLOW:


As que un buffer overflow nos permite cambiar la direccin de retorno (return address) de una
funcin. Vamos a nuestro primer ejemplo y veamos de nuevo como se dispona la pila:

parte baja parte alta


de memoria de memoria
buffer2 buffer1 sfp ret a b c
<------ [ ][ ][ ][ ][ ][ ][ ]

parte alta parte baja


de la pila de la pila

Intentemos modificar nuestro primer ejemplo para que sobrescriba la direccin de retorno
(return address), y demostrar cmo podemos hacer para ejecutar cdigo arbitrario. Antes de
buffer1[] en la pila esta SFP, y antes de esto, la direccin de retorno (return address). Eso es 4
bytes despus del final de buffer1[]. Pero recuerda que buffer1[] son 2 word as que tiene una
longitud de 8 bytes. As que la direccin de retorno (return address) est a 12 bytes desde el
principio de buffer1[]. Modificaremos el valor de retorno en tal modo que la declaracin 'x = 1;'
despus de la llamada a la funcin ser saltada. Haciendo esto aumentaremos 8 bytes a la
direccin de retorno. Nuestro cdigo esta ahora:

ejemplo3.c:
------------------------------------------------------------------------------
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
int *ret;

ret = buffer1 + 12;


(*ret) += 8;
}

void main() {
int x;

x = 0;
function(1,2,3);
x = 1;
printf("%d\n",x);
}
------------------------------------------------------------------------------
Lo que hemos hecho es aumentar 12 a la direccin del buffer1[]. Esta nueva direccin es donde
se almacenaba la direccin de retorno (return address). Queremos pasar por alto la asignacin
a la llamada printf. Como aumentamos en 8 la direccin de retorno (return address)? Usamos
primero un valor de testeo (por ejemplo 1), compilamos el programa, y despus usamos el gdb:
------------------------------------------------------------------------------
[aleph1]$ gdb example3
GDB is free software and you are welcome to distribute copies of it
under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.15 (i586-unknown-linux), Copyright 1995 Free Software Foundation,
Inc...
(no debugging symbols found)...
(gdb) disassemble main
Dump of assembler code for function main:
0x8000490 <main>: pushl %ebp
0x8000491 <main+1>: movl %esp,%ebp
0x8000493 <main+3>: subl $0x4,%esp
0x8000496 <main+6>: movl $0x0,0xfffffffc(%ebp)
0x800049d <main+13>: pushl $0x3
0x800049f <main+15>: pushl $0x2
0x80004a1 <main+17>: pushl $0x1
0x80004a3 <main+19>: call 0x8000470 <function>
0x80004a8 <main+24>: addl $0xc,%esp
0x80004ab <main+27>: movl $0x1,0xfffffffc(%ebp)
0x80004b2 <main+34>: movl 0xfffffffc(%ebp),%eax
0x80004b5 <main+37>: pushl %eax
0x80004b6 <main+38>: pushl $0x80004f8
0x80004bb <main+43>: call 0x8000378 <printf>
0x80004c0 <main+48>: addl $0x8,%esp
0x80004c3 <main+51>: movl %ebp,%esp
0x80004c5 <main+53>: popl %ebp
0x80004c6 <main+54>: ret
0x80004c7 <main+55>: nop
------------------------------------------------------------------------------
Se puede ver que cuando llamamos a function() la RET es 0x8004a8, y queremos saltar a la
asignacin 0x80004ab. La siguiente instruccin que queremos ejecutar es la de 0x8004b2. Un
uso de las matemticas nos dices que la distancia es 8 bytes.

Shell Code
Ahora que sabes que se puede modificar la direccin de retorno (return address) y el flujo de
ejecucin, que programa queremos ejecutar? En la mayora de los casos querremos el programa
simplemente para producir una shell. Desde la shell podemos usar los comandos que deseemos.
Pero que pasa si no hay tal cdigo en el programa que estamos intentando exploitear?
Como podemos emplazar arbitrariamente instrucciones en el espacio de una direccin de
memoria? La respuesta es situar el cdigo que estamos intentando ejecutar en el buffer que
estamos desbordando, y sobrescribir la direccin de retorno as que apuntara hacia atrs en el
buffer. Asumiendo que la pila empieza en la direccin 0xFF, y que S es del cdigo que queremos
ejecutar la pila aparecera como a continuacin:

parte baja DDDDDDDDEEEEEEEEEEEE EEEE FFFF FFFF FFFF FFFF parte alta
de memoria 89ABCDEF0123456789AB CDEF 0123 4567 89AB CDEF de memoria
buffer sfp ret a b c

<------ [SSSSSSSSSSSSSSSSSSSS][SSSS][0xD8][0x01][0x02][0x03]
^ |
|____________________________|
parte alta parte baja
de la pila de la pila

El cdigo para crear la shell en C es como el que viene a continuacin:


shellcode.c
-----------------------------------------------------------------------------
#include <stdio.h>
void main() {
char *name[2];

name[0] = "/bin/sh";
name[1] = NULL;
execve(name[0], name, NULL);
}
i

i
Este ejemplo fue tomado de la siguiente pagina:
http://julianor.tripod.com/bc/smashing/P49-4-Smashing_the_stack-Spanish.txt.

Вам также может понравиться