Proj 6x: Stealing Personal Data from the Staples Android App (20 pts + 20 pts. extra credit)

Summary

The Staples Android app stores the user's password with insecure encryption, because it uses a predictable password. It also uses Electronic Code Book mode, which preserves patterns in the input and is unsuited for protecting private data.

This is the #6 most important security flaw in mobile apps, according to OWASP.

Responsible Disclosure

I notified Staples about this on Jan. 2, 2017. I got an automated response saying it would be fixed, but they failed to reply to a follow-up email I sent on Feb. 16. On April 13, I decided to give up on Staples and publish this publicly.

Launch your Genymotion Android VM

Start Genymotion, and launch your Android virtual phone. Any version of Android 4.3 or later is fine.

Getting the App

I found this vulnerabilty in January 2017 and told Staples. They said they'd fix it but they never did. However, they did change the app on other ways and apktool can't rebuild it anymore.

So to make the project easier, we'll use the old app from January.

In the extra-credit portion, you can prove that the modern version of the app still has the same flaw.

Download this APK file:

app.staples-2.apk

Drag it and drop it onto your Genymotion phone to install it.

The Staples app launches, as shown below.

Creating an Account

In your virtual phone, at the top left, click the little head icon.

The Account page opens, as shown below.

Click "CREATE YOUR STAPLES ACCOUNT".

Fill in any email address and password, as shown below. Click the "CREATE ACCOUNT" button.

If your password is too simple, you may need to change it. I found that P@ssw0rd worked.

The Account page now shows that you are logged in, as shown below.

Examining the Locally Stored Password

On your host operating system, open a Terminal or Command Prompt window and move to the directory containing adb.

Here are common examples of SDK paths:

From that directory, open a shell on the Android device, as shown below.

NOTE: If you are using Windows, remove the "./" before "adb".

cd ~/Library/Android/sdk/platform-tools
./adb shell
cd /data/data/app.staples
grep -r Password .
exit
You see the "EncryptedPassword" string, in a file named shared_prefs, as shown below.

Local Password Storage Options

Storing the password locally is unwise and unnecessary. It would be far better to assign the user a randomly-generated token and store that.

If a password must be stored locally, it should be stored in the Android Keystore, as explained here:

Where is the best place to store a password in your Android app

The password can be recovered from the local store for this app, as detailed below.

Testing for ECB Mode

The encrypted password is a Base64-encoded binary blob. Its security depende on how it's encrypted, and how the key is handled.

One common error in cryptography is using ECB (Electronic Code Book) mode. In ECB, each block of cleartext encodes to a block of ciphertext without adding any varying "nonce" to it. This means that input with two identical blocks of cleartext will encode to identical ciphertext blocks.

Creating an Account with a Long Repeating Password

On your Android device, in the Staples app, click the little head icon at the top left.

At the top of the "Account" page, click Preferences.

In the Preferences screen, click the "Sign out" button, as shown below.

In your virtual phone, at the top left, click the little head icon.

In the Account page, click "CREATE YOUR STAPLES ACCOUNT".

Fill in any email address, and use this password, which is 32 "x" characters followed by "123A".

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx123A
and password, as shown below. Click the "CREATE ACCOUNT" button.

The Account page opens, showing your new email address at the top, as shown below.

Examining the Encrypted Password

On your host operating system, open a Terminal or Command Prompt window and move to the directory containing adb.

From that directory, open a shell on the Android device, as shown below.

NOTE: If you are using Windows, remove the "./" before "adb".

cd ~/Library/Android/sdk/platform-tools
./adb shell
cd /data/data/app.staples
grep -r Password .
exit
You see the "EncryptedPassword" string, as shown below.

Highlight the Base64 blob, as shown below, right-click it, and copy it into the clipboard.

Decoding the Base64 Blob

In a browser, go to this page:

http://tomeko.net/online_tools/base64.php?lang=en

In the "Base64 string" field, paste in the blob you copied from the Android device.

