Is this real crypto

Aperi'CTF 2019 - Mobile (100 pts).

Aperi’CTF 2019 - Is this real crypto

Challenge details

Event Challenge Category Points Solves
Aperi’CTF 2019 Is this real crypto Mobile 100 12

Encore un système d’authentification client-side révolutionnaire :)

Fichier : chall.apk - md5sum: 66a5f2667a9210927684d188b83d94fd

Methodologie

La difficulté de ce chall dépends de la version et du décompilo que vous utilisez pour faire ce chall :) ( je sais c’est méchant, mais faut utiliser des outils à jour ). Le Write Up suivant se fera sur la version “compliquée”

Premier approche de l’application

En ouvrant l’application dans Jadx, on voit une simple mire de login qui prend en entrée l’username et le password de l’utilisateur.

En dessous le code de validation (/!\ Je rapelle que ce challenge dépends du décompileur utilisé /!):

MainActivity.this.checkPassword(MainActivity.this.username.getText().toString().getBytes(), MainActivity.this.password.getText().toString().getBytes(), "a1b2c3d4e5f601234abcdef".getBytes());

...

   private void checkPassword(byte[] username, byte[] password, byte[] iv) throws Exception {
		AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
		SecretKeySpec newKey = new SecretKeySpec(password, "AES");
		Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
		cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
		password = cipher.doFinal(password);
		this.random = "1234567890abcdefgh".getBytes();
		isValid(this.random ,password,"a56c789b23d1908276351726380028387".getBytes());
	}

	public void isValid(byte[] random, byte[] password, byte[] iv) throws Exception {
        for (int i = 0; i < password.length; i++) {
            password[i] = (byte) (((password[i] ^ iv[i]) ^ this.random[i]) & 255);
        }
        boolean found = true;
        byte[] cipher = hexStringToByteArray("6f076a2a782e79225e2e743639053f2d28697a7c672d36");
        for (int i2 = 0; i2 < cipher.length; i2++) {
            if (password[i2] != cipher[i2]) {
                found = false;
                break;
            }
        }
        if (found) {
            Toast.makeText(this, "You can validate with APRK{<password>}", 1).show();
            return;
        }

On remarque vite que le challenge est insolvable cryptographiquement parlant (ou difficilement).

Le nom Is this real crypto peut également nous mettre sur la voie, il y a carabistouille.

Détecter l’obfuscation

En passant à plus bas level avec ApkTool, on s’aperçoit assez rapidement de la supercherie : une partie du code ci-dessus n’existe pas en réalité et a été introduit dans l’application comme nom de paramètre.

    .param p1, "username, byte[] password, byte[] iv) throws Exception {\r\n\t\tAlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);\r\n\t\tSecretKeySpec newKey = new SecretKeySpec(password, \"AES\");\r\n\t\tCipher cipher = Cipher.getInstance(\"AES/CBC/PKCS5Padding\");\r\n\t\tcipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);\r\n\t\tpassword = cipher.doFinal(password);\r\n\t\tthis.random = \"1234567890abcdefgh\".getBytes();\r\n\t\tisValid(this.random ,password,\"a56c789b23d1908276351726380028387\".getBytes());\r\n\t}\r\n\r\n\tpublic void isValid(byte[] random"    # [B

Solution

Il ne reste plus qu’a retirer la partie superflue et le chall est plutôt simple à résoudre, un triple xor :).

private void checkPassword(byte[] username,  byte[] password, byte[] iv) throws Exception {
        for (int i = 0; i < password.length; i++) {
            password[i] = (byte) (((password[i] ^ iv[i]) ^ this.random[i]) & 255);
        }
        boolean found = true;
        byte[] cipher = hexStringToByteArray("6f076a2a782e79225e2e743639053f2d28697a7c672d36");
        for (int i2 = 0; i2 < cipher.length; i2++) {
            if (password[i2] != cipher[i2]) {
                found = false;
                break;
            }
        }
        if (found) {
            Toast.makeText(this, "You can validate with APRK{<password>}", 1).show();
            return;
        }
        EditText editText = this.username;
        String str = BuildConfig.FLAVOR;
        editText.setText(str);
        this.password.setText(str);
    }

Flag

APRK{a_little_jadx_fooling!!}

Appendix

De ce que j’ai relevé, l’injection est effectif sur certaines versions non à jour de jadx et jadx-gui , les décompilers en ligne l’utilisant sont également affectés.

Areizen