Una de las cosas que más llaman mi atención últimamente es mirar las tripas del
framework de explotación
Metasploit. Al final nos damos cuenta de que tantos años de desarrollo y el apoyo de la comunidad hace de este entorno una navaja suiza con miles de funcionalidades. Preparando el
Rooted Lab de este año topé con un pequeño software que proporciona un servidor web llamado
Kolibri. Visitando algunos sitios de
exploits, como
PacketStorm o
Exploit-DB, encontré
uno público escrito en Python. Además, preparando el
curso de Metasploit con Criptored del mes de Julio, decidí meter esta práctica.
|
Figura 1: Cómo migrar un exploit en Python a un módulo de Metasploit |
Este
exploit se aprovecha de un
Stack Buffer Overflow, con
CVE-2014-4158, escrito por
Christian Ramirez. El
exploit se encontraba testeado para sistemas operativos
Windows XP SP3 en español.
|
Figura 2: Exploit para CVE-2014-4158 |
Como mencioné anteriormente, estaba probando algunas cosas para el
Rooted Lab y decidí migrar dicho
exploit a un módulo de
Metasploit, ya que para este software no teníamos un módulo implementado en el
framework. En este artículo vamos a hablar de cómo llevar a cabo la migración de este
exploit a un módulo de tipo
exploit en
Metasploit.
Requisitos de un módulo exploit en Metasploit
En primer lugar, vamos a ver cuáles son los requisitos. Cuando creamos un módulo de tipo
exploit necesitamos, al menos dos funciones. La primera es la función
initialize y la segunda es la función
exploit. Opcionalmente, se puede implementar la función
check cuyo objetivo es indicar al
pentester si el
target es vulnerable o no.
|
Figura 3: Include de HttpClient |
Otro requisito que el framework nos va a facilitar es saber cómo conectaremos con el software remoto, en este caso con el servidor web.
Metasploit nos proporciona esto de forma trasparente, por lo que podemos utilizar la clase
HTTPClient para interactuar con el servidor web de manera sencilla. Para poder utilizar
HTTPClient se utilizará
include Msf::Exploit::Remote::HttpClient.
Función initialize()
Esta función proporciona diferente tipo de información. Es la función encargada de inicializar el módulo y sus diferentes atributos, como por ejemplo la descripción de éste cuando el usuario ejecuta el comando info en la consola. Otros atributos descriptivos son
Author, References, DisclosureDate o
License.
El atributo
Platform y
Arch indican para qué plataforma y arquitectura se implementa el módulo. Esto es importante para los
payloads disponibles, ya que si
Platform no es
Windows, no podremos configurar un
Payload para este sistema. El atributo
Payload es una colección de elementos, entre los que podemos destacar
BadChars y
Space.
Badchars indica que
bytes no deben ser generados por
Metasploit cuando el
Payload se genere.
|
Figura 4: Funcion initialize() |
El atributo
Targets indica la colección de diferentes versiones del software que son vulnerables. En este caso solo tenemos la versión
Kolibri 2.0 sobre
Windows XP SP3. Un parámetro muy importante es
Ret, ya que en este se indica la dirección de memoria a la que apuntará el
EIP cuando se realice la explotación. Esta dirección de memoria apuntará a la dirección de memoria dónde encontraremos una instrucción
JMP ESP con la que conseguiremos llegar a nuestra
shellcode.
Función check()
Como se comentó anteriormente, esta función indica si el objetivo es vulnerable o no. Para la implementación en este módulo se utiliza el método
http_fingerprint, el cual devuelve el
banner de
Kolibri. Después hay que realizar la comparación, por ejemplo mediante el uso de una expresión regular, para verificar que el servidor remoto coincide con la versión de
Kolibri vulnerable.
|
Figura 5: Implementación de la función check() |
Función exploit()
Esta función es la más compleja del módulo, aunque en este caso tenemos que hacer una migración del
exploit original escrito en
Python. Observando el
exploit de
Christian podemos ver que hay una parte de
33 A’s y
20 bytes con valor
‘\x90’. Si utilizamos una transcripción tal cual, almacenamos en una variable basura las
33 A’s y utilizando
make_nops generamos
20 nops almacenados en la variable
nops.
Ahora, en la variable
pay se almacena el
Payload encodeado. Este valor es introducido por el
pentester cuando ejecuta la instrucción
set PAYLOAD [ruta payload], por ejemplo
set PAYLOAD windows/meterpreter/reverse_tcp.
En el código se puede ver dos
puts a modo de
debbuging, ya que deberíamos utilizar funciones como
print_status, print_good o
print_error. Estos
puts nos muestran la longitud de
nops y del
payload, ya que éste último es de longitud variable, ya que podemos optar por una
meterpreter, una
shell o la ejecución de una calculadora.
Luego toca rellenar la parte denominada
junk. Aquí introduciremos
C’s hasta llegar al
byte 515. Para saber cuántas
C’s debemos introducir se resta a la suma de
nops y el tamaño variable del
payload. El valor que sobreescribirá el
EIP está almacenado cuando se lanzó la función
initialize, por lo que para recuperarlo debemos utilizar
target.ret.
|
Figura 6: Implementación de la función exploit |
La instrucción
[target.ret].pack(‘V’) recupera el valor, que es la dirección de memoria a la que el
EIP apuntará y realizará el salto, y lo añade en la posición adecuada. Esto es muy importante, podríamos colocar el valor en
Little Endian, es decir
ret = ‘\x63\x46\x92\7c’.
Ruby nos pone las cosas fáciles y con
pack podemos indicarle que la dirección de memoria va en
Little Endian, pero el programador la escribe tal cual, en este caso, y como puede verse en el código
0x7c924663.
Una vez configurados los trozos parciales, utilizamos la variable
sploit para concatenar las diversas partes en el orden adecuado. Por último, se utiliza la función
send_request_cgi para enviar la petición con el código malicioso. En este caso, el
stack buffer overflow se encontraba en el envío de la
URI. Se lanza un
GET a la raíz y se le concatena la variable
sploit y después se concatena el típico
“HTTP/1.1\r\n” que nos indica la versión del protocolo.
PoC: Probando el módulo exploit en Metasploit
Tras
añadir el módulo al framework, lo cargamos mediante el uso del comando use. Una vez el módulo está cargado configuramos los siguientes atributos:
• RHOST, indicándole la dirección dónde se encuentra el software vulnerable.
• RPORT, indicándole el puerto dónde se encuentra Kolibri a la escucha, por defecto el 8080.
• PAYLOAD, el que queramos que se ejecute una vez realizada la explotación.
• Si el payload es de tipo reverse, tenemos que configurar el atributo LHOST para indicar al payload dónde debe devolver el control.
En este momento ya tenemos la sesión, y vemos que tenemos el control de la máquina gracias a esta vulnerabilidad y la migración del
exploit. Se puede observar los valores de los
nops, del
payload y de
junk en el propio cuerpo del módulo. Ahora vamos a cambiar el payload por uno
“de juguete”.
|
Figura 7: PoC de explotación del módulo exploit |
El
payload que vamos a utilizar es el de
windows/messagebox, dónde podemos indicarle qué texto y qué tipo de
message box de
Windows vamos a sacarle al usuario por pantalla. Para ello ejecutamos
set PAYLOAD windows/messagebox, y os recomiendo que miréis las opciones de este
payload. El resultado es el que se puede ver, en la máquina dónde se ejecuta
Kolibri, tras explotar la vulnerabilidad podemos encontrar un
“Hello, from MSF!”.
|
Figura 8: Resultado tras explotar el módulo en un servidor Kolibri vulnerable |
En la tercera edición del
libro de Metasploit para Pentesters podéis encontrar información sobre cómo realizar módulos de tipo
exploit,
auxiliary,
creación de scripts de Meterpreter, etcétera. Por otro lado, el día 1 de Julio, a través de
Criptored, comienza el
Curso Online de Especialización en Seguridad Informática para la Intrusión de Sistemas. Metasploit en Profundidad, en el que inscribiéndote recibirás el
libro de Metasploit para Pentesters.
Autor: Pablo González Pérez (@pablogonzalezpe)
Escritor de los libros "Metasploit para Pentesters" y "Ethical Hacking"