Android Penetration Testing

Android Penetration Testing: APK Reversing (Part 2)

Android reverse engineering refers to the process of decompiling the APK to investigate the source code that is running in the background of an application. In part 1 (refer here), we saw how an attacker would be able to decompile, change the small files, and recompile and sign the APK to perform some kind of function, for example, changing root detection logic of the application. In this extension of reversing articles on APK Reversing for Android Penetration Testing, we’ll see different scenarios in which an attacker can extract juicy information by decompiling an APK while understanding various default files present in Android. It is wrong to say this article covers all of the aspects of reversing and extracting info, however, it will lay out a fundamental process as to how one can proceed to do so. Let’s begin

Table of Content

  • Understanding default files
  • Understanding improper WebView implementation
  • Hardcoded secrets
  • Secrets in strings.xml file
  • Insecure classes implementation
  • Insecure decryption method for hardcoded values
  • Insecure cryptography in SQLite database
  • Hard coded AWS credentials

Understanding default files

AndroidManifest.xml

“Manifest” literally means “to show.” This file is the most literal in the entire application because it does exactly what its name implies. A tag is used at the start. Additionally, “xmlns: attribute”, which declares a number of system attributes utilized in the file, should be included. It states:

  • <permissions> – Permissions that APK requires to run
  • <activity> – Various activities in the APK
  • <intent-filter> – Intent filters
  • <data android:scheme=”string” /> – Data Schemes
  • <action android:name=”string” /> – Action that an intent performs
  • <uses-configuration> tag – specifies input mechanisms
  • <uses-sdk> tag – specifies android API to be used

Hence, Manifest file is the guide which is needed by the package to make particular components behave the way the developer intended them to.

Strings.xml

This XML file holds strings that the application or other resource files (such as an XML layout) can reference. In other words, I can use a reference to strings’ object in my actual Java class so that I don’t have to type in the complete value then and there and also if there is a need to change that value in future, I won’t need to go to my java class every single time to change it, I can just change the value in the strings file. One example occurs in the Java file where the code flows like this:

String string = getString(R.string.hello);

 Here, R.string.<string object> sets the value of variable string. I can make its reference in the layout file like this:

<TextView
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”@string/hello” />

This sets the type of view that the hello object would have while displaying in app. Here, @string/hello refers to strings.xml file’s hello object. So, finally in the strings.xml file code would be something like:

<?xml version=”1.0″ encoding=”utf-8″?>
<resources>
<string name=”hello”>Hello!</string>
</resources>

So, the variable string would indirectly get assigned a value “Hello!” Note that <resources> tag allocates a string value.

R.java file

AAPT (Android Asset Packaging Tool) automatically generates a file that contains resource IDs for all the resources in the res/ directory. When you create any component in the activity_main.xml file, this file automatically generates the id for the corresponding component. You can use this id in the activity source file to perform any action on the component. If you delete this, the system will auto-generate it again.

There are various other default files as well, we’ll talk about them later when we discover each.

Understanding improper WebView implementation

If you have no idea what a WebView is please first read this article. This will lay up your basics. Now, this article specifically talks about what code to look for in order to understand if webview implementation is insecure or not. Now, for the purpose of this article, I’ll be using InjuredAndroid.apk developed by Kyle Benac. You can find it here. It would look something like this

APK Reversing for Android Penetration Testing

In the very first challenge of the application, we’ll see a poor webview implementation. First activity’s source code is:

Here, we can see that a string type variable post is receiving a value from an input field and supplying it to DisplayPostXSS.class using intent. We’ll understand what happens when it reaches the said class from the source code:

Here, we can easily see that the said input is getting parsed as an HTML and being displayed within a webview. Also, JavaScript is enabled. This means only one thing for us researchers. XSS!

APK Reversing for Android Penetration Testing

After sending in the payload we can see that WebView is able to display the supplied input in an HTMl format like this

Hence, this taught us how we can look for XSS bugs by decompiling the application

HardCoded Secrets

Oftentimes, for ease of access developers would hard code various secret keys, decryption functions and other juicy things within the application and so by reversing the APK we can extract them. For example, if we see FlagOneLoginActivity developer has laid out a little hint at the bottom.

APK Reversing for Android Penetration Testing

Now, let’s reverse the application using JADX and see what’s hidden under GUI. Even after obfuscation, we can easily infer that the submitFlag() method compares a user-supplied input with the given flag “F1ag_0n3”. Hence, we bypass the entire login mechanism just by looking for the right class after reversing.

After we input the flag, we see that it was indeed correct.

APK Reversing for Android Penetration Testing

Secrets in strings.xml file

Oftentimes, developers create a reference string and use that object in Java class whose actual value is stored in strings.xml file. For example, in FlagThreeActivity we can see the developer has laid out a little hint at the bottom.

