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.
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.
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.
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.
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.
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.
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:
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!”.
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"
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.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”.
• 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.
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"
https://github.com/pablogonzalezpe/metasploit-framework/blob/master/modules/exploits/windows/http/kolibri_overflow_GET_2.0.rb :)
ResponderEliminarInteresante. Justamente este ejemplo se da en el training de CORELAN exploiting.
ResponderEliminarEn el training no utilizan mona para hacer el módulo?
ResponderEliminarLa vulnerabilidad que utilizan en el training creo que es el cve-2010-5301
https://www.exploit-db.com/exploits/15834/
Muy interesante Pablo, felicidades por el artículo.
ResponderEliminarNo obstante, ¿de qué sirve esto? Quiero decir, si ya tienes el exploit, para que te vas a parar a migrarlo a metasploit si lo puedes correr con python?
Gracias,
Saludos.
@Anónimo3, sencillamente lo hice por varias cosas: por trastear la primera, y la segunda por la misma razón que los de Rapid7 migran otros exploits a su framework. Al final es interesante tener el mayor número de exploits bajo el mismo paraguas. Imagina un autopwn sobre tus exploits y los del framework, más posibilidades y todo centralizado... pero es una buena pregunta ;)
ResponderEliminarun saludo!
Muuuy interesante y bien explicado.
ResponderEliminar