android.permission.INTERNET
.android.permission.RECORD_AUDIO
.android.permission.ACCESS_MOCK_LOCATION
.android.permission.ACCESS_DOWNLOAD_MANAGER
.READ_CONTACTS
permission, queries for contact's usage data will return approximations rather than exact values (the auto-complete API is not affected by this change).GET_ACCOUNTS
permission granted, unless the authenticator owns the accounts or the user grants that access.PHONE
permissions group:ANSWER_PHONE_CALLS
permission allows to answer incoming phone calls programmatically (via acceptRingingCall
).READ_PHONE_NUMBERS
permission grants read access to the phone numbers stored in the device.STORAGE
group contains READ_EXTERNAL_STORAGE
and WRITE_EXTERNAL_STORAGE
). Before Android 8.0 (API level 26), it was sufficient to request one permission of the group in order to get all permissions of that group also granted at the same time. This has changed starting at Android 8.0 (API level 26): whenever an app requests a permission at runtime, the system will grant exclusively that specific permission. However, note that all subsequent requests for permissions in that permission group will be automatically granted without showing the permissions dialog to the user. See this example from the Android developer documentation:Suppose an app lists both READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE in its manifest. The app requests READ_EXTERNAL_STORAGE and the user grants it. If the app targets API level 25 or lower, the system also grants WRITE_EXTERNAL_STORAGE at the same time, because it belongs to the same STORAGE permission group and is also registered in the manifest. If the app targets Android 8.0 (API level 26), the system grants only READ_EXTERNAL_STORAGE at that time; however, if the app later requests WRITE_EXTERNAL_STORAGE, the system immediately grants that privilege without prompting the user.
READ_CALL_LOG
, WRITE_CALL_LOG
, and PROCESS_OUTGOING_CALLS
(dangerous) permissions are moved from PHONE
to the new CALL_LOG
permission group. This means that being able to make phone calls (e.g. by having the permissions of the PHONE
group granted) is not sufficient to get access to the call logs.READ_CALL_LOG
permission when running on Android 9 (API level 28).WifiManager.getConnectionInfo
unless all of the following is true:ACCESS_FINE_LOCATION
or ACCESS_COARSE_LOCATION
permission.ACCESS_WIFI_STATE
permission.Build.getSerial
) unless the READ_PHONE_STATE
(dangerous) permission is granted.READ_FRAME_BUFFER
, CAPTURE_VIDEO_OUTPUT
, and CAPTURE_SECURE_VIDEO_OUTPUT
permissions are now signature-access only, which prevents silent access to the device's screen contents.android:permission
attribute within the <activity>
tag in the manifest. These permissions restrict which applications can start that Activity. The permission is checked during Context.startActivity
and Activity.startActivityForResult
. Not holding the required permission results in a SecurityException
being thrown from the call.android:permission
attribute within the <service>
tag in the manifest restrict who can start or bind to the associated Service. The permission is checked during Context.startService
, Context.stopService
and Context.bindService
. Not holding the required permission results in a SecurityException
being thrown from the call.android:permission
attribute within the <receiver>
tag restrict access to send broadcasts to the associated BroadcastReceiver
. The held permissions are checked after Context.sendBroadcast
returns, while trying to deliver the sent broadcast to the given receiver. Not holding the required permissions doesn't throw an exception, the result is an unsent broadcast.Context.registerReceiver
to control who can broadcast to a programmatically registered receiver. Going the other way, a permission can be supplied when calling Context.sendBroadcast
to restrict which broadcast receivers are allowed to receive the broadcast.android:permission
attribute within the <provider>
tag restrict access to data in a ContentProvider. Content providers have an important additional security facility called URI permissions which is described next. Unlike the other components, ContentProviders have two separate permission attributes that can be set, android:readPermission
restricts who can read from the provider, and android:writePermission
restricts who can write to it. If a ContentProvider is protected with both read and write permissions, holding only the write permission does not also grant read permissions.ContentResolver.query
requires holding the read permission; using ContentResolver.insert
, ContentResolver.update
, ContentResolver.delete
requires the write permission. A SecurityException
will be thrown from the call if proper permissions are not held in all these cases.Intent.FLAG_GRANT_READ_URI_PERMISSION
and/or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
. This grants permission to the activity for the specific URI regardless if it has permissions to access to data from the content provider.android:grantUriPermissions
attribute or the node help restrict the URIs.AndroidManifest.xml
by creating a permission tag with two mandatory attributes: android:name
and android:protectionLevel
.START_MAIN_ACTIVITY
, which is required when launching the TEST_ACTIVITY
Activity.android:permission
attributes.START_MAIN_ACTIVITY
has been created, apps can request it via the uses-permission
tag in the AndroidManifest.xml
file. Any application granted the custom permission START_MAIN_ACTIVITY
can then launch the TEST_ACTIVITY
. Please note <uses-permission android:name="myapp.permission.START_MAIN_ACTIVITY" />
must be declared before the <application>
or an exception will occur at runtime. Please see the example below that is based on the permission overview and manifest-intro.com.domain.application.permission
) in order to avoid collisions with other applications.INTERNET
permission in the AndroidManifest.xml file is necessary for an Activity to load a web page into a WebView. Because a user can revoke an application's right to use a dangerous permission, the developer should check whether the application has the appropriate permission each time an action is performed that would require that permission.aapt comes with the Android SDK within the build-tools folder. It requires an APK file as input. You may list the APKs in the device by runningadb shell pm list packages -f | grep -i <keyword>
as seen in "Listing Installed Apps".
ContextCompat.checkSelfPermission
method is called to check if an activity has a specified permission. Whenever you see code like the following snippet, make sure that the same permissions are enforced in the manifest file.ContextCompat.checkSelfPermission
which compares it to the manifest file.requestPermissions
method in order to obtain them. The app passes the permissions needed and an integer request code you have specified to the user asynchronously, returning once the user chooses to accept or deny the request in the same thread. After the response is returned the same request code is passed to the app's callback method.requestPermissions
, since the system dialog box can not be altered once called.onRequestPermissionsResult
to see if the permission was granted. This method receives the requestCode
integer as input parameter (which is the same request code that was created in requestPermissions
).WRITE_EXTERNAL_STORAGE
.onRequestPermissionsResult
handler will automatically be triggered without any user interaction.READ_EXTERNAL_STORAGE
and WRITE_EXTERNAL_STORAGE
are listed in the Android Manifest but only permissions are granted for READ_EXTERNAL_STORAGE
, then requesting WRITE_EXTERNAL_STORAGE
will automatically have permissions without user interaction because they are in the same group and not explicitly requested.DANGEROUS
and SIGNATURE
permissions, since they can affect both the user and the application if mishandled. For instance, it should be suspicious if a single-player game app requires access to android.permission.WRITE_SMS
.DANGEROUS
permissions in use. A good example is the SMS Retriever API which streamlines the usage of SMS permissions when performing SMS-based user verification. By using this API an application does not have to declare DANGEROUS
permissions which is a benefit to both the user and developers of the application, who doesn't have to submit the Permissions Declaration Form.adb
. The following extract demonstrates how to examine the permissions used by an application.android.permission.WRITE_SMS
, might not be a good idea.AndroidManifest.xml
above defines a content provider that's exported and therefore available to all other apps. The query
function in the OMTG_CODING_003_SQL_Injection_Content_Provider_Implementation.java
class should be inspected.content://sg.vp.owasp_mobile.provider.College/students
, the query statement is prone to SQL injection. Obviously prepared statements must be used to avoid SQL injection, but input validation should also be applied so that only input that the app is expecting is processed.Integer.parseInt
if only integers are expected. The OWASP Input Validation Cheat Sheet contains more information about this topic.OR 1=1--
if, for example, a local SQL injection vulnerability has been identified.Preferences activity
to users, allowing the developers to extend and adapt this abstract class.PreferenceActivity.EXTRA_SHOW_FRAGMENT(:android:show_fragment)
and Preference Activity.EXTRA_SHOW_FRAGMENT_ARGUMENTS(:android:show_fragment_arguments)
fields.Fragment
class name, and the second one is expected to contain the input bundle passed to the Fragment
.PreferenceActivity
uses reflection to load the fragment, an arbitrary class may be loaded inside the package or the Android SDK. The loaded class runs in the context of the application that exports this activity.java.lang.CastException
, but the empty constructor will be executed before the exception is thrown, allowing the code present in the class constructor run.isValidFragment
was added in Android 4.4 (API level 19). It allows developers to override this method and define the fragments that may be used in this context.true
on versions older than Android 4.4 (API level 19); it will throw an exception on later versions.android:targetSdkVersion
less than 19.PreferenceActivity
class.isValidFragment
has been overridden.android:targetSdkVersion
in the manifest to a value less than 19 and the vulnerable class does not contain any implementation of isValidFragment
then, the vulnerability is inherited from the PreferenceActivity
.android:targetSdkVersion
to 19 or higher. Alternatively, if the android:targetSdkVersion
cannot be updated, then developers should implement isValidFragment
as described.isValidFragment
method being overridden with an implementation that allows the loading of MyPreferenceFragment
only:SafeBrowsing API
, which allows your application to detect URLs that Google has classified as a known threat.TYPE_POTENTIALLY_HARMFUL_APPLICATION
and TYPE_SOCIAL_ENGINEERING
threat types.When sending URLs or files to be checked for known threats make sure they don't contain sensitive data which could compromise a user's privacy, or expose sensitive content from your application.
WebViewClient
which allows navigation requests to be handled by the app itself. If this is the case, be sure to search for and inspect the following interception callback functions:shouldOverrideUrlLoading
allows your application to either abort loading WebViews with suspicious content by returning true
or allow the WebView to load the URL by returning false
. Considerations:<script>
tags. Instead, shouldInterceptRequest
should take care of this.shouldInterceptRequest
allows the application to return the data from resource requests. If the return value is null, the WebView will continue to load the resource as usual. Otherwise, the data returned by the shouldInterceptRequest
method is used. Considerations:http(s):
, data:
, file:
, etc.), not only those schemes which send requests over the network.javascript:
or blob:
URLs, or for assets accessed via file:///android_asset/
or file:///android_res/
URLs. In the case of redirects, this is only called for the initial resource URL, not any subsequent redirect URLs.setSafeBrowsingWhitelist
or even ignore the warning via the onSafeBrowsingHit
callback.WebViewClient
Documentation.EnableSafeBrowsing
is true
, some applications might opt to disable it. To verify that SafeBrowsing is enabled, inspect the AndroidManifest.xml file and make sure that the configuration below is not present:shouldOverrideUrlLoading
, shouldInterceptRequest
methods while using the app and clicking on links within the WebView. Be sure to also hook other related Uri
methods such as getHost
, getScheme
or getPath
which are typically used to inspect the requests and match known patterns or deny lists.myapp
, which will result in the URI prefix "myapp://". These kind of deep links are also referred to as "Custom URL Schemes" and are typically used as a form of inter-app communication where an app can define certain actions (including the corresponding parameters) that can be triggered by other apps.Whatismyname
parameter. In this concrete case, the deep link payload would trigger reflected cross site scripting within the context of the WebView.http://
and https://
schemes, any other custom URL schemes are not allowed.<intent-filter>
elements.myapp://
. You should pay special attention to the attributes as they give you clues about how the deep link is used. For example, the category BROWSABLE
will allow the deep link to be opened within a browser.http://
and https://
schemes, along with the host and path which will activate it (in this case, the full URL would be https://www.myapp.com/my/app/path
):<intent-filter>
includes the flag android:autoVerify="true"
, which makes it an App Link and causes the Android system to reach out to the declared android:host
in an attempt to access the Digital Asset Links file in order to verify the App Links.valueOne
and valueTwo
: myapp://path/to/what/i/want?keyOne=valueOne&keyTwo=valueTwo
. In order to retrieve the input data and potentially process it, the receiving app could implement a code block similar to the following acting as a data handler method. The way to handle data is the same for both deep links and App Links:getIntent
and getData
should be verified in order to understand how the application handles deep link input data, and if it could be subject to any kind of abuse. This general approach of locating these methods can be used across most applications when performing reverse engineering and is key when trying to understand how the application uses deep links and handles any externally provided input data.<intent-filter>
elements from the AndroidManifest.xml and any custom URL schemes that they might define. For each of those deep links you should be able to determine which data they receive, if any. Remember that you might need to perform some reverse engineering first to find out if there are any input parameters that you might apply to the deep link. Sometimes you can even take advantage of other applications which you know that interact with your target app. You can reverse engineer them or use them as triggers, while hooking the data handler methods on the target app side. This way you can discover which ones are triggered and inspect valid or legitimate input parameters.android:exported="true"
. The second way involves defining an <intent-filter>
within the component element (<activity>
, <service>
, <receiver>
). When this is done, the export tag is automatically set to "true". To prevent all other Android apps from interacting with the IPC component element, be sure that the android:exported="true"
value and an <intent-filter>
aren't in their AndroidManifest.xml
files unless this is necessary.android:permission
) will also limit other applications' access to a component. If your IPC is intended to be accessible to other applications, you can apply a security policy with the <permission>
element and set a proper android:protectionLevel
. When android:permission
is used in a service declaration, other applications must declare a corresponding <uses-permission>
element in their own manifest to start, stop, or bind to the service.<activity>
:PWList.java
activity, we see that it offers options to list all keys, add, delete, etc. If we invoke it directly, we will be able to bypass the LoginActivity. More on this can be found in the dynamic analysis below.<service>
:android.app.Service
:AuthService
provides functionality for changing the password and PIN-protecting the target app.<receiver>
:sendBroadcast
, sendOrderedBroadcast
, and sendStickyBroadcast
. Make sure that the application doesn't send any sensitive data.LocalBroadcastManager
can be used to prevent other apps from receiving the broadcast message. This reduces the risk of leaking sensitive information.android.content.BroadcastReceiver
and the Context.registerReceiver
method, which is used to dynamically create receivers.android:permission
attribute; otherwise, other applications can invoke them. You can use Context.sendBroadcast(intent, receiverPermission);
to specify permissions a receiver must have to read the broadcast. You can also set an explicit application package name that limits the components this Intent will resolve to. If left as the default value (null), all components in all applications will be considered. If non-null, the Intent can match only the components in the given application package.com.mwr.example.sieve
.DBContentProvider
.com.mwr.example.sieve.DBContentProvider
, you'll see that it contains several URIs:activity
elements: