English [PoliCTF 2015] [Reverse 100 – Crack me if you can] Write Up

Description

John bets nobody can find the passphrase to login!
GPG key: viphHowrirOmbugTudIbavMeuhacyet’

Download

This challenge provided us with an apk file. I decompiled it with apktools

apktool d crack-me-if-you-can.apk

This lets us open the android application into Android Studio.

Capture d’écran 2015-07-13 à 12.28.12android and com folders are some libs classes (android.support.* and com.google.android.gms.*), and we have 4 interesting classes in it.polictf2015 which are a, b, c and LoginActivity.

We take a look at LoginActivity and check the onCreate method, which is the first called method when opening the app.

protected void onCreate(Bundle bundle)
{
  super.onCreate(bundle);
  setContentView(0x7f040017);
  if (a(getApplicationContext(), 2) || a(getApplicationContext(), "flagging{It_cannot_be_easier_than_this}") || a(getApplicationContext(), false) || a(getApplicationContext(), 2.7799999999999998D))
  {
    Toast.makeText(getApplicationContext(), getString(0x7f0c003d), 1).show();
  } else
  {
    Toast.makeText(getApplicationContext(), getString(0x7f0c003a), 1).show();
  }
  a = (EditText)findViewById(0x7f0a0055);
  ((Button)findViewById(0x7f0a0056)).setOnClickListener(new a(this));
  b = findViewById(0x7f0a0053);
}

The first if/else is useless, just some checking on the phone used (I didn’t even try to understand, it checks some IMEI stuffs, phone carrier, phone number, I think it only allows this apk to be launched on a virtual device).

We then have the inflation of an EditText, and a onClickListener attached to a button. This listener is new a(this).

a class looks like this :

class a
    implements android.view.View.OnClickListener
{

    final LoginActivity a;

    a(LoginActivity loginactivity)
    {
        a = loginactivity;
        super();
    }

    public void onClick(View view)
    {
        LoginActivity.a(a);
    }
}

Meaning that when the button is clicked, onClick(View view) method will be called, therefore LoginActivity.a(a) is called. Taking a look at LoginActivity shows us that static method a(LoginActivity loginActivity) calls another method a().

private void a()
    {
        EditText edittext = null;
        a.setError(null);
        String s = a.getText().toString();
        boolean flag = false;
        if (TextUtils.isEmpty(s))
        {
            a.setError(getString(0x7f0c003b));
            edittext = a;
            flag = true;
        }
        EditText edittext1 = edittext;
        boolean flag1 = flag;
        if (!TextUtils.isEmpty(s))
        {
            edittext1 = edittext;
            flag1 = flag;
            if (!a(s))
            {
                a.setError(getString(0x7f0c0037));
                edittext1 = a;
                flag1 = true;
            }
        }
        if (flag1)
        {
            edittext1.requestFocus();
        }
    }

Here lies the logic. After some checks on the content of the editText, we have the check if(!a(s)) with s the string typed in the editText.

Here is a(String s) code :

private boolean a(String s)
    {
        if (s.equals(c.a(it.polictf2015.b.a(it.polictf2015.b.b(it.polictf2015.b.c(it.polictf2015.b.d(it.polictf2015.b.g(it.polictf2015.b.h(it.polictf2015.b.e(it.polictf2015.b.f(it.polictf2015.b.i(c.c(c.b(c.d(getString(0x7f0c0038))))))))))))))))
        {
            Toast.makeText(getApplicationContext(), getString(0x7f0c003c), 1).show();
            return true;
        } else
        {
            return false;
        }
    }

Returning true means our string has to pass this UGLY test. I checked all the calls and transformed it in Python code. It’s much clearer and looks like this :

ourString == aString.replace("spdgj", "yb%e").replace("aat", "his").replace("buga", "Goo").replace("=", "_").replace("\\}", "", 1).replace("\\{", "",1).replace("R", "f",1).replace("c", "f",1).replace("]", "").replace("[", "").replace("%", "").replace("c", "a").replace("aa", "ca")

Last thing we have to find out it the resource string referenced by

getString(0x7f0c0038)

After having a look at res folder (with all resources), we find the string


"[[c%l][c{g}[%{%Mc%spdgj=]T%aat%=O%bRu%sc]c%ti[o%n=Wcs%=No[t=T][hct%=buga[d=As%=W]e=T%ho[u%[%g]h%t[%}%"

in res/values/strings.xml.

Giving our decoding code, it looks like the string we are looking for ! So we try to decode this string with our python code and it gives us :

fla{g}{Maybe_This_Obfuscation_Was_Not_That_Good_As_We_Thought}

I must have messed up with something, because a flag starts with flag{ so the real flag is :

flag{Maybe_This_Obfuscation_Was_Not_That_Good_As_We_Thought}

2 thoughts on “[PoliCTF 2015] [Reverse 100 – Crack me if you can] Write Up”

  1. hi,I would like to ask you what anti-compiler you use for smali to java? jd-gui is not good than your

Leave a Reply

Your email address will not be published. Required fields are marked *