Click the Convert button to decode this blob to a hexadecimal string, as shown below.

Highlight the "Decoded data (hexadecimal)" field and copy it to the clipboard.

Paste it into a text editor so you can examine it.

Resize the text editor to prove that the first 32 characters are repeated, as shown below.

Saving a Screen Image: Image A

Make sure you can see two identical lines of 32 characters, as shown above.

Save a full-desktop image. On a Mac, press Commmand+3. On a PC, press Shift+PrntScrn and paste into Paint.

YOU MUST SUBMIT A FULL-SCREEN IMAGE FOR FULL CREDIT!

Save the image with the filename "YOUR NAME Proj 6xa", replacing "YOUR NAME" with your real name.

Examining the Smali Code

We now know that the encryption uses ECB mode, but we don't yet know the algorithm or what the key is.

To find out, we'll examine the source code.

Disassembling the APK with apktool

You should already have apktool. If you don't, get it here:

https://connortumbleson.com/2017/01/23/apktool-v2-2-2-released/

Save the file in the same folder you used for the Staples APK file you downloaded previously, such as Downloads.

Open a Command Prompt or Terminal.

Change directory to the location you placed the downloaded file and open it with java, as shown below.

cd Downloads

java -jar apktool_2.2.2.jar d app.staples-2.apk

Messages appear as apktool disassembles the app, as shown below.

Searching the Code with Grep

Execute these commands to move into the app's directory and search for interesting code:
cd app.staples-2
grep -r encryptedPassword .
As shown below, only one file contains this string: the /smali/app/staples/mobile/cfa/k/e.smali file.

Viewing e.smali

Open that file in a text editor.

Find the code shown below and notice these features:

Viewing the gu() function

In the e.smali file, find the code shown below. This is key generation routine.

This code simply finds five strings and appends them together. Here are the five strings it uses, as shown below.

Viewing the Lapp/staples/mobile/cfa/k/a;->m() Function

In a text editor, open the staples/mobile/cfa/k/a.smali file. Find the code shown below.

This function calls the Lapp/staples/mobile/cfa/k/a;->b() function, as shown below.

Viewing the Lapp/staples/mobile/cfa/k/a;->b() Function

In the staples/mobile/cfa/k/a.smali file, scroll up to find the b() function, as shown below.

Notice these two features, as shown below.

Viewing the Lapp/staples/mobile/cfa/k/a;->M() Function

In the staples/mobile/cfa/k/a.smali file, scroll up to find the M() function, as shown below.

Notice these two features, as shown below.

Adding Trojan Code to the App

In the staples/mobile/cfa/k/a.smali file, make these two changes in the M() function, as shown below.

First, change ".locals 3" to ".locals 4"

Then insert these lines before the 'const-string v1, "UTF-8"' line:

# EVIL TROJAN   
const-string v3, "TROJAN: Encryption String: " 
invoke-static {v3, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I 
# END OF EVIL TROJAN CODE

Rebuilding the App

Execute this command:
java -jar ../apktool_2.2.2.jar b .

Making a Self-Signed Certificate

You should already have a certificate from previous projects, but if you don't, make one with this command:
keytool -genkey -keyalg RSA -alias selfsigned -keystore YOURNAME-keystore.jks -storepass password -validity 360 -keysize 2048

Re-Signing the APK

Execute this command:
jarsigner -keystore YOURNAME-keystore.jks dist/* selfsigned
When you are prompted to, enter the key store password of password

Uninstalling the Original App

On your Genymotion virtual Android device, tap the envelope-shaped button at the bottom center to get to the Home screen.

Tap the circle at the bottom center.

Tap Settings.

Tap Apps.

Tap Staples.

Tap Uninstall.

Tap OK

Monitoring the Log

Open a new Terminal window and execute these commands, adjusting the first command to move to the directory containing adb on your system:
cd ~/Library/Android/sdk/platform-tools
./adb logcat | grep TROJAN

In the Staples app, log in or create a new account

The log shows the encryption string, as shown below.

Highlight the entire string and copy it to the Clipboard.

Saving a Screen Image: Image B

Make sure you can see the encryption string, beginning with 3xtraS@lt, as shown above.

Save a full-desktop image. On a Mac, press Commmand+3. On a PC, press Shift+PrntScrn and paste into Paint.

YOU MUST SUBMIT A FULL-SCREEN IMAGE FOR FULL CREDIT!

Save the image with the filename "YOUR NAME Proj 6xb", replacing "YOUR NAME" with your real name.

Generating the AES Key

In a Web browser, go to

http://www.sha1-online.com/

Paste in the encryption string, as shown below.

Click the hash button.

The SHA-1 hash appears, as shown below. This hash is 160 bits long, but an AES key is only 128 bits long.

Carefully highlight the first portion of the hash, omitting the last 8 hexadecimal characters, as shown below, and copy that to the Clipboard.

Encrypting your Password

In a Web browser, go to

http://aes.online-domain-tools.com/

In the "Input text" field, enter your password of

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx123A
In the Key field, paste in the hexadecimal key you copied from the SHA-1 hash.

Below the Key field, click the Hex box.

Click the Encrypt button. The encrypted text at the bottom shows the hexadecimal values of the encrypted text, as shown below.

Comparing to the Previous Encrypted Value

Look at the image you captured as image A above. The encrypted hexadecimal data should match the data you got by Base64-decoding the stored data on the phone. This means that we have completely cracked the Staples encryption system.

Extra Credit: Steal My Partial Credit Card Number (20 pts. extra credit)

You have now completed the required part of the project.

To get extra credit, use the information below to hack into my account and steal my stored credit card number. You'll only get the type of card and the last 4 digits. Send in an image with the correct credit card information to get credit.

I used the latest version of the Staples app, on a much more modern device running Android 7.0.0, to generate this data. The fact that the same process works proves that Staples has not changed their encryption method at all.

/data/data/app.staples/shared_prefs/com.staples.mobile.cfa.xml File

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<long name="locationTimestamp" value="0" />
<string name="wcToken">2191966755%2Col7HhTWcNrvTx8c2sB%2Fd3G5sBjKxGQBUiKImRY2dkkfSQ2ZrrOz21VbMrzpeZODRi4PfDicLaqAoyeyWpFZawQiaU8s4O90PUdlD6HtFd%2B%2B3%2FChSYygb4LQEUSTJkAW2rcI0C6a9R2glIjypffeM5kmPHTZjBz%2FcHqi9NavHhuyM3M%2B%2Bj4Wyco78w7CKrSH87yQfeMp8WrOqCr42dOHw5g%3D%3D</string>
<string name="postalCode">01702</string>
<string name="username">proj6x@mailinator.com</string>
<float name="locationLongitude" value="-71.4889" />
<boolean name="preferredLocationFlag" value="true" />
<float name="locationLatitude" value="42.291313" />
<string name="encryptedPassword">YHjpLAbxAgCMaIHKouN0pc1yis5dbNSwqlA9+cwAYww=</string>
<string name="wcTrustedToken">2191966755%2CFXIocQ9oyLIotOVQH2rnWaTz6kw%3D</string>
<string name="locationProvider">Default</string>
</map>

Device Information

Sams-MacBook-Pro-3:platform-tools sambowne$ ./adb shell
vbox86p:/ # getprop ro.product.brand
Android
vbox86p:/ # getprop ro.product.device
vbox86p
vbox86p:/ # getprop ro.product.model
Google Nexus 9 - 7.0.0 - API 24 - 1536x2048
vbox86p:/ # getprop ro.product.serial

vbox86p:/ # exit
Sams-MacBook-Pro-3:platform-tools sambowne$ 

Turning in your Project

Email the images to to cnit.128sam@gmail.com with the subject line: Proj 6x from YOUR NAME
Posted 5-17-17 by Sam Bowne