AndroidManifest Analysis
Now that we have seen how to decode/decompile the application, let’s dive in and start looking for sensitive data, exported activities, and other items to help define our attack surface.
- Strings & String Concatenation
- Intents, Activities, Broadcasts
- Permissions
- HTTP URL’s
- Hardcoded data
The first place you will want to start is on the AndroidManifest.xml file. As mentioned earlier, this file holds a lot of app specific information such as the Permissions, Activities, etc.
Permissions
The app permissions are defined in the following format:
<uses-permission android:name=”android.permission.INTERNET”/>
Using that pattern, we can quickly extract all of the defined permissions for the app:
% grep "<uses-permission" AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.USE_CREDENTIALS"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.READ_PROFILE"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
Backup / Debugging Flags
Next, check the AndroidManifest.xml file for the backup and debug flags. The backup flag allows you to easily backup the data from the app to your laptop, which is not necessarily a good thing. The debug flag checks to see if the app is running in debug mode. If it is, you will get much more information from the console logging.
These two flags are defined in the “application” portion of the file, and are defined like this:
android:debuggable=”true”
android:allowBackup=”true”
We would want to see these set to “false” to be secure. Note that if the flag is not present in the AndroidManifest.xml file, then Android will default to a false setting for each flag.
% grep -Ei 'debug|backup' AndroidManifest.xml
<application android:allowBackup="true" android:debuggable="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@android:style/Theme.Holo.Light.DarkActionBar">
For this app, both of these flags are set to true.
Exported Functionality
For this, we are specifically looking for functionality that has been “exported”. Most apps will have a lot of functionality that is used within the app. If a function has been exported, that means it is available for other apps to use. As you can imagine, this is not generally something that you want an app to allow.
The following functionality can be exported:
- Activities
- Created using the
<activity>
tag - An activity is typically a “view” or a screen that the app shows
- Created using the
- Services
- Created using the
<service>
tag - Services are usually some processing that occurs in the background
- Created using the
- Content Providers
- Created using the
<provider>
tag - Returns some content to the function calling it
- Created using the
- Receivers / Broadcast Receivers
- Created using the
<receiver>
tag - Receives data from intents which then performs some action
- Created using the
There are two ways that functionality can be exported; explicitly & implicitly.
Explicitly exported functions are clearly defined in the AndroidManifest.xml file. They will typically follow this format:
android:exported="true"
% grep 'android:exported="true"' AndroidManifest.xml
<activity android:exported="true" android:label="@string/title_activity_post_login" android:name="com.android.insecurebankv2.PostLogin"/>
<activity android:exported="true" android:label="@string/title_activity_do_transfer" android:name="com.android.insecurebankv2.DoTransfer"/>
<activity android:exported="true" android:label="@string/title_activity_view_statement" android:name="com.android.insecurebankv2.ViewStatement"/>
<provider android:authorities="com.android.insecurebankv2.TrackUserContentProvider" android:exported="true" android:name="com.android.insecurebankv2.TrackUserContentProvider"/>
<receiver android:exported="true" android:name="com.android.insecurebankv2.MyBroadCastReceiver">
<activity android:exported="true" android:label="@string/title_activity_change_password" android:name="com.android.insecurebankv2.ChangePassword"/>
We see that there are 4 activities, 1 content provider, and 1 receiver that are explicitly exported. These are all part of the attack surface for the app, and will be investigated later.
Implicitly exported functions are not as clearly defined. As we can see in the entries below, they do not contain the exported=true flag. However, they do have an intent-filter. Anywhere there is an intent-filter defined, that entry is automatically “exported”!
% grep "<intent-filter" -B 1 AndroidManifest.xml
<activity android:label="@string/app_name" android:name="com.android.insecurebankv2.LoginActivity">
<intent-filter>
<receiver android:exported="true" android:name="com.android.insecurebankv2.MyBroadCastReceiver">
<intent-filter>
<receiver android:exported="false" android:name="com.google.android.gms.wallet.EnableWalletOptimizationReceiver">
<intent-filter>
Since there is an intent-filter for the LoginActivity that makes the count of exported activities to 5.
Our five exported activities are listed below.
- LoginActivity
- PostLogin
- DoTransfer
- ViewStatement
- ChangePassword
We also have one exported provider:
- TrackUserContentProvider
Search for the Java files that may correspond to these functions.
# change to the directory where you decoded/decompiled the app:
$ cd App
$ find . -iname \*loginactivity\*.java
sources/com/android/insecurebankv2/LoginActivity.java
$ find . -iname \*postlogin\*.java
sources/com/android/insecurebankv2/PostLogin.java
$ find . -iname \*dotransfer\*.java
sources/com/android/insecurebankv2/DoTransfer.java
$ find . -iname \*viewstatement\*.java
sources/com/android/insecurebankv2/ViewStatement.java
$ find . -iname \*changepassword\*.java
sources/com/android/insecurebankv2/ChangePassword.java
While a couple of these look interesting, we will only look at the ChangePassword.java
file. It is up to you to review the other files on your own – which will be needed for the dynamic analysis labs.
Even if you are not a programmer, you should be able to follow some of the flow and pick up on certain keywords in the code. We will look at some small snippets of code from the ChangePassword.java
file below using the standard “//” pattern for comments in the code:
Here we can see that we are creating a URL using HTTP with a server IP address and port. There is a text field that is used for the username, and a variable named “uname” that will presumably hold the username!
String protocol = "http://";
BufferedReader reader;
String result;
SharedPreferences serverDetails;
String serverip = "";
String serverport = "";
TextView textView_Username;
String uname;
The URL appears to be http://serverip:port/changepassword
.
It does not appear to contain code to enter the current password in order to make a change – which could be good!
public void postData(String valueIWantToSend) throws ClientProtocolException, IOException, JSONException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(ChangePassword.this.protocol + ChangePassword.this.serverip + ":" + ChangePassword.this.serverport + "/changepassword");
List<NameValuePair> nameValuePairs = new ArrayList<>(2);
nameValuePairs.add(new BasicNameValuePair("username", ChangePassword.this.uname));
nameValuePairs.add(new BasicNameValuePair("newpassword", ChangePassword.this.changePassword_text.getText().toString()));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
Pattern unused = ChangePassword.this.pattern = Pattern.compile(ChangePassword.PASSWORD_PATTERN);
Matcher unused2 = ChangePassword.this.matcher = ChangePassword.this.pattern.matcher(ChangePassword.this.changePassword_text.getText().toString());
From a quick look at the code, it seems like we may be able to change the password of a user without knowing their current password. Of course, we still need to obtain the username’s which we will do in dynamic analysis.
NOTE: Since this is an open source application, we do know the passwords, but for these purposes let’s act like we don’t know.
Let’s also take a look at our provider’s source code.
% grep -ri trackuser sources
sources/com/android/insecurebankv2/DoLogin.java: trackUserLogins();
sources/com/android/insecurebankv2/DoLogin.java: private void trackUserLogins() {
sources/com/android/insecurebankv2/DoLogin.java: DoLogin.this.getContentResolver().insert(TrackUserContentProvider.CONTENT_URI, values);
sources/com/android/insecurebankv2/TrackUserContentProvider.java:public class TrackUserContentProvider extends ContentProvider {
sources/com/android/insecurebankv2/TrackUserContentProvider.java: static final String PROVIDER_NAME = "com.android.insecurebankv2.TrackUserContentProvider";
sources/com/android/insecurebankv2/TrackUserContentProvider.java: static final String URL = "content://com.android.insecurebankv2.TrackUserContentProvider/trackerusers";
sources/com/android/insecurebankv2/TrackUserContentProvider.java: super(context, TrackUserContentProvider.DATABASE_NAME, (SQLiteDatabase.CursorFactory) null, 1);
sources/com/android/insecurebankv2/TrackUserContentProvider.java: db.execSQL(TrackUserContentProvider.CREATE_DB_TABLE);