Thursday, March 26, 2015

SSL MiTM attack in AFNetworking 2.5.1 - Do NOT use it in production!

During a recent mobile application security analysis for one of our clients, we identified a quite unobvious behaviour in apps that use the AFNetworking library.

It turned out that because of a logic flaw in the latest version of the library, SSL MiTM attacks are feasible in apps using AFNetworking 2.5.1.

The issue occurs even when the mobile application requests the library to apply checks for server validation in SSL certificates.
Given that AFNetworking library is one of the most popular networking library for iOS and OS X and it is used by Pinterest, Heroku and Simple among others, the problem could affect a very high number of mobile users.
Here's the usage of AFNetworking library on Github:
Github statistics for the AFNetworking library

Although the vendor has been aware of this issue since February 13th, 2015, there's still no official patch for it.


Update 27.03.15: AFNetworking patched the issue in version 2.5.2 a few hours after this post, we appreciated that.

Update 22.04.15: As correctly pointed out in this post (English version) by mala, AFNetworking 2.5.2 cannot still be considered secure, since it  does not enforce hostname validation by default.
We did not stress such circumstance in our blogpost as we were optimistically assuming that developers read the validatesDomainName property documentation, stating:

"- Whether or not to validate the domain name in the certificate's CN field. Defaults to `YES` for `AFSSLPinningModePublicKey` or `AFSSLPinningModeCertificate`, otherwise `NO`."

This default behaviour is present and documented since the first introduction of the property, that is from version 2.1.0.
Since the library does not verify by default that the hostname of the request matches to the hostname in the certificate, an attacker could use an arbitrary certificate signed by a trusted CA and successfully perform a MiTM attack.

In other words, if you're using a version of AFNetworking which is >= 2.1.0 and <= 2.5.2, then you should be vulnerable by default, unless you set validatesDomainName to YES.

The "new" issue was addressed in AFNetworking 2.5.3, where the default value of validatesDomainName has been properly set to YES under all security policies.

 

The Issue

On the 6th of March, when looking at the tested application source code, we identified the following part:
#if TARGET_IPHONE_SIMULATOR && defined(DEBUG)     [AFSecurityPolicy setAllowInvalidCertificates:YES]  #endif

SSL certificate validation was disabled if and only if the build target was the iPhone simulator and the DEBUG flag was set. Let's remind that the default value of the allowsInvalidSSLCertificate property is NO.

We tested the app on a real device and, unexpectedly, we found that all the SSL traffic could be regularly intercepted through a proxy like Burp without any intervention!

Further investigation led us to a particular part in AFNetworking code where trust evaluation was somehow disabled.
After few minutes, we figured out that there was a logical bug while evaluating trust for SSL certificate, whose consequence was to completely disable SSL certificate validation.

- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain 
method within the AFSecurityPolicy.m file: 

- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
      forDomain:(NSString *)domain
{
  NSMutableArray *policies = [NSMutableArray array];
  if (self.validatesDomainName) {
     [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
  } else {
     [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
  }

  SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);

  if (self.SSLPinningMode != AFSSLPinningModeNone &&
 !AFServerTrustIsValid(serverTrust) && 
!self.allowInvalidCertificates) {
   return NO;
 }

 NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
    switch (self.SSLPinningMode) {
        case AFSSLPinningModeNone:
            return YES;

Which means that if pinning is not used,

 SSLPinningMode == AFSSLPinningModeNone

then the yellow-highlighted  `if` statement evaluates to `false`, even though the property `allowInvalidCertificates` is set to `NO`.

The code flow will hence reach the red-highlighted branch, with the result of cancelling out the whole SSL certificate validation.

It is also important to note that the default value of SSLPinningMode is, indeed, `AFSSLPinningModeNone`.

After a few "feeling cool" moments, we discovered that the implementation flaw was already known and reported here. One month later a new issue was submitted with a more clear description.
Further investigation allowed us to understand that the bug was introduced in late January during the development of AFNetworking 2.5.1.
Warning: 2.5.1 is the latest version at the time of this writing and is installed by default using CocoaPods if not stated otherwise. Refer to the update note above.

 

The impact: SSL MiTM attacks

Eventually, the overall risk can be evaluated as high since a MiTM attack is feasible in all iOS applications using AFNetworking 2.5.1, even though the developers were mindful enough to disable debug settings in the production build.
Moreover, take into consideration that mobile apps are typically used while being connected via public hotspots.


Remediation

Minded Security suggests to consider applying the patch proposed by duttski on his GitHub AFNetworking code, as a workaround until an official patch will be released (click to enlarge):
Unofficial Patch of AFNetworking issue


Finally, it's worth mentioning that setting allowInvalidCertificates to YES would make you deliberately vulnerable no matter what the library does (yes, we know you know, but.. you know..;).

Brought to you by Simone Bovi and Mauro Gentile

12 comments :

  1. AFNetworking 2.5.2 is the latest as of March 26, and does not suffer from the described vulnerability.

    ReplyDelete
  2. What about responsible disclosure?

    ReplyDelete
  3. @Mikel , as state in our post, there's no need for responsible disclosure since the issue was already public in AFNetworking repository, you should ask that to the guy that posted the issue on Github. :)

    ReplyDelete
  4. @Anonymous, thanks for the heads up! We've just updated the post.

    ReplyDelete
  5. Hmm,
    https://github.com/AFNetworking/AFNetworking/blob/master/AFNetworking/AFSecurityPolicy.m#L249
    https://github.com/AFNetworking/AFNetworking/issues/2549

    The default value of validatesDomainName is NO,
    I think that AFNetworking 2.5.2 is still vulnerable.

    ReplyDelete
  6. The validatesDomainName problem is fixed with https://github.com/AFNetworking/AFNetworking/commit/3e631b203dd95bb82dfbcc2c47a2d84b59d1eeb4

    ReplyDelete
  7. This article includes wrong information. Please fix it.
    The version of less than 2.5.1 is also vulnerable, and not fixed yet in 2.5.2.

    ReplyDelete
  8. By the way, the patch referenced in this article was never used... (I know because I re-made it and recognise the difference -- the patch you mention was withdrawn and re-made with some better names.). Check the commits leading to 2.5.2 and the subsequent update mentioned in these comments. Worth adding a correction/edit to the article IMO.

    ReplyDelete
  9. Is this problem applicable for AFNetworking 1.x library too?

    ReplyDelete
  10. If you are still using AFNetworking 1.x on new projects you have a totally different existential issue
    If your project hasn't been updated since september/october 213, probably no one cares about your project

    ReplyDelete
  11. I want to more information's in your blog, Really good in your networking bogs for ours.Thank for sharing.

    ReplyDelete
  12. See also:
    https://github.com/AFNetworking/AFOAuth2Manager/issues/98

    ReplyDelete