hacktricks/mobile-apps-pentesting/android-app-pentesting/android-applications-basics.md

420 lines
28 KiB
Markdown
Raw Normal View History

2021-04-21 16:06:28 +02:00
# Android Applications Basics
## Android Security Model
**There are two layers:**
* The **OS**, which keeps installed applications isolated from one another.
* The **application itself**, which allows developers to **expose certain functionalities** and configures application capabilities.
### UID Separation
**Each application is assigned a specific User ID**. This is done during the installation of the app so t**he app can only interact with files owned by its User ID or shared** files. Therefore, only the app itself, certain components of the OS and the root user can access the apps data.
### UID Sharing
**Two applications can be configured to use the same UID**. This can be useful to share information, but if one of them is compromised the data of both applications will be compromised. This is why this behaviour is **discourage**.
**To share the same UID, applications must define the same `android:sharedUserId` value in their manifests.**
### Sandboxing
The **Android Application Sandbox** allows to run **each application** as a **separate process under a separate user ID**.
From Android 5.0\(L\) **SELinux** is enforced. Basically, SELinux denied all process interactions and then created policies to **allow only the expected interactions between them**.
### Permissions
When you installs an **app and it ask for permissions**, the app is asking for the permissions configured in the **`uses-permission`** elements in the **AndroidManifest.xml** file. The **uses-permission** element indicates the name of the requested permission inside the **name** **attribute.** It also has the **maxSdkVersion** attribute which stops asking for permissions on versions higher than the one specified.
Note that android applications don't need to ask for all the permissions at the beginning, they can also **ask for permissions dynamically** but all the permissions must be **declared** in the **manifest.**
When an app exposes functionality it can limit the **access to only apps that have a specified permission**.
A permission element has three attributes:
* The **name** of the permission
* The **permission-group** attribute, which allows for grouping related permissions.
* The **protection-level** which indicates how the permissions are granted. There are four types:
* **Normal**: Used when there are **no known threats** to the app. The user is **not required to approve i**t.
* **Dangerous**: Indicates the permission grants the requesting application some **elevated access**. **Users are requested to approve them**.
* **Signature**: Only **apps signed by the same certificate as the one** exporting the component can be granted permission. This is the strongest type of protection.
* **SignatureOrSystem**: Only **apps signed by the same certificate as the one** exporting the component or **apps running with system-level access** can be granted permissions
## Pre-Installed Applications
These apps are generally found in the **`/system/app`** directory and some of them are **optimised** \(you may not even find the `classes.dex` file\). Theses applications are worth checking because some times they are **running with too many permissions** \(as root\).
* The ones shipped with the **AOSP** \(Android OpenSource Project\) **ROM**
* Added by the device **manufacturer**
* Added by the cell **phone provider** \(if purchased from them\)
## Rooting
In order to obtain root access into a physical android device you generally need to **exploit** 1 or 2 **vulnerabilities** which use to be **specific** for the **device** and **version**.
Once the exploit has worked, usually the Linux `su` binary is copied into a location specified in the user's PATH env variable like `/system/xbin`.
Once the su binary is configured, another Android app is used to interface with the `su` binary and **process requests for root access** like **Superuser** and **SuperSU** \(available in Google Play store\).
{% hint style="danger" %}
Note that the rooting process is very dangerous and can damage severely the device
{% endhint %}
### ROMs
It's possible to **replace the OS installing a custom firmware**. Doing this it's possible to extend the usefulness of an old device, bypass software restrictions or gain access to the latest Android code.
**OmniROM** and **LineageOS** are two of the most popular firmwares to use.
Note that **not always is necessary to root the device** to install a custom firmware. **Some manufacturers allow** the unlocking of their bootloaders in a well-documented and safe manner.
### Implications
Once a device is rooted, any app could request access as root. If a malicious application gets it, it can will have access to almost everything and it will be able to damage the phone.
## Android Application Fundamentals <a id="2-android-application-fundamentals"></a>
This introduction is taken from [https://maddiestone.github.io/AndroidAppRE/app\_fundamentals.html](https://maddiestone.github.io/AndroidAppRE/app_fundamentals.html)
### Fundamentals Review <a id="fundamentals-review"></a>
* Android applications are in the _APK file format_. **APK is basically a ZIP file**. \(You can rename the file extension to .zip and use unzip to open and see its contents.\)
* APK Contents \(Not exhaustive\)
* **AndroidManifest.xml**
* resources.arsc/strings.xml
* resources.arsc: a file containing precompiled resources, such as binary XML for example.
* res/xml/files\_paths.xml
* META-INF/
* Certificate lives here!
* **classes.dex**
* Dalvik bytecode for application in the DEX file format. **This is the Java \(or Kotlin\) code** compiled that the application will run by default.
* lib/
* Native libraries for the application, by default, live here! Under the lib/ directory, there are the cpu-specific directories.
* `armeabi`: compiled code for all ARM based processors only
* `armeabi-v7a`: compiled code for all ARMv7 and above based processors only
* `x86`: compiled code for X86
* `mips`: compiled code for MIPS processors only
* assets/
* Any other files that may be needed by the app.
* Additional native libraries or DEX files may be included here. This can happen especially when malware authors want to try and “hide” additional code, native or Dalvik, by not including it in the default locations.
* res/
* the directory containing resources not compiled into resources.arsc
### **Dalvik & Smali**
Most Android applications are written in Java. Kotlin is also supported and interoperable with Java. For ease, for the rest of this workshop, when I refer to “Java”, you can assume that I mean “Java or Kotlin”. **Instead of the Java code being run in Java Virtual Machine** \(JVM\) like desktop applications, in Android, the **Java is compiled to the** _**Dalvik Executable \(DEX\) bytecode**_ **format**. For earlier versions of Android, the bytecode was translated by the Dalvik virtual machine. For more recent versions of Android, the Android Runtime \(ART\) is used.
If developers, write in Java and the code is compiled to DEX bytecode, to reverse engineer, we work the opposite direction.
![Flowchart of Developer&apos;s process. Java to DEX bytecode](https://maddiestone.github.io/AndroidAppRE/images/DevelopersFlow.jpg)
![Flowchart of Reverse Engineer&apos;s process. DEX bytecode to SMALI to Decompiled Java](https://maddiestone.github.io/AndroidAppRE/images/ReversersFlow.jpg)
**Smali is the human readable version of Dalvik bytecode**. Technically, Smali and baksmali are the name of the tools \(assembler and disassembler, respectively\), but in Android, we often use the term “Smali” to refer to instructions. If youve done reverse engineering or computer architecture on compiled C/C++ code. **SMALI is like the assembly language: between the higher level source code and the bytecode**.
### Application Entry Points <a id="application-entry-points"></a>
One of the most important points of reverse engineering is knowing where to begin your analysis and entry points for code execution is an important part of that.
#### Content Provider <a id="services"></a>
Content Providers are the way **apps share structured data**, such as relational databases. Therefore, it's very important to use **permissions** and set the appropriate protection level to protect them.
Content Providers can use the **`readPermission`** and **`writePermission`** attributes to specify which permissions an app must have. **These permissions take precedence over the permission attribute**.
Moreover, they can also **allow temporary exceptions** by setting the **`grantUriPermission`** to true and then configuring the appropriate parameters in the **`grant-uri-permission`** element within the provider element inside the manifest file.
The **`grant-uri-permission`** has three attributes: path, pathPrefix and pathPattern:
* **path**: Allows to specify the entire path to exclude
* **pathPrefix**: Allows to specify the beginning of the path
* **pathPattern**: Allows the use of wildcards and symbolic replacements to gain more granular control.
It's important to validate and sanitise the received input to avoid potential vulnerabilities like SQL injection.
* Content Provider component supplies data from one application to others on request.
* You can store the data in the file system, an SQLite database, on the web, or any other persistent storage location your app can access.
* Through the content provider, other apps can query or even modify the data \(if the content provider allows it\).
* Content Provider is useful in cases when an app want to share data with another app.
* It is much similar like databases and has four methods.
* insert\(\)
* update\(\)
* delete\(\)
* query\(\)
#### FileProvider
This is a type of Content Provider that will **share files** from a folder. You can declare a file provider like this:
```markup
<provider android:name="androidx.core.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true" android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
```
Note the **`android:exported`** attribute because if it's **`true`** external applications will be able to access the shared folders.
Note that the configuration `android:resource="@xml/filepaths"` is indicating that the file _res/xml/filepaths.xml_ contains the configuration of **which folders** this **FileProvider** is going to **share**. This is an example of how to indicate to share a folder in that file:
```markup
<paths>
<files-path path="images/" name="myimages" />
</paths>
```
Sharing something like **`path="."`** could be **dangerous** even if the provider isn't exported if there is other vulnerability in some part of the code that tried to access this provider.
You could **access** an **image** inside that folder with `content://com.example.myapp.fileprovider/myimages/default_image.jpg`asd
[More information about FileProviders here](https://developer.android.com/training/secure-file-sharing/setup-sharing).
#### AIDL <a id="services"></a>
**AIDL** \(Android Interface Definition Language\) describes the API offered by a Service to external applications. **AIDL enables IPC** \(InterProcess Communication\).
Services using AIDL are referred to as **Bound Services**. In the Service's class you will find the `onBind` method. This is **where the interaction begins** so it's initial part of the code to review looking for potential vulnerabilities.
#### Messenger
A Messenger is another type of IPC mechanism. Since the Messenger us also a "Bound Service", the data passed from the client app is also processed through the `onBind` method. So, the code review should start on this method and you should look for the invocation of sensitive functionality or unsafe handling of data.
#### Binder
It's weird to find a Binder class directly invoked as it's much easier to use AIDL \(which abstracts the Binder class\). However, it's good to know that Binder is a kernel-level driver which moves data from one process's memory to another's \([https://www.youtube.com/watch?v=O-UHvFjxwZ8](https://www.youtube.com/watch?v=O-UHvFjxwZ8)\).
#### Components
These include: Activities, Services, Broadcast Receivers and Providers.
#### Launcher Activity and other activities <a id="launcher-activity"></a>
An **Android activity** is one screen of the **Android** app's user interface. In that way an **Android activity** is very similar to windows in a desktop application. An **Android** app may contain one or more activities, meaning one or more screens.
The **launcher activity** is what most people think of as the **entry point** to an Android application. The launcher activity is the activity that is started when a user clicks on the icon for an application. You can determine the launcher activity by looking at the applications manifest. The launcher activity will have the following MAIN and LAUNCHER intents listed.
Keep in mind that not every application will have a launcher activity, especially apps without a UI. Examples of applications without a UI \(and thus a launcher activity\) are pre-installed applications that perform services in the background, such as voicemail.
```markup
<activity android:name=".LauncherActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
```
Activities can be exported allowing other processes on the device to launch the activity. By default, they aren't exported but you can export them setting:
```markup
<service android:name=".ExampleExportedService" android:exported="true"/>
```
Note that the ability to bypass activity protections isn't always a vulnerability, you need to check to which data you have obtained access.
Also, some activities returns data to a caller. In these scenarios you need to search for the setResult method and check the data that is passed into the Intent parameter. IF it's sensitive data you may have an information leakage vulnerability and it's exploitable with apps capable of communicating with the Activity.
#### Services
[Services](https://developer.android.com/guide/components/services) run in the background without a UI. They are used to perform long-running processes, even if the user starts using a different application.
There is a myriad of ways that they can be started and thus are an entry point for applications. The default way that a service can be started as an entry point to an application is through [Intents](https://developer.android.com/guide/components/intents-filters).
When the `startService` method is called to start a Service, the `onStart` method in the Service is executed. It will run indefinitely until the stopService method is called. If the service is only needed as long as the client is connected, the client should "bind" to it using the bindService method.
For a "bound" service, the data will be passed to the onBind method.
For example, a service might play music in the background while the user is in a different application, or it might fetch data over the network without blocking user interaction with an activity.
A service can be exported which allows other processes on the device to start the service. By default services aren't exported but it can be configured in the Manifest:
```markup
<service android:name=".ExampleExportedService" android:exported="true"/>
```
#### Application Subclass <a id="application-subclass"></a>
Android applications can define a subclass of [Application](https://developer.android.com/reference/android/app/Application). Applications can, but do not have to define a custom subclass of Application. If an Android app defines a Application subclass, this class is instantiated prior to any other class in the application.
If the `attachBaseContext` method is defined in the Application subclass, it is called first, before the `onCreate` method.
#### Intents
Intent is basically a message that is passed between components \(such as Activities, Services, Broadcast Receivers, and Content Providers\). Intents can be directed to specific components or apps, or can be sent without a specific recipient.
To be simple Intent can be used:
* To start an Activity, typically opening a user interface for an app
* As broadcasts to inform the system and apps of changes
* To start, stop, and communicate with a background service
* To access data via ContentProviders
* As callbacks to handle events
Improper implementation could result in data leakage, restricted functions being called and program flow being manipulated.
[**Learn more about intents reading here.**](what-are-intents.md)\*\*\*\*
#### Intent Filter
An IntentFilters specifies the types of Intent that an activity, service, or Broadcast Receiver can respond to. An Intent Filter declares the capabilities of a component. It specifies what an activity or service can do and what types of broadcasts a Receiver can handle. It allows the corresponding component to receive Intents of the declared type. IntentFilters are typically defined via the AndroidManifest.xml file. For BroadcastReceiver it is also possible to define them in coding. An IntentFilters is defined by its category, action and data filters. It can also contain additional metadata.
If any of the component is public then it can be accessed from another application installed on the same device. In Android an activity/services/content provider/broadcast receiver is **public** when exported is set to true but a component is also public if the **manifest specifies an Intent filter** for it. However,
developers can **explicitly make components private** \(regardless of any intent filters\)
by setting the **“exported” attribute to false** for each component in the manifest file.
Developers can also set the “permission” attribute to require a certain permission to access each component, thereby restricting access to the component.
#### Implicit Intents
Intents are programatically created using an Intent constructor:
```java
Intent email = new Intent(Intent.ACTION_SEND, Uri.parse("mailto:"));
```
The **Action** of the previously declared intent is **ACTION\_SEND** and the **Extra** is a mailto **Uri** \(the Extra if the extra information the intent is expecting\).
This intent should be declared inside the manifest as in the following example:
```markup
<activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
```
An intent-filter needs to match the **action**, **data** and **category** to receive a message.
The "Intent resolution" process determine which app should receive each message. This process considers the priority attribute, which can be set in the intent-filter declaration, and the one with the higher priority will be selected. This priority can be set between -1000 and 1000 and applications can use the `SYSTEM_HIGH_PRIORITY` value. If a conflict arises, a "choser" Window appears so the user can decide.
#### Explicit Intents
An explicit intent specifies the class name it's targeting:
```java
Intent downloadIntent = new (this, DownloadService.class):
```
In other applications in order to access to the previously declared intent you can use:
```java
Intent intent = new Intent();
intent.setClassName("com.other.app", "com.other.app.ServiceName");
context.startService(intent);
```
#### Pending Intents
These allow other applications to **take actions on behalf of your application**, using your app's identity and permissions. Constructing a Pending Intent it should be **specified an intent and the action to perform**. If the **declared intent isn't Explicit** \(doesn't declare which intent can call it\) a **malicious application could perform the declared action** on behalf of the victim app. Moreover, **if an action ins't specified**, the malicious app will be able to do **any action on behalf the victim**.
#### Intent Broadcast Receivers <a id="broadcast-receivers"></a>
Broadcasts can be thought of a messaging system and [broadcast receivers](https://developer.android.com/guide/components/broadcasts#receiving-broadcasts) are the listeners. If an application has registered a receiver for a specific broadcast, the code in that receiver is executed when the system sends the broadcast. Note that in this case **several apps can receive the same message**.
From API version 14, it's **possible to specify the app that should receive** the message using Intent.set Package.
There are **two types** of Broadcasts: **Normal** \(asynchronous\) and **Ordered** \(synchronous\). The order is base on the configured priority within the receiver element. Each app can process, relay or drop the Broadcast.
It's possible to **send** a **broadcast** using the function **`sendBroadcast(intent, receiverPermission)`** from the `Context` class.
You could also use the function `sendBroadcast` from the **`LocalBroadCastManager`** ensures the **message never leaves the app**. Using this you won't even need to export a receiver component.
There are 2 ways that an app can register a receiver: in the apps Manifest or dynamically registered in the apps code using the `registerReceiver()` API call.
In both cases, to register the receiver, the intent filters for the receiver are set. These intent filters are the broadcasts that should trigger the receiver.
When the specific broadcasts are sent that the receiver is registered for are sent, `onReceive` in the BroadcastReceiver class is executed.
An application may register a receiver for the low battery message for example, and change its behaviour based on that information.
{% hint style="danger" %}
Note that any application can set itself as top priority to receive a Broadcast.
{% endhint %}
Broadcast Receivers can be statically defined in the `AdroidManifest.xml` file or dynamically using the `registerReceiver` method. In the manifest you can limit the broadcasts you accept through the use of permissions within the receiver element, When dynamically defined you can pass the permission to the registerReceiver method.
To examine the code implemented into a Broadcast Receiver you need to search for the onReceive method of the class of the receiver.
Note that Ordered Broadcasts can drop the Intent received or even modify it using one of the setter methods. Therefore, the receivers should validate the data.
#### Sticky Broadcasts
This kind of Broadcasts **can be accessed long after they were sent**.
These were deprecated in API level 21 and it's recommended to **not use them**.
**They allow any application to sniff the data, but also to modify it.**
If you find functions containing the word "sticky" like **`sendStickyBroadcast`** or **`sendStickyBroadcastAsUser`**, **check the impact and try to remove them**.
#### URL schemes / Deep links
**Deep links allow to trigger an Intent via URL**. An application can declare an **URL schema** inside and activity so every time the Android device try to **access an address using that schema** the applications activity will be called:
![](../../.gitbook/assets/image%20%28141%29.png)
In this case the scheme in `myapp://` \(note also the category BROWSABLE\)
If inside the `intent-filter`you find something like this:
![](../../.gitbook/assets/image%20%28150%29.png)
Then, it's expecting something like `http://www.example.com/gizmos`
If you find something like this:
![](../../.gitbook/assets/image%20%28242%29.png)
It will mean that it's expecting a URL starting by `example://gizmos`
In this case you could try to abuse the functionality creating a web with the following payloads. It will try to navigate to arbitrary pages and try to execute JS:
```markup
<a href="example://gizmos/https://google.com">click here</a>
<a href="example://gizmos/javascript://%250dalert(1)">click here</a>
```
In order to find the **code that will be executed in the App**, go to the activity called by the deeplink and search the function **`onNewIntent`**.
![](../../.gitbook/assets/image%20%28436%29%20%281%29%20%281%29%20%281%29.png)
Learn how to [call deep links without using HTML pages below](./#exploiting-schemes-deep-links).
### WebViews
WebViews are effectively **web browsers** embedded into Android Apps.
WebViews content can be pulled from remote sites or can be files included in the app.
WebViews are **vulnerable to the same vulnerabilities affecting any web browsers**. However there are some **configurations** that can be useful to **limit** the **attack** **surface**.
There are two types of WebViews in Android:
* The **WebViewClient**, best suited for simpleHTML rendering. This won't run the JS alert function. So, XSS tests using that function will be invalid.
* The **WebChrome** **client**, is a Chrome browser.
Note that **WebView browsers doesn't have access to the native browser's cookies**.
To load a URL or file it's possible to use the functions **`loadUrl`**, **`loadData`** or **`loadDataWithBaseURL`**. **It's important to only access sanitised URLs.**
The WebView security can be configured through the **`WebSettings`** object.
For example, JS code execution can be disabled using the **`setJavaScriptEnabled`** method with the **`false`** value. This will **remove** the possibility of a **XSS** and other JS related vulnerabilities.
The JavaScript "**Bridge**" functionality **inject Java objects into a WebView making them accessible to JS**. From Android 4.2 methods must be annotated with **`@JavascriptInterface`** in order to be accessible to JavaScript.
If **`true`** is passed to **`setAllowContentAccess`**, **WebViews will be able to access Content Providers** via **`content://`** scheme. This obviously poses a security risk. Note that if this access is given, it's very important to **ensure** that the **`content://`** URL is **safe**.
By default, local files can be accessed by WebViews via file:// URLs, but there are several ways to prevent this behaviour:
* Passing **`false`** to **`setAllowFileAccess`**, prevents the access to the filesystem with the exception of assets via `file:///android_asset` _and_ `file:///android_res`. These paths should be used only for non-sensitive data \(like images\) so this should be safe.
* The method **`setAllowFileAccess`** indicates if a path from a `file://` URL should be able to access the content from other file scheme URLs.
* The method **`setAllowUniversalAccessFromFileURLs`** indicates if a path from a `file://` URL should be able to access content from any origin.
### Other App components
**Application Signing**
* Android requires that all apps be digitally signed with a certificate before they can be installed. Android uses this certificate to identify the author of an app.
* To run application on the device ,it should be signed.When application is installed on to an device then package manager verifies that whether the application has been properly signed with the certificate in the apk file or not.
* Application can be self signed or can be signed through CA.
* Application signing ensures that one application cant access any other application except through well-defined IPC and also that it is passed unmodified to the device.
**Application Verification**
* Android 4.2 and later support application verification. Users can choose to enable “Verify Apps” and have applications evaluated by an application verifier prior to installation.
* App verification can alert the user if they try to install an app that might be harmful; if an application is especially bad, it can block installation.
**Android Sandbox**
Once installed on a device, each Android app lives in its own security sandbox: The Android operating system is a multi-user Linux system in which each app is a different user.
* By default, the system assigns each app a unique Linux user ID \(the ID is used only by the system and is unknown to the app\). The system sets permissions for all the files in an app so that only the user ID assigned to that app can access them.
* Each process has its own virtual machine \(VM\), so an apps code runs in isolation from other apps.
* By default, every app runs in its own Linux process. Android starts the process when any of the apps components need to be executed, then shuts down the process when its no longer needed or when the system must recover memory for other apps.