Monday 17 March 2014

HTML 5 Local Storage with iOS app.

It all starts with the Concept of SSO(Single Sign On):

The concept is simple- If there are a set of different apps which performs validation -while logging in- from the same server ,then if the validation is done by the server once there is no need to validate the end user again for any other app that uses the same validating server(for a predefined time period, after the time period elapses the validation has to be done again) .How does one ensure that validation has been done once by the server? Simple - once successfully validated, the server returns a token which is saved by the app in a persistent store. This persistent store has to be common so that the other apps can access this store and if the token is present in the store the auto validation occurs.

Can Keychain be used as the required persistent store?
   
No. The iOS keychain allows us to share data between applications that share a common app -id prefix.The apps in question may or may not have the common app -id prefix.Thus this is not a very optimal solution.However if the apps in question are guaranteed to use a same app - id keychain can be used.

Alternate Solution:

HTML- 5 Local Storage:

Definition -
 Simply put, it’s a way for web pages to store named key/value pairs locally, within the client web browser. Like cookies, this data persists even after you navigate away from the web site, close your browser tab, exit your browser, or what have you. Unlike cookies, this data is never transmitted to the remote web server (unless you go out of your way to send it manually).
                                                                                                        - Mark Pilgrim (Dive into HTML 5)

Mechanism to save Data in HTML5 Local Storage:

The working of SafariStore(iOS app):

The SafariStore app is designed to work by intercepting the Ajax calls made by a url shown loaded in a UIWebView. The interceptor logic works by employing a javaScript injection that captures the Ajax requests before they hit the server. 
Once the Ajax calls are caught hold of, the SafariStore monitors the response of a Ajax call which returns a response with the header OBSSOTOKEN and JSESSIONID. These are key value pairs which are separated from the header and they are loaded in the local Storage of the Safari Browser.



Code for Ajax capturing - ajax_handler.js file :

var s_ajaxListener = new Object();
s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open;
s_ajaxListener.tempSend = XMLHttpRequest.prototype.send;
s_ajaxListener.callback = function () {
      window.location  = 'mpajaxhandler://' + this.url;
}

XMLHttpRequest.prototype.open = function(a,b) {
  if (!a) var a='';
  if (!b) var b='';
  s_ajaxListener.tempOpen.apply(this, arguments);
  s_ajaxListener.method = a;  
  s_ajaxListener.url = b;
  if (a.toLowerCase() == 'get') {
    s_ajaxListener.data = b.split('?');
    s_ajaxListener.data = s_ajaxListener.data[1];
  }
}

XMLHttpRequest.prototype.send = function(a,b) {
  if (!a) var a='';
  if (!b) var b='';
  s_ajaxListener.tempSend.apply(this, arguments);
  if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a;
  s_ajaxListener.callback();
}

Script Injection when Page loads:

+ (void)initialize {
    JSHandler = [NSString stringWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"ajax_handler" withExtension:@"js"] encoding:NSUTF8StringEncoding error:nil] ;
 }

- (void)webViewDidStartLoad:(UIWebView *)webView {
    //Injecting the javaScript before the view starts to load.Employing Script Injection
      [webUIView stringByEvaluatingJavaScriptFromString:JSHandler];
   
}

Safari Local Storage with SafariStore:



The OBSSOToken so collected is sent to a scripting file(.js) which handles the saving of the token in safari local cache this makes calling Safari from the SafariStore essential. This is achieved through an HTML file saved in the  local recourses of Xcode which calls the above mentioned scripting file.This HTML file is loaded in the Safari browser when safari is invoked from the SafariStore.This makes sure that the OBSSOTOKEN is stored in Safari and not locally on a UIWebView.



Code for the .js file:

var result =function (tokenValue) {
    //if browser does not support this feature give a error code
    if (typeof (localStorage) == 'undefined') {
        return 404;
    }
    else {
        try {
            localStorage.setItem("ssoToken", tokenValue); //Set the key-value pair
            if (localStorage.getItem("ssoToken")) {
                //Get the value from storage area
                var output = '';
                output = localStorage.getItem("ssoToken");
                return output;
            }
        }
        catch (e) {
            //if the memory is full show a error code
            if (e == QUOTA_EXCEEDED_ERR) {
                return 400;
            }
        }
    }
    
};

Code for HTML file calling the .js file:

<!DOCTYPE html>
<html>
    <body>
        <script src="localStorageScriptHandler.js"></script>
    </body>
</html>

Challenges in the above logical flow:



While the above logic works flawlessly when executed in a simulator.The logic fails while executing on an iOS device.The point of failure is when we try to load the local HTML file in a Safari browser from the app. The reason for this failure is due to Apple disallowing any app from running a local scripting file in Safari due to security reasons.
The following link from Apple communities discuss this:https://discussions.apple.com/thread/2206391?start=0&tstart=0