Now, let’s look at this activity’s code in jadx first. We’ll observe that an object with a gibberish name is being used.

It is quite easily understood that user-supplied input is being compared with a resource that is stored in strings.xml file. Hence, what we’ll do is decompile the package using apktool and then traverse to the directory: /res/values/strings.xml

apktool d InjuredAndroid-1.0.10-release.apk
cd InjuredAndroid-1.0.10-release/res/values
cat strings.xml | grep cmVz

Hence, we have our third flag.

Insecure classes implementation

Just like you can refer to an object from the strings.xml file, you can also implement other classes to perform a specific function with an object and use its return value. For example, in the FlagFourActivity, we see something similar.

Now, after observing the code underneath the class we see that return value from a certain g class’ a() method. Now, due to obfuscation the original classes and methods names have been changed.

APK Reversing for Android Penetration Testing

Pondering over g.a() we’ll see that a base64 encoded value is being decoded and supplied as an input and typecasted in a byte array.

Finally, after encoding this, we’ll get this flag.

echo "NF9vdmVyZG9uZV9vbWVsZXRz" > to_decode
cat to_decode | base64 --decode

Insecure decryption method for hard coded values
Oftentimes, developers implement methods to generate keys and encrypt some information that they either receive from a user or encrypt a secret such as login credentials within the application. For example, in FlagSixLoginActivity, we can see that a certain k.a() return value compares with a user input.

This gibberish value is a base64 encoded byte array. Now, we are going to inspect k.a() method.

APK Reversing for Android Penetration Testing

This certainly implies that a is receiving string str, which is getting base64 decoded first and then encrypted using a DES key generated. Reversing this function manually in very difficult, but it is certainly possible if we intercept the () method’s return value when it calculates and supplies the value to FlagSixLoginActivity. Kyle Benac has given a code in his repository to do this with javascript using Frida. Here is the code:

console.log("Script loaded successfully ");
Java.perform(function x() {
console.log("Inside java perform function");
var my_class = Java.use("b3nac.injuredandroid.VGV4dEVuY3J5cHRpb25Ud28");
var string_class = Java.use("java.lang.String");
my_class.decrypt.overload("java.lang.String").implementation = function (x) { //hooking the new function
console.log("*************************************")
var my_string = string_class.$new("k3FElEG9lnoWbOateGhj5pX6QsXRNJKh///8Jxi8KXW7iDpk2xRxhQ==");
console.log("Original arg: " + x);
var ret = this.decrypt(my_string);
console.log("Return value: " + ret);
console.log("*************************************")
return ret;
};
Java.choose("b3nac.injuredandroid", {
onMatch: function (instance) {
console.log("Found instance: " + instance);
console.log("Result of secret func: " + instance.decrypt());
},
onComplete: function () { }
});
});

Pretty easy to code this right? No? Then you must follow my previous article on Frida here to understand how to create hooks in a better way.

Insecure cryptography in SQLite database

Oftentimes, juicy information is obtained from an application’s SQLite database. This happens because the developer has stored some values like credentials, keys etc. within the sqlite itself. Let’s look at one such implementation in FlagSevenSqliteActivity

APK Reversing for Android Penetration Testing

Now, each database has its own SQLite database associated with itself. We simply need to traverse to this database and dump values. Note that having root access is sometimes critical to do this, other times if your user has the permissions you’d be able to have a look at the database.

adb shell
cd /data/data/b3nac.injuredandroid/databases
ls
sqlite3 Thisisatest.db
select * from Thisisatest;

And just like that we have the flag’s hash which is in MD5 and password which is encrypted in some format as well (ROT47). One can decrypt it and is good to go. It is essential for developers not to use old encryption and hashing techniques.

Hardcoded AWS key and access ID

“World is moving to cloud” ~ Google

“But stupidity exists everywhere” ~ Pentesters

Oftentimes developers hard code or create a reference value of AWS bucket credentials. One such example could be seen in FlagEightLoginActivity. Here, the developer has given a little hint at the bottom too.

APK Reversing for Android Penetration Testing

On exploring the activity’s code we see that this client authenticates with aws.

One of the most common places to look for AWS creds is in the strings.xml file. So we check it:

cd /InjuredAndroid-1.0.10-release/res/values
cat strings.xml | grep AWS

And it worked like a charm.

Then, we’ll create a profile of AWS and can easily use AWS cli to connect to it. To make profile:

cd ~ && mkdir .aws
cd .aws && nano credentials

Copy the obtained ID and access key in it.

APK Reversing for Android Penetration Testing

Conclusion

Even after string obfuscation, various classes, objects and strings can be reversed and used to harm an organisation. It is very essential that developers follow strict practices for security given by OWASP MSTG. Thanks for reading.

Author: Harshit Rajpal is an InfoSec researcher and left and right brain thinker. Contact here