Saturday 12 October 2013

SQL Injection in Android Applications

A lot has been talked about the threat of SQL Injection attack for web applications but we don’t find many instances that point to the relevance of this attack in the case of mobile applications.

Aren't mobile applications prone to this attack?
The answer is yes, in this article we will see why SQL Injection flaw manifests in android applications and how can we mitigate it.
Let’s look at hybrid and browser-based applications first. A hybrid android application that loads a web application in its “webview” faces the threat of SQL injection if the application that it loads is vulnerable to it.
Consider a similar hybrid android application that loads a web portal as shown below. On launching the application it displays a web login page.



Now, if a SQL Injection flaw exists on this web page we can exploit it using this mobile interface in a similar manner as we would do it using a web browser.
Let’s see how.
We will try to enter a SQL Injection attack vector i.e. “‘ OR ‘1’ = ‘1’ #  and attempt to bypass the authentication. Here a true condition is used instead of a valid login ID in-order to manipulate the backend query and succeed it.

Woo! Observe that the attack vector succeeds and a valid login is obtained without valid credentials, as depicted in the screenshot below.

This means that the server side code that handles the login request has a SQL Injection vulnerability.

The case that we have seen here illustrates a server side SQL injection flaw that was exploited on a mobile interface. Similar flaws can exist in many “hybrid” and “browser-based” mobile application that loads the web application. This is server side SQL injection flaw.

Is this the only kind of SQL Injection flaw applicable to mobile applications?
No, there could be instances where even the native code is vulnerable to this attack. We will see the case of Android applications here.
Android application uses a light weight SQLite database and an extensive set of API provided by android SDK to process it.
A classic example of the use of SQLite database by android applications is in the case of local authentication.
Consider a case of an android application that stores the user data locally on the device and implements client-side authentication logic. Though local authentication is an insecure design in itself it has been used in this example just for the sake of illustrating the SQL Injection attack.
On launching the application it throws up a native login screen:


On successful login it takes the user to the next screen, as shown below. 

And in case the login is invalid it disallows access to the next screen and alerts the user.  


Now, consider bypassing this local authentication using SQL Injection technique?

Let’s attempt it. We will use the same attack vector that we used in the case of the server side flaw i.e. “ ‘ OR 1=1 --


  Bingo!! The application grants access to the next screen, as shown in the below screenshot. This means that the attack vector succeeded and the application got hacked.


This is client side SQL Injection flaw.
Let’s understand it in more detail.
Why did the attack occur in general?
The root cause of SQL Injection vulnerability is use of dynamic or concatenated SQL queries. If the SQL queries are constructed by concatenating user supplied inputs it leads to this flaw. The user can then supply SQL attack vectors instead of valid inputs and manipulate the backend SQL query.

What went wrong in that Android application?

Let’s look at vulnerable piece of code that led to the attack.

The authentication logic of the application is written within the “check_login” method, which fires a SQL query to authenticate the user. And the flaw lies in the way that SQL query is formed and executed.

We will see 3 different instances of the “check_login” method in order to get familiar with most of the insecure implementations that can be present in Android applications.

Insecure implementation 1: Vulnerable use of “rawQuery” method

In this implementation the “getReadableDatabase” method returns an instance of SQLiteDatabase class. And then its “rawQuery” method is used to execute the login SQL query as shown below.

Observe that the SQL query is formed in a concatenated fashion with the values of the username and password fields and the resultant string is passed as an argument to the “rawQuery” method.














As the user inputs are concatenated with the login query the SQL attack vector sent by an attacker as an input (“OR 1=1” in our case) is able to modify the backend query and yield desired results. Thus, we could bypass login authentication using a true condition.
Similarly, there is one more method of “SQLiteDatabase” class that is often use to execute SQL queries called “execSQL” that takes SQL string as an input and executes it. However it does not result any cursor values unlike “rawQuery”. Use of “execSQL” to run concatenated SQL queries will also lead to this flaw.

Mitigation:

The only fool proof way of preventing SQL Injection is the use of parameterized queries i.e. instead of using concatenated SQL queries we must use parameterized SQL queries. The parameterized queries are formed using place holders (“?”) in the place of input values wherever they are expected in the query. These place holders are then bound with the corresponding user inputs while processing it. This way the SQL query is not influenced by the input and SQL injection attack is mitigated.

But, does android provide any such API to write parameterized queries?

Yes, definitely. Observe that “rawQuery” that takes 2 arguments. The first argument takes the SQL query and the second argument is used to supply the input values that must be bound to the place holders present in the query, if the query supplied is parameterized as shown below.





So, in order to prevent SQL Injection we must write the SQL queries in a parameterized way.
And in the case of “execSQL” an overloaded method is present that takes 2 arguments, one for the query and other for the bind variables.

Make use appropriate “rawQuery” and “execSQL” methods that take bind values as input, as illustrated above.
Insecure Implementation 2: Use of concatenated SQL queries in the selection criteria.
There are some methods provided by Android APIs that offer a different way of querying the database. One of such instances is the "query" method of "SQLiteDatabase" class. Here, the table to be queries, the columns to be returned and the condition used to fetch the data (i.e. where clause condition) are taken as separate arguments. Here, even if a complete SQL query is not taken as a single argument but the chances of SQL Injection vulnerability exists. The developers usually make a mistake of adding a concatenated string in the argument related to the where clause condition leading to a SQL Injection hole as shown below.

Similar is the case with the “query” method of the “SQLiteQueryBuilder” class , as shown below:


 
















Mitigation:

Observe the method invocation snippet shown above carefully and note that the argument next to the where clause condition is set to null. However, this argument is supposed to take bind variables value in case the condition supplied is parameterized. Though the API provides a mechanism to use parameterized conditions but it does not enforce it.

Use parameterized where clause condition and pass the bind variables separately while using the "query" and all such methods like - update, delete, etc. that have similar implementations.
Insecure Implementation 3: Use of SQLStatement
This is an alternate way of executing SQL queries, here an instance of “SQLiteStatement” class is used to execute the SQL query. The SQL string is passed as an argument to "compileStatement" method which returns the instance of the SQLiteStatement class.
The SQL query is then executed by calling the execute method of the statement class.
As the “compileStatement” method takes a single argument, developers often supply a concatenated SQL query to it creating a hole for this vulnerability, as shown below.














Mitigation:
Even though “compileStatement” method takes only one argument, a parameterized query can be passed to it. And later the bind variable values can be bound to the inputs with the help of the “bindString” method.
As a thump rule always read the description of the method carefully given in the Android developer guide before using them. Most of the methods that are used to write SQL queries give an option to write parameterized queries and add bind variables. But they don’t enforce it. So be cautious about SQL Injection, use only parameterized SQL queries at all the places in the application.