Ir al contenido principal

Hydra android malware (Part 2)

Reversing Write-up Hatred (Bitup19)


Buenas a todos,

Después de un fin de semana intenso peleándome con C++ un poco ( ya veréis el churro de código que he hecho), me he decidido hacer un write-up de como resolví el reto de Hatred, con la compañía de un "figura" de CrackLatinos @bym24v..., bueno sentimentalismos atrás, vamos al turrón!

Comenzamos abriendo el binario y comprobamos que un un binario de x64( por lo tanto, necesitamos ejecutarlo en un SO de x64), seguidamente, vemos que al ejecutarse el binario, se nos cierra automáticamente sin mostrar nada..... (SOSPECHOCHO!)

Lo abrimos con IDA para ver porque se sale y comenzamos a "debuggearlo", lo primero que hacemos es buscar la función main() y re-nombrarla para verlo mas bonito con IDA.



Una vez ya la tenemos localizada, nos metemos dentro de la función, y vemos que nada mas comenzar hace una llamada a IsDebbugerPresent() (esta función nos devuelve eax = 0x1 cuando estamos "debugueando" y eax= 0x0 cuando no). Vemos que independientemente de que eax = 0x1 o eax=0x0 se saldrá del programa sin hacer nada, por lo tanto, tenemos que parchearlo, he creado un parche para que nos permita  hacer debugging sin problema, aunque no ejecutarlo (eso ya os lo dejo a vosotros) :).

ANTES


DESPUÉS


                                  

Una vez que nuestro programa nos permite debuggearlo sin problemas, empezamos a analizar el funcionamiento del mismo. Para ello, comenzamos como siempre mirando las strings y localizando si hay alguna que consideremos interesante. De hecho así es, y localizamos una que nos dice "Good Job!".



Vemos que hemos coloreado la parte de código donde queremos llegar, pero para llegar ahí hay una comparación de "al" donde al==0x1 para llegar a esa string "ganadora" que hemos localizado. Vemos también que justo antes de esa comparación hay una llamada a una función la cual re-nombraré como check_password().

Dentro ya de la función check_password(), sabemos que debe de terminar con al=0x1, por lo tanto vamos a analizar el camino del programa que nos guarde ese valor en el registro "al".

Vamos a "debuguear" un poco, introduciendo varios input distintos y comprobando que valores se chequean en esa función. En la siguiente imagen utilizo como input="aaaa" y hace la siguiente comparación:


Vemos que independientemente del input que introduzcamos, hay una cadena que se repite es: "g;jf"db%",  que se compara con otra para determinar si ponemos eax=1 o eax=0, por lo tanto deducimos que nuestro input tras algunas modificaciones que hace el programa internamente, tiene que tener ese valor para que vayamos por el path que pone eax=0x1.

Vale pues, una vez tenemos esto claro, vamos a ir viendo cuales son las modificaciones que va haciendo nuestro programa sobre nuestro input, para ver si podemos reversearlas y así sacar el input bueno.

Nos vamos a la parte donde nos pide "introduce una password",  y tras analizarla vemos que lee los caracteres que hemos introducido y además hay una función que "desofusca" una cadena que estaba en una parte de la memoria dando lugar a la cadena "notooeasy" (esto no tiene nada que ver con el reto, pero intento describirlo tal y como yo lo fui haciendo), a esa función la llamé, desofusca_cadenaarriba().



Vemos en las siguiente imagen, lo que os he comentado:

                                         



