De We Live Security: Solución al Desafío ESET #32: conoce cómo explotar la aplicación vulnerable (01/03/2015)

Saludos nuevamente.

En el sitio de We Leave Security cada cierto tiempo ESET publica posts que constituyen desafíos para los usuarios, los cuales, si son resueltos, otorgan premios a los que proveen dichas soluciones. En esta, el desafío fue explotar la vulnerabilidad de una aplicación en Linux, y ya está resuelto. Aquí les va:

Solución al Desafío ESET #32: conoce cómo explotar la aplicación vulnerable

Por Matías Porolli publicado 1 mar 2016 – 02:19PM

 

La semana pasada, desde el Laboratorio de Investigación de ESET Latinoamérica, abrimos un nuevo reto relacionado con la explotación de una aplicación vulnerable en Linux. Hoy tengo el agrado de mostrarles la respuesta al Desafío ESET #32.

El primer paso consiste en analizar la aplicación vulnerable, para así poder explotarla. Para ello, vamos a abrir el ejecutable con gdb:

Debuggeando aplicacion vulnerable con gdb

Podemos ver que la aplicación tiene información de debug; en particular nos interesa su única rutina de usuario: main. Si pedimos a gdb que nos muestre el disassembly de main, obtenemos:

Analizando simbolos con gdb

Del código observamos que se reservan 64 bytes (40h) para variables locales en el stack. También vemos que se llama a una función estándar y se le pasa uno de los argumentos con que se ejecutó la aplicación y un puntero a ese buffer de 64 bytes en el stack. No sabemos qué hace esa rutina estándar, pero cuando colocamos un breakpoint y corremos la aplicación, gdb nos muestra que esa rutina es realmente un strcpy que copia argv[1] a buf. Luego, si cerramos gdb y volvemos a debuggear con el argumento “string_prueba”, podemos verificar que esa cadena es copiada al stack:

Debuggeando con gdb

Resulta evidente que, si se ejecuta la aplicación con un argumento de mayor longitud que 64 bytes, se va a pisar el stack, pudiendo alterar la dirección de retorno de main de tal modo de ejecutar código arbitrario. El código correspondiente (en C) es el siguiente:

Codigo vulnerable en C

Si compilamos el código de la shell, veremos que no es apto para usarlo como payload, dado que contiene bytes nulos que detendrían la copia de strcpy:

payload no util

Hay varias formas de modificar el código para que sea útil. A continuación se muestra una posible solución que se me ocurrió (aunque no la más sencilla):

codigo shell ok

En forma resumida, se realizaron los siguientes cambios:

  • El código de execve se deposita en AL y no EAX: así las instrucciones generadas no rellenan el valor 11 con bytes nulos.
  • No se asigna el valor cero a ECX y EDX; se hace uso de xor.
  • Para no depender de una dirección fija de memoria, la string “/bin/sh\x00” se construye en el stack y se copia ESP en EBX.
  • Uso de la instrucción ROL para que la string termine en null (esta parte es optimizable, y hay soluciones más sencillas).

Al compilar se obtiene lo siguiente:

payload shell util

Y pegamos los opcodes en el archivo que servirá de input al programa vulnerable:

construccion shellcode

Vemos que el tamaño del payload es de 29 bytes. El resto de los 64 bytes del buffer se rellenará con instrucciones NOP. Luego se pisarán los 4 bytes correspondientes al frame pointer almacenado por main (EBP), con un valor cualquiera (en nuestro caso, escribimos “AAAA”). Como último paso, debemos escribir la dirección de memoria que pisará la dirección de retorno de main (EIP almacenado), por lo que acudiremos nuevamente al debugger:

buscando eip en gdb

Ahí vemos que, para la sesión de gdb, el buffer comienza en 0xbffff2f8. Por lo tanto, podemos elegir la dirección de retorno para que salte al medio del bloque de NOP, por ejemplo en 0xbffff309. Luego, modificamos nuestra shellcode agregando esa dirección (little endian).

shellcode actualizado con eip

Podríamos probar el exploit en gdb, pero vamos a correr la aplicación vulnerable fuera del debugger. Debemos, sin embargo, considerar una pequeña trampa: dado que no podemos garantizar el espacio de direcciones donde se va a cargar el ejecutable, dejando inservible la dirección elegida entre ejecución y ejecución, por simpleza desactivaremos ASLR.

desactivando aslr

La ejecución falla porque la dirección base del buffer en el stack ha cambiado, pero podemos activar un dump completo y revisar si el shellcode quedó por debajo o encima:

debug del core

Se observa que la dirección base del buffer está en 0xbffff328. Salimos de gdb, actualizamos la dirección a la mitad del bloque de NOP y corremos nuevamente la aplicación vulnerable:

aplicacion vulnerable explotada

Ha funcionado el buffer overflow y se ha abierto una shell bajo el mismo usuario, sin privilegios. Está claro que si la aplicación vulnerable tuviese mayores privilegios, también los tendría la shell.

Concluido el reto, felicitamos a @nitr0usmx por haber resuelto el desafío con éxito y resultar ganador de las tres licencias de ESET Smart Security; pueden ver su solución en la sección de comentarios.

¡Hasta la próxima!

Acerca de Hector Suarez Planas

Es Licenciado en Ciencia de la Computación (3 de julio de 2002). Ha sido Administrador de Red en varias organizaciones, Programador y Analista de Sistemas. Actualmente se desempeña como Administrador de Red del Telecentro Tele Turquino de Santiago de Cuba. Tiene experiencia con sistemas Windows y GNU/Linux, Infraestructura de Redes (Cisco, AlliedTelesis, Netgear y HP ProCurve, Vyatta/VyOS), Servidores tanto físicos como virtuales (plataformas VMWare, Proxmox VE y Xen), Sistemas de Seguridad Informática (Snort/Suricata IDS, appliances AlienVault OSSIM), programador (Delphi, C++ Builder, Perl [poco], Python [algo]), entre otras cosas. Actualmente estoy incursionando en todo lo que tiene relación con Cloud Computing (OpenStack) y Centros de Datos. :-)
Esta entrada fue publicada en Desafíos ESET, ESET, Seguridad, Soluciones a Desafíos ESET. Guarda el enlace permanente.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *