viernes, 30 de noviembre de 2018

Criptografía (CXV): Solución Reto Cybercamp "Redundancia innecesaria"

En este post la solución a uno de los retos de criptografía de Cybercamp 2018 Online.

Este reto tiene el título "Redundancia innecesaria" y mi valoración sobre su dificultad es: .

Su enunciado dice lo siguiente:


Nuestros expertos han capturado un pendrive que contenía estos dos ficheros, pero parece que uno de ellos ha sufrido daños... (Respuesta: flag{X})


Como recursos asociados al retnos dan los archivos key.pem y secret.txt.


El primero de ellos (key.pem) contiene una clave privada RSA, pero está dañada:

-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBAMSwf+/I42wFwNpDQiGuv0fb9w5Ria2JJAjzrYEYKp4HAKB8nXxmyGx6O
WAhI+4PYFYT3pf95J/mg5buCvP19fMCAwEAAQJAKuxRnyR57PL8eSVAY1VdTPNF4QwO
PZ62DHYRISEC++UtRemqE1eBPkRgswiJ91+r9y8EnVw/SvL4GYQmeovSsQIhAOq8Heinx
e4udriNOd35SgJV9e87YglCCIfCoAirR0qtAiEA1oIMcKaiRiUj2S/Q4YFTNySdT+fH16huoS
QrEapD9x8*********************************************************************
************************************************************************
-----END RSA PRIVATE KEY-----

Mientras que el segundo (secret.txt) parece ser un archivo cifrado mediante el algoritmo de cifrado asimétrico RSA.

Por el título del reto deduzco que la parte de la clave privada RSA que está dañada es redundante, es decir, puede obtenerse a partir de la parte que no está dañada y, por tanto, es posible reconstruir la clave original. Veamos qué podemos obtener.

Para ello, en primer lugar sustituimos todos los "*" de la clave que nos dan por "0", es decir:

-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBAMSwf+/I42wFwNpDQiGuv0fb9w5Ria2JJAjzrYEYKp4HAKB8nXxmyGx6O
WAhI+4PYFYT3pf95J/mg5buCvP19fMCAwEAAQJAKuxRnyR57PL8eSVAY1VdTPNF4QwO
PZ62DHYRISEC++UtRemqE1eBPkRgswiJ91+r9y8EnVw/SvL4GYQmeovSsQIhAOq8Heinx
e4udriNOd35SgJV9e87YglCCIfCoAirR0qtAiEA1oIMcKaiRiUj2S/Q4YFTNySdT+fH16huoS
QrEapD9x8000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
-----END RSA PRIVATE KEY-----

A este archivo lo llamo key_2.pem.

Antes que nada decir que el archivo PEM de clave privada RSA PKCS#1 comienza y termina con las etiquetas:

-----BEGIN RSA PRIVATE KEY-----
BASE64 ENCODED DATA
-----END RSA PRIVATE KEY-----

y que dentro de los datos codificados en base64 está presente la siguiente estructura:

RSAPrivateKey ::= SEQUENCE {
  version                 Version,
  modulus               INTEGER,  -- n
  publicExponent    INTEGER,  -- e
  privateExponent   INTEGER,  -- d
  prime1                  INTEGER,  -- p
  prime2                  INTEGER,  -- q
  exponent1            INTEGER,  -- d mod (p-1)
  exponent2            INTEGER,  -- d mod (q-1)
  coefficient            INTEGER,  -- (inverse of q) mod p
  otherPrimeInfos   OtherPrimeInfos OPTIONAL
}

El comando asn1parse es una utilidad de diagnóstico que puede analizar estas estructuras y que también se puede utilizar para extraer los datos con este formato, por lo que probamos con:

openssl asn1parse -in key_2.pem

Y obtenemos lo siguiente:
Como se observa en la figura anterior hemos obtenido (parte no dañada de la clave), lo siguiente:

Módulo (hexadecimal):
n = C4B07FEFC8E36C05C0DA434221AEBF47DBF70E5189AD892408F3AD81182A9E0700A07C9D7C66C86C7A39602123EE0F605613DE97FDE49FE68396EE0AF3F5F5F3

Exponente de la clave pública (hexadecimal):
e = 010001

Exponente de la clave privada (hexadecimal):
d = 2AEC519F2479ECF2FC79254063555D4CF345E10C0E3D9EB60C7611212102FBE52D45E9AA1357813E4460B30889F75FABF72F049D5C3F4AF2F81984267A8BD2B1

