lunes, 26 de diciembre de 2016

Resolviendo el reto Nro 10 Android de ESET Ekoparty 2016 #eko12 - PARTE 1


Buenas, decidí terminar el año posteando como resolver este reto Android de ESET que me pareció muy bueno.

Vamos a necesitar APK-Multi-tool, dex2jar, JD-GUI, signapk.jar y un emulador de Android, en mi caso use bigNOX porque tengo una maquina con AMD y el emulador de Google de Windows no permite la aceleración de VM si no se posee un cpu Intel.

El Desafio:

**************************************************
Este es el desafío de reversing en Android.

Para encontrar el flag deberás utilizar técnicas sencillas de análisis de APK y algo de ingenio.

Al comienzo, probablemente debas utilizar algún motor de búsqueda para dar con la contraseña correcta, que es la respuesta a una adivinanza.

Encontrarás pistas que te guiarán en la dirección correcta.

Mucha suerte y happy reversing.


ROMPIENDO CrackMeBabe.apk

SHA256: ca80b0c050233ad6c9d70793ba76effeaffb9ede79508993f965beb04598233d



Cargamos el APK y ni bien lo lanzamos obtenemos la siguiente imagen de un personaje de Tv, por lo que se debe estar haciendo algún tipo de comprobación.





Decompilamos el APK con Multi-tool opción 9, con el obtendremos los archivos SMALI y el classes.dex que luego lo pasaremos por el dex2jar para obtener un .jar para abrirlo con el JD-Gui






d2j-dex2jar.bat classes.dex 

dex2jar classes.dex -> .\classes-dex2jar.jar

JD-Gui




Tenemos varias classes (Login, a, b, c, d, e, f)

Vamos a repasar a ojo de pájaro las principales funciones que me van a permitir sortear el entuerto.


Class f

Función  chk 
(se hacen comprobaciones de que tipo de dispositivo se esta utilizando y lo comprueba con un llamado a la clase d)

 if ((!Build.MODEL.contains(d.h)) && (!Build.MODEL.contains(d.i)) && (!Build.MODEL.contains(d.m)) && (!Build.FINGERPRINT.startsWith(d.k)) && (!Build.FINGERPRINT.startsWith(d.l)) && (!Build.MANUFACTURER.contains(d.n)) && (!Build.PRODUCT.contains(d.c)) && (!Build.MODEL.contains(d.c)))

Función chks(boolean) 

  return Build.VERSION.SDK_INT == 22;

Retorna verdadero si la versión del APLI level es 22 (Android Lollipop 5.0 - 5.1.1)
Por lo que tendríamos que ejecutarlo en un dispositivo con ese nivel de S.O. o emularlo con el AVD correspondiente.



Nombre códigoNúmero de versiónFecha de lanzamientoNivel de API
Apple Pie1.023 de septiembre de 20081
Banana Bread1.19 de febrero de 20092
Cupcake1.527 de abril de 20093
Donut1.615 de septiembre de 20094
Eclair2.0–2.126 de octubre de 20095–7
Froyo2.2–2.2.320 de mayo de 20108
Gingerbread2.3–2.3.76 de diciembre de 20109–10
Honeycomb13.0–3.2.622 de febrero de 201111–13
Ice Cream Sandwich4.0–4.0.418 de octubre de 201114–15
Jelly Bean4.1–4.3.19 de julio de 201216–18
KitKat4.4–4.4.4, 4.4W–4.4W.231 de octubre de 201319–20
Lollipop5.0–5.1.112 de noviembre de 201421–22
Marshmallow6.0–6.0.15 de octubre de 201523
Nougat7.0 - 7.122 de agosto de 201624 - 25

-----------------------------------------------------------------------------------------------------



Class Login en la cual se hacen varias comprobaciones para presentar el frame de login y pasar a la segunda etapa del desafío que es la de desencriptar un recurso y ejecutarlo (otro apk).

Función chkn (boolean) retorna verdadero si la latitud es 40 y la longitud es -74 en la geolocalización del dispositivo.

