PoliCTF 2015 - Crack Me If You Can

on under writeups
6 minute read

We get presented with the following challenge:

John bets nobody can find the passphrase to login!
    GPG key: viphHowrirOmbugTudIbavMeuhacyet'
    crack-me-if-you-can

The file extracts to an apk (Android package file). Running strings on it doesn’t give us any insight into what’s going on. Let’s load it into Genymotion:

Genymotion

Ok, so we have to guess a password. Let’s pop this open in JD-GUI:

protected void onCreate(Bundle paramBundle)
{
  super.onCreate(paramBundle);
  setContentView(2130968599);
  if ((a(getApplicationContext(), 2)) || (a(getApplicationContext(), "flagging{It_cannot_be_easier_than_this}")) || (a(getApplicationContext(), false)) || (a(getApplicationContext(), 2.78D))) {
    Toast.makeText(getApplicationContext(), getString(2131492925), 1).show();
  }
  for (;;)
  {
    this.a = ((EditText)findViewById(2131361877));
    ((Button)findViewById(2131361878)).setOnClickListener(new a(this));
    this.b = findViewById(2131361875);
    return;
    Toast.makeText(getApplicationContext(), getString(2131492922), 1).show();
  }
}

The flagging{It_cannot_be_easier_than_this} looked interesting, but didn’t turn out to be anything. However, the following snippet of code performs the validation check:

private boolean a(String paramString)
{
  if (paramString.equals(c.a(b.a(b.b(b.c(b.d(b.g(b.h(b.e(b.f(b.i(c.c(c.b(c.d(getString(2131492920))))))))))))))))
  {
    Toast.makeText(getApplicationContext(), getString(2131492924), 1).show();
    return true;
  }
  return false;
}

That’s interesting. So we could theoretically use those functions to compute the answer. However, it doesn’t appear to be dynamic in nature, it just builds the string to test against each time. I decided to just run the apk in a debugger. Looking through the smali output for this apk, we find the following:

.method private a(Ljava/lang/String;)Z
    .locals 3

    const/4 v0, 0x1

    const v1, 0x7f0c0038

    invoke-virtual {p0, v1}, Lit/polictf2015/LoginActivity;->getString(I)Ljava/lang/String;

    move-result-object v1

    invoke-static {v1}, Lit/polictf2015/c;->d(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-static {v1}, Lit/polictf2015/c;->b(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-static {v1}, Lit/polictf2015/c;->c(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-static {v1}, Lit/polictf2015/b;->i(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-static {v1}, Lit/polictf2015/b;->f(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-static {v1}, Lit/polictf2015/b;->e(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-static {v1}, Lit/polictf2015/b;->h(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-static {v1}, Lit/polictf2015/b;->g(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-static {v1}, Lit/polictf2015/b;->d(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-static {v1}, Lit/polictf2015/b;->b(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-static {v1}, Lit/polictf2015/b;->a(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-static {v1}, Lit/polictf2015/c;->a(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-virtual {p1, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v1

    if-eqz v1, :cond_0

    invoke-virtual {p0}, Lit/polictf2015/LoginActivity;->getApplicationContext()Landroid/content/Context;

    move-result-object v1

    const v2, 0x7f0c003c

    invoke-virtual {p0, v2}, Lit/polictf2015/LoginActivity;->getString(I)Ljava/lang/String;

    move-result-object v2

    invoke-static {v1, v2, v0}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v1

    invoke-virtual {v1}, Landroid/widget/Toast;->show()V

    :goto_0
    return v0

    :cond_0
    const/4 v0, 0x0

    goto :goto_0
.end method

My guess is the invoke-virtual {p1, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z would be a good place to pause since we’re checking if our input is correct. Sure enough, out pops the flag.

Flag

flag{Maybe_This_Obfuscation_Was_Not_That_Good_As_We_Thought}

Links

2015, polictf, writeup, reverse, android