Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Tema 2
Tema 2
[2.3] Metasploit
2
TEMA
Vulnerabilidades
Esquema
TEMA 2 – Esquema
protección vulnerabilidades vulnerabilidades
2
OpenVas •La memoria
Comandos
básicos •La pila
•Características Off-by-one
ASLR
•Funcionamiento PoC 1 (Linux)
Meterpreter Race Condition
•¿Qué es? PoC 2 (Windows)
Nexpose •Comandos Integer overflow
básicos
•Características Tipos de saltos
•Funcionamiento Format String
Backdooring Buffers pequeños
Buffer Overflow
Otras Otras formas de
herramientas salto
Fuzzers
Ideas clave
Para estudiar este tema lee las Ideas clave que se exponen a continuación.
Este segundo tema tratará del análisis de las vulnerabilidades así como su
explotación, utilizando diferentes pruebas de concepto (PoC), en las que se
demostrará paso a paso como aprovecharse de cierto tipo de vulnerabilidades para
tomar el control o ejecutar alguna acción en una máquina local o remota.
Se explicarán los tipos de interfaces con las que se podrá trabajar con Metasploit,
centrándonos exclusivamente en el de línea de comandos. También se explicarán
sus principales comandos y funcionalidades.
Tras esto se explicarán los diferentes tipos de vulnerabilidades que nos podremos
encontrar en aplicaciones y ejecutables (las vulnerabilidades web se verán en el tema
siguiente). Las principales vulnerabilidades son: Heap Overflow (desbordamiento
de pila), Buffer Overflow (desbordamiento de buffer), Off-By-One, Race condition,
Integer Overflow y Format String.
Nos centraremos sobre todo en los desbordamientos de buffer, ya que son los más
comunes a día de hoy. Se explicará un poco de teoría básica de la arquitectura de los
computadores actuales, necesaria para entender el funcionamiento de esta
vulnerabilidad (partes fundamentales de un computador, lenguaje ensamblador e
instrucciones básicas de este, funcionamiento de las zonas de memoria y
funcionamiento de la pila).
La primera PoC será en un entorno Linux, con un ejecutable sencillo creado a propósito
con esta vulnerabilidad. Se podrá reproducir de nuevo siguiendo la explicación de la
PoC paso a paso utilizando solamente una máquina con Kali Linux.
La segunda PoC será en un entorno Windows con una aplicación real (aunque ya tenga
algunos años). Esta aplicación será vulnerable a un desbordamiento de buffer y se
explicará, también paso a paso, como generar un exploit portable de ella para que se
pueda reproducir. En este caso harán falta dos máquinas, una con Kali Linux y otra con
Windows XP.
Tras las pruebas de concepto se explicarán otras formas de realizar los exploits vistos y
el caso concreto de hacer desbordamientos en buffers con tamaños reducidos. También
se tratarán rápidamente los fuzzers para realizar las tareas de descubrimiento de
desbordamientos de buffer.
Una vez hemos obtenido toda la información posible de la víctima, gracias al tema
anterior, nos dedicaremos a explotar las vulnerabilidades de su sistema para intentar
hacernos con el control de su máquina y los privilegios de administrador.
1. Nessus
Elegiremos Kali Linux y la versión que tengamos (32 o 64 bits). Después utilizaremos
los comandos:
En este otro ejemplo vemos el escaneo basic network scan realizado sobre un Windows
XP SP3. Como se puede ver, Nessus ha encontrado una vulnerabilidad crítica en la
máquina que se puede explotar remotamente y dar acceso total al atacante. En el
próximo capítulo se verá este ataque.
2. OpenVas
A causa de que Nessus se hiciera de pago, surgió OpenVas, herramienta que es igual de
potente que la anterior y como ventaja tiene que se actualiza diariamente. OpenVas
viene por defecto en la distribución Kali Linux.
Para iniciarla primero deberemos ir a: Aplicaciones > Kali Linux > Análisis de
vulnerabilidades > OpenVas > openvas initial setup. Esto arrancará la configuración
inicial descargando los plugins necesarios.
Tendremos que ingresar un usuario y contraseña para arrancar el servicio por primera
vez, el usuario por defecto es admin.
Nota: la primera vez que arranquemos la aplicación puede tardar un buen rato ya que
tiene que descargar toda la base de datos.
Antes de nada, deberemos actualizar la base de datos y para ello iremos a la pestaña
administration > NVT Feed > Synchronise with Feed Now.
Finalmente asignaremos una tarea para realizar en el objetivo. Para ello iremos a la
pestaña Scan Management > New Task. Seleccionaremos un tipo de escaneo a realizar
y el objetivo sobre el que realizarlo y le daremos un nombre también.
3. Nexpose
Tiene una gran ventaja y es que si encuentra alguna vulnerabilidad, nos dirá además si
esta se encuentra en la base de datos de Metasploit. El único problema con esta
herramienta es que solo está para sistemas operativos Linux o Windows de 64 bits, por
lo que no podremos instalarlo en nuestra máquina Kali si hemos optado por usar la de
32 bits.
Primero nos identificaremos y tendremos que definir el sistema a escanear. Para ello,
en la página principal pulsaremos en New Static Site.
A partir de ahí podremos definir el nombre del sistema a escanear, la/s dirección/es IP
que lo forman y el tipo de escaneo que vamos a llevar a cabo.
2.3. Metasploit
MsfConsole. Es una interfaz por consola, pero es la más usada ya que permite un
acceso a todas las funcionalidades de Metasploit. Es la que más juego y flexibilidad
da.
Todas estas herramientas estarán por defecto en Kali Linux. Nosotros utilizaremos
MsfConsole por su versatilidad. A continuación se explicarán sus diferentes funciones
y comandos:
MsfConsole permite ejecutar también algunos procesos de terceros como nmap, ping o
irb (un intérprete de comandos del lenguaje Ruby). Además, al pulsar el tabulador
mientras escribimos en la línea de comandos mostrará todas las posibilidades y
completará las palabras.
help -> Mostrará todos los comandos de Metasploit y una breve descripción,
podremos cargar plugins con funcionalidades extra usando el comando load
«plugin». También se mostrará la ayuda de estos plugins con el comando help una
vez se hayan cargado.
background -> Ejecuta a Meterpreter en segundo plano, se puede acceder a cada
una de las sesiones abiertas con el comando «sessions» visto antes.
ps -> Muestra los procesos activos.
sysinfo -> Muestra información del sistema en el que estamos.
getuid -> Muestra los permisos con los que contamos en la sesión actual.
getpid -> Indica el pid del proceso al que estamos conectados.
migrate -> Cuando explotamos una vulnerabilidad de software, si la víctima cierra
la aplicación perderemos la sesión, con este comando migraremos el proceso para
que esto no ocurra.
ipconfig -> Muestra las interfaces de red y las direcciones de la máquina remota.
idletime -> Muestra el tiempo de inactividad del usuario remoto.
pwd/ls/cd/mkdir/rm/rmdir -> Nos permiten movernos por los directorios de la
máquina remota y modificar archivos y carpetas.
run hashdump -> Obtendrá los hashes de las contraseñas del sistema.
upload/download -> Para subir y bajar archivos de la máquina remota.
screenshot -> Hace una captura de pantalla de la máquina víctima.
run vnc -> Devuelve una sesión gráfica del equipo remoto, pudiendo ver todas las
acciones del usuario.
keyscan -> Captura las pulsaciones del equipo remoto. Usaremos tres comandos:
keyscan_start/keyscan_dump/keyscan_stop.
load sniffer -> Cargará el plugin para poder capturar paquetes en la víctima.
víctima que cada cierto tiempo intente activamente conectarse a la máquina atacante,
siendo el atacante el que deba estar a la escucha.
Utilizaremos el comando run metsvc para crear la puerta trasera y luego nos
conectaremos a ella con el manejador de exploits multi/handler y el payload
metsvc/reverse_bind_tcp.
Para realizar una backdoor persistente que intente conectarse al atacante de forma
activa utilizaremos la función «persistence».
Cuando creemos la conexión persistente nos dirá en que archivo de nuestra máquina se
encuentra el cleanup para borrar la conexión persistente. Para hacer esto usaremos el
comando:
Para conectarnos será como antes, pero esta vez con el payload de meterpreter.
Metasploit también tiene herramientas para generar sus propios payloads o codificar
su código malicioso para que los antivirus no los detecten. Estas herramientas son:
msfpayload, msfencode y msfvenom (esta última unifica a las otras dos).
Msfpayload
A veces no podremos ejecutar un exploit remotamente para obtener una Shell. Por
ello, este módulo nos permitirá generar un payload personalizado para enviárselo a
la víctima. Esta herramienta ya es deprecated pero todas sus funcionalidades las
incluye la herramienta msfvenom.
Msfencode
Para poder evitar ser detectados por los antivirus, a veces tendremos que codificar
los ficheros infectados. Por ello, esta herramienta permite realizar diferentes
codificaciones, tantas veces como se deseen, para hacer pasar desapercibidos a estos
ficheros. También es deprecated y todas sus funcionalidades las incluye msfvenom.
Msfvenom
Esta herramienta es la evolución de las dos anteriores y las unifica en una
herramienta para facilitar la tarea de creación de payloads y su codificación.
msfvenom –h.
Nos creará un fichero que tendremos que enviar a la víctima por correo, por enlace
web, por algún dispositivo de almacenamiento externo… Nosotros pondremos nuestra
máquina a la escucha y, para ello, usaremos:
use multi/handler
Con set seleccionaremos el payload y las opciones necesarias de este. Cuando lancemos
el exploit se quedará a la escucha de que la máquina víctima abra el archivo infectado.
Para saber más sobre este y otros módulos de Metasploit, mira los siguientes enlaces:
http://ns2.elhacker.net/TallerMetasploit2012.pdf
http://ns2.elhacker.net/timofonica/manuales/Manual_de_Metasploit_Unleashed.
pdf (Manual de Metasploit de Offensive Security en español)
http://www.offensive-security.com/metasploit-unleashed/Introduction (Manual de
Metasploit de Offensive Security en inglés)
msfconsole
Desde los años 80 ya se conocen los errores de tipo buffer overflow y que hay ciertas
funciones en algunos lenguajes de programación que pueden llegar a provocar estos
fallos (como strcpy o get en C/C++). Pero aun así, a día de hoy, muchos desarrolladores
de software siguen utilizando estas y otras funciones con todo tipo de fallos generando
multitud de vulnerabilidades.
Hay diversos tipos de vulnerabilidades, algunas más peligrosas que otras. Unas pueden
llegar a causar denegación de servicio y otras ejecución de código remoto, pero que
pueden comprometer el sistema de una forma u otra.
Tipos de vulnerabilidades:
1 Heap Overflow
2 Off-By-One
3 Race condition
4 Integer Overflow
5 Format String
6 Buffer Overflow
Heap Overflow
Por ello, se puede utilizar la técnica de Heap Spraying, que consiste en llenar el
heap de NOPs y shellcodes, haciendo que cuando se acceda a este puntero tenga
o Dereference after free: es un tipo concreto de use after free y ocurre cuando
intentamos acceder a memoria dinámica previamente liberada como
consecuencia de un free(). El término dereference se refiere a la acción, de
acceder a la variable a la que apunta el puntero en cuestión con el operador ‘*’.
o Double free: ocurre cuando se libera un puntero más de una vez (sin
reasignarse entre ambas liberaciones). Al hacer esta doble liberación se corrompe
la estructura de datos que gestiona la memoria y se podrían sobrescribir algunos
registros o valores en la estructura corrompida para alterar el flujo del programa
y ejecutar código arbitrario.
Off-By-One
if ( strlen(param) > 64 )
{
printf(“Argumento demasiado largo”);
exit(0);
}
Race condition
Los errores generados por una condición de carrera son producidos por el cambio
que experimenta el estado de un recurso (fichero, memoria, registros…) desde que se
comprueba su valor hasta que el recurso es utilizado. Se convierten en una
vulnerabilidad si el atacante puede influir en este cambio de estado entre la
comprobación y uso. Generalmente, este tipo de problemas suelen darse bien por la
interacción entre hilos en un proceso multihilo o bien por la concurrencia de otros
procesos ajenos al proceso vulnerable.
El ejemplo más común es un proceso que modifica un archivo; para ello comprueba
si un usuario tiene permiso para escribir y si lo tiene, lo abre y permite modificarlo;
si un usuario creara otro proceso que se ejecutara simultáneamente a este y que
cambiara el valor del archivo a modificar, con un enlace simbólico por ejemplo,
podría modificar el archivo aunque no tuviera permisos necesarios.
Integer Overflow
Format String
En algunos lenguajes como C, es necesario para las funciones que imprimen por
pantalla que se indique el tipo de dato que se quiere imprimir (mediante ‘%d’,
‘%c’…). Este tipo de vulnerabilidad se da cuando el programador no define el
formato de los datos que se van a imprimir, permitiendo al atacante dar el formato a
su antojo y provocando que la función devuelva los valores que hay en la pila hasta
que se llegue a una zona que no tiene acceso y el programa acabe su ejecución.
#include <stdio.h>
int main(void)
{
char texto[30];
int a = 1;
int b = 2;
int c = 3;
scanf(“%29s”, texto);
printf(texto); //No da formato al texto leído
para imprimirlo
return 0;
}
Buffer Overflow
//overflow.c
int main ()
{
char strl [10] ; //Declaramos una variable con tamaño de 10
caracteres (bytes)
//a continuación, copiamos 35 bytes de "A" a
strl
strcpy (strl, " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
}
Pero… ¿Qué son estas zonas? ¿Qué es y cómo funciona el flujo de un proceso? Para
poder responder a estas preguntas, y antes de comenzar con la explicación del
funcionamiento y la explotación de los desbordamientos de buffer, se va a hacer una
pequeña introducción/repaso a la arquitectura básica de un computador.
La CPU deberá realizar una serie de acciones para leer y ejecutar cada una de las
instrucciones, dividiéndose en diferentes fases.
Estas son:
Los flags servirán para guardar valores especiales del flujo del programa como
overflow, valor negativo o interrupciones activadas.
Tanto los registros de la pila (EBP y ESP), como el puntero de instrucción serán claves a
la hora de hacer un desbordamiento de buffer.
Las instrucciones que lee la CPU están codificadas en lenguaje máquina (ceros y unos)
pero para facilitar al programador su trabajo, se creó un lenguaje a base de
mnemónicos, el lenguaje ensamblador.
Jcc: salta si la condición (cc) se cumple. Esta condición está relacionada con los
flags vistos antes, puede saltar si cero, si mayor igual, etc. También modifica EIP.
CALL subrutina: llama a la subrutina que esté indicada en la dirección de la
etiqueta subrutina. De manera implícita guarda EIP en la pila (PUSH EIP).
RET: retoma la ejecución en el punto antes de llamar a la subrutina. De manera
implícita saca EIP de la pila (POP EIP).
NOP: no hace nada, pierde un ciclo de reloj. Aunque no lo parezca, esta instrucción
es una de las más importantes a la hora de realizar los desbordamientos de buffer.
La mayoría de los sistemas operativos, entre ellos Windows, utilizan el formato Little-
endian. Si, por ejemplo, tenemos la dirección de memoria 0x0804B22A, la
guardaríamos en memoria principal de la forma “\x2A\xB2\x04\x08”.
Estas zonas tendrán diferentes propiedades, la más importante será los permisos que
tenga la zona (escritura, lectura o ambas).
El funcionamiento de la pila
La pila funciona a través de dos registros ESP y EBP, mediante los cuales puede
cumplir todas sus funciones.
o SUB esp, 04h: resta 4 bytes a la pila. Restar significa añadir bytes a la pila, por
lo que hemos visto de su crecimiento inverso. Este método de añadir bytes
directamente se usa para reservar espacio de variables locales dentro de las
subrutinas.
o POP reg: saca de la cima de la pila, apuntada por ESP, el valor que haya y lo
guarda en el registro. Disminuye el valor de ESP en tantos bytes como ocupe el
registro.
El otro registro que maneja la pila será EBP. Este registro apuntará a la base o parte
inferior de la pila. Su uso principal será la diferenciación entre las rutinas y
subrutinas dentro de un proceso, tomando valores relativos a cada una.
Cada vez que se llame a un nuevo procedimiento se hará: PUSH EBP, para poder
recuperarlo una vez acabe el procedimiento; luego se moverá el nuevo valor de ESP a
EBP, convirtiéndose EBP en la base de referencia para las variables locales de la
forma [EBP – 32].
¿Qué ocurrirá si quisiéramos copiar 200 A’s en el buffer del ejemplo anterior cuyo
tamaño es 100?
Como se puede ver, podríamos ser capaces de sobrescribir EIP. Al hacer esto podemos
introducir cualquier valor en EIP, que será la dirección de la siguiente instrucción a
ejecutar. Por lo que podremos ir redirigiendo el flujo del programa hacia donde
nosotros queramos.
1. PoC 1
#include <stdio.h>
#include <string.h>
{
int A;
char B[100];
if (argc < 2)
{
printf("Uso: %s argumento\n",argv[0]);
return -1;
}
A = argc;
strcpy(B,argv[1]);
printf("A=%d\nB=%s\n",A,B);
return 0;
}
Como se puede ver, el programa puede dar lugar a un buffer overflow, pues declara la
variable B con 100 bytes y utiliza la función strcpy() para copiar en esta variable el
primer argumento introducido por el usuario.
También será necesario utilizar una orden en la terminal para desactivar otro
mecanismo de seguridad llamado ASLR que genera direcciones aleatorias en la pila y
en el heap para evitar de nuevo este tipo de vulnerabilidades.
echo 0 > /proc/sys/kernel/randomize_va_space
Ahora utilizaremos lenguajes de script como Perl, Python o Ruby para generar una
entrada de texto suficientemente grande como para que sobrescriba otras zonas. Para
ello deberemos introducir más de 99 caracteres (ya que el carácter ‘\0’ de fin de cadena
lo añade siempre al final).
Usaremos el acento invertido para pasar como argumentos de la función la salida del
script, en cualquier lenguaje de los mencionados, que se encuentra a la derecha de la ‘P’
en el teclado.
Para saber exactamente qué hemos sobrescrito en EIP, utilizaremos GDB, el depurador
que viene por defecto en Linux.
En este caso encontramos que si introducimos 116 caracteres, los siguientes 4 serán
EIP.
Para comprobarlo introduciremos la letra ‘a’ 116 veces y después la letra b (0x62 en
hexadecimal) 4 veces.
Podemos ver que ha funcionado, así que, ya sabemos donde debemos colocar la
dirección a la que queremos saltar tras realizar el desbordamiento.
El siguiente paso será crear una shellcode para cuando explotemos la vulnerabilidad,
poder obtener una shell con los privilegios de la aplicación (en nuestro caso, al ser Kali,
tendrá siempre privilegios de root).
La shellcode que utilizaremos será un pequeño programa de C que devuelve una shell
pero pasado a lenguaje ensamblador:
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89
\xe1\xb0\x0b\xcd\x80"
Este script sobrescribirá el buffer con la shellcode (las instrucciones para ejecutar una
shell), el resto de a’s para completar los 116 bytes y EIP. Ahora tenemos que averiguar a
qué dirección debemos saltar para que se comience a ejecutar nuestra shell. De nuevo
usaremos GDB.
Posición:
0xbffff408
Primera posición
de la fila, es decir,
0xbffff400.
Podemos ver la primera instrucción de nuestra shellcode remarcada, así que esa será la
posición que tendremos que introducir en EIP. Modificaremos entonces nuestro script
exploit.rb y colocaremos la dirección en la variable eip recordando ponerla en formato
Little-endian: “\x08\xf4\xff\xbf”.
Obteniendo finalmente:
Estos problemas surgen porque hace falta ir instalando todas las actualizaciones tanto
de Metasploit como de cada una de las librerías de Ruby.
Para solucionarlo sin necesidad de realizar todas las actualizaciones, que a veces
pueden llegar a ser muy pesadas, vamos a modificar ambos archivos para que no realice
la comprobación de que todas las librerías estén actualizadas para poder funcionar.
2. PoC 2
realizar el desbordamiento de buffer, pero se podría tardar mucho y es una tarea muy
tediosa. Así que ya sabemos de antemano que esta aplicación es vulnerable y que tiene
un desbordamiento de buffer cuando intentamos cargar un archivo .m3u muy grande.
Al pulsar el botón de load nos permitirá incluir un archivo con una extensión específica.
Entre las permitidas se encuentra la m3u, a la que sabemos que es vulnerable. Pero
ahora… ¿cómo generamos un archivo .m3u para que lo cargue y hacer el
desbordamiento de buffer?
La respuesta será nuestra máquina Kali y no hará falta ninguna herramienta especial,
solamente crearemos un ejecutable en algún lenguaje de script de los ya mencionados
(Perl, Ruby, Python…) que genere un archivo con la extensión .m3u. En esta prueba de
concepto se usará de nuevo Ruby.
Para esta primera fase, estos archivos solo tendrán basura en su contenido, como una
letra repetida, y gran tamaño, ya que queremos determinar en qué punto aproximado
se produce el desbordamiento y luego solo generar un pequeño número de bytes con
pattern_create para averiguar el punto exacto.
Se ha usado una carpeta compartida entre las máquinas virtuales para enviar los
archivos entre ellos, aunque también se puede usar un USB, la nube…
El último de ellos, OllyDbg, es el más sencillo de utilizar, con una interfaz muy simple,
posee funcionalidades y plugins específicos para la explotación de vulnerabilidades,
como los otros dos.
WinDbg es el depurador para Windows hecho por Microsoft, también posee múltiples
paquetes y plugins. Será útil descargarlo junto con el paquete de símbolos del sistema
de Windows para realizar las funciones de búsqueda de instrucciones o bytes en el
código.
Immunity Debugger es similar en interfaz a OllyDbg pero cuenta con una pequeña
línea de comandos para la ejecución de plugins basados en Python. Uno de estos
plugins, llamado mona, será el que usemos más adelante para esta prueba de concepto.
Puedes acceder a un manual del uso del plugin desde la siguiente dirección:
https://www.corelan.be/index.php/2011/07/14/mona-py-the-manual/
Este plugin tiene múltiples funcionalidades, entre las que están: obtener el opcode de
una instrucción, buscar palabras, instrucciones o bytes dentro del código ensamblador,
comparar archivos… Para añadirlo a Immunity deberemos copiarlo en la carpeta de
PyCommands.
Ahora modificaremos nuestro script para crear un nuevo archivo .m3u. Esta vez
queremos reducir el rango de 10.000 caracteres para averiguar posteriormente la
posición de EIP. Para ello crearemos un patrón del siguiente modo:
22.000 letras ‘a’.
Cada 2.000 cambiaremos de letra hasta las 30.000.
Encontramos que EIP tiene la letra ‘d’ (64 en hexadecimal) por lo que está entre las
posiciones 26.000 y 28.000.
También se pueden usar antes en lugar de ir reduciendo poco a poco, pero en esta
prueba de concepto se prefiere que se entienda el concepto en lugar de realizarlo todo
de golpe. Generaremos el patrón con:
./pattern_create.rb 2000
Lo sustituiremos por las letras ‘d’ del script y lo ejecutaremos de nuevo en la aplicación
mientras la depuramos. En este caso obtenemos EIP: 63413263.
Tendremos que introducir 26.067 caracteres basura en el buffer antes que EIP.
¿Por qué no podemos usar bytes nulos? En los bytes nulos se basa el desbordamiento
de buffer, funciones como strcpy copian todo el contenido de un lugar a otro hasta que
se encuentre un byte nulo; si introducimos nosotros uno de estos bytes a la hora de
llenar el buffer parará en ese punto, aunque haya más texto. Un ejemplo sería
0x00341a2b, vemos que el último byte (Little-endian) es 0x00.
Por ello vamos a utilizar una técnica para que nuestro exploit no dependa de la
dirección específica a la que vaya a saltar, sino que sea siempre la misma, evitando el
uso de bytes nulos. Esta técnica será saltar a ESP.
Vamos a ver este ejemplo de una forma práctica en la aplicación y además obtendremos
la posición exacta de ESP ya que a veces no se encuentra justo después que EIP.
Lo ejecutamos de nuevo y vemos que hay una línea entre EIP y ESP, marcada en azul,
por lo que hay que añadir 4 bytes extra después de EIP
Nuestro objetivo ahora será introducir nuestro sled de NOPs y Shellcode a partir de
aquí. Pero no saltaremos directamente a la posición de ESP, si no que buscaremos la
instrucción jmp esp dentro de las propias librerías de Windows y de la aplicación, para
que hagan el salto por nosotros, las conocidas DLL. Estas librerías son estáticas y serán
portables de una máquina a otra; podremos hacer la aplicación portable para el mismo
sistema operativo (con las librerías del sistema) o para cualquiera (con las librerías de
la aplicación).
En este caso queremos usar las de la aplicación. Para ello tenemos que encontrar en
estas librerías la instrucción jmp esp, por lo que usaremos el Immunity Debugger y el
plugin mona. Primero iremos a la ventana de Log pulsando la ‘l’ en la barra de
herramientas, en esta ventana nos aparecerán los módulos que han necesitado la
aplicación y la información de la ejecución de los plugins.
Tenemos dos formas de buscar una instrucción o conjunto de instrucciones en todas las
librerías:
Ambas opciones dan el mismo resultado creando un archivo de texto llamado find.txt
en la carpeta del Immunity Debugger en Archivos de programa. En esta PoC se usa la
segunda opción junto con el modificador ‘-n’ que elimina los módulos que tengan bytes
nulos.
El archivo find.txt tiene dos partes, la primera nos indicará todos los módulos en los
que se ha encontrado una coincidencia (nos dirá si el módulo es del sistema operativo o
no, si tiene algún tipo de protección…) y la segunda parte irá mostrando dirección por
dirección todas las que haya encontrado.
Vamos a comprobar que el salto funciona y para ello usaremos la instrucción break
“\xcc” que detiene el flujo de la ejecución. Modificaremos nuestro script:
Tipos de saltos
Hemos conseguido crear un exploit en un entorno real, pero ha sido bastante ideal:
había espacio en la pila para nuestro payload, pudimos utilizar ESP para encontrar el
payload generado, encontramos la instrucción de salto que queríamos en las librerías
de la aplicación para hacer nuestro exploit más portable… Normalmente no se tiene
una situación ideal así que tendremos que utilizar diversas formas para ejecutar
nuestros payloads.
En el caso de la PoC 2:
Buscamos la instrucción call esp con mona y encontramos una dirección en una
DLL de la aplicación: 0x01c53f0f.
Para buscar este tipo de instrucciones usaremos los comandos según el número de
posiciones que queramos:
o !mona find -type instr -s “pop” # “ret”.
o !mona find -type instr -s “pop” # “pop” # “ret”.
[aaaaaaa…][0x01DEB22A][cccc][NOPNOPNOPNOP…][Payload]
Al simularlo obtendríamos:
[aaaaaaa…][0x0x01AB6A10][cccc][ddddeeee][0x01DEB22A][NOPNOPNOPNOP…][Payload]
Para que funcione hemos de buscar la secuencia Push [Reg] + Ret en alguna DLL. Si
por ejemplo, el payload estuviera apuntado directamente por ESP pero no
encontráramos jmp esp ni call esp.
o Usando mona, buscaremos las dos instrucciones consecutivas en las DLL con
“!mona find -type instr -s “push esp” # “ret -n”.
o También podríamos buscar los opcodes de cada instrucción y realizar la búsqueda
sobre ellas. En este caso “!mona find -s "\x54\xc3" -n”.
Blind Return. Esta técnica se usa cuando no podemos utilizar EIP para apuntar
directamente a un registro (porque no se puedan utilizar instrucciones JMP o CALL
y no quede más remedio que escribir la dirección en la pila) y tenemos control sobre
ESP (al menos los 4 siguientes bytes).
Consiste en:
o Sobrescribir EIP con la dirección a una instrucción RET de una DLL.
o Colocar la dirección del payload en los 4 bytes posteriores a ESP.
o Al ejecutar el RET se hace un POP implícito a los últimos 4 bytes de la pila, que
será la dirección que hemos introducido.
o Se saltará a nuestro payload.
Buffers pequeños
Podríamos utilizar todo el espacio que hemos usado para desbordar el buffer (las letras
«a» basura que introdujimos) para albergar nuestro payload. Para que esta técnica
funcione necesitamos encontrar las direcciones de memoria que albergan estos bytes y
una manera de referenciarlos.
Primero vamos a crear el exploit de prueba que simule una situación de buffer
pequeño:
Encontramos que ESP es 0x000ffd38 y que hay 4 bytes de desplazamiento entre EIP y
ESP, por lo que solo tenemos 50 bytes de buffer en realidad. Pero, además,
encontramos que cuando acaban los NOPs está el carácter ‘0x00’ (fin de cadena)
porque es el final de la cadena que hemos copiado y a partir de ahí hay un montón de
letras «a».
Estas letras son parte del buffer inicial que hemos introducido antes de EIP, así que si
somos capaces de realizar un salto a esta parte podremos ejecutar un payload en ella.
Nuestro objetivo será guardar el payload en las posiciones de memoria donde haya a’s
y utilizar el buffer pequeño de las x para saltar a este.
Primero tendremos que encontrar la posición exacta de las a’s encontradas en la basura
introducida. Podemos hacerlo con ensayo y error, creando un patrón propio o como en
nuestro caso, usando el patrón de Metasploit (pattern_create y pattern_offset).
Ahora sabemos que las primeras 257 a’s serán basura pero a partir de ahí, tendremos
espacio para introducir un payload.
El siguiente paso será añadir en la zona de las x, los 50 bytes que tenemos disponibles
en ESP, el código que nos permita hacer Jmp [ESP + 257]. Dividiremos el problema en
dos partes:
ADD ESP, 119h (281 en hexadecimal, ya que hemos añadido NOPs y nos da igual el
offset mientras sea mayor igual que 257).
JMP ESP (ESP será ESP + 281, por lo que saltará a nuestro payload).
Nos encontramos un problema, el opcode de «add esp, 119h» contiene bytes nulos,
pues es \x81\xc4\x19\x01\x00\x00 y no nos sirve. Vamos a tener que encontrar otra
forma para dividir el número en varias sumas parciales. Además en esta ocasión,
probaremos con WinDbg, ya que su base de símbolos es mayor que la de mona (mona
para la suma nos dará siempre opcodes con bytes nulos).
Nota: al realizar el exploit ha sido necesario quitar los últimos NOPs (marcados con **)
pues sobrepasaban el espacio total disponible en la pila y no permitía la ejecución
correcta del payload. Además al reducirse este número de NOPs, la posición a la que
saltar de ESP disminuye por lo que deberemos quitar la línea marcada con asteriscos
del código de salto. Solo saltaríamos (188 posiciones).
Y al ejecutarlo:
Es aconsejable que si se desea seguir las PoC o los ejemplos, todos los archivos se
copien en el Escritorio o en alguna carpeta de la máquina donde se ejecuten y no se
haga directamente desde la carpeta compartida por las máquinas virtuales ya que
puede generar fallos.
Popad (Pop all double). Hace POP a dobles palabras de la pila y las guarda en los
registros de propósito general en la misma instrucción.
o Un solo popad sacará 32 bytes de la pila.
o Se cargarán en los registros en el siguiente orden: EDI, ESI, EBP, ESP, EBX,
EDX, ECX y EAX. (En ESP no se cargan datos sino que son descartados).
o El código de operación es ‘\x61’ (Las a’s que hemos usado como basura).
o Es muy útil para tamaños de buffer muy pequeños. Si tenemos que saltar 260
bytes con un espacio de salto de 14 bytes, podremos usar 9 POPAD y un JMP ESP
ocupando solo 11 bytes.
Fuzzers
Como apartado final se quiere hablar de un tipo de fuzzer especial usado para testear
aplicaciones en busca de desbordamientos de buffer. Este tipo de fuzzer se dedicará por
nosotros a la tarea de enviar grandes cantidades de caracteres a las entradas de ciertos
servicios de protocolos conocidos, como HTTP o FTP. Usaremos Metasploit para
encontrar estos fuzzers, en el módulo auxiliary > fuzzers.
Uno de ellos, desarrollado por Corelan Team (los autores del plugin mona), se usa para
realizar este tipo de testeo de buffer overflow en servidores FTP. Introduce tantos
caracteres como le indiquemos siguiendo patrones para cada una de las opciones del
protocolo (nombre de usuario, contraseña, ningún comando, comando STOR…)
avisándonos si se ha lanzado alguna excepción a causa de desbordar el buffer por la
introducción de texto.
Vamos a realizar una pequeña prueba de concepto con un servidor FTP vulnerable
llamado WarFTP en una máquina XP y nuestra máquina Kali.
Pondremos exploit y el fuzzer irá enviando texto a la aplicación. Como tenemos puesto
el depurador, cuando encuentre algún error este parará la aplicación y el fuzzer no
seguirá funcionando. En un entorno normal, sin el depurador, cuando la aplicación
deje de funcionar, el fuzzer lo notificará y acabará.
Será siempre conveniente comprobar fase por fase las entradas del fuzzer una vez
descubramos que hay un fallo en aplicación del servidor.
Habrá disponible en el aula virtual el vídeo con la prueba de concepto más detallada y
paso a paso.
o DEP por hardware consiste en un bit que se coloca en las páginas de memoria de
un proceso en el que se indica si esta puede ejecutar o no código. Este bit se llama
NX (no execute) en arquitectura Intel y XD (execute disable) en AMD. Esta
solución es en tiempo de ejecución y no requiere volver a recompilar las
aplicaciones para que funcione.
o DEP forzado por software no posee este bit mencionado, sino que consiste en
evitar que se sobrescriban los manejadores de excepciones SEH. Puede ayudar a
evitar que se ejecute código malintencionado. A diferencia del anterior hará falta
compilar específicamente para implementar esta medida, también llamada
/SafeSEH.
o Otra forma de solución, basada en librerías es detectar cualquier intento de
ejecución de código ilegítimo en la pila, ejemplo de esto es la solución
SecureStack desarrollada por SecureWave.
o Aunque haya formas de saltarse DEP, tanto software como hardware, supone
dificultar la tarea de generar vulnerabilidades y aumenta la complejidad de los
exploits.
#include <stdio.h>
Activar ASLR:
echo 2 > /proc/sys/kernel/randomize_va_space
Desactivar ASLR
echo 0 > /proc/sys/kernel/randomize_va_space
Este pequeño programa devolverá el valor de ESP cada vez que se ejecute, pudiendo ver
en cada ejecución como cambia su valor según tengamos o no activado ASLR.
o De nuevo esta medida se podrá saltar, ya sea usando grandes sleds de NOPs,
esperando que el salto caiga en ellos o accediendo a librerías que sean estáticas.
Lo + recomendado
Lecciones magistrales
No dejes de leer…
Hacking práctico
+ Información
A fondo
Guía de Metasploitable
Webgrafía
Tutoriales de corelan
Página web que contiene los mejores tutoriales acerca de exploit para Windows.
https://www.corelan.be/index.php/articles/
Exploit-db
Página web donde podemos encontrar información sobre los últimos exploits
descubiertos.
http://www.exploit-db.com/shellcode/
Bibliografía
VV. AA. (2006). Extreme exploits (hackers y seguridad). Madrid: Ediciones Anaya
Multimedia.
VV. AA. (2005). Blindaje de redes: tu red invulnerable a los hackers. Madrid:
Ediciones Anaya Multimedia.
Actividades
» Metasploitable. Esta máquina no hay que instalarla, solamente utilizar la ISO con
Virtual Box. Se puede descargar desde esta dirección URL:
https://sourceforge.net/projects/metasploitable/files/Metasploitable2/
» Windows 7. Se debe obtener una máquina Windows 7, la cual podéis descargar
desde DreamSpark
En este hito debéis crear la máquina para Metasploitable y arrancar desde el CD/DVD
con la ISO. Es recomendable configurar la red de la máquina Metasploitable de forma
que tengáis conectividad con vuestras otras máquinas y con la máquina anfitriona
(máquina física).
Test