Alters

Aventuras de DoHITB: parte III

Buenas!

Empezamos la parte III de mi curioso relato. Hoy con energías renovadas!

Antes de empezar, me gustaría hacer un pequeño inciso... han contactado conmigo desde una de las editoriales donde envié uno de mis libros, ¡y me han dicho que les intereso! Espero que esto sea el comienzo de algo bueno...

En fin, iré informando :-P

Sigamos con el blog... jejeje

Como comentaba en la entrada anterior, voy a explicar cómo hice para agrandar el efecto de la brecha.

Supongo que pensaréis que una brecha que consiste nada más que en un poco de SPAM no es demasiada cosa... pero, ¿Qué pasa si indagamos un poco más?

Vamos allá.

Primero, hice lo que creí correcto, así que intenté contactar con el webmaster para avisarle de la brecha... y no me dijo nada. Así que decidí investigar un poco más por puro placer...

Así, me dirijo a la página de inicio de sesión, y abro el explorador de elementos (F12 en Chrome).

Voy a ver qué hace el botón "submit" del formulario de inicio de sesión...

onclick="return check();"

Ajá! hace una pequeña comprobación mediante JS. Busco la función en el archivo externo, y veo que hace una llamada AJAX para recuperar ciertos datos. Concretamente llama a un archivo llamado "acciones.php", al que envía, como si fuera una línea de comandos, varios parámetros; concretamente "accion=login&u=email&p=pass".

Así, modifico un poco mi VB.net para desviar la llamada HTML. Ahora llamaré a "acciones.php" con algunos datos de prueba. Dejo una pequeña referencia de lo que hice:

  • accion=login;u=mi email;p=mi pass
    • Retorno HTML: "correcto"
  • accion=asdf
    • Retorno HTML: "error"
  • accion=login;u=mi email;p=""
    • Retorno HTML: "falta pass"
  • accion=login;u=mi email;p=otro pass
    • Retorno HTML: "mal pass"
Es decir, este archivo "acciones.php" manda un código "estándar" de respuesta para cada posible acción. Traducido en PHP, y partiendo de las investigaciones que hice, podría tener esta estructura:

if($_GET['accion'] == 'login'){
  if(isset($_GET['u']) && isset($_GET['p'])){
    //select para comprobar el email
    if(**email está bien**){
      //select para comprobar el pass
      if(**pass está bien**){
        return "correcto";
      }else{
        return "mal pass";
      }
    }else{
      return "mal email";
    }
  }else{
     if(isset($_GET['u']){return "falta pass";}
     else{return "falta email";}
  }
}else{
  return "error";
}

En este caso en particular veo un error que es "de manual".

NUNCA DEBES DECIR SI LO QUE ESTÁ MAL ES EL EMAIL O EL PASSWORD.

¿Porqué?

Fácil. Imaginad que no conozco ninguno de los dos datos; puedo ir probando emails hasta que me diga que el email está bien pero no el password. Siempre se tiene que decir algo genérico, para evitar estas cosas...

Pero bueno, en este caso no importa mucho, ya que yo se que mi email sirve.

En este caso, yo se que el password lo asigna la propia web, y que además tiene 4 caracteres de longiutd.

Aquí veo otro fallo... 4 caracteres de longitud es bastante poco. Deberían ser 6 caracteres mínimo, incluyendo símbolos.

Y a todo esto... ¿Cómo combinar la vulnerabilidad anterior?

Sencillo: se puede usar la primera herramienta para hacer SPAM masivo a todas las publicaciones, y así conseguir emails válidos, con los que usaremos nuestro conocimiento...



Pues, vamos a hacer algo sencillo: fuerza bruta.

Creo un archivo con todas las posibilidades de 4 caracteres (14.773.663 entradas). Éste lo parto en 160 archivos llamados CC_X (x es un contador, de 0 a 159). Esto ya veremos de que sirve.

Así, vamos a ver qué hara nuestro programa de fuerza bruta:

  • Obtiene una clave del archivo
  • Llama a acciones.php?accion=login&u=email&p=clave
  • Si sale bien sabemos qué HTML retornará. Paramos la ejecución
  • Sino, siguiente código.
¿Y repetir esto casi 15 millones de veces? Bueno, para eso usaremos los Threads de JAVA.
Crearemos 160 hilos paralelos (un por cada archivo), y cada uno hará este proceso de manera paralela. Por lo que podemos aprovechar más el rendimiento de nuestro PC.

Bien, de momento dejamos la entrada en suspense (para el código JAVA). En la próxima entrada veremos:

 - Cómo hacer los Thread
 - Cómo hacer peticiones HTTP desde JAVA
 - Cómo manejar los errores HTTP

Como veis, hay errores HTTP (lanzar 160 peticiones simultáneas tiene su cosa). Esto quiere decir que a veces la petición HTTP fallará, por lo que tenemos que tener algún sistema que vaya comprobando todo.

A modo de información, dejaré unas estadísticas:

Cuando acabé el proyecto JAVA, dejé el programa 2 horas mientras salí a pasear, y al volver me encontré lo siguiente:

  • Peticiones lanzadas correctamente: 72.489
  • Peticiones falladas: 29.473
  • Tiempo: 120 minutos
  • Total peticiones: 101.962
  • Porcentaje de acierto: 71,1%
  • Peticiones/segundo: 14.16 peticiones/segundo
  • Tiempo estimado para recorrer los 14773663 registros: 12 días

Bien, como comprenderéis es un tiempo largo... pero el aspecto "aleatorio" de acceder a 160 registros de claves diferentes aumenta la probabilidad de encontrar la clave antes de finalizar todos los ficheros, con lo que dificilmente tardaría 12 días.

De todas maneras, si tenéis una contraseña de 4 dígitos y alguien quiere vuestra contraseña... será cuestión de tiempo que os la pillen... si es algo "importante", 12 días es tiempo que se puede esperar.

Con esta reflexión espero que algunos piensen en las contraseñas que usan en su vida cotidiana....

Saludos, y

¡Hasta la próxima!