public boolean chkn()
  {
    int j = 0;
    int i = j;
    if (this.l != null)
    {
      i = j;
      if ((int)this.l.getLatitude() == 40)
      {
        i = j;
        if ((int)this.l.getLongitude() == -73)
          i = 1;
      }
    }
    return i;
  }

Acá tenemos una comprobación importante, se debe cumplir las dos, la chkn (lat:40 y long:-73) y la chks (version del SDK) de la class f para mostrar el frame del login, por otro lado se imprime un hint en el logcat

if ((chkn()) && (f.chks()))


    {
      setContentView(2130968602);
      this.bt = ((Button)findViewById(2131492970));
      this.tx = ((EditText)findViewById(2131492969));
      this.vw = ((TextView)findViewById(2131492971));
      this.vw.setOnClickListener(new c());
      Toast.makeText(this.con, "HINT: *Escucha* lo que Gollum responde y la clave encontrarás, o encuentra el enlace ofuscado que te guiará.", 1).show();
      Log.i(d.z, "HINT: *Escucha* lo que Gollum responde y la clave encontrarás, o encuentra el enlace ofuscado que te guiará.");
      return;
    }

Tenemos un hash md5 que corresponde a una clave a ingresar.


  public void onClick(View paramView)
  {
    if (((paramView instanceof Button)) && (paramView == this.bt))
      try
      {
        paramView = this.tx.getText().toString();
        MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");
        localMessageDigest.update(paramView.getBytes("UTF-8"));
        paramView = String.format("%032x", new Object[] { new BigInteger(1, localMessageDigest.digest()) });
        if (!paramView.equalsIgnoreCase("16cc45d14201e8caf26d48e636b1c48d"))


Buscamos en internet el MD5 y corresponde a  3gg535


Desencripción del recurso "enc" localizado en assets/ mediante la class b  función b.decrypt();





protected String doInBackground(String[] paramArrayOfString)
    {
      try
      {
        File localFile = new File(Environment.getExternalStorageDirectory().getPath() + "/content.apk");
        if ((localFile.exists()) && (localFile.length() > 0L))
          return "Error";
        InputStream localInputStream = Login.this.getApplicationContext().getResources().getAssets().open("enc");
        FileOutputStream localFileOutputStream = new FileOutputStream(localFile);
        b.decrypt(paramArrayOfString[0], localInputStream, localFileOutputStream);
        paramArrayOfString = new Intent("android.intent.action.VIEW");
        paramArrayOfString.setDataAndType(Uri.fromFile(localFile), "application/vnd.android.package-archive");
        Login.this.startActivity(paramArrayOfString);
        this.blnResult = true;
        return "Executed";
      }
      catch (Exception paramArrayOfString)
      {
        while (true)
        {
          paramArrayOfString.printStackTrace();
          Log.e(d.z, paramArrayOfString.getMessage());
        }
      }
    }


-----------------------------------------------------------------------------------------------------

Class d donde se llama a la class e y se desencriptan varios strings que serán utilizados en la class f para comprobar en que tipo de dispositivo especifico se esta ejecutando y desviar un poco la atención del reverser.

package eset.ekoparty.challenge.crackmebabe;

public class d
{
  public static String a = "12321322869";
  public static final String b = e.pqz("htDaDYyZOg==");
  public static final String c = e.pqz("tNrV");
  public static final String g = e.pqz("5Y6OT9PAbvGYtDsxJChCQI0=");
  public static final String h = e.pqz("5dnREIScO57b4GAj");
  public static final String i = e.pqz("5fvTCo+RKq7apg==");
  public static final String k = e.pqz("5dnbEYaCN6KK");
  public static final String l = e.pqz("5cvQFI2fKa+K");
  public static final String m = e.pqz("5f/QG5GfN6WI109KNHoHGcNbxcOzZ57tl8xC");
  public static final String n = e.pqz("5fnbEZqdMbXB62Uj");
  public static final String y = e.pqz("r8rKD9nfca3F439nbTYRH8IA2tThctH5w48NXoLVdHkq1Yo=");
  public static final String z = e.pqz("hMzfHIjQE6SIxmpjcQ==");
}


Decodificadas quedan

a = 12321322869
b = Android
c = sdk
g = 000000000000000
h = google_sdk
i = Emulator
k = generic
l = unknown
m = Android SDK built for x86
n = Genymotion
y = http://lmgtfy.com/?q=gollum+riddles
z = Crack Me Babe

-----------------------------------------------------------------------------------------------------


Class e se encarga de pasar a texto las cadenas base64 encontradas en la classe d

public class e
{
  static String pqz(String paramString)
  {
    try
    {
      paramString = new String(new a(d.a.getBytes("UTF-8")).a(Base64.decode(paramString.getBytes(), 0)), "UTF-8");
      try
      {

        String str = paramString.replace("\"", "");


-----------------------------------------------------------------------------------------------------


Bueno como salimos de este lio....

La clave la tenemos que es 3gg535 quiere decir que lo mas difícil son las comprobaciones de las funciones de las class Login y F

Entonces vamos a modificar el código SMALI  para que nos permita pasar a la pantalla de ingreso de password y lograr desencriptar el recurso enc.

Luego de modificar los .SMALI  re-compilamos con el APK-Multi-tool y firmamos con el signapk.jar 



Modificando Login.SMALI


Código java:

Cambiamos el  if ((chkn()) && b(f.chks())) por  if ((f.chks()) && (f.chks())) 


if ((f.chks()) && (f.chks())) 
    {
      setContentView(2130968602);
      this.bt = ((Button)findViewById(2131492970));
      this.tx = ((EditText)findViewById(2131492969));
      this.vw = ((TextView)findViewById(2131492971));
      this.vw.setOnClickListener(new c());
      Toast.makeText(this.con, "HINT: *Escucha* lo que Gollum responde y la clave encontrarás, o encuentra el enlace ofuscado que te guiará.", 1).show();
      Log.i(d.z, "HINT: *Escucha* lo que Gollum responde y la clave encontrarás, o encuentra el enlace ofuscado que te guiará.");
      return;

    }

En .SMALI sería:

    .line 63
    :cond_1
    invoke-static {}, Leset/ekoparty/challenge/crackmebabe/f;->chks()Z

    move-result v0

    if-eqz v0, :cond_2

    invoke-static {}, Leset/ekoparty/challenge/crackmebabe/f;->chks()Z

    move-result v0


    if-eqz v0, :cond_2


Modificando f.SMALI

Código java:

Modificamos  chks()  para que retorne verdadero si utilizamos una versión menor a 99, con esto podemos probarlo en cualquier API level.



  public static boolean chks()
  {
    return Build.VERSION.SDK_INT < 99;

  }


En .SMALI sería:

    sget v0, Landroid/os/Build$VERSION;->SDK_INT:I

    const/16 v1, 0x63 
                   
    if-ge v0, v1, :cond_0


Compilamos con opción 12 de APK-Multi-tool




Luego firmamos el APK con signapk.jar


set usrc=0
set heapy=512
echo Signing Apk
java -Xmx%heapy%m -jar signapk.jar -w testkey.x509.pem testkey.pk8 in.apk out.apk




Instalamos y ejecutamos el APK.


Y vemos que ya paso de largo las comprobaciones y nos muestra el ingreso de la password.



Ingresamos la password 3gg535 y se descifra el recurso enc.





Para luego solicitar ser instalado.







Instalamos y ejecutamos.... pero lo vemos la próxima.


Les dejo el apk original, el apk parchado y los .SMALI para que pueda hacerlo 
Uds. en sus casas.

https://dl.dropboxusercontent.com/u/80008916/CrackMeBabe.7z


Próxima entrega antes de fin de año :D

Eso es todo por el momento @Dkavalanche 2016 







No hay comentarios:

 Hola, me mudé a medium .... nos vemos!!! FELIZ 2022!!!