Primer factor primo del módulo (hexadecimal):
p = EABC1DE8A7C5EE2E76B88D39DDF94A0255F5EF3B6209420887C2A008AB474AAD

Segundo factor primo del módulo (hexadecimal):
q = D6820C70A6A2462523D92FD0E1815337249D4FE7C7D7A86EA1242B11AA43F71F

Los datos que faltan (parte dañada de la clave) son: d mod (p-1), d mod (q-1), (inverse of q) mod p, que se pueden obtener a partir de los anteriores y, de esta forma, reconstruir la clave privada RSA original. Tal y como dije en este postjunto con su clave privada (d, n), el receptor debe guardar los números primos p y q, y, además, para aplicar de forma óptima el teorema chino del resto en el descifrado y así simplificar los cálculos, los tres valores que faltan.

Para reconstruir la clave privada RSA original y, posteriormente, poder obtener la flag creo el siguiente script de python:

#!/usr/bin/python

from egcd import egcd
import pyasn1.codec.der.encoder
import pyasn1.type.univ
import base64

def inv(a, m):
    gcd, x, y = egcd(a, m)
    if gcd != 1:
        return None
    else:
        return x % m

def generar_pem(n, e, d, p, q, dp, dq, q1):
    key = '-----BEGIN RSA PRIVATE KEY-----\n{}-----END RSA PRIVATE KEY-----\n'
    seq = pyasn1.type.univ.Sequence()
    for x in [0, n, e, d, p, q, dp, dq, q1]:
        seq.setComponentByPosition(len(seq), pyasn1.type.univ.Integer(x))
    der = pyasn1.codec.der.encoder.encode(seq)
    return key.format(base64.encodestring(der).decode('ascii'))

# Valores de la clave correspondientes a modulo (n), exponente clave publica (e), exponente clave privada (d) y factores primos del modulo (p y q)
n = 0xC4B07FEFC8E36C05C0DA434221AEBF47DBF70E5189AD892408F3AD81182A9E0700A07C9D7C66C86C7A39602123EE0F605613DE97FDE49FE68396EE0AF3F5F5F3
e = 0x010001
d = 0x2AEC519F2479ECF2FC79254063555D4CF345E10C0E3D9EB60C7611212102FBE52D45E9AA1357813E4460B30889F75FABF72F049D5C3F4AF2F81984267A8BD2B1
p = 0xEABC1DE8A7C5EE2E76B88D39DDF94A0255F5EF3B6209420887C2A008AB474AAD
q = 0xD6820C70A6A2462523D92FD0E1815337249D4FE7C7D7A86EA1242B11AA43F71F

print('')

# Calculo de los valores que faltan en la clave: d mod (p-1), d mod (q-1), (inverse of q) mod p
print('Los valores que faltan en la clave privada RSA son:')
dp = d%(p-1)
print('dp = ', dp)
dq = d%(q-1)
print('dq = ', dq)
q1 = inv(q, p)
print('q1 = ', dq)

print('')

# Generacion de la clave privada RSA original
key = generar_pem(n, e, d, p, q, dp, dq, q1)
print('La clave privada RSA original es:')
print('key = ', key)
f = open("key_3.pem", "w")
f.write(key)
f.close()

Tras ejecutar este script obtenemos la clave privada RSA original, que se graba en el archivo key_3.pem:
Y ya sólo nos queda descifrar el contenido del archivo secret.txt:

openssl rsautl -decrypt -in secret.txt -inkey key_3.pem
Por tanto, la Flag es: flag{gk83h280fwlo2}.

domingo, 25 de noviembre de 2018

Criptografía (CXIV): Solución Reto Cybercamp "It is not Caesar"

En este post la solución a uno de los retos de criptografía de Cybercamp 2017 Online.

Este reto tiene el título "It is not Caesar" y mi valoración sobre su dificultad es: ☆☆.

Su enunciado dice lo siguiente:


A time traveler saved the following message:

ESNTOTGCESLDUMOHIESLF:QACAIEOS

Como recurso asociado al retnos dan el archivo objective1.jpg, que contiene la siguiente imagen:
La primer pista para resolver este reto está en su título, ya que aunque se nos dice que no se trata de un cifrado César, parece indicarnos que se ha utilizado un criptosistema clásico para cifrar el mensaje. Además, entiendo que en esa misma línea va también el enunciado al referirse a un viajero del tiempo. Todo ello, unido a la columna clásica que aparece en la imagen más al "6x5" que figura en la misma, hace que podamos especular que el criptosistema empleado es la transposición columnar simple.

