bendera3 (re)

Challenge file

file was not able to tell what binary type this is:

❯ file bendera3
bendera3: data

So, I inspected the hexdump to see if there are any interesting values:

❯ xxd bendera3 | head
00000000: 7664 6578 3032 3700 0400 0000 0000 0000  vdex027.........
00000010: 3c00 0000 0400 0000 0100 0000 4000 0000  <...........@...
00000020: 702f 1d00 0200 0000 b02f 1d00 ab35 0000  p/......./...5..
00000030: 0300 0000 5c65 1d00 0440 0000 4c50 68a2  ....\e...@..LPh.
00000040: 6465 780a 3033 3700 07df b049 905c a902  dex.037....I.\..
00000050: 6299 7fe2 26a1 804c 9bfc e126 3480 c860  b...&..L...&4..`

Doing an online search, I see that this is related to Android Dex bytecode. There’s an extractor at anestisb/vdexExtractor and in particular this PR vdexExtractor#72 by IgorEisberg contains the patch needed to support vdex027.

So I checked out this branch, built the extractor, and extracted a bendera3_classes.dex.

❯ mkdir out
❯ vdexExtractor/bin/vdexExtractor -i bendera3 -o out
❯ ls out
bendera3_classes.dex

Then, I loaded this file into jadx-gui and got this p004my.wargames.mobile.bendera3.MainActivity class:

package p004my.wargames.mobile.bendera3;

import android.os.Bundle;
import android.support.p003v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;
import android.widget.Toast;

/* renamed from: my.wargames.mobile.bendera3.MainActivity */
/* loaded from: /Users/daniellimws/ctfs/wargames21/bendera/out/bendera3_classes.dex */
public class MainActivity extends AppCompatActivity {

    /* renamed from: wx */
    private static char[] f32wx = {'t', 'h', '1', 's', '-', 'i', '5', '_', '4', '_', 'k', '3', 'y'};

    /* renamed from: eT */
    private EditText f33eT;

    /* JADX INFO: Access modifiers changed from: protected */
    @Override // android.support.p003v7.app.AppCompatActivity, android.support.p000v4.app.FragmentActivity, android.support.p000v4.app.ComponentActivity, android.app.Activity
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(C0273R.layout.activity_main);
        final EditText editText = (EditText) findViewById(C0273R.C0275id.editText);
        editText.addTextChangedListener(new TextWatcher() { // from class: my.wargames.mobile.bendera3.MainActivity.1
            @Override // android.text.TextWatcher
            public void afterTextChanged(Editable editable) {
            }

            @Override // android.text.TextWatcher
            public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
            }

            @Override // android.text.TextWatcher
            public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
                if (MainActivity.m1cF(editText.getText().toString())) {
                    Toast.makeText(MainActivity.this, "Correct! Submit it!!", 0).show();
                }
            }
        });
    }

    public static byte[] hStB(String str) {
        int length = str.length();
        byte[] bArr = new byte[length / 2];
        for (int i = 0; i < length; i += 2) {
            bArr[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));
        }
        return bArr;
    }

    /* renamed from: cF */
    public static boolean m1cF(String str) {
        if (str.length() == 0) {
            return false;
        }
        if ((str.length() > 5 && !str.substring(0, 5).equals("wgmy{")) || str.charAt(str.length() - 1) != '}') {
            return false;
        }
        if (str.substring(5, str.length() - 1).equals(m0xx(f32wx, hStB(new StringBuilder("kxk1x4xxkx11O4TxkOc6xxb64Obxk1613xdxx1F11x9OT6Txd31xcOd1O1OOcO64").reverse().toString().replace("O", "0").replace("T", "7").replace("b", "8").replace("x", "5").replace("F", "f").replace("k", "e"))))) {
            return true;
        }
        return false;
    }

    /* renamed from: xx */
    private static String m0xx(char[] cArr, byte[] bArr) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bArr.length; i++) {
            sb.append((char) (bArr[i] ^ cArr[i % cArr.length]));
        }
        return sb.toString();
    }
}

From this snippet, we can tell that m1cF is used to check the flag:

            @Override // android.text.TextWatcher
            public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
                if (MainActivity.m1cF(editText.getText().toString())) {
                    Toast.makeText(MainActivity.this, "Correct! Submit it!!", 0).show();
                }
            }

The top part is easy to understand, just making sure the flag is in the correct format:

    public static boolean m1cF(String str) {
        if (str.length() == 0) {
            return false;
        }
        if ((str.length() > 5 && !str.substring(0, 5).equals("wgmy{")) || str.charAt(str.length() - 1) != '}') {
            return false;
        }

Then, it compares the contents in the wgmy{...} burrito with a string that gets reversed and undergoes some replacements.

        if (str.substring(5, str.length() - 1).equals(m0xx(f32wx, hStB(new StringBuilder("kxk1x4xxkx11O4TxkOc6xxb64Obxk1613xdxx1F11x9OT6Txd31xcOd1O1OOcO64").reverse().toString().replace("O", "0").replace("T", "7").replace("b", "8").replace("x", "5").replace("F", "f").replace("k", "e"))))) {
            return true;
        }
    }

We can just copy this whole thing into Python and run it to get the expected flag.

from pwn import xor
from binascii import unhexlify

aaa = unhexlify("kxk1x4xxkx11O4TxkOc6xxb64Obxk1613xdxx1F11x9OT6Txd31xcOd1O1OOcO64"[::-1].replace("O", "0").replace("T", "7").replace("b", "8").replace("x", "5").replace("F", "f").replace("k", "e"))

print(b"wgmy{" + xor(aaa, "th1s-i5_4_k3y") + b"}")

# wgmy{2d1c0edbc8bbfa5be3117a3ed9e6d637}