not crypto
4 minutos de lectura
This is the not crypto flag which is totaly not crypto, but crypto! Can we get a clap from the team for excessive crypto usage?
Se nos proporciona el siguiente script en Python:
import base64
input_string = "REMOVED"
def secret(raw_string):
result = []
for char in raw_string:
if 'a' <= char <= 'z':
offset = ord('a')
result.append(chr(((ord(char) - offset + 13) % 26) + offset))
elif 'A' <= char <= 'Z':
offset = ord('A')
result.append(chr(((ord(char) - offset + 13) % 26) + offset))
else:
result.append(char)
return ''.join(result)
encoded_bytes = base64.b64encode(input_string.encode("utf-8"))
encoded = encoded_bytes.decode("utf-8").lower()
print(secret(encoded))
# ehagd3gzmjrmajvkamx5mql4zqdmmgewa2z5a2iymqx2zjdmz2h2lwyuzjmubtzjbqwvbqowbgpkbgxmazv5mgmwagavsd==
La salida del script es el comentario en la parte inferior.
Análisis del código fuente
Básicamente, el script toma la flag, la codifica en Base64, transforma el resultado en minúsculas y luego aplica la función secret
, que es simplemente ROT13.
Solución
Para resolver esto, primero podemos aplicar ROT13 para decodificarlo (la codificación y decodificación de ROT13 es la misma), y luego obtenemos una cadena Base64 en minúsculas:
runtq3tmzweznwixnzk5zdy4mdqzztrjn2m5n2vlzdk2mwqzm2u2yjlhmwzhogmwodjiodbjotcxotkznmi5ztzjntnifq==
Ahora, todo lo que debemos hacer es averiguar qué letras deben estar mayúsculas y cuáles deben ser minúsculas.
Codificación Base64
Base64 es solo una forma de representar un número, como la base 10 (decimal), base 16 (hexadecimal), base 2 (binaria), base 256 (ASCII), base 8 (octal)…
Para codificar (manualmente) una cadena en Base64, debemos codificar la cadena en binario y luego asignar cada fragmento de 6 bits a su símbolo correspondiente (A
a Z
, a
a z
, 0
a 9
, +
y /
). Un poco de relleno extra (=
) se requiere al final en caso de que la longitud de la cadena binaria no sea divisible entre 6.
Una forma de abordar este reto es decodificar en Base64 la cadena en minúsculas, y lo mismo con la cadena en mayúsculas:
r u n t q 3 t m z w e z ...
10101110 11101001 11101101 10101011 01111011 01100110 11001111 00000111 10110011 ...
R U N T Q 3 T M Z W E Z ...
01000101 01000011 01010011 01000011 01110100 11001100 01100101 01100001 00011001 ...
Las cadenas en binario están separadas en trozos de 8 bits, para que podamos identificar bytes válidos que puedan estar presentes en la flag, y cada símbolo de Base64 se coloca en el comienzo de cada trozo de 6 bits.
Dado que los caracteres de la flag son todos imprimibles, sabemos que la parte más significativa de cada trozo de 8 bits es 0
, por lo que podemos eliminar algunas posibilidades:
- - - t - 3 t m - w - z ...
-------- -------- --101101 ------11 01111011 01100110 ------11 0000---- --110011 ...
R U N T Q 3 - M Z W E Z ...
01000101 01000011 01010011 01000011 0111---- --001100 01100101 01100001 00011001 ...
Podemos eliminar un poco más sabiendo que los bytes ASCII imprimibles están entre 0x20
y 0x7e
:
- - - t - - t m - - - z ...
-------- -------- --101101 -------- ----1011 01100110 -------- -------- --110011 ...
R U N T Q 3 - M Z W E - ...
01000101 01000011 01010011 01000011 0111---- --001100 01100101 01100001 00------ ...
Si agregamos los caracteres que corresponden a cada trozo de 8 bits, tenemos esto:
- - - t - - t m - - - z ...
-------- -------- --101101 -------- ----1011 01100110 -------- -------- --110011 ...
R U N T Q 3 - M Z W E - ...
01000101 01000011 01010011 01000011 0111---- --001100 01100101 01100001 00------ ...
E C m/S C { f/L e a 3
Después de hacer más trozos manualmente, podemos suponer que el contenido de la flag son todos dígitos hexadecimales en minúsculas, por lo que tenemos:
- - - - - - t m - - - z ...
-------- -------- -------- -------- ----1011 01100110 -------- -------- --110011 ...
R U N T Q 3 - - Z W E - ...
01000101 01000011 01010011 01000011 0111---- -------- 01100101 01100001 00------ ...
E C S C { f e a 3
Durante la competencia, resolví este reto manualmente. Ahora que tengo más tiempo, implementé un algoritmo para encontrar la flag.
La idea es tomar trozos de 4 símbolos Base64 ($4 \cdot 6 = 24$ bits) y decodificarlos en Base64, dando como resultado $24 / 8 = 3$ bytes. Para cada fragmento, consideraremos todas las posibilidades de mayúsculas/minúsculas ($2^4 = 16$) y cogemos aquellas que se decodifican como caracteres ASCII imprimibles (en realidad, dígitos hexadecimales en minúsculas o ECSC{}
). Una vez que tenemos todos los trozos posibles, los unimos y los decodificamos en Base64.
Flag
El script solo devuelve una única posibilidad:
$ python3 solve.py
ECSC{fea35b1799d68043e4c7c97eed961d33e6b9a1fa8c082b80c9719936b9e6c53b}
El script completo se puede encontrar aquí: solve.py
.