Si no estoy equivocado, para descifrar el criptograma, en primer lugar, disponemos sus caracteres en una tabla de 6 columnas y 5 filas, por columnas, de arriba a abajo y de izquierda a derecha:
Lo siguiente que tenemos que hacer es reordenar las columnas conforme a la clave utilizada. Pero, ¿cuál puede ser la clave?. Puede serlo perfectamente la palabra "BLANCO", que aparece en la imagen y tiene 6 caracteres:
Y, finalmente, obtenemos el texto en claro leyendo la tabla anterior por filas, de izquierda a derecha y de arriba a abajo, es decir:

THE FLAG IS: DICEN QUE ESTAMOS LOCOS

Hemos obtenido la solución de forma manual, pero también lo podríamos haber hecho mediante una de las muchas herramientas de cifrado/descifrado online existentes. Por ejemplo:

Reversing (I): Solución Reto Cybercamp "Oh my G0d!"

En este post la solución a uno de los retos de reversing de Cybercamp 2018 Online.

Este reto tiene el título "Oh my G0d!" y mi valoración sobre su dificultad es: .

Su enunciado dice lo siguiente:


Se ha interceptado un código en la conversación entre dos delincuentes cuyo funcionamiento tendrás que averiguar para llegar a la FLAG.


Como recurso asociado al reto nos dan el archivo medium_8.pyc, es decir, un fichero compilado de python.

Solución: al ejecutar el archivo medium_8.pyc vemos lo siguiente:
Por tanto, queda claro que lo primero que hay que hace es decompilar este archivo.

Para ello utilizo un decompilador de Python y obtengo el siguiente script:
Básicamente, lo que hace este script es comprobar la longitud de la Flag que se introduce; si ésta es menor o igual que 25, múltiplo de 5 y diferente de 0, compara el hash MD5 de los cinco primeros caracteres de la Flag (en decimal) con el primer elemento de la lista SHA1, y si son iguales repite esta comparación con el hash MD5 de los cinco siguientes caracteres de la Flag (en decimal) y el siguiente elemento de la lista SHA1, y así sucesivamente hasta finalizar con todos los caracteres de la Flag (recordar las validaciones sobre su longitud efectuadas anteriormente). Finalmente, si la longitud de la Flag introducida es 25 y previamente el hash MD5 de los 5 grupos de 5 caracteres de la misma han coincidido con los respectivos elementos de la lista SHA1, el script nos confirma que la Flag que hemos introducido es la correcta.

Para obtener la Flag creo el siguiente script de Python:

import hashlib
from colorama import init, Fore, Back, Style

init()

hashes_decimal = [15474416150235697017043280589699178375,
 291181071307803139498438131966588955205,
 109873136872180403981887852593133114079,
 115202235886395046817983293445716821568,
 242056712403709180973346710358452011247]

print('')
print(Fore.WHITE+Back.BLUE+'Los cinco hashes MD5 correspondientes a las 5 palabras de la Flag, cada una de ellas de 5 letras, son:'+Back.RESET)
print('')
hashes_hexadecimal=[]
for hash in hashes_decimal:
    hashes_hexadecimal.append('{:032x}'.format(hash))
    print('{:032x}'.format(hash))

print('')
print(Fore.WHITE+Back.BLUE+'Obtenga la palabra correspondiente a cada uno de los hashes MD5 indicados mediante una herramienta online'+Back.RESET)
print('')

i=1
flag=''
while i < 6:
    print(Style.RESET_ALL+'Introduzca la palabra numero', i, 'de 5 letras de la Flag ..... ', end='')
    palabra=str(input())
    if len(palabra)!=5:
       print (Style.BRIGHT+Fore.RED+'La palabra tiene que tener una longitud de 5 caracteres')
    else:
       hash_palabra=(hashlib.md5(palabra.encode()))
       j=i-1
       if (hash_palabra.hexdigest())==hashes_hexadecimal[j]:
          error=0
          flag=flag+palabra
          print(Style.BRIGHT+Fore.GREEN+'La palabra numero', i, 'de 5 letras de la Flag es correcta')
          i+=1
       else:
          error=1
          print(Style.BRIGHT+Fore.RED+'La palabra numero', i, 'de 5 letras de la Flag es incorrecta')
          print(Style.RESET_ALL+'Desea continuar introduciendo la palabra numero', i, '(S/N) ... ', end='')
          cont=str(input())
          if cont!='S' and cont!='s':
             i=6