Solution and Workaround:



While Apple stops an app from running a local scripting file in Safari it however does not stop loading a fully qualified web URL from the app into the safari browser.This brings us to a solution that if we are able to host our HTML file and the scripting file in a secured-server which can be reached from our app,we will be able to achieve the desired result while working with an iOS device.Practically we managed to create an app which uses DropBox as a hosting server for the HTML file needed to set the local storage in mobile safari browser and then another app using the same  hosting server managed to retrieve the value of the local storage from Safari.



SideEffects:



The only side effect to the above mentioned solution would be a bad user experience because a user sees a Safari-browser being launched suddenly from the  app.
   
Result:

The Final result is awesome. We connect the iOS device that we have been using to our MAC and launch safari. We launch the app from the spring board and the test- url we loaded in the web view comes up. Now we goto the develop option in our MAC safari and we find the name of our app listed ,on clicking it we have a  web - inspector pane where we can actually see the OBSSOTOKEN and JSESSIONID stored in local Storage as a key-value pair.


Saturday 8 March 2014

Writing and Coding:

There is a peculiar comfort in arranging instructions till it makes logical sense and gets a particular work done. It's like solving a  jig-saw puzzle or a sudoku. There is a feeling of elation, of mental satisfaction which comes whenever the logical pattern created by our brain matches with the understanding of the computer. The first code I wrote in my life(I was in the fourth grade then) was in basic- a simple addition of two numbers,when the computer finally produced an output of the sum of two integers ,I had the feeling-"Dear God, I have the ability to think like a machine".
  
There is another occupation in life that matches this elation of coding.It's writing.It's just like coding, arranging particular words in a sentence so that it makes sense to another individual.The clarity of thought is brought out in both cases. A good coder is the one whose goals are set and the path to that goal is clearly thought out similarly a good writer expresses his thoughts clearly in a logical order to his readers and reaches his/her own conclusions.The beauty of both the arts come from the simplicity of thought which achieves the most direct method of solving a problem.A good coder gets his/her work done by the minimum intricacy possible similarly  a good writing is simple,direct and concise.There is a remarkable absence of intricacy, ornamentation and clutter in both good writing and good coding.Now here's a thing that intrigues me most - Are all good coders good writers and vice versa.I am still working on that.

Thursday 20 February 2014

UNIX Domain Sockets - An unusual way for inter app communication -iOS

Yes,they did it again. The penetration testers irritated me once again. This time it is exchanging data between two applications.Initially these were the methods used by me to achieve inter app communication:

1.Use Keychain - Age old technique of encrypting the data with a salted SHA -256 algorithm and storing the data in the keychain.

2. Use UIPasteBoards - Technique uses a customized UIPasteBoard to share data between applications.

There are other techniques as well like URL -Schema , HTML 5 local storage etc. but in my case I had the use-case, where I was not allowed to launch a second app  or a browser from my parent app. Thus I had to rule out a few techniques.Of the remaining techniques that were available- using UIPasteBoards had to be ruled out because my app needed to support jail-broken devices as well. The penetration testers were able to access the binary property list file created by UIPasteBoards - /private/var/mobile/Library/Caches/com.apple.UIKit.pboard/pasteboardDB
in a jail Broken devices-consequently the app was exposed. 

I held a strong opinion that the keychain is virtually unbreakable,but it proved inadequate as well.The penetration testers used a app called Snoop -it  for a jailbroken device and the app was exposed again.Here is a basic idea about how it's done - http://resources.infosecinstitute.com/ios-application-security-part-12-dumping-keychain-data/

This is where I discover a very obscure technique called UNIX domain sockets. Here is what wiki describes Unix domain sockets as -http://en.wikipedia.org/wiki/Unix_domain_socket

This is the way we achieved inter app communication using Unix Domain Sockets :

1.Creating and Opening a Unix domain socket:


#define SOCKET_PATH "/var/mobile/Library/AddressBook/SOCKET"
int serverSocket = socket(AF_UNIX, SOCK_STREAM, 0);
if (serverSocket < 0) {
  perror("socket");
  exit(EXIT_FAILURE);
}
// Ensure that SOCKET_PATH does not exist
unlink(SOCKET_PATH);
struct sockaddr_un address;
address.sun_family = AF_UNIX;
strcpy(address.sun_path, SOCKET_PATH);
socklen_t addressLength = SUN_LEN(&address);
if (bind(serverSocket,
         (struct sockaddr *)&address,
         addressLength) != 0) {
  perror("bind");
  exit(EXIT_FAILURE);
}
if (listen(serverSocket, 5) != 0) {
  perror("listen");
  exit(EXIT_FAILURE);
}
int connection = 0;
while ((connection = accept(serverSocket,
                            (struct sockaddr *)&address,
                            &addressLength)) >= 0) {
  NSString *message = @"This is a message from the other program.";
  NSMutableData *messageData =
    [[[message dataUsingEncoding:NSUTF8StringEncoding] mutableCopy]
     autorelease];
  write(connection,
        [messageData mutableBytes],
        [messageData length]);
  close(connection);
}
close(serverSocket);
// Remove socket at SOCKET_PATH
unlink(SOCKET_PATH);

