Threat Research

InsomniDroid Part 2 - Write-Up

By Axelle Apvrille | April 04, 2015

Insomni'hack's CTF included iOS challenges, but also an Android challenge in two parts.
The write-up of part 1 of the Android challenge can be found on SCRT's blog. It is quite complicated, but in the end, we get a decrypted filesystem with the flag for part 1, and an Android application to investigate for part 2 (download)

87f10242d7662a9cf8158bd85e4a17df9279a961f1d2a2e469cfd1be5501bfa1  ch.scrt.insomnidroid-1.apk

According to the text of part 2, we are meant to find a way to buy movies without paying.

The applications launches gracefully on an Android emulator, although this is indeed absolutely useless to solve the challenge, as we'll see.

Let's inspect the Android applications. There are several tools to disassemble an Android applications, for example apktool, baksmali. I used JEB, but any disassembler/decompiler will do.

In, we spot a method FillCreditCard():

 private void FillCreditCard() {
        try {
            this.getCreditCardDao().create(new CreditCard("Britney Spears", "wDwf0L7NYrIYA9uSYkI8Cg==$K5vP4xZBf2XDsaDwlOo9OA==$3nQg4MImOaPN9ElYxw6UvQ=="));
        catch(SQLException v1) {

Britney is the nickname of the person who created the challenge, so this is particularly interesting. Next to the name, we recognize a Base64 encoded string.
We have a look at the CreditCard object constructor:

 public CreditCard(String name, String encrypted) {
        super(); = 1; = name;
        this.number = encrypted;

So, "Britney Spears" is the name indeed, and the second string corresponds to an encrypted number. Hmm. Perhaps an encrypted card number?
The class also has a method called getDecryptedNumber(), which looks like it will decrypt the encrypted credit card number if provided with the correct pin code:

 public String getDecryptedNumber(String pin) {
        String v0 = !this.validatePin(pin) ? null : Security.decrypt(pin, this.number);
        return v0;

So, we navigate to Security.decrypt (located in
The encrypted card number is split into 3 chunks separated by $.
The first part corresponds to the ciphertext, the second part to the crypto initialization vector (IV) and the last part to a salt.

The decrypt method derives an AES key from the pin code and the salt, using PBKDF2 with HMAC-SHA1.
Then, the ciphertext is decrypted with AES-CBC, using the key and IV.

We adapt the challenge's code to a standalone program to decrypt the card number:

public static String decrypt(String pin, String ciphertext) {
    String result = null;
    String [] sp = ciphertext.split("\\$");
    byte [] ct = Base64.getDecoder().decode(sp[0]);
    byte [] iv = Base64.getDecoder().decode(sp[1]);
    byte [] salt = Base64.getDecoder().decode(sp[2]);
    try {
        SecretKeySpec sks = Challenge.deriveKey(salt, pin);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(2, ((Key)sks), new IvParameterSpec(iv));
        result = new String(cipher.doFinal(ct), "UTF-8");
    catch(Exception exp) {
        System.out.println("An exception occurred: "+exp.toString());
    return result;

Note this code requires Java 8's Base64 class.

In the Android challenge part 1, the pin for the encrypted partition was 1970, so we naturally try this pin but fail with an exception:

An exception occurred: javax.crypto.BadPaddingException: Given final block not properly padded

Arg! We double check our code and the input strings, but everything is correct, so maybe 1970 is not the right pin code.

In the Storage class, we check the validatePin() method. It explicitly states the expected pin code is 4 digits:

 private boolean validatePin(String pin) {
        boolean v0 = false;
        if(pin.length() == 4 && (pin.matches("\\d+"))) {
            v0 = true;
        return v0;

Good! This is easy to brute-force: we are going to attempt to decrypt the encrypted card number with pin codes from 0000 to 9999.

    for (int pin=0; pin < 10000; pin++) {
        String cardnumber = Challenge.decrypt(String.format("%04d", pin),
        if (cardnumber != null) {
        System.out.printf("Pin: %04d - Credit card number: %s\n", pin, cardnumber);

And the output quickly yields the result:

Pin: 1336 - Credit card number: 373601533586263

The Android application redirects to hxxp://mobile.insomni.hack (now offline). We enter that credit card number and retrieve the flag :)
I found part 2 far easier than part 1...

-- the Crypto Girl


Join the Discussion