Si bajamos un poco mas en el código, observamos otra función que yo le he llamado funcion_decodificacion2() donde le estamos pasando nuestro input introducido por consola a través del registro rdx, rdx=Input  y  la dirección de la cadena "notooeasy" a través del registro rcx, rcx=*("notooEasy). tal y como vemos en la siguiente imagen.



Nos metemos dentro de la función para ver que estamos haciendo, y vemos que se van cogiendo de 3 en 3 los caracteres introducidos por consola(input) y se le hacen algunas modificaciones tal y como vemos en la siguiente imagen.


                               

 Las modificaciones que se van haciendo al input las puedes ver en el siguiente código en C++ donde tienes en comentarios la instrucciones en ensamblador  a las que están representando.

                                   

Mas abajo en la misma función, nos encontramos que con esos valores calculados, (en nuestro código c++ salida1,salida2,salida3,salida4), leemos los valores de un  array que está definido en el programa, en esas posiciones en concreto que hemos calculado, obteniendo unos valores determinados.

  • Array[salida1]
  • Array[salida2]
  • Array[salida3]
  • Array[salida4]
Donde Array [] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8',',9','/' };

Por lo tanto vemos que de cada 3 caracteres introducidos, generamos 4.

Vemos que esas salida generada se va guardando en la posición de memoria donde antes estaba la cadena "notooEasy", de ahi que se lo pasáramos a la función.


*En el caso de que el input que introducimos no sea múltiplo de 3, hace el mismo procedimiento pero machaca algunos valores, por ejemplo:

  • Input % 3  =1 --> Salida [] = {Array[salida1], Array[salida2], "=", "="}
  • Input % 3 = 2 --> Salida [] = {Array[salida1], Array[salida2], Array[salida3], "="}
Aquí vemos la parte donde se añade el "=" a fuego.



Vale, terminamos esta función y con el input= "aaaa" hemos obtenido la siguiente cadena="YWFhYQ==".




Si seguimos avanzando en el código del programa, vemos que mas abajo se llama de nuevo a una función que yo he renombrado como siguiente_paso()  y le estamos pasando la cadena que habíamos generado anteriormente tras las modificaciones("YWFhYQ=="), así que, nos meteremos en esa función para ver si hace algún tipo de modificación sobre la cadena.

                                         



Dentro de la función, vemos que hace modificaciones sobre la cadena("YWFhYQ=="), y luego sobrescribe la misma, con el resultado de dichas operaciones:

                                           




Las modificaciones que se hacen sobre cada uno de los elementos de la cadena están implementadas en el siguiente código en C++.


                                       


Tras terminar las modificaciones y sobrescribir la cadena("YWFhYQ=="), por los nuevos valores calculados, dando lugar a (0xD70,0xD1,0x6A,0x26,0xD7,0x61,0x1D,0x1D):

                                         


Que es ya la cadena que se compara con "g;jf"db%" para comprobar si somos los ganadores de este reto...

Pues hasta aquí, la parte de reversing, ahora viene la parte de hacer el Keygen, que lo he hecho en C++ y lo he colgado en la siguiente dirección de github por si alguien lo quiere usar (el código es basura, lo sé ) pero, ¿no esta mal para ser la 1ª vez que hago algo en C++ no?.


PD: Para sacar la flag, solo tenéis que usar el programa y haber entendido un poco el razonamiento descrito en el blog, de todas formas si hay dudas, dejadme algún comentario.


En el keygen comenzamos de atrás para adelante, hasta llegar a saber que valor inicial.

  1. Calculamos el input necesario para obtener la cadena "g;jf"db%"  tras la segunda modificación.

                     
  2. Una vez tenemos ese input(recordad que el orden es importante), el keygen nos pide de nuevo que introduzcamos ese input, que será en el orden necesario para generar "g;jf"db%" los valores calculados y al introducir esa cadena nos dará los indices usado del Array [] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8',',9','/' };                              

                                    



Dándonos por lo tanto, el input real (este pixelado obviamente).


                                     


Un saludo!

Comentarios

Entradas populares de este blog

Hydra android malware (Part 2)

Buenas de nuevo, En esta segunda parte del tutorial de Hydra , vamos a coger una muestra mas reciente, y vamos a ahondar en las características técnicas de la muestra. Información de la muestra y Herramientas:  -) Muestra : 2fc050a06dab9dbc019dfdd768580ebe66f178a210fda23a02ce005742c5e262 -) JADX : Para poder leer el codigo Java/kotlin decompilado de la aplicación. -) Apktool : Para hacer el dissasembler de la APK, y poder parcherla y reconstruirla.  -) Genymotion : Para emular la aplicación -) Burp Suite: para capturar las comunicaciones -) Frida : Para TODO :) Análisis Estático Antes de comenzar con el archivo AndroidManifest.xml, como explicamos en la entrada anterior, vamos a introducir un poco de teoría de como es cargada y ejecutada una aplicación sobre el sistema operativo Android. Echamos un vistazo al androidManifest.xml : Al igual que en la entrada anterior, hay referencias a actividades  que no se encuentran presentes en el código de la aplicación al abrirlo con la herramien

Hydra Android Malware (Part 1)

 Buenos Días, Hoy escribiré una entrada de análisis de malware en Android después de un tiempo sin escribir por aquí. La idea era coger de nuevo soltura con las herramientas open-source que hay para el análisis de aplicaciones android. Estuve leyendo información sobre alguna familias y me tope con Hydra (siguen apareciendo casos activos en Android (Twitter)) y me puse con ella. Arranqué con la lectura de este blog : Es el "padre nuestro" de la primera parte de nuestro tutorial, lo único que voy a hacer yo aquí en la primera parte es "puntualizar" algunos problemas que me he encontrado durante el análisis al seguir su tutorial. Información de la muestra y Herramientas:  -) Muestra : 46aeb04f2f03ebe7c716fc6e58a5dea763cd9b00eb7a466d10a0744f50a7368f -) JADX : Para poder leer el codigo Java/kotlin decompilado de la aplicación. -) Apktool : Para hacer el dissasembler de la APK, y poder parcherla y reconstruirla.  -) Ghidra : Decompilado de librerias Nativas. -) GEF : Debu

Radare2- Set de comandos básicos

Buenas a todos y Feliz navidad lo primero. Entre mantecado y mantecado, y motivado por el curso de Ricardo Narvaja (CrackLatinos), me he decidido a publicar una entrada que es mas para mí que para el resto. Pero supongo que puede ser útil para otras personas, de ahí que lo ponga lo mas bonito posible en la web. Vamos a ver un "cheatsheet" con comandos útiles de Radare2 y su funcionalidad, todo esto puede extraerse del --help de las herramientas, pero para los que como yo le gusta ir al grano y ahorrar el mayor tiempo posible, tienen esta entrada. RABIN2: rabin2 -I file_.exe --> Nos proporciona información básica del binario, como arquitectura, y las protecciones del binario como (nx,dep,aslr...) rabin2 -i file_.exe --> Nos muestra los imports del binario. rabin2 -e file_.exe --> Dirección del Entry point. (Dirección virtual y raw offset en el executable) rabin2 -zz file_.exe --> Muestra las strings rabin2 -g file_.exe --> Este comando nos muestr