Éste es el script comentado del nivel, línea a línea:
#!/bin/sed -rnuf
s/.*/Password:/; # sustituir la primera línea por Password:
p; #imprimir
n; # leer siguiente línea
s/[^a-zA-Z0-9]/_/g; # sustituir todo carácter no alfanumérico por _
s/./ /g; # añadir un espacio en blanco tras cada carácter
s/[0-9] /0 /g; # añadir un prefijo de 0 a todos los dígitos
s/[a-p] /1 /g; # añadir un prefijo de 1 a todas las letras entre a y p
s/[q-z] /2 /g; # añadir un prefijo de 2 a todas las letras entre q y z
s/[A-P] /3 /g; # añadir un prefijo de 3 a todas las letras entre A y P
s/[Q-Z] /4 /g; # añadir un prefijo de 4 a todas las letras entre Q y Z
y/abcdefghijklmnopqrstuvwxyz/0123456789abcdef0123456789/; # replace cada carácter de la primera ristra por su equivalente de la segunda ristra
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/0123456789abcdef0123456789/; # sustituir a por b
s/_/50/g; # sustituir _ por 50
s/(.)(.) /21/g; # invertir: "XY " pasa a ser "YX "
x; # intercambiar buffer y pattern (buffer sólo contiene un salto de línea)
s/$/-----/g; # el salto de línea se cambia por 5 guiones
s/-/---/g; # ahora tenemos 3*5 = 15 guiones
s/-/----/g; # ahora tenemos 15*4 guiones
s/-/---/g; # ahora tenemos 15*4*3 guiones = 180 en total
x; # intercambiar buffer y pattern (guardamos los 180 guiones y recuperamos pattern)
:x; # label :x (es un destino de salto)
y/072b346d18a9f5ce/143c527e9ab0d6f8/; # replace cada carácter de la primera ristra por su equivalente de la segunda ristra
ta; # salta a a: si el último s/// tuvo éxito
:a; # label :a (es un destino de salto)
s/[^0x]/x /g; # si el carácter actual no es un 0 ni una x, sustituirlo por x0.
# P. ej. 051 quedaría como 0x5x1
y/fedcba987654321/edcba9876543210/; # find&replace
ta; # va a saltar a la etiqueta "a" si el anterior s/// tuvo éxito...
s/(x*)0(x*)0/12020/g; # sustituir xxxxx0xxxxxx0 por xxxxxxxxxxx0xxxxxxx0
s/x{16}//g; # eliminar apariciones de 16x seguidas
s/x{15}0/f/g; # sustituir 15x0 (xxxxxxxxxxxxxxx0) por f
s/x{14}0/e/g; # sustituir 14x0 por e
s/x{13}0/d/g; # sustituir 13x0 por d
s/x{12}0/c/g; # sustituir 12x0 por c
s/x{11}0/b/g; # sustituir 11x0 por b
s/x{10}0/a/g; # sustituir 10x0 por a
s/x{9}0/9/g; # sustituir 9x0 por 9
s/x{8}0/8/g; # sustituir 8x0 por 8
s/x{7}0/7/g; # sustituir 7x0 por 7
s/x{6}0/6/g; # sustituir 6x0 por 6
s/x{5}0/5/g; # sustituir 5x0 por 5
s/x{4}0/4/g; # sustituir 4x0 por 4
s/x{3}0/3/g; # sustituir 3x0 por 3
s/x{2}0/2/g; # sustituir 2x0 por 2
s/x{1}0/1/g; # sustituir 1x0 por 1
s/^(0)(.{3})(.*)/132/;
s/^(1)(.{8})(.*)/132/;
s/^(2)(.{7})(.*)/132/;
s/^(4)(.{2})(.*)/132/;
s/^(6)(.{10})(.*)/132/;
s/^(8)(.{9})(.*)/132/;
s/^(a)(.{11})(.*)/132/;
s/^(c)(.{5})(.*)/132/;
s/^(e)(.{16})(.*)/132/;
s/(...)(.*)/21/;
tz;
:z;
x;
s/-//;
x;
tx;
s/^017c43a81ddb8b638fb3a32c51f4$/Win!/;
Tf;
p;
q;
:f;
s/.*/You Fail It!/;
p;
q |
#!/bin/sed -rnuf
s/.*/Password:/; # sustituir la primera línea por Password:
p; #imprimir
n; # leer siguiente línea
s/[^a-zA-Z0-9]/_/g; # sustituir todo carácter no alfanumérico por _
s/./ /g; # añadir un espacio en blanco tras cada carácter
s/[0-9] /0 /g; # añadir un prefijo de 0 a todos los dígitos
s/[a-p] /1 /g; # añadir un prefijo de 1 a todas las letras entre a y p
s/[q-z] /2 /g; # añadir un prefijo de 2 a todas las letras entre q y z
s/[A-P] /3 /g; # añadir un prefijo de 3 a todas las letras entre A y P
s/[Q-Z] /4 /g; # añadir un prefijo de 4 a todas las letras entre Q y Z
y/abcdefghijklmnopqrstuvwxyz/0123456789abcdef0123456789/; # replace cada carácter de la primera ristra por su equivalente de la segunda ristra
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/0123456789abcdef0123456789/; # sustituir a por b
s/_/50/g; # sustituir _ por 50
s/(.)(.) /21/g; # invertir: "XY " pasa a ser "YX "
x; # intercambiar buffer y pattern (buffer sólo contiene un salto de línea)
s/$/-----/g; # el salto de línea se cambia por 5 guiones
s/-/---/g; # ahora tenemos 3*5 = 15 guiones
s/-/----/g; # ahora tenemos 15*4 guiones
s/-/---/g; # ahora tenemos 15*4*3 guiones = 180 en total
x; # intercambiar buffer y pattern (guardamos los 180 guiones y recuperamos pattern)
:x; # label :x (es un destino de salto)
y/072b346d18a9f5ce/143c527e9ab0d6f8/; # replace cada carácter de la primera ristra por su equivalente de la segunda ristra
ta; # salta a a: si el último s/// tuvo éxito
:a; # label :a (es un destino de salto)
s/[^0x]/x /g; # si el carácter actual no es un 0 ni una x, sustituirlo por x0.
# P. ej. 051 quedaría como 0x5x1
y/fedcba987654321/edcba9876543210/; # find&replace
ta; # va a saltar a la etiqueta "a" si el anterior s/// tuvo éxito...
s/(x*)0(x*)0/12020/g; # sustituir xxxxx0xxxxxx0 por xxxxxxxxxxx0xxxxxxx0
s/x{16}//g; # eliminar apariciones de 16x seguidas
s/x{15}0/f/g; # sustituir 15x0 (xxxxxxxxxxxxxxx0) por f
s/x{14}0/e/g; # sustituir 14x0 por e
s/x{13}0/d/g; # sustituir 13x0 por d
s/x{12}0/c/g; # sustituir 12x0 por c
s/x{11}0/b/g; # sustituir 11x0 por b
s/x{10}0/a/g; # sustituir 10x0 por a
s/x{9}0/9/g; # sustituir 9x0 por 9
s/x{8}0/8/g; # sustituir 8x0 por 8
s/x{7}0/7/g; # sustituir 7x0 por 7
s/x{6}0/6/g; # sustituir 6x0 por 6
s/x{5}0/5/g; # sustituir 5x0 por 5
s/x{4}0/4/g; # sustituir 4x0 por 4
s/x{3}0/3/g; # sustituir 3x0 por 3
s/x{2}0/2/g; # sustituir 2x0 por 2
s/x{1}0/1/g; # sustituir 1x0 por 1
s/^(0)(.{3})(.*)/132/;
s/^(1)(.{8})(.*)/132/;
s/^(2)(.{7})(.*)/132/;
s/^(4)(.{2})(.*)/132/;
s/^(6)(.{10})(.*)/132/;
s/^(8)(.{9})(.*)/132/;
s/^(a)(.{11})(.*)/132/;
s/^(c)(.{5})(.*)/132/;
s/^(e)(.{16})(.*)/132/;
s/(...)(.*)/21/;
tz;
:z;
x;
s/-//;
x;
tx;
s/^017c43a81ddb8b638fb3a32c51f4$/Win!/;
Tf;
p;
q;
:f;
s/.*/You Fail It!/;
p;
q
En resumidas cuentas, le pasamos una entrada al script sed (de 2 líneas, la primera puede ser cualquier cosa, porque la va a sustituir por «Password:»), ciclamos 181 veces (una por cada guión y una inicial antes de llegar a la condición de salto) por una serie concreta de sustituciones y al finalizar, comprobamos que la cadena que nos queda después de tanta sustitución es, exactamente ésta: «017c43a81ddb8b638fb3a32c51f4». Si así fuera, escribimos (comando ‘p’ de sed) «Win» y salimos (comando ‘q’). Si no fuera así, saltamos a la etiqueta «f» (comando Tf, es decir, un salto condicionado a que la última sustitución no tuviera éxito). En la etiqueta f sustituimos todo por «You Fail It!», lo escribimos y terminamos.
Me han gustado dos cosas: el uso de etiquetas y saltos condicionales por un lado (desconocía este aspecto), y la forma de controlar la condición del bucle. En concreto, desconocía el uso del comando «x», que viene a decir: coge lo que tenemos en el buffer y pónlo en el cursor del patrón que estamos analizando (lo sustituye, es decir, la línea que estábamos analizando pasa al buffer):
x; # intercambiar buffer y pattern (buffer sólo contiene un salto de línea)
s/$/-----/g; # el salto de línea se cambia por 5 guiones |
x; # intercambiar buffer y pattern (buffer sólo contiene un salto de línea)
s/$/-----/g; # el salto de línea se cambia por 5 guiones
Inicialmente en el buffer sólo hay un fin de línea, así que tras hacer x y «s/$/—-/g», nos quedamos con una línea de 5 guiones. Como necesitamos 180, usamos este truco:
s/-/---/g; # ahora tenemos 3*5 = 15 guiones
s/-/----/g; # ahora tenemos 15*4 guiones
s/-/---/g; # ahora tenemos 15*4*3 guiones = 180 en total |
s/-/---/g; # ahora tenemos 3*5 = 15 guiones
s/-/----/g; # ahora tenemos 15*4 guiones
s/-/---/g; # ahora tenemos 15*4*3 guiones = 180 en total
Lo dicho, me gustó el planteamiento del problema. Pero claro, ¿cómo encontrar la cadena inicial que se usó para, tras todas las sustituciones indicadas, obtener «017c43a81ddb8b638fb3a32c51f4»? Bueno, invirtiendo el proceso de sustituciones. Se puede hacer con el propio sed, pero mis compañeros se curraron un script en VBA que resolvía al 95% (son magos del Excel…).
Con ese script conseguimos saber cómo debía estar formado el string de entrada correcto justo después de la instrucción «s/_/50/g;» . Si justo después de esa instrucción introducimos ésta otra:
s/(.*)/22 43 41 03 10 1c 23 04 12 24 1b 00 24 42 /;
y ejecutamos el script (recordad dadle permisos de ejecución al crackme):
$ echo -e "cualquier cosancualquier cosa" | ./crackme
Password:
Win! |
$ echo -e "cualquier cosancualquier cosa" | ./crackme
Password:
Win!
Ya sólo queda darle un poco a la pelota para saber cómo interpretar las primeras líneas del script sed para que nos salga ese string mágico. Es cuestión de pensar unos minutos y hacer un script rápido para probar algunas combinaciones (un 2 en el string «mágico» puede ser porque inicialmente tenías una ‘c’ o una ‘s’ en la entrada:
y/abcdefghijklmnopqrstuvwxyz/0123456789abcdef0123456789/; Cuando tengas más de una opción, prueba a escribirlas todas – con un script – y verás que una de ellas se lee fácil 😉
Al pasar esta prueba llegarás al level 7, donde tendrás que desempolvar tus conocimientos de la era Spectrum!