Whenever an app performs interprocess communication via Unix domain Sockets one of the app must run in the background.The application in the background can can initiate a long running task by using beginBackgroundTaskWithExpirationHandler:
This is how the app which created the socket using the above code starts the long running task when it enters background:

// Begin async execution in background. ‘socketTaskID’ (of type // UIBackgroundTaskIdentifier) is an instance variable of the // current class.
UIApplication *sharedApp = [UIApplication sharedApplication]; socketTaskID = [sharedApp
                beginBackgroundTaskWithExpirationHandler:^(void) {
  [sharedApp endBackgroundTask:socketTaskID];
   socketTaskID = UIBackgroundTaskInvalid;
}];
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // Listen for incoming connections -> See Listing 4-10
// ...
  [sharedApp endBackgroundTask:socketTaskID];
  socketTaskID = UIBackgroundTaskInvalid;
});

Now the second app which receives the data comes to the foreground - we have already send our app that has created the socket to the background.This is how the second application receives string from the first application via the socket already created:


#define SOCKET_PATH "/var/mobile/Library/AddressBook/SOCKET"
int clientSocket = socket(AF_UNIX, SOCK_STREAM, 0);
if (clientSocket < 0) {
  perror("socket");
  exit(EXIT_FAILURE);
}
struct sockaddr_un address;
address.sun_family = AF_UNIX;
strcpy(address.sun_path, SOCKET_PATH);
socklen_t addressLength = SUN_LEN(&address);
if (connect(clientSocket,
            (struct sockaddr *)&address,
            addressLength) != 0 ) {
  perror("connect");
  exit(EXIT_FAILURE);
}
// Receive the string.
NSMutableData *receivedData = [[[NSMutableData alloc]
                                initWithLength:100]
                               autorelease];
read(clientSocket,
     [receivedData mutableBytes],
     [receivedData length]);
