La vulnerabilidad
ShellShock ha traído un nuevo caos a
Internet, miles de servidores se ven comprometidos por esta vulnerabilidad, la cual dispone de diversos
CVE. Si echamos un ojo por
Internet podemos observar como la vulnerabilidad ha sido explotada en diversos entornos, para
explotar servidores web y meter shels, a través
de VMWare Fusion en los OS X de Apple, o para
distribuir malware como Kaiten.
 |
Figura 1: Crea tu módulo de Metasploit para Shellshock |
En el congreso de seguridad informática
Navaja Negra, celebrado en
Albacete, yo quería que la gente que asistía al
workshop de Metasploit pudiera entender y ver como se corresponden los módulos que ellos pueden configurar con el código que podemos desarrollar. Para esto quise tomar como base la vulnerabilidad, con el primer
CVE, de
ShellShock.
Mi idea fue desarrollar un módulo en vivo para explotar dicha vulnerabilidad, ya que era realmente sencillo realizarlo, y los asistentes podrían fácilmente guiarse, tal y como se pudo ver en el artículo de
RetroMalware para controlar NetBus desde Metasploit. Es cierto que la gente de
Rapid7 ya tiene sus módulos sobre esta vulnerabilidad realizada, pero mi idea era hacerlo un poco más sencillo para que cualquiera de los asistentes con nociones cero de
Ruby pudieran seguirlo.
 |
Figura 2: Cosas básicas para hacer un módulo de tipo exploit remoto |
¿Qué necesitamos para llevar a cabo el módulo? En la imagen se puede ver que al menos la función de inicialización y la función exploit son necesarias. El objetivo de estos módulos son las de conseguir una sesión para controlar el equipo o realizar alguna acción sobre él, tras aprovechar una vulnerabilidad. Opcionalmente, podemos definir la función
check, con la que podemos chequear que una vulnerabilidad existe en la máquina remota, siempre y cuando el módulo no sea
client-side, ya que en este escenario no tiene sentido realizar un chequeo.
La función: initialize(info={})
Esta función permite inicializar valores al módulo y actualizar información que es heredada por el propio
framework. Podemos entender que la información de ayuda e informativa que debemos proporcionar en los módulos de
Metasploit debemos configurarla en esta función. Por ejemplo, cuando nosotros ejecutamos el comando info la información proporcionada por la consola se corresponde con el atributo description que previamente hemos definido, o la información sobre el autor, las referencias a los
CVE, etcétera.
A continuación se presenta el código, cuya descripción corresponde con la del módulo de
Rapid7. Simplemente es importante ver que en esta parte del código son datos a rellenar, y que estos datos son informativos. Hay que recordar que la función de inicialización puede tener más instrucciones relevantes, como veremos después.
 |
Figura 3: Función de inicialización |
Hasta aquí, no hemos tocado nada. Existe un método denominado r
egister_options con el que podemos modificar los atributos configurables que tendrá mi módulo. Recordemos que por ser un módulo de tipo
exploit remoto se heredan atributos propios del módulo, como por ejemplo
RHOST, pero en muchas ocasiones nosotros querremos añadir atributos configurables para que un usuario pueda realizar otro tipo de acciones con esos parámetros.
Nosotros queremos varias cosas en nuestro módulo:
- El usuario pueda indicar cuál es la URI. Al atributo lo llamaremos TARGETURI.
- Que el usuario pueda seleccionar el método HTTP a utilizar (GET | POST). El atributo se llama METHOD.
- Que el usuario pueda indicar al exploit el path remoto que debe utilizar mediante el atributo RPATH.
- El usuario puede indicar el comando que quiere lanzar mediante el atributo COMMAND.
- Mediante la configuración del atributo TIMEOUT se indica el número de segundos para obtener respuesta de una petición HTTP.
- El atributo FULL es algo especial. Lo que queremos hacer es que si el parámetro FULL vale false, el módulo se comporte como una consola remota en la cual sólo se ejecutará la orden que se introduzca en COMMAND. Pero si el atributo FULL vale true, el módulo estará programado para lanzar una secuencia de acciones sobre el servidor remoto con el que se conseguirá subir una shellcode y obtendremos el control remoto de la máquina.
- El atributo NAMESHELLBIN será utilizado en caso de que FULL sea true, y proporciona el nombre que utilizaremos para crear el binario en la máquina remota.
 |
Figura 4: Opciones nuevas en el módulo |
En la imagen podemos ver que cada atributo aparte del nombre tiene una serie de información extra introducida en un listado. El primer campo
true o
false indica si el atributo será requerido para ejecutar el módulo o no. Cuando se ejecuta un
show options vemos una columna denominada
required, dónde los atributos tienen valor
yes o
no. El segundo campo del listado es la descripción del atributo, mientras que el tercero es el valor por defecto que tiene ese parámetro.
 |
