Crypto Wallet Local Storage Attack

Background

During our mobile security pen testing, we have found a very interesting attack scenario in (Android application). The attack can lead the user to unknown changes contents of their inheritance from the rooted device, for example, their crypto wallet address had been changed to the attacker’s address. This could lead to a security hazard because the user cannot double-check the long strings of the address placed in the wallet. Or another scenario is the attacker just need to change the favourite contact address to their own address, thus, every time the victim sends their money to their fellows whom already assigned in the contact list while their fellows’ address has already been changed to the victims’ address.

In this case, we have implemented the research on an Android phone (8.1). The crypto wallet application is “unknown”. We were trying to change the contact’s address and research further if we could also change the owner Etherium, Bitcoin and other crypto addresses. We realized that changing owners’ address is more dangerous than fixing contacts’ address because the owner usually does not care about their own address but re-checking recipients’ address is necessary. We all know that IOS device is much harder to jailbreak as well as the percentage of successful rooting it is quite low, it also takes time as well. For an Android device, it is much more straightforward and does not take a long time to make it root. Therefore, borrowing a friend’s phone in 2-3 hours, or even you lost your phone in during the time is really dangerous if you are using any crypto wallet. Why it’s too dangerous?

Ethereum addresses are composed of the prefix "0x", a common identifier for hexadecimal, concatenated with the rightmost 20 bytes of the Keccak-256 hash (big endian) of the ECDSA public key. In hexadecimal, 2 digits represent a byte, meaning addresses contain 40 hexadecimal digits. One example is 0xb794F5eA0ba39494cE839613fffBA74279579268 [1]

Given an Ethereum address like afore example, 0xb794F5eA0ba39494cE839613

fffBA74279579268. We probably need to learn it by heart to memorize, unlikely the normal users do not pay too much attention to memorizing their own address. The address created by the application that they trust. When the address gets changed, the user shows their QR code generated from the changed address (attacker’s address). Once the QR code has been scanned by other people, nothing can stop it.

This yellow paper will be writing up about the “legal experiments crypto wallet attack” during the research, indicating how dangerous if you lose your mobile phone that has a crypto wallet installed, and also describing the solutions in order to mitigate the attack by following the security best practice and our experience in the field.

The paper is just for educational purpose only, we are not responsible for any loss or damage.

Understanding Android File Structure

Android provides several options for you to save your app data. The solution you choose depends on your specific needs, such as how much space your data requires, what kind of data you need to store, and whether the data should be private to your app or accessible to other apps and the user.

This page introduces the different data storage options available on Android:

  • Internal file storage: Store app-private files on the device file system.

  • External file storage: Store files on the shared external file system. This is usually for shared user files, such as photos.

  • Shared preferences: Store private primitive data in key-value pairs.

  • Databases: Store structured data in a private database.

Except for some types of files on external storage, all these options are intended for app-private data—the data is not naturally accessible to other apps. If you want to share files with other apps, you should use the FileProvider API. [2]

By default, files saved to the internal storage are private to your app, and other apps cannot access them (nor can the user, unless they have root access). This makes internal storage a good place for internal app data that the user doesn't need to directly access. The system provides a private directory on the file system for each app where you can organize any files your app needs.

When the user uninstalls your app, the files saved on the internal storage are removed. Because of this behaviour, you should not use internal storage to save anything the user expects to persist independently of your app. For example, if your app allows users to capture photos, the user would expect that they can access those photos even after they uninstall your app. So you should instead save those types of files to the public external storage.[2]

This is an example of a data/data installed “unknown” package.

Attacking Rooted Device

Install a cyrpto wallet app names “unknown”. Open the app and create the new wallet, after creating it successfully, you will receive your Ethereum address as other crypto money such as BTC, EOS,..etc. As shown in the picture below, the ETH address is created along with its QR code. If you scan this QR by using another mobile phone, you will get the ETH address in the plain text. Regarding the QR code vulnerability, beware if you are using the open-source QR library. Unforeseen failures could happen at any time, a massive amount of money could lose if the QR code generates a wrong character, remember regardless of giving just “01” wrong character in the address, your money will go away!!!. Thus, making the best use of EIP55 that will truly help to ensure that the ETH address is generated properly.

So in this case, the QR is generated based on the ETH address given by the app. The QR code will be changed every time the address gets changed. Therefore, if the attacker can change your ETH address, your QR code will probably be made up to another one.

The address is shown afore picture is the original ETH address created by the wallet. This is the original address aka intact one. Your friend now is named “attacker”, the attacker will borrow your phone for 2,3 hours, or whatever way to have your phone. Now they proceed to change your ETH address to their ETH address.

From now, they start shooting it. To change the address, they need to go to the sandbox area where normal users are restricted. Rooting device is the first step they are forced to do to reach that restricted area. (I will not show you how to root an android device, google it!)

Enable entire needed modes to get ADB working, the attacker is able to dig into the data/data/unknown directory

There are 4 places the attacker might pay attention to which are files, cache, databases, shared_prefs.

The attacker starts looking for the file where the ETH address resides, by using some grep command or other Linux command lines, the ETH address can be found straightforwardly. The data in sandbox are stored in many different ways, whether in plaintext in an xml file, a sqlite3 database with encryption/plaintext, binary file, ..etc. (more detail). Therefore, it takes time to find the exact place where the owners’ address stored. For the example below, plaintext data is introduced.