NSString *receivedMessage = [[[[NSString alloc]
                              initWithData:receivedData
                              encoding:NSUTF8StringEncoding]
                             autorelease];
NSLog(@"Received: %@", receivedMessage);
[receivedData release];
// Close the connection.
close(clientSocket);

There we go, we have managed to set up an inter app communication using Unix sockets which is difficult for penetration testers to crack - at least for the time being.I guess the only limitation of this method is that is uses a  common directory - /var/mobile/Library/AddressBook/ for both the communicating applications.
Wish my readers many many happy hours of Coding....






Wednesday 19 February 2014

Mobile Security - Save your iOS- app data from Burp Suite

Recently I had bad time with penetration testers. They orchestrated a MIM (Man In the Middle) attack on the iOS -app that we were developing and were able to intercept all our sensitive data.
For those of you who are have never dealt with penetration testers, they can be a real pain. This is how they made a MIM attack:

1.App interacts with a server - Ngenix to interchange data.
2.Using Burp-Suite the app was fooled to believe that a intermediate server was the Ngenix server.
3.App interacts with Ngenix server - Data is intercepted.

Here is a link to demonstrate the Burp-Suite capability:
http://www.tuaw.com/2011/02/21/how-to-inspect-ioss-http-traffic-without-spending-a-dime/

After knitting brows for a long time we finally cracked it. For those of you out there who still have their brows knitted, here's some help.
Algorithm to stop Burp Suite redirection to fake server.

1.Install a signed certificate to Ngenix server - Our's was an AlphaSSL certificate.This needs to be done only once on the server end.
2.AlphaSSL gives a client certificate as well. At the client end we had put the client certificate in our documents directory- Ideally save the client certificate in KeyChain.
3.In order to confirm that the app is interacting with Ngenix and not some MIM attacker's server- We match the fingerprint of our client certificate with  the fingerprint of the server certificate.If these fingerprints match  only then communications are allowed .
4.Request parameters are encrypted with a pre- defined algorithm - either SHA -251 or SHA -1 and are sent to the server.
5.The Ngenix server logic decrypts the parameter and sends the corresponding encrypted response.

Here are some key code snippets:

1. Generating Client FingerPrint:

-(NSString*)generateClientFingerPrint
{
    NSString *certificateName = [NgenixLib returnValueForKey:@"certificateName" ];
    NSLog(@"The certificate name is :::::::::%@",certificateName);
    NSString *rootCertPath = [[NSBundle mainBundle] pathForResource:certificateName  ofType:@"cer"];    
NSData *rootCertData = [NSData dataWithContentsOfFile:rootCertPath];
   //Code to generate the fingerPrint
    NSLog(@"root Data=%@",[self sha1:rootCertData]);
    NSString *clientFingerPrint = [NSString stringWithString:[self sha1:rootCertData]];
    return clientFingerPrint;

}

-(NSString*)sha1:(NSData*)certificatData {
    unsigned char sha1Buffer[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1(certificatData.bytes, certificatData.length, sha1Buffer);
    NSMutableString *fingerprint = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 3];
    for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; ++i)
        [fingerprint appendFormat:@"%02x ",sha1Buffer[i]];
    return [fingerprint stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

}

2.Verifying the Server :

- (void)connection:(NSURLConnection *)connection  didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    //This is where the action truely lies!!
    //This delegate method gets the public key from the certificate
    //Gets the fingerprint from the certificate and notifies that the
    //Fingerprint has been generated
   NSString* trustUrl = [NgenixLib returnValueForKey:@"trustUrl"];
    NSLog(@"The trustUrl++++++%@",trustUrl);
    NSArray *trustedHosts = [NSArray arrayWithObject:trustUrl];
    BOOL isAuthMethodServerTrust = [challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
    NSLog(@"<%p %@: %s line:%d> Result:%s", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __PRETTY_FUNCTION__, __LINE__, (isAuthMethodServerTrust == YES) ? "YES" : "NO");
    if (isAuthMethodServerTrust)
    {
        NSLog(@"####### =%@",challenge.protectionSpace.host);
        if ([trustedHosts containsObject:challenge.protectionSpace.host])
        {
            NSLog(@"<%p %@: %s line:%d> trustedHosts containsObject:challenge.protectionSpace.host", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __PRETTY_FUNCTION__, __LINE__);
            NSURLCredential* urlCredential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            NSLog(@"<%p %@: %s line:%d> Url credential", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __PRETTY_FUNCTION__, __LINE__);
            [challenge.sender useCredential:urlCredential forAuthenticationChallenge:challenge];
            
            //Code to verify server certificate info
            //The server’s SSL transaction state, or nil
            //if the authentication method of the protection space is not server trust.
            
            SecTrustRef trustRef = [[challenge protectionSpace] serverTrust];
            CFIndex count = SecTrustGetCertificateCount(trustRef);
            NSLog(@"The count is =%ld",count);
            //for (CFIndex i = 0; i < count; i++)
            
                SecCertificateRef certRef = SecTrustGetCertificateAtIndex(trustRef, 0);
                CFStringRef certSummary = SecCertificateCopySubjectSummary(certRef);
               
                //This is where the server certificate data is finally collected.This method
                //Returns a DER representation of a certificate given a certificate object.
                certData = SecCertificateCopyData(certRef);
                
                NSLog(@"<%p %@: %s line:%d> Certificate summary:%@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __PRETTY_FUNCTION__, __LINE__, (__bridge NSString*) certSummary);

                
                //Calling SecTrustCopyPublicKey method to get the public Key of the server
                SecKeyRef status =  SecTrustCopyPublicKey(trustRef);
                NSLog(@"<%p %@: %s line:%d> Certificate data:%@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __PRETTY_FUNCTION__, __LINE__, (__bridge NSString*) status);
            
                //Getting the SHA1 finger print from the server
                //The CFDataRef type is converted to data and is send over
                //For generating the fingerPrint
                //NSLog(@"*********%@",(__bridge NSData *)(certData));
               NSString * fingerPrint = [self sha1:(__bridge NSData *)(certData)];
                NSLog(@"the FingerPrint is =%@",fingerPrint);
               
                //Saving the user certificate in KeyChain
                //[self saveCertificate];
                //getting the client fingerprint
              NSString* clientFingerPrint =  [NSString stringWithString:[self generateClientFingerPrint]];
                if([fingerPrint isEqualToString:clientFingerPrint])
                {
                    connectionResult = YES;
                    //Posting a notification that the FingerPrint has been obtained
                    //After a previous notification is removed
                    [[NSNotificationCenter defaultCenter] postNotificationName:@"HandleFingerPrintReceived" object:nil];

                }
                else{
                    UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"Alert!!" message:@"The Certificate is invalid,this is a SECURITY THREAT!!The application will exit now" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
                    [alertView show];
                    }
                        
        }
    }
    
}
These are basically the main methods to handle server verification.I will post the  complete source code soon. Keep watching this space ....
Happy Coding....