Figura 5: Atributos del módulo visto con show options |
La función: request(command)
Antes de empezar a destripar las funciones
check y
exploit vamos a necesitar una función request para agilizar y no repetir código en el envío de peticiones. Esta función será utilizada para
explotar la vulnerabilidad de ShellShock en su versión para Apache mod_cgi.
La función tiene una implementación básica, utiliza el método
send_request_cgi para enviar la petición
HTTP. Se le pasa un parámetro a la función que es el comando que se quiere ejecutar en remoto, si la vulnerabilidad está presente en el servidor remoto. A continuación se muestra el código sencillo de la función.
 |
Figura 6: Código de request |
El atributo
TARGETURI,
METHOD y
TIMEOUT, explicados anteriormente, son utilizados para la generación del paquete.
La función: check()
La función check permitirá comprobar si el servidor remoto es vulnerable sin necesidad de dañar o aprovecharse del sistema remoto. Es cierto que
check lo que está realizando es una ejecución de comandos remota, pero lo que ejecutaremos será un simple
echo hola, que intentaremos ver reflejado en el
body de la respuesta.
 |
Figura 7: Código de check |
Como puede verse en la función se llama a request con el comando
echo hola. Si la respuesta incluye hola en el cuerpo es vulnerable. Tenemos que tener cuidado, porque si, lógicamente, la respuesta incluyera el texto “
hola” porque la web tuviera dicha palabra nos aparecería como vulnerable. Lo ideal sería generar un
hash o un texto que fuera “
imposible” encontrar en la respuesta.
La función: exploit()
Esta función la tenemos pensada para dos cosas en esta prueba de concepto. La primera es que nos permita ejecutar comandos, por así decirlo línea a línea o petición a petición con el servidor. El segundo modo de funcionamiento se tiene pensado para que automáticamente genere las peticiones necesarias realizando lo siguiente:
1. Generar una shellcode, que definirá el usuario en el atributo PAYLOAD antes de lanzar el módulo, es decir, antes de lanzar el método exploit.
2. Esta shellcode se transforma a base64 con la intención de poder “pegarla” con un echo en un archivo del servidor remoto. La instrucción a ejecutar en remoto sería algo tal que así echo shellcode_en_base_64 > /var/tmp/fichero_almacena_shellcode_base64.
3. Una vez se dispone de la shellcode en un fichero en base64 se realiza su transformación a binario y se le cambia los permisos para que el nuevo binario pueda ejecutar.
4. Por último, se realiza una petición para ejecutar ese binario, el cual lanzará la shellcode. En función del tipo de shellcode se realizará unas acciones u otras. Automáticamente el módulo de Metasploit nos lanzará por debajo el handler con el que podremos gestionar de forma trasparente las conexiones con las shellcode.
 |
Figura 8: Generación, subida y ejecución de Shellcode, Toma de control |
En el código se puede ver como se genera el
payload mediante la instrucción
payload.encoded_exe. Este payload se codifica en
base64 almacenándolo en la variable
enc. Es importante realizar el cambio de los
“\n” en el
base64 para que la
shellcode no se rompa.
Después podemos observar las 4 peticiones que se realizan con lo comentado anteriormente. Una vez se termina la cuarta petición la
shellcode se genera y se obtiene el control remoto de la máquina, si el payload seleccionado es para tomar el control, por ejemplo un
meterpreter.
Configuración y ejecución
Ahora vamos a probar el módulo programado, cuyo
código se puede encontrar en mi github. La configuración para probar el código en modo
FULL a true, será el siguiente:
- FULL = true.
- NAMESHELLBIN = poc.
- RHOST = dirección IP servidor remoto, en este caso 192.168.56.102.
- TARGETURI = URI remota, en este caso /cgi-bin/vuln.cgi.
- PAYLOAD = linux/x86/meterpreter/reverse_tcp.
- LHOST = dirección IP máquina del atacante.
Tras lanzar el módulo con la configuración podemos obtener el control remoto de la máquina, tal y como se puede ver en la imagen.
 |
Figura 9: Configuración y obtención del control remoto a través de ShellShock |
Si elegimos la opción
FULL = false, realmente podemos seleccionar en
COMMAND que binario lanzar, y con
RPATH cuál es la ruta remota dónde se encuentra. En el taller de
Navaja Negra lo estuvimos viendo, y con las prisas las cosas no quedaron del todo claras, por eso decidí hacer este post.
Autor: Pablo González Pérez (@pablogonzalezpe)
Escritor del libro "Metasploit para Pentesters" 3ª Ed.