 |
| 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 register_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.
Fuente