Descripcion:#
El primer Sherlock que resuelvo y con una muy grata experiencia, toca hacerle reversing a un ramsomeware para poder recuperar unos archivos que fueron victimas del ataque, el ramsomeware usa un XOR para encriptar la información por lo que es muy facil solucionar este reto.
Forela needs your help! A whole portion of our UNIX servers have been hit with what we think is ransomware. We are refusing to pay the attackers and need you to find a way to recover the files provided. Warning This is a warning that this Sherlock includes software that is going to interact with your computer and files. This software has been intentionally included for educational purposes and is NOT intended to be executed or used otherwise. Always handle such files in isolated, controlled, and secure environments. Once the Sherlock zip has been unzipped, you will find a DANGER.txt file. Please read this to proceed.
Para este reto vamos a estar usando Ghidra y Python para hacer el desencriptado lo primero es abrir el ejecutable de Linux que nos dieron en el zip en un espacio de ghidra y analizarlo, nos vamos a dirigir a la función main:
Vemos que le pasa a la función process_directory dos parámetros el primero si revisamos el zip que nos dan es el directorio de todos los archivos que se encriptaron por culpa del malware, el segundo parámetro de momento no sabemos que es.
La función a la que le pasa estos parámetros es la siguiente:
Vamos a ir revisando poco a poco esto cambiando variables para así entender un poco que esta haciendo esto.
Sabemos que el param_1 es el directorio el cual el malware va a afectar además opendir() lo que hace es darnos un puntero de un directorio, por lo que ya sabemos que hace la primera parte del programa verifica si el directorio esta vacío, luego vemos local_18 que es igual a la función readdir() la cual devuelve el nombre de la próxima entrada en el directorio identificado por el puntero que obtuviste con opendir() , además en la variable local_418 guarda el directorio a atacar y el nombre del archivo que esta procesando.
En este punto el programa revisa que el directorio sea diferente a . y .. que son el directorio actual y el anterior, además de esto si es un directorio hace que se repita este proceso de nuevo para abarcar todo el contenido del directorio a atacar, ya por ultimo revisa que el archivo tenga como extensión alguno de los que vemos ahí como lo son txt, sql, pdf, docx, xlsx, csv, json o xml si es así muestra que esta encriptando el archivo y lo manda a una nueva función llamada encrypt_file donde pasa la ruta del archivo y el segundo parámetro que vimos que estaban pasando en el main a continuación podemos ver como quedaría la función con las nuevas variables para que sea mas entendible:
En la función encrypt_file vemos lo siguiente:
Sabemos que el parámetro_1 es la ruta al archivo a encriptar por lo que sabemos que loca_28 es el puntero al archivo, fseek lo que hace es que posiciona el puntero en el final del archivo:
- local_28: es el puntero al archivo abierto (tipo
FILE*). - 0: es el desplazamiento (offset) en bytes.
- 2: es el valor de la constante
SEEK_END, que indica que el desplazamiento se calcula desde el final del archivo.
ftell indica el tamaño que tiene el archivo, rewind reposiciona el puntero al inicio del archivo, malloc reserva un bloque de memoria del tamaño del archivo a encriptar, fread lee el contenido de local_28 lo guarda en local_38 y lo va a leer byte por byte hasta llegar al tamaño del archivo el cual lo sabemos con local_30.
Ya entrando en el for local_20 es nuestro iterador i , además esto solo va a parar cuando local_20 sea igual a local_30.
Ya dentro del for es donde se produce todo el encriptado, en la primera linea lo que hacemos es guardar el byte actual en la variable bVar1, en la segunda calculamos la longitud del parámetro 2 y lo guardamos en la variable sVar4, ya al final remplazamos el byte actual con la operatorio XOR entre el byte actual y el parámetro 2 que se repite hasta tener la misma longitud que el byte actual, por lo que podríamos decir que el parámetro dos desde el inicio ha sido la clave para encriptar y desencriptar los archivos, ya lo que continua es el programa guardando los cambios en un archivo con el mismo nombre pero con la extensión .24bes y creando una nota, además de eliminar el archivo original.
A continuación vemos el código mas legible:
Script#
Ahora vamos a comenzar a a realizar un script que nos haga el proceso inverso para recuperar los archivos, lo primero es seleccionar los archivos que vamos a tratar esto lo podemos hacer usando la extensión que tienen los archivos:
def seleccionar_archivos():
lista_archivos = os.listdir(
"/forela-criticaldata/"
)
archivos_encriptados = []
for elemento in lista_archivos:
if elemento.endswith(".24bes"):
archivos_encriptados.append(elemento)
print(archivos_encriptados)
return archivos_encriptados
Y los guardamos en una lista para así poder hacer el proceso uno por uno, lo siguiente que tenemos que hacer recordando que el malware usa un XOR y tenemos la clave que uso es volver a usar el XOR con esta clave de esta forma tendremos el contenido original.
def decrypt():
for elemento in archivos_encriptados:
# Elimina los últimos 6 caracteres de la extensión del archivo cifrado (elimina el .24bes)
elemento_sin_extension = elemento[:-6]
# Abre el archivo cifrado en modo lectura binaria ('rb')
with open(os.path.join("/forela-criticaldata/", elemento,), "rb",) as f:
# Lee todo el contenido del archivo y lo almacena como un bytearray (para modificarlo)
datos = bytearray(f.read())
clave = b"bhUlIshutrea98liOp"
# Recorre cada byte del archivo y aplica el XOR con el byte correspondiente de la clave (cíclicamente)
for i in range(len(datos)):
datos[i] ^= clave[i % len(clave)]
# Abre un nuevo archivo en la carpeta de archivos descifrados, en modo escritura binaria ('wb')
with open(os.path.join("/archivos_decrypt/",elemento_sin_extension,),"wb",) as f:
# Escribe los datos descifrados en el nuevo archivo
f.write(datos)
print(f"Archivo desencriptado: {elemento_sin_extension}")
De modo que el script completo para su uso quedaría de la siguiente forma:
import os
def seleccionar_archivos():
lista_archivos = os.listdir(
"/home/loaxert/Documentos/Sherlocks/Lockpick/forela-criticaldata/"
)
archivos_encriptados = []
for elemento in lista_archivos:
if elemento.endswith(".24bes"):
archivos_encriptados.append(elemento)
print(archivos_encriptados)
return archivos_encriptados
def decrypt():
for elemento in archivos_encriptados:
elemento_sin_extension = elemento[:-6]
with open(
os.path.join(
"/home/loaxert/Documentos/Sherlocks/Lockpick/forela-criticaldata/",
elemento,
),
"rb",
) as f:
datos = bytearray(f.read())
clave = b"bhUlIshutrea98liOp"
for i in range(len(datos)):
datos[i] ^= clave[i % len(clave)]
with open(
os.path.join(
"/home/loaxert/Documentos/Sherlocks/Lockpick/archivos_decrypt/",
elemento_sin_extension,
),
"wb",
) as f:
f.write(datos)
print(f"Archivo desencriptado: {elemento_sin_extension}")
archivos_encriptados = seleccionar_archivos()
decrypt()
Ejecutando esto tendremos los archivos originales y podremos responder las preguntas del Sherlock sin ningún problema.





