Static Analysis
It’s about examining the code without executing the program
We are going to see the important files within the android application and how can we benefit from them
Android Manifest.xml
It contains the basic info about the application
- minSDKVersion : which will give us info about the version and then we can detect vulnerability depending on just the version
-
package name : It’s a unique identifier for the application on the device
As an attacker we address the application through this identifier in our tools and scripts, so it’s important information for us -
Permissions
What data & HW components the app needs access to: (camera, BT, internet, etc..)
You can see list of permissions here
Permissions other than uses-permission are more interesting for us. These permissions are defined by the application and if you perform specific task and want to share it with other application then they can request this permission to exchange the data between each other. - Queries
It may contain application we want to exchange data with and to do that we need to be visible to it
<queries>
<package android:name="com.mwr.example.sieve"/>
</queries>
In this example we became visible to sieve
application so we can exchange data with it.
We can use that when we write our attacking app to bypass login screen as example.
- application
We can see many entries like:allow backup="true"
: This means that the data can be backed up (may be senstive or not)debuggable="true"
: we are allowed to debug this process of the applicationextractNativeLibs="false"
: If we have native libs included they can’t be compressed (not important for us), we will need it to be false when we inject fridaneworkSecurityConfig=".."
: Important in dealing with ssl pinning and if it’s not included we can define it (we will talk more about it later)
In the appliction we have many components (what the app has in the background)
-
Activities
UI element that represents screens in the application (some of them need to be protected)
protection is done using intent-filters which says (before you go to this screen you need to go to through this screen based on factors like cookies)
exported="True"
means that this activity is exposed and can be accessed from outside the app -
Intent-Filter
They are filters listening to specific intents and we will discuss them later -
service
It gots executed in the background as it may be resource intensive and not allowed to be done on UI -
broadcast receiver
It receive info to the application like receiving sms or any data from other application
It’s an important attack surface -
Content Providers
serve data from ur app to other apps
most of the time it’s related to database
exported content provider can be very dangerous and expose data to any user or app
the xml tag isprovider
You may find API keys defined
At the top of the manifest you can see backup
option
We will discuss these parts in more details
permissions
Each app in android system is sandboxed which means that app1 can’t access the data of app2
This is implemented by making use of the linux core of android by creating user for each application, so each app can’t access the others because it willnot have the privileges by default.
/etc/permission/platform.xml
: this file defines the users’ IDs which are individual for each app
But what if app wants to access another app or utility like photos, etc….
- this is defined in
/etc/system/packages.xml
There are users who should be active before the system starts (hardcoded in kernel) like adb shell.
- this is defined in
android_filesystem_config.h
Now we need to know how can we ask for permission ???
we knew that we can see that defined permissions in AndroidManifest.xml
file
and these permission will be added to /etc/system/packages.xml
What about custom permissions ??
It makes the apps exchange data between each others
- This permission is defined not used directly
as example
```xml
This permission allows reading keys table in sieve application
When we go to content provider we will understand this more
and this defined permission can be used in another app like this
```xml
<uses-permission ns0:name="com.mwr.example.sieve.READ_KEYS"/>
protection of data is depending on choosing the suitable protection level
We have levels:
dangerous
: The user is informed about this and the user decides to allow or deny (depending on user decision isn’t the best case)normal
: You won’t be informed and this isn’t considered a protection for senstive data, but it’s important for things like internet which doesn’t need to be decision before being usedsignature
: Each apps signed with the same key can access the data (to access database as example which is protected by signtature level then we need the private key of the sieve to access it) This isn’t practicle approach as private key can’t be shared.
activity
basically they are the screens of the application.
as example we may have login activity
, profile activity
, settings activity
, code activity
There are activities like profile as example who need us to login first before accessing it
We see that the only visible activity or the frontline of our app is login page as example, so what if we want to reach the code activity
directly by scanning QR code from QR scanner app directly?
The QR scanner must be able to see the code activity
and this moves us to exported
: which means that the activity is reachable by outside world (dangerous and handled by intents which will be discussed later)
We can know if the activity is exported or not from AndroidManifest.xml
file and exported can be implicit and explicit:
- explicit : occures when the activity has the attribute
exported="true"
- implicit : occurs if the activity has
intent-filter
so it’s also reachable from outside world
Exported scheme doesn’t only affect activities
we can make access exported activity using malicious app or adb shell
after getting adb shell we use the command am
which is activity manager but we need to identify the activity to be opened
the activity is identified to be <package name>/<activity name(keep the dot)>
so the command becomes am start-activity -n <package name>/<activity name(keep the dot)>
intents
It’s a messaging object and it can be implict and explicit
- implicit : We don’t know the exact destination application like we know it’s email app but we don’t know which app exactly
-
explicit : We know the destination we want to call and the destination can be in the same app or in a different app
It doesn’t work with activities only but also services and BroadcastReceivers
- Explicit Intents
Consider you have login activity and you want to login to reach profile activity, this can be implemented like this in login activity source codeIntent myIntent = new Intent(this,ProfileActivity.class); // defining the intent by passing the source and the target this.startActivity(myIntent);
If we want to start the new activity with parameters
Intent myIntent = new Intent(this,ProfileActivity.class); // defining the intent by passing the source and the target
myIntent.putExtra("username","admin"); // passing username parameter with value = "admin"
this.startActivity(myIntent);
and the parameter is used in the profile activity like this
@Override
Protected void onCreate(Bundle savedInstanceState){
Intent intent = getIntent();
String user = intent.getStringExtra("username"); // get the passed parameter username
}
-
Implicit Intents
Here we said that we don’t know the destination exactly as example we did an action that send mail and the exact mail app isn’t choosed.
The system sends out this intent and we want to open mail app to do this action (gmail app may be opened as example) but we will know more details in BroadcastReceiver.
If parameters are passed with the intent then there’s an attack vectorif the passed data are sensitive as we can create malicious app that listens to this type of intents (mail as example) and it will sniff the system for this information and this is calledIntent - Sniffing
-
Intent-Filter
As example the main activity will have an intent-filter with action:MAIN and category:LAUNCHER.
It’s just listening to bus system and filtering out the info related to the app we need to react with and ignore the others
It has certain tags :action
,category
anddata
we can know more about them and the possible values here
Note: if you want to interact with
intent-filter
which is considered implicit use this commandam start-activity -a <action> -c <category> --es <key> <value>
–es is to pass key value pair data as string
If there’s many apps with the same action, category the user will choose which app to use
BroadcastReceiver
They are a kind of notification system for ur applications.
There’s a specific events like connecting the headphone
, connecting to wifi
, etc…. these events are sent as broadcast to all apps
Not all apps react to this, some of them ignore it and the other can react to it through onReceive
method.
- ordered priority
It was an issue at android 4.3
each app is assigned a specific priority (as example sms has the highest priority = 200)
So it will be the first app to receive the msg and can decide to leave it to the next app with lower priority or not
The problem that in android <= 4.3 The attacker was able to assign it’s app a priority up to 999.
This is fixed in android 4.4 and the priority assignment is limited now.
To find which event each app is listening to, There are 2 approaches:
- old approach (until Android version 8): in
AndroidManifest.xml
- new approach: Finding onReceive function within the Java code
In some broadcast events important data are passed so if we could receive them we may be able to move forward in the target.
Local broadcast manager can’t be exploited because we can’t interact with it, It’s just a messages bewtween classes as example.
adb.exe logcat
: to show logging of the app
to open local console we useadb.exe local
=> this is console at which we can get the output of print function
- Sending broadcast through adb:
am broadcast -a <action in the intent filter or from the source code depending on android version>
we may not have the permission, so make sure u r root
pm -U
: List packages with uid so we can broadcast to specific uid and replcacea
with 10, so the broadcast command can beam broadcast --user <uid> -a <action>
If there’s string info to be sent with the Intent filter we can use --es
option as we know.
Services
Consider you have a game and it needs some processes like rendering the game and organization of objects (in UI) and we also need network requesting as example.
If all these components are in the main activity we will have a problem: The network request may stop the UI thread until the request is done which may result in closing the app (the app in android is closed if the UI thread isn’t working for some seconds).
The solution is to make the components which isn’t in the UI to be services in background
We have 2 types of services: start service
& bound service
start
: very simple just the service started when we need it to do some task then close it.bound
: binding client to service (we may have client interacting with the app) then we need to wait for the clients to disconnect to shutdown this service
The services can’t make UI updates as they work in the background
If we want to do so we may make use of BroadcastReceiver and make them trigger the service viaonReceive()
This was the common behvior till android 8 cause this background execution isn’t allowed any more.
What to look for ?
start
: here you will look into intentbound
: look into the message object
to attack the service it needs to be Exported and Permissions to interact with this one.
ContentProvider
It’s simply provide a content and usually it’s used with databases, we can interact with them via content URI.
as example The Contacts they are stored in db and there’s content provider for this data base.
content URI is used to interact with them and in consists of:
prefix
: which is content:// and it’s a good keyword to search for when reversing the appauthorty
: It’s a unique identifier for the content providertable entry
row in table
Content provider are excluded from intents so interaction with them is done in different way like using adb shell
and then the command will be $ content query --uri content://com.android.contacts/contacts/1
What if we don’t have adb shell access, so we will write our malicious app.
in our app we want to define ContentResolver
that asks the content provider to provide the content to us
we need 2 use cases:
- Having permissions
- Exported: True
Then after asking, thew content provider returns a Cursor
(pointer to data in db) to our app
The content provider must include query
, update
, insert
and delete
methods and we will use them in the resolver for interaction with the provider
The data base of custom content provider are stored in data/data/<package>/db
Here we see the structure of query
function and how it’s mapped to sql query.
and here we see a basic application of sqli.
content providers aren’t invoked by intents so to interact with it, it must be exported.
ContentProvider can also read and write files this moves us to path traversal
vulenerability.
Let’s look in accessing file using content provider
we see that the file is vulenrable to path traversal so the app can get pin.xml file in this example
The content provider is exported if we have read or write permissions, but the protection level may prevent us from exploitation if it’s signature.
protection level dangerous can be ok if the data is encrypted.
from the source code we can reach the implementation information of db like the database.db file and the tables’ names.
note: if table name is db structure source code =
key
and it’s refrenced in the manifest askeys
we will usekey
in sqli.
interaction with content provider using adb shell is done using content query|insert|... --uri <content provider uri>
OFC the table must be accessable (we should have Read or write permissions), but we have another accessable table we can make use of it to reach the protected table.
Example: passwords table is accessable but key isn’t and we have this command content query --uri content://.....DBContentProvider/passwords
we can make use of projection for sqli like this content query --uri content://.....DBContentProvider/passwords --projection "* from key--"
so the query became select * from key -- from passwords ...
but all after the – is commented so we can ignore it now and celebrate with the key data we got.
If the protected uri isn’t defined in regex we can query it directly like this content query --uri content://.....DBContentProvider/keys/
Insertion in DB: we can see its syntax from the help of adb shell content.
Deep links
Deep Links can be implicit
or explicit
They are links to specific part of an application, so with links you can access apps not only browsers.
And this is the reason for opening youtube app when we click on a youtube video link instead of opening the browser.
The app which is able to handle deep links has intent filter with category : browsable
.
The intent filter may also contain one or more data tags.
this is example:
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="hex"/>
<data android:host="open"/>
<data android:host="flag"/>
</intent-filter>
we can access this component using the url hex://open
or hex://flag
Example
acode
is IDE for programming using the phone and when you decompile its apk you will find that it has an intent filter with a category browsable
and the data scheme is acode
and after digging in the source you can see that if we want to install a plugin we the url should be acode://plugin/install/<plugin ID>
.
If you can register a malicious plugin then this functionality will be critical as you can force the victim to install it if he clicked the link.
The speech above is implicit deeplink
.
Chrome on Android implements a custom scheme intent: with a lot more features than the regular deep links.
It has many features
- It’s a generic intent
- Control the action and category
- Target specific app and class
- Add extra values
This is called explicit deeplink
at which only specified app can handle the deep link which lowers the risk.
There another way to decrease the risk which is app links
apps with httpor https schemes maybe used to hijack websites, but this can avoided with app links.
by making this intent filter <intent-filter android:autoVerify="true">
we will avoid the vulnerability
but this link must be registered through Google Search Console.
If the website is requested, assetlinks.json file must be included under /.well-known/
directory, and the app itself should be declared as an authorized app.
Web View
It’s a component that allows developers to embed web content into the app (acts as browser within the app).
It consists of
- Browser Engine
: render HTML, CSS , JS to create the UI
- JS Engine
: resposible for js execution and DOM manipulation
- Android Networking Framework
: establish connections and handle https requests and fetching HTML, CSS, JS pages from a server
- performance enhancement
: done by using GPU to enhance visual quality and responsiveness
signing
It’s needed in many things like keeping track if there’s an update for the app in the store
package name isn’t enough because it’s unique on the phone only but we can create apps with the same package name of other apps in the store.
So the developer signs the application with a private key and the signature with the package name are used to know that the app on our phone is the one on the store and this update is for it.
Private keys used for signing applications must be super safe.
This process is for verifing the author of the app.
we can sign 2 different apps with the same signature so they can share data together without the need of exported components so the components are no longer exposed to the whole world, but the app we need to exchange the data with only.
If we want to modify app.
- use apktool to decompile the apk using
apktool d game.apk
- you will get the decompiled files and you can modify what you want
- build the apk again
apktool b game.apk
- We can’t install the apk if it isn’t signed so we sign it using
zipalign
for preparing offset for the certificate to be placed in the correct place andapksigner
for signing the app - before android 11 we could use
jarsigner
directly for signing
Let’s see the process in more details
- generation the key
keytool -genkey -v -keystore <path/to/keystore file> -alias alias_name -keyalg RSA -keysize 2048 -validity 365
-getkey
for generating the private key-v
make the certificate human readablekeystore
is a file which is the place at which the key will be storedalias
it’s the way we will define the keynote that many keys can be saved in the same keystore but of course the alias will be different
- for signing
zipalign -v 4 base.apk out.apk
apksigner sign --ks-key-alias <alias name> -ks <path/to/keystore file> out.apk
alias is needed if there are more than a key in the keystore
METAINF dir contains all signing information so it must exist after signing
Common Application Strings
We may find useful strings to get more info
- Hardcoded Strings
can be found in:resources/strings.xml
,activity source code
we may find:login creds
,api key
,exposed url
,firebase URLs