Introduction
Android reverse engineering 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
●
Understanding
default files
●
Understanding
improper WebView implementation
●
Hard coded
secrets
●
Secrets in
strings.xml file
●
Insecure
classes implementation
●
Insecure
decryption method for hard coded values
●
Insecure
cryptography in sqlite database
●
Hard coded
AWS credentials
Understanding default files
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
●
etc.
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
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 strings file. One example is suppose in Java
file 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, 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
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
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
Hard coded 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
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 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.
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 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 a 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 a() 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
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.
Hard coded 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:
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:
cd ~ && mkdir .aws
cd .aws && nano credentials
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.
0 comments:
Post a Comment