if error==0:
   print('')
   print(Style.BRIGHT+Fore.GREEN+'La Flag es:', flag)
else:
   print('')
   print(Style.BRIGHT+Fore.RED+'Flag no encontrada')

En primer lugar y tras ejecutar este script, se nos pide obtener las 5 palabras de 5 letras que se corresponden con los hashes MD5 que se muestran:
Para obtener las 5 palabras utilizo una de la muchas herramientas online existentes para ello:
Como se observa en la figura anterior el texto en claro correspondiente a cada uno de los 5 hashes MD5 introducidos se corresponde, respectivamente, con las siguientes palabras: "check", "group", "zezex", "happy" y "tests".

Introducimos esas 5 palabras y el script, tras validar que cada una de ellas es correcta, nos muestra la Flag (la concatenación de todas ellas):
Por tanto,  la Flag es: checkgroupzezexhappytests.

miércoles, 21 de noviembre de 2018

Criptografía (CXIII): Solución Reto Atenea "Durin's Gates" (III)

Tercera y última entrega de las entradas en las que voy compartiendo la solución al quinto reto de "Criptografía y Esteganografía" de la plataforma ATENEA del CCN-CERT con desafíos de seguridad.

En esta entrada desvelaré ya la solución.

En el primer post llegamos a la obtención de un archivo de texto (SgaSizcn.txt) cuyo contenido estaba codificado en base64, mientras que en el segundo post me quedé en la obtención de otro archivo de texto (SgaSizcn_decoded.txt) con la decodificación del contenido del anterior:
En este caso la pista puede estar en la cabecera del archivo. La cadena de caracteres ASCII "Salted__" puede indicar que el contenido del archivo se ha cifrado utilizando openssl.

Desconozco si es posible, a partir de un archivo cifrado, conocer qué algoritmo de cifrado concreto se ha utilizado (entiendo que no es posible, pero si algún lector de este blog me puede sacar del error se lo agradecería), por lo que me temo que sólo me queda probar diferentes alternativas.

Pero hay un problema adicional: ¿Cuál será la password para descifrar el contenido de este archivo?. Cuando me pregunté ésto, recordé el metadato en la etiqueta "Artist" del fichero .jpg asociado al reto:
¿Será ésta la password?. Probemos a descifrar el archivo (SgaSizcn_decoded.txt) con el siguiente comando:

openssl aes-256-cbc -d -salt -in SgaSizcn_decoded.txt -out SgaSizcn_deciphered

Y nos pide que introduzcamos la password (enter aes-256-cbc decryption password):

Introducimos 68913499125FAA y obtenemos el fichero de salida (SgaSizcn_deciphered).

Abrimos ese archivo con un editor hexadecimal:
Con lo que parece que el archivo obtenido (SgaSizcn_deciphered) es un  archivo multimedia. En concreto y por su cabecera parecer ser un archivo .mp4. Lo reproducimos:
Y ya podemos ver la solución al reto: "Minas_Tirith_2017" (recordar que hay que introducirla con formato flag{md5}).

martes, 20 de noviembre de 2018

Criptografía (CXII): Solución Reto Atenea "Durin's Gates" (II)

Ésta es la segunda parte de este post. En estas entradas voy compartiendo la solución al quinto reto de "Criptografía y Esteganografía" de la plataforma ATENEA del CCN-CERT con desafíos de seguridad.

En esta segunda entrega adelantaré en la solución del reto, pero todavía quedará una tercera entrada en la que desvelaré su solución.

En el citado primer post me quedé en la obtención de un archivo de texto (SgaSizcn.txt), el siguiente:
Y preguntaba: ¿Qué puede significar ésto?. ¿Cómo continuamos para resolver este reto?. Pues bien, el contenido de este archivo de texto parece ser código base64, por lo que podemos utilizar openssl para decodificarlo, mediante el siguiente comando:

openssl base64 -d -in SgaSizcn.txt -out SgaSizcn_decoded.txt

Abrimo el archivo así obtenido (SgaSizcn_decoded.txt) con un editor hexadecimal y vemos lo siguiente:
Pues otra vez creo que son pertinentes las preguntas que hacía al final del post anterior: ¿Qué puede significar ésto?, ¿Cómo continuamos para resolver este reto?.

Se admiten comentarios, sugerencias, soluciones... ;)

