Authors: Tianfang Guo, Jinjian Zhai, Allan Zhang
“When you do not have the means to attack your enemy directly, then attack using the strength of another. Trick an ally into attacking him, bribe an official to turn traitor, or use the enemy’s own strength against him.”
– “Kill with a borrowed sword”, Thirty-Six Stratagems, Sun Tzu
After showing the “master key” and “FakeID” vulnerabilities in Android’s signature verification, today we demonstrate a new vulnerability. This was first discovered by Alibaba’s security team and disclosed at BlackHat Mobile Security Summit 2015.
In this article we will highlight one of the major vulnerabilities in Android signature verification, and demonstrate a new way to exploit this vulnerability- “To kill with a borrowed sword.” Namely, getting AntiVirus software to remove an innocent target app.
Android’s signature mechanism
Android is decentralized not only in its system, but also in its app distribution. To ensure an app’s integrity and traceability, Android enforces that all apps must be signed by the developer’s’ private key. After being signed, an app will be linked to the developer with that developer’s public key (or certificate). Thus, any changes in the package will result in signature verification failure and rejection upon installation.
The signature verification process is shown in the figure above. Each file in the package will generate a digest using the SHA-1 hash function. Afterwards, they will be encrypted by the developer’s private key and put into the certificate file (ended with .RSA or .DSA depending on the public key algorithm). Without the developer’s private key, nobody could forge or modify any file.
SHA1 digests for the files in CERT.SF file in the META-INFO folder.
There is a loophole in the Android’s signature mechanism: any file containing the APK file’s digest can not also be included in the file digest list.
This is obvious: it’s difficult to generate a file containing its own SHA-1 hash. In other words, finding a hash(AB) = A is undoable. So the digest summary file, CERT.SF, cannot contain its own SHA1 digest.
Let’s look in detail about how Android handles this dilemma:
Any file ending with .SF, .DSA, .RSA or .EC, and those in the META-INFO folder, will be ignored when verifying the signature. That gives attackers a chance to put arbitrary files into the package without breaking the signature verification.
To launch an attack:
1. Prepare a malware file (e.g. the EICAR malware test file which can be identified by most AntiVirus vendors), and the APK you would like the AVs to remove.
2. Unzip the APK, put the malware file into the META-INFO folder, and zip it back. Due to the vulnerability, you now have a APK file which contains malware components, yet one that can still be identified as legit by the certificate verification.
3. Replace the original APK on the user’s phone. You need a 3rd party app to download the repacked APK from the Internet, and fool the user with an “upgrade notification”. Then the upgrade activity should be launched by the new Intent:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(“[repacked APK path]")), "application/vnd.android.package-archive");
Even when the version of the repackaged APK is the same as the original APK, the repackaged one can still replace the original one.
4. Additional Attack: If the repacked APK is uploaded to Android app vendors, it will be identified as written by the original developer instead of repackaged by an attacker. If the designated Android market scans viruses before publishing, the original developer might be put in trouble because the repackaged app signed by their certificate contains malware (namely, the EICAR malware testing file).
The Proof of Concept video can be found in the link below, where the genuine ‘Angry Birds 2’ app is replaced by the repackaged app containing malware. Then the McAfee Anti-Virus software – with its signature based detection – identified it as malware:
To fix it
To fix this vulnerability, the digest files cannot simply be skipped when calculating the digest – at least not skipped by file extension or folder name. To solve the self-digest conflict, here is a simple idea: fill the self-digest with 0x00 before calculating the SHA1 of CERT.SF files:
Through this approach, no file would be ignored: every file would be verified against the digest list. Any new file additions would cause an authentication error.