Analizamos el código fuente de un ransomware escrito en Python bajo el nombre de detección: Python/Filecoder.AX. Esta variante, que ya no está activa, sí lo estuvo durante los años 2017 y 2018 y fue distribuida empaquetada en un ejecutable .exe mediante PyInstaller, con lo cual será necesario descompilarlo para obtener su código fuente en texto plano. El proceso de descompilación es sencillo y fue explicado paso a paso en el post: cómo descompilar un ejecutable malicioso (.exe) escrito en Python.
Una vez obtenido el código fuente nos encontraremos con muchas funciones y variables que deberemos ir leyendo detenidamente para poder comprender las actividades maliciosas realizadas. Es una buena idea comenzar a analizar el código desde el entry point; es decir, desde la primera instrucción que será ejecutada. De esta manera es más fácil seguir el flujo de ejecución y se evita estudiar funciones basura o residuales (presentes en el código, pero nunca utilizadas).
En este caso, la amenaza comienza ejecutando este fragmento de código:
La finalidad de este código será ejecutar la función “run_crypt” para cada una de las unidades de almacenamiento presentes en la computadora o para una específica pasada como parámetro al momento de ejecutar el malware. De esta observación se deduce que “run_crypt” será el componente principal de la amenaza. Además de llamar a dicha función, este código también se encargará de generar un código para identificar la computadora de la víctima y que más adelante, luego de ser hasheado, será utilizado como clave para cifrar los archivos. Uno de los valores utilizados para generar este código se pasa al ransomware como un parámetro al momento de ser ejecutado, lo cual sugiere que, como parte de un ataque, esta amenaza muy probablemente sea ejecutada por otra.
Analizando las funciones
Como se mencionó anteriormente, la función “run_crypt” es el componente central de la amenaza.
Esta función itera uno por uno sobre todos los archivos presentes en la unidad con algunas excepciones:
- Omite todos los archivos cuya ruta comience con “C:\Windows” es decir, no cifra los archivos del sistema para no afectar la estabilidad de este y permitir que la víctima pueda leer el mensaje de rescate.
- Omite todos los archivos que se encuentran en la papelera de reciclaje, lo cual tiene sentido dado que se supone que son archivos que la víctima no desea.
- Omite los archivos ya cifrados (.RQUILT).
- Omite los archivos donde escribe el mensaje de rescate para la víctima (RECOVER.txt).
- Omite el ejecutable de sí mismo.
- Omite los archivos .bak o aquellos cuyo nombre o ruta contenga la palabra “backup”. Estos son eliminados directamente.
- Omite los archivos que no tienen una extensión considerada valida o relevante para el ransomware (basándose en la lista contenida en la variable valid_extension).
Luego, todos los archivos que pasen los controles previamente enunciados serán cifrados mediante la función “createAdamantium” y el archivo original no cifrado será eliminado inmediatamente.
Aquí podemos observar tres elementos interesantes:
- Variable “valid_extension”
- Función “createAdamantium”
- Función “grandpaSlacks”
valid_extension
Esta variable contiene una lista donde se definen todas las extensiones de archivo que serán consideradas validas o relevantes y, por ende, que serán cifradas por este ransomware.
En esta lista podemos observar formatos muy variados asociados a:
- Documentos: .pdf, .doc, .docx, .odt, .xls, .xlsx, etc.
- Código fuente: .php, .py, .cpp, .vbs, .java, .asp, .asm, .pas, etc.
- Bases de datos: .sqlitedb, .sqlite3.
- Archivos comprimidos: .tar, .zip, .rar, etc.
- Wallet de criptomonedas: wallet.dat
- Etc
Muchos de los formatos apuntados son encontrados en la mayoría de las computadoras, por ejemplo, imágenes, videos, documentos, archivos comprimidos, etc. Sin embargo, esta lista contiene muchos otros formatos asociados a software muy específico como .unity3d (software profesional de diseño de videojuegos) o asociados a bases de datos y a código fuente de programas, entre otros. Esto sugiere que la amenaza podría estar dirigida principalmente a organizaciones, apuntando a los archivos de mayor valor cuya perdida podría representar un serio inconveniente económico u operativo.
grandpaSlacks
Esta función es muy simple dado que su único objetivo es aplicar una función de hash (SHA3 de 256 bits) al valor recibido como parámetro y devolver el resultado. Dentro del contexto del código, esta función procesará el identificador de la computadora de la víctima y devolverá su hash. Luego, este hash será la clave que utilizará el ransomware para cifrar los archivos.
createAdamantium
Esta función se encarga de cifrar el archivo pasado como parámetro utilizando la clave también pasada como parámetro (hash SHA3 del identificador de la PC de la víctima). Para almacenar el archivo cifrado se crea un nuevo archivo con el mismo nombre que el original pero añadiendo la extensión correspondiente a los archivos cifrados por este ransomware: “.RQUILT”.
Luego, para cifrar el archivo se utiliza el algoritmo de cifrado AES 256 en modo CBC. Este modo de cifrado requiere el uso de un vector de inicialización, el cual es generado aleatoriamente. Antes de escribir el contenido cifrado se escribe el tamaño del archivo original seguido por el valor del vector de inicialización. Estos dos datos serán necesarios para poder descifrar el archivo, por lo que el cibercriminal los almacena dentro del mismo.
Finalmente, una vez inicializado AES y resguardados los datos para descifrar, se comienza a iterar el contenido del archivo original, cifrando cada bloque (chunk) y guardando el resultado en el nuevo archivo.
Pedido del dinero de rescate
Dentro de la función “run_crypt” podemos observar un fragmento de código encargado de escribir el mensaje de rescate dentro de un archivo llamado “readme.txt”. Parte del contenido del mensaje se encuentra cifrado mediante el algoritmo de sustitución ROT-13, específicamente, aquellos fragmentos que contienen información vinculada con el cibercriminal como su dirección de email y las direcciones de la billetera de bitcoin donde se enviará el dinero de rescate.
Luego de descifrar los fragmentos que estaban cifrados podemos observar la totalidad del mensaje:
Aquí se le solicita a la víctima que envíe el equivalente de 700 dólares en bitcoin a la dirección indicada (hay dos direcciones, pero solo se le mostrará una elegida en forma aleatoria). Además, el atacante también pide que se le envíe por email el identificador y un archivo cualquiera para demostrarle a la víctima que sus archivos pueden ser descifrarlos y transmitirle seguridad a la hora de pagar el rescate.
Un detalle interesante es que el atacante aclara que ese monto se corresponde a la devolución del acceso a los archivos de una única computadora, pero también le da a la víctima la posibilidad de enviar el equivalente a 5000 dólares a cambio de devolverle el acceso a todas las computadoras infectadas en su red. Esto sugiere que este ransomware puede haber sido distribuido por una amenaza de tipo gusano con una presencia más extendida.
Por la forma en que está escrito el mensaje puede concluirse que el inglés no es el lenguaje nativo del cibercriminal, dado que contiene muchos errores gramaticales. De hecho, en el código fuente hay una variable no utilizada llamada garbage (basura, en inglés), la cual almacena una string que contiene un fragmento escrito en chino.
También puede observarse otro fragmento interesante “im doing this to pay for my student loans”, en español: “estoy haciendo esto para pagar mis préstamos estudiantiles”.
Por otro lado, si analizamos el historial de transferencias de las billeteras de bitcoin podemos notar que ambas billeteras han recibido transferencias por un monto total de 1.24 bitcoins.
Luego de cada transferencia recibida el dinero es enviado a otras billeteras, dando un balance final de 0 bitcoins. Esto sugiere que algunos usuarios han sido víctimas de este ransomware y han pagado el dinero del rescate al cibercriminal.
¿Pagar o no pagar?
Se ha hablado mucho sobre los riesgos que acarrea pagar el dinero correspondiente al rescate ya que nunca se tiene una garantía de que el cibercriminal cumpla con su promesa al recibir el dinero. Hay muchos casos donde estos realmente descifran los archivos de la víctima, pero también hay muchos casos donde no es así y la victima termina perdiendo sus archivos y el dinero.
Es difícil saber si este cibercriminal devolverá o no los archivos al usuario luego del pago. En principio, no hay ningún fragmento del código del ejecutable malicioso que haga referencia al descifrado, con lo cual el atacante debería enviarle a la víctima otro ejecutable que realice esta función. El problema es que no sabemos si el atacante querrá entregarlo a la víctima, con lo cual el pago del rescate sigue siendo muy arriesgado.
Descifrar archivos
Como vimos anteriormente, la clave con la que se cifra cada archivo está formada por el id de la computadora de la víctima (fácil de obtener) y un valor arbitrario pasado como argumento al ejecutable del ransomware (podría ser fácil de obtener si se tiene acceso al ejecutable que lo lanzó). A su vez, el vector de inicialización aleatorio utilizado al momento de cifrar cada archivo se encuentra escrito dentro de cada uno de ellos. Por lo tanto, todos los datos necesarios para poder descifrar los archivos se encuentran en la computadora de la víctima y pueden obtenerse sin la intervención del cibercriminal, incluso de manera offline. Luego, programar un script que extraiga dichos datos de cada archivo y descifre su contenido sería sencillo.
Conclusión
Hemos visto un ejemplo práctico en el cual descompilar el ejecutable malicioso para obtener su código fuente puede ser de mucha utilidad, tanto para comprender en detalle el funcionamiento interno de la amenaza como para mitigar y revertir su accionar. Esto también se extiende a otras familias de ransomware donde, según como estén diseñadas, realizar un análisis en profundidad podría permitir desarrollar un script para recuperar los archivos sin la necesidad de pagar un rescate.