lunes, 19 de noviembre de 2018

Criptografía (CXI): Solución Reto Atenea "Durin's Gates" (I)

En este post la primera entrada correspondiente a la solución al quinto reto de "Criptografía y Esteganografía" de la plataforma ATENEA del CCN-CERT con desafíos de seguridad.

Con esta primera entrada pretendo aportar pistas para que participen en su resolución aquellos lectores de este humilde blog que estén interesados en este tipo de retos, pero sin facilitarles la solución completa al mismo.

En concreto, este quinto reto tiene el título de "Durin´s Gates" y tras su resolución se obtienen 300 puntos (Dificultad: ☆☆).

Su enunciado dice lo siguiente:


Informaciones fidedignas han revelado que cierto grupo de atacantes utilizan técnicas de esteganografía y cifrado junto con determinados servicios online para comunicarse entre ellos y compartir información confidencial. Recientemente se ha podido interceptar una de las imágenes empleadas para compartir este tipo de mensajes. Se sospecha que la imagen se ha enviado para remitir una clave compartida con la que es posible acceder a uno de los servicios en la nube utilizados por los atacantes.

Tu objetivo será investigar el fichero adjunto .jpg y averiguar si está relacionado con una clave o mensaje de estas características.


Solución: la imagen asociada al reto es la siguiente.
La Wikipedia nos cuenta que, en la novela "El Señor de los Anillos"las Puertas de Durin eran la entrada occidental al reino de Khazad-Dûm (la Mina del Enano) y que fueron construidas en colaboración por Elfos y Enanos. Desde el exterior, ninguna fuerza enana, élfica o humana podía mover las puertas, excepto la contraseña inscrita en ellas; entonces se abrían solas, hacia los lados, hasta tocar la pared de roca.

Investigando un poco más en Internet encontré que la primera línea de la inscripción decía: "Puertas de Durin, Señor de Moria. Di amigo, y entra", y que la contraseña era "Amigo" en élfico, es decir, "Mellon". Cuando intentaba resolver este reto no tenía ni idea de si esto podía ser útil para solucionarlo, pero me había entretenido buscando la información :).

Vamos a ver qué podemos hacer para resolver el reto. En primer lugar, descargamos la imagen asociada al mismo, la abrimos con el software ExifToolGUI y analizamos los metadatos:
Salvo en la etiqueta "Artist" no veo nada que me llame la atención.

Tras realizar varias pruebas con diverso software de estegoanálisis sin obtener ningún resultado, pruebo con steghide, con el siguiente comando:

steghide extract -sf doors_of_durin-f686f3e1aa18d5e3f4261bea89a24c17.jpg

y nos pide una contraseña. Tras introducir como password "Mellon" obtenemos el archivo url.txt.
Accedemos con el navegador a la dirección indicada y nos encontramos con el siguiente archivo (SgaSizcn.txt):
¿Qué puede significar ésto?, ¿Cómo continuamos para resolver este reto?.

Se admiten comentarios, sugerencias, soluciones... ;)

viernes, 2 de noviembre de 2018

Programación (XI): Solución Reto 2

El  enunciado del reto de programación que puse en este post era el siguiente:

"La policía vigila de cerca a los miembros de una secta satánica, ya que sospecha que están involucrados en la comisión de diversos delitos, y ha interceptado las comunicaciones entre sus líderes. Hasta el momento sabe cuándo se Reunirán la próxima vez, pero no ha podido averiGuar dónde. Entre los ficheros interceptados se encuentra el fichero asociado como recurso a este resto y en el que se cree que puede esconderse algún tipo de mensaje; incluso quizá el lugar en el que se mantendrá dicha reunión. ¿Puedes oBtener el mensaje oculto en la imagen y ayudar a la policía a su detención?".

1.- En la primera pista que puse para resolver este reto decía que no es difícil darse cuenta de que dentro del fichero de imagen asociado al reto (Reto_2.pnghay otros dos archivos (Lugar cita.zip y password.txt), ya que para ello basta abrir ese fichero con un software de compresión de archivos o con un editor hexadecimal.
Lógicamente, lo más probable es que la solución a este reto se encuentre en el archivo comprimido Lugar cita.txt que contiene el fichero Lugar cita.zippero al intentar abrirlo o descomprimirlo nos pide una contraseña que desconocemos.

2.- Por tanto, centramos ahora nuestra atención en el otro archivo, password.txt, que podría contener la contraseña que necesitamos.

También decía en la primera pista que puse para resolver este reto que las letras en mayúsculas del enunciado pueden dar una pista importante para entender el contenido de este segundo archivo. A la vista del contenido del archivo password.txt, las letras 'R', 'G' y 'B' pueden hacer referencia a los canales 'Red' (Rojo), 'Green' (Verde) y 'Blue' (Azul) de una imagen en la que los pixeles de la misma contendrían valores en un rango de entre 0 y 255 para la intensidad correspondiente a cada uno de dichos canales.

Si esto es así podemos intentar construir una imagen a partir de los valores que contiene el archivo password.txt, una lista plana de n elementos; donde n/3 sería el número total de pixeles de la imagen y cada uno de los elementos se correspondería con un elemento de una tupla de tres elementos para los canales 'RGB' (cuatro elementos para 'RGBA', caso de que la imagen cuente con canal alfa).

Para ello utilizo el siguiente script de python:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from PIL import Image

def factorizacion_2(n):
# Descomponer un numero en dos factores no triviales
    factores=[]
    i=2
    while i <= int(n**(1/2)):
        if (n%i==0):
           factores.append(i)
           factores.append(int(n/i))
        i+=1
    return factores

# Abrir y leer fichero
fichero=open('password.txt','r')
valores=fichero.read()

# Contar numero de pixels
numero_pixels=int((valores.count(',')+1)/3)
print('Numero de pixels......................................',numero_pixels)

valores=valores.split(",")

factores=factorizacion_2(numero_pixels)
print('Los pares de posibles valores para alto y ancho son...',factores)
x=0
y=x+1
#Crear imágenes considerando los posibles valores para alto y ancho de la imagen y a partir de los valores de los pixels
imagen_ok='N'

while x < len(factores) and (imagen_ok=='N' or imagen_ok=='n'):
    print('*** Probamos con:*************************************')
    print('Ancho imagen..........................................',factores[y])
    print('Alto imagen...........................................',factores[x])
    imagen=Image.new('RGB',(factores[y],factores[x]))
    pixels=imagen.load()
    k=0
    for i in range(factores[x]):
        for j in range(factores[y]):
            pixels[j,i]=(int(valores[k]),int(valores[k+1]),int(valores[k+2]))
            k+=3
    imagen.show()
    imagen_ok= str(input('La imagen es correcta (S/N)?.......................... '))
    if imagen_ok=='N' or imagen_ok=='n':
       if x%2==0:
          x+=1
          y-=1
       else:
          x+=1
          y+=3
    else:
       if imagen_ok=='S' or imagen_ok=='s':
          imagen.save('password.png','PNG')

# Cerrar fichero e imagen
fichero.close()
imagen.close()

Ejecuto este script:
Inicialmente vemos que la imagen tendría 328.635 pixeles, y el script empieza a probar todos los posibles valores para el ancho y alto de la imagen. Tras cada una de las pruebas que realiza nos muestra la imagen resultado y nos pregunta si es correcta.

Finalmente, para un ancho de 603 pixeles y un alto de 545 pixeles, el script nos muestra la siguiente imagen:
Con lo que muy probablemente "4k3l4rr3" sea la contraseña del archivo Lugar cita.zip. Por cierto, para quienes no sepan lo que significa "Akelarre" en euskera ("Aquelarre" en castellano) aquí les dejo este enlace de la Wikipedia.

Probamos a abrir el archivo Lugar cita.txt con la contraseña "4k3l4rr3", efectivamente es la password correcta, y nos encontramos con la siguiente cadena de caracteres:

"4qCg4qC14qCl4qCb4qCB4qCX4qCX4qCB4qCN4qCl4qCX4qCZ4qCK"

3.- ¿Qué significado puede tener esto?. Pues veamos que ocurre si utilizamos un decodificador de Base64 de los muchos que existen online:
Decía en la tercera pista que puse para ayudar a resolver este reto que "salta a la vista" de qué código se trata. Por tanto, yo diría que lo que obtenemos como salida es código Braille :) y, aunque existen diversas herramientas online para ello, vamos a decodificarlo manualmente, de la siguiente manera:
Con lo que ya tendríamos la solución a este reto. El lugar de la reunión es: "Zugarramurdi"; un precioso pueblo navarro y con una cierta relación con el tema escogido para este reto, pero eso ya lo dejo para que aquellos que no lo conozcan y estén interesados lo investiguen por Internet.