Navigate to shared_prefs

Grep the ETH address to find its location and analyze it to assure that it derives from owner ETH address

The data gives the attacker some consciousness by analyzing it. Given btcAddress":"1Mnp53qKYzhpwVez2JowRkW1tnNJJTSQ7N" this could be meant BTC address is 1Mnp53qKYzhpwVez2JowRkW1tnNJJTSQ7N. Similarly to others eosAddress":"EOS7kukYEfL5KrC8XcB46E8cxWeBP8ciQbt9qQq4G92fP9dhXX9ZH", Or ethAddress":"0xaC04fAc67fd509d2dCD380edb5A3B784ca03d9C2"

Thus, the attacker just needs to change this address 0xaC04fAc67fd509d2dCD380edb5A3B784ca03d9C2 to their ETH address (ETH address is chosen for this research, they can change other crypto addresses as well)

Changing the data inside the sandbox is not efficient, this could break files system and lead to “unknown wallet has stopped, send bug report to….”. To avoid this, the attacker copies the file to sdcard where external storages are defined, then using ADB pull to pull it back to their own local computer and edit the file without any restrictions.

$ cp wallet_info_sp.xml /mnt/sdcard/

On their local computer terminal

$ adb pull /mnt/sdcard/wallet_info_sp.xml /home/attacker/unknown/

Now, the attacker is able to edit the file as they desire. Their objectives is to change their friends’ ETH address to their (attacker) address. The attackers’ address: 0x587Ecf600d304F831201c30ea0845118dD57516e

The address has been changed, he/she just needs to push it back to sdcard then copy it to shared_prefs.

$ cp /mnt/sdcard/wallet_info_sp.xml /data/data/unknown/shared_prefs

To ensure the app will run as expected, the wallet_info_sp.xml file permissions are set correctly as well as the owner, groups,..etc. Otherwise, the application will stop and the error will pop up.

Open the app after editing the ETH address successfully, the attacker ETH address has been replaced.

The attacker uses another QR code reader application to verify if the QR code on the wallet has been changed along with its address.

And it matches!

For other examples, storing the address in a database or binary file is often used. But it is not sufficient to prevent the attack regardless of storing them in a database. Two cases will be shown and describing how the attacker exploit them.

The picture above shows the data is written in binary format saved in default.realm.

Use the “strings” command to read the data in plaintext.

The attacker is able to grep the ETH address by combining with strings

Again, in order to be able to edit the file. The attacker needs to repeat the steps of copying the file to /mnt/sdcard/, then pull them back to the local computer. The ETH address is still the main target 0x69759fed0a72cc…..

The attacker cannot change the data in plaintext by using any text editors because the binary file does not allow to do, or even if any possbility, the file would be broken down. They use “hexdump” command. Hexdump is a command-line tool used to show the raw bytes of a file in various ways including hexadecimal, available on Linux, FreeBDS, OS X, and other platforms.[3]

$ hexdump -C default.realm | less

By using the hexdump command, the attacker is now able to determine the ETH address written in binary. The original ETH address is 0x69759fed0a72cc6ed5 79352f2da517c1fdfbce4d . The attacker tries to change from 0x69759f to 0x69789a (the actual attack will surely change the entire address). But in this case, the example describes how to make a change (not fully attack).

From the afore picture, 0x69759f is “30 78 36 39 37 35 39 66” in binary. Thus, 0x69789a is “30 78 36 39 37 38 39 61”. (38 → 8, 61 → a)

$ sed -i "s/\x30\x78\x36\x39\x37\x35\x39\x66/\x30\x78\x36\x39\x37\x38\x39\x61/g" default.realm

The address gets changed, the attacker just needs to push it back to the previous place in the sandbox where the ETH address assigned.

In conclusion, there are many ways, may scenarios the attacker can exploit the local storage to find out where the address stored in, internal or external enclaves. Changing friends’ contact address is a quintessential example. Abusing the trust between the owner and the application, additionally the long string of crypto addresses, it’s linked to the fact the the typical users never pay attention to their own address, especially when they show their QR code to others.

Protection

To be honest, we still do not know what is the best method to prevent or mitigate this kind of attack, we are still working on it. Give your phone away at friends’ home or you lose your phone accidentally, for these situations, setting the passcode for your phone is not fully protective because many other phones are rooted easily without prompting the passcode.

If you are crypto-wallet developers, I highly recommend you to put owners’ address onto the database with encryption by combining owners’ password. Moreover, I’ve seen many secure wallet applications, the owners’ address is created every time the “receive” function called. Which means if the attacker had changed the owners’ address,the next time the owner navigates to the “receive” function, the adddress gets generated again to replacing the attackers’ address, this happens when they use database-sqlite3.

For friends’ contact address attack. This is much more difficult to prevent because it’s independent data, meaning it does not belong to the app or be generated by the application. Encryption might work in this case, by combining sqlite3 and users’ password could be helpful to prevent the change. Again, we are still working on this, thus if you think of other solutions, please navigate to enderlocphan@gmail.com to have further discussion and make our wallet safer.

Last updated