x32x01
ADMINISTRATOR
- by x32x01 ||
Android reverse engineering (Part 2) refers to the process of decompiling the APK for the purpose of investigating 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 smali 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, we’ll see different scenarios in which an attacker is able to 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
AndroidManifest.xml – Manifest literally means to show. This is the most literal file in the whole of the application as it does precisely what it’s name suggests. It begins with a <manifest> tag. It should also contain “xmlns: attribute” which declares several system attributes used within the file. It declares:
Strings.xml – This XML file contains strings that can be referenced from the application or from other resource files (such as an XML layout). 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 is supposed in Java file the code flows like this:
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 – It is an auto-generated file by aapt (Android Asset Packaging Tool) that contains resource IDs for all the resources of res/ directory. If you create any component in the activity_main.xml file, id for the corresponding component is automatically created in this file. This id can be used in the activity source file to perform any action on the component. If you delete this, it’ll get auto-generated again.
There are various other default files as well, we’ll talk about them later when we discover each.
Understanding improper WebView implementation
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
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!
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.
Now, let’s reverse the application using JADX and see what’s hidden under GUI. It can be easily inferred even after obfuscation that submitFlag() method is comparing a user supplied input with a given flag “F1ag_0n3”. Hence, the entire login mechanism is bypassed just by looking for the right class after reversing.
After we input the flag, we see that it was indeed correct.
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
Hence, we have our third flag.
Insecure classes implementation
Just like an object can be referred from strings.xml file, similarly, other classes can also be implemented to perform a specific function with an object, and it’s return value be used. 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.
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.
After encoding this, we’ll get this flag.
Insecure decryption method for hard coded values
Oftentimes, developers implement methods to generate keys and encrypt some information which is either received from a user or to encrypt a secret such as login credentials within the application. For example in FlagSixLoginActivity we can see that a certain k.a() return value is being compared with a user input.
This gibberish value is a base64 encoded byte array. Now, we are going to inspect k.a() method.
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:
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
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.
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.
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:
And it worked like a charm.
Now we’ll create a profile of aws and can easily use AWS cli to connect to it. To make profile:
Copy the obtained ID and access key in it.
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.
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
AndroidManifest.xml – Manifest literally means to show. This is the most literal file in the whole of the application as it does precisely what it’s name suggests. It begins with a <manifest> tag. It should also contain “xmlns: attribute” which declares several system attributes used within the file. It declares:
- <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
Strings.xml – This XML file contains strings that can be referenced from the application or from other resource files (such as an XML layout). 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 is supposed in Java file the code flows like this:
Code:
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 – It is an auto-generated file by aapt (Android Asset Packaging Tool) that contains resource IDs for all the resources of res/ directory. If you create any component in the activity_main.xml file, id for the corresponding component is automatically created in this file. This id can be used in the activity source file to perform any action on the component. If you delete this, it’ll get auto-generated again.
There are various other default files as well, we’ll talk about them later when we discover each.
Understanding improper WebView implementation
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
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.
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.
Code:
apktool d InjuredAndroid-1.0.10-release.apk
cd InjuredAndroid-1.0.10-release/res/values
cat strings.xml | grep cmVz
Insecure classes implementation
Just like an object can be referred from strings.xml file, similarly, other classes can also be implemented to perform a specific function with an object, and it’s return value be used. For example, in the FlagFourActivity we see something similar
Code:
echo "NF9vdmVyZG9uZV9vbWVsZXRz" > to_decode
cat to_decode | base64 --decode
Oftentimes, developers implement methods to generate keys and encrypt some information which is either received from a user or to encrypt a secret such as login credentials within the application. For example in FlagSixLoginActivity we can see that a certain k.a() return value is being compared with a user input.
JavaScript:
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 () { }
});
});
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
Code:
adb shell
cd /data/data/b3nac.injuredandroid/databases
ls
sqlite3 Thisisatest.db
select * from Thisisatest;
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.
Code:
cd /InjuredAndroid-1.0.10-release/res/values
cat strings.xml | grep AWS
And it worked like a charm.
Now we’ll create a profile of aws and can easily use AWS cli to connect to it. To make profile:
Code:
cd ~ && mkdir .aws
cd .aws && nano credentials
Copy the obtained ID and access key in it.
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.