domingo, octubre 05, 2008

2 puntos más

El año se acaba y queda sólo un Reto Hacking, será el último, para aclarar la clasificación final aunque parece que “The Doctor” Kachakil tiene ya matemáticamente su segundo título (además de un badge de la Defcon, un libro, ene camisetas, un par de tiras de No Lusers, unos dvds, etc… que entregaré el martes en el evento de Valencia), pero…. Aunque matemáticamente tenga asegurada la primera posición, queda el orgullo de ver quién gana el Reto Hacking X y un par de mini-retos… y aquí va el primero.

En una página web de un sitio de matemáticos encontré este sistema de acceso a la zona privada. Al verlo me trajo viejos recuerdos, pues es igual que el nivel 3 del concurso de Boinas Negras. La idea es sencilla, para llegar a la página privada se usa la contraseña, esto quiere decir que o la contraseña es directamente el nombre de la página o el nombre de la página se calcula derivando la password. Esto se usa para que si se introduce una password que no es, el sistema no intente navegar a una página inexistente, obteniéndose el poco amigable 404.

Para solucionar esto… bueno, para muestra os dejo cómo nuestro amigo RoMaNSoFt lo solucionó en Bonias Negras: Solucionario Boinas Negras por RoMaNSoFt.

Y ahí va el código:

<SCRIPT LANGUAGE="Javascript">
var alfabeto= "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHI"
var cod1 = "140638";
var cod2 = "JUUESVU";

function decodificar(formulario) {
passcod = codificarC(formulario.password.value,3);
if (passcod == cod1) {
aux = "" + codificarC(formulario.password.value,10)
pagina = decodificarP(cod2, aux);
location.href = pagina + ".php";
}
else
alert("Contraseña Incorrecta");
}

function codificarC(passw,num) {
var codigo = 0;
texto = passw.toUpperCase();
for (i=0; i<texto.length; i++) {
letra = texto.substring(i,i+1);
c = alfabeto.indexOf(letra,0) + 1;
codigo = codigo * num + c;
}
return codigo;
}

function decodificarP(pagina,num) {
var result="";
for (i=0;i<pagina.length;i++) {
letra=pagina.substring(i,i+1).toUpperCase();
a=alfabeto.indexOf(letra,0);
a-=(num.substring(i,i+1)*1);
if (a<0) a+=26;
result += alfabeto.substring(a,a+1).toLowerCase();
}
return result;
}
</SCRIPT>

<FORM NAME="decodificator" onSubmit="decodificar(this); return false;">
Contraseña: <INPUT TYPE="password" NAME="password">
<INPUT TYPE="submit" VALUE="Enviar">
</FORM>



          
Todos los que me envíen la solución antes del viernes que viene obtendrán 2 puntos extras y un pequeño premio que, según los que sean será un libro, un reloj, una camiseta, una chapa de Spectra o un beso en los morros.

Saludos Malignos!

23 comentarios:

  1. Con dedicarle unos 10 minutos, extraigo las siguientes conclusiones:

    - Hay muchísimas passwords que hacen cumplir la primera condición de la función "decodificar" (ej: iyxzzzzky)
    - Se requiere un mínimo de 9 letras en el password para que cod1 alcance la cifra de 140638, así que a priori descartaría un ataque por fuerza bruta. Si acaso, probaría con un ataque de diccionario, pero eso no garantizaría nada.
    - El nombre del fichero .php es de solo 7 letras. Puestos a lanzar un ataque, a lo mejor acabaríamos antes si lo hacemos contra el nombre del fichero del servidor...
    - Con ese planteamiento, no tenemos forma de comprobar si un password es válido (y probablemente tú tampoco) ;-)

    Vamos, que no le veo la gracia al minireto este.

    Saludos!

    ResponderEliminar
  2. Dani con 2 condiciones si se puede saber si es el correcto aunque haya muchos que cumplan la primera condición, pero como dices mínimo 9 caracteres, por lo que o quiere que lo ataquemos con diccionario(lo más probable) o por fuerza bruta en otro lenguaje que no sea javascript, cosa que del viernes se pasa jeje.

    Si nos chivas 2 o 3 letras cualquiera y su posición, mejor que mejor jeje, que de momento solo tengo el código con fuerza bruta y en js...jeje

    Funciona porque no es la primera vez que hago este reto, en yashira.org lo tuve que hacer.

    ResponderEliminar
  3. Bueno yo ya tengo 9 passwords que funcionan pero me falta lo más importante... a dónde tengo que mandar la solución?

    ResponderEliminar
  4. @trancek: Precisamente por eso, porque en realidad no hay dos condiciones en ese código. En todo caso ahí hay solamente una (la otra está en el servidor, el nombre del fichero PHP, que es lo que nos falta para resolver el reto con certeza).

    ¿Quién dice que la contraseña no pueda ser la que yo he puesto en el ejemplo anterior (iyxzzzzky) y que la página secreta se llame "itnyknm.php"? ¿Simplemente porque no es léxicamente bonita?

    Sin la segunda parte, nadie puede asegurar al 100% que haya encontrado LA solución. ¿Me equivoco?

    ResponderEliminar
  5. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  6. Si pero el nombre del fichero se obtiene de aqui:
    ---------
    pagina = decodificarP(cod2, aux);
    location.href = pagina + ".php";
    ---------
    var cod2 = "JUUESVU";
    ---------

    Yo tengo un codigo que poniendo como condicion que codifique "txt", siendo "txt" los password que va probando por fuerza bruta, sea igual a 140638 y que "pagina" sea igual a "txt" con lo de decodificarP y todo ese royo.

    Por lo que ya hay 2 condiciones, y me funciona bien. No se si me entiendes bien que explicandome...jeje

    Mira el ejemplo este a ver si aqui lo dejo mas claro:
    aad(pass) = 16(codificado)
    aleas(pagina) = BMIAS(pág. cod)
    --
    aba(pass) = 16(codificado)
    aleas(pagina) = BNFAS(pág. cod)


    Lo edite que habia puesto aad en los 2

    ResponderEliminar
  7. @trancek: Sin el servidor devolviendo un 404 o la página privada, creo que estamos en las mismas.

    Te lo planteo de otra forma... ¿Puedes refutar que esta sea una solución perfectamente válida?

    PASSWORD = iyxzzzzky
    PÁGINA --> itnyknm.php

    ResponderEliminar
  8. Trancec: no siempre da la misma página con distintos códigos. Por ejemplo con IYYZTUKVS y IYYZTUKWP dan ambos itnxkts como página pero son distintos a la página que da con el pass de kachakil, por lo tanto o está mal hecho el planteamiento o hay algo más.

    Saludos

    ResponderEliminar
  9. vale si perdon, jeje eso me pasa por probarlos con otros mas pequeños, pues a esperar a que el chema venga y diga porque elijio ese, pero al igual que en el md5 hay colisiones, pues en un algoritmo asi mas debil tambien pasan estas cosas, solo que aqui es mas facil encontrar coincidencias.
    Digo yo que a lo mejor hay que sacar todas las posibles o la mas logica, pero si un problema lo de este reto.

    ResponderEliminar
  10. @No, no lo elegí yo, es una web real, y sí, hay colisones, como en el reto de Boinas Negras...

    ResponderEliminar
  11. ...así que deberíais enviar una forma de probar todas para sacar los 2 puntitos...

    ResponderEliminar
  12. @Maligno: ¿Así que al final nos pides un simple algoritmo de fuerza bruta? ¡Haber empezado por ahí! ;-)

    Lo único que tengo claro es que la contraseña tiene entre 9 y 11 caracteres (ej: aaaxaavaava --> itrarss.php). Por lo demás, para mí que el código del JS no ayuda a reducir el orden o grado de complejidad del algoritmo necesario.

    Si no me equivoco, dicho algoritmo requerirá billones de pruebas (del orden de 26^11) únicamente para acotar la lista de contraseñas probables, que luego habría que probar online para ver cuál es la correcta, por lo que sigo sin verle la gracia al minireto.

    ¡Suerte para aquellos que lo estéis intentando!

    Saludos

    ResponderEliminar
  13. Efectivamente Dani, esta mañana hice el algoritmo, pero dudo que nunca nadie quiera ejecutarlo... yo no lo haría :P

    Además, el algoritmo es muy feo...

    ResponderEliminar
  14. Dani Kachakil for president.

    Lo primero sería obtener todos los posibles passwords y esos van a ser muchos muchos.

    A ver si alguien consigue decir cuantos exactamente :D

    ResponderEliminar
  15. totalmente offtopic con el tema del post, pero... la entrada al evento en valencia será gratuita?

    ResponderEliminar
  16. @Dani, te he enviado un mail en privado.

    @anónimo, sí, la entrada será gratis.

    Saludos!

    ResponderEliminar
  17. Bueno Chema, yo ya te he enviado mi solución... sé que no será la óptima, pero a que queda bonito :)

    Saludos!

    ResponderEliminar
  18. Al final he picado el anzuelo y me ha dado por resolver el minireto. En realidad se puede hacer un algoritmo sin usar la fuerza bruta como tal, lo que obtiene resultados de forma muy eficiente. Aún así, con 9 letras me salen 33.048.964 de passwords posibles, las cuales se reducen a 393.259 páginas diferentes tras la segunda parte del proceso (que resulta acotar muchísimo más de lo que pensaba).

    Tengo calculadas todas las passwords posibles, incluso de 10 y 11 letras (en total ocupan más de 2 Gb en disco!!), pero aún no he sacado las URLs correspondientes, aunque ya tengo más de 600.000 (y con esa cifra sí que sería necesaria la fuerza bruta contra el servidor, para ver cual de ellas es la correcta).

    Bueno, ya os explicaré el planteamiento del algoritmo que he usado (a partir del viernes, en cuanto se dé por cerrado).

    Saludos!

    ResponderEliminar
  19. Yo al final hice el algoritmo porque vi que podía reducirse mucho la complejidad.

    Al final mi algoritmo saca 1.000.000 de passwords válidos cada 3 minutos y pico (en un ordena normalucho) pero vamos, paso de sacar las páginas "no-repetidas", eso ya es sólo cuestión de tiempo y paciencia...

    ¿"a cuanto va" el tuyo Dani?

    ResponderEliminar
  20. @tayoken: El mío sacó todas las passwords posibles en menos de 20 minutos (2m25 las de 9, 12m20 las de 10 y 3m40 las de 11). Y eso en una máquina bastante antigua y bajo el .NET Framework (por ejemplo, en C compilado a nativo se supone que debería ir bastante mejor). La verdad es que tampoco me he molestado en optimizarlo en absoluto, porque tal y como está ya va bastante bien y el código es muy sencillito.

    La parte de sacar las URLs es bastante más lenta, sobre todo por tener que hacer algunos cálculos más y por el tema de eliminar duplicados, pero aún así tampoco tarda mucho. De todas formas, por muy bueno que sea el algoritmo, siguen saliendo varios cientos de miles de URLs posibles que habría que lanzar contra el servidor. El hecho de estar en programado en JavaScript no siempre implica que sea tan mala protección, ¿verdad? ;-)

    Un saludo!

    ResponderEliminar
  21. Ups, perdón, me lié, dije 3 minutos, y eran 3 segundos... es que los muestro por pantalla y eso me reduce mucho el tiempo, de hecho la versión que he enviado a Chema es la pesada que muestra por pantalla :P pero el tiempo lo marca bien, 3 segundos en generar 1.000.000 de passwords de 9, 10 u 11 letras y mogollón de tiempo en rellenar el listbox :D

    Bueno, eso Chema, si tienes un especial interés en generar los passwords con mi programa (que lo dudo) cambia el listbox por un streamwriter... y listos, que sino te vas a morir esperando :S

    ResponderEliminar
  22. Donde dije "reduce" quería decir amplía :P

    ResponderEliminar
  23. Quería saber si habéis publicado las soluciones al Reto Hacking IX en algun sitio.

    Gracias y 1 saludo

    ResponderEliminar