Vulnerable Library Warning: TwitterKit for iOS

The Twitter Kit framework through 3.4.2 for iOS does not properly validate the TLS certificate for api.twitter.com. That’s a finding found with our static binary analysis and reported to Twitter.

There will be no fixed version, as this library is no longer supported by Twitter, but this vulnerable library was still found in many apps. It is urgently advised that their app developers switch to alternative APIs.

Such issues are likewise common, which illustrates the need to check for vulnerable or outdated 3rd party code.

What makes this issue a bit special is the way the developers broke the validation of TLS certificates. Apparently, they wanted to increase the security by implementing a public key pinning of trusted root certificate authorities (CA), such as VeriSign, DigiCert and GeoTrust. So they created the following array with entries of 21 public key hashes for the CAs:

"1a21b4952b6293ce18b365ec9c0e934cb381e6d4",  // "VERISIGN_CLASS3_G2"
"2343d148a255899b947d461a797ec04cfed170b7",  // "VERISIGN_CLASS1"
"5519b278acb281d7eda7abc18399c3bb690424b5",  // "VERISIGN_CLASS1_G3"
"1237ba4517eead2926fdc1cdfebeedf2ded9145c",  // "VERISIGN_CLASS2_G2"   
"5abec575dcaef3b08e271943fc7f250c3df661e3",  // "VERISIGN_CLASS2_G3"    
"22f19e2ec6eaccfc5d2346f4c2e8f6c554dd5e07",  // "VERISIGN_CLASS3_G3"
"ed663135d31bd4eca614c429e319069f94c12650",  // "VERISIGN_CLASS3_G4"
"b181081a19a4c0941ffae89528c124c99b34acc7",  // "VERISIGN_CLASS3_G5"
"3c03436868951cf3692ab8b426daba8fe922e5bd",  // "VERISIGN_CLASS4_G3"
"bbc23e290bb328771dad3ea24dbdf423bd06b03d",  // "VERISIGN_UNIVERSAL"
"c07a98688d89fbab05640c117daa7d65b8cacc4e",  // "GEOTRUST_GLOBAL"
"713836f2023153472b6eba6546a9101558200509",  // "GEOTRUST_GLOBAL2"
"b01989e7effb4aafcb148f58463976224150e1ba",  // "GEOTRUST_PRIMARY"
"bdbea71bab7157f9e475d954d2b727801a822682",  // "GEOTRUST_PRIMARY_G2"
"9ca98d00af740ddd8180d21345a58b8f2e9438d6",  // "GEOTRUST_PRIMARY_G3"
"87e85b6353c623a3128cb0ffbbf551fe59800e22",  // "GEOTRUST_UNIVERAL"
"5e4f538685dd4f9eca5fdc0d456f7d51b1dc9b7b",  // "GEOTRUST_UNIVERSAL2"
"d52e13c1abe349dae8b49594ef7c3843606466bd",  // "DIGICERT_GLOBAL_ROOT"
"83317e62854253d6d7783190ec919056e991b9e3",  // "DIGICERT_EV_ROOT"
"68330e61358521592983a3c8d2d2e1406e7ab3c1",  // "DIGICERT_ASSUREDID_ROOT"
"56fef3c2147d4ed38837fdbd3052387201e5778d",  // "TWITTER1"

On every new connection, TwitterKit for iOS checks in method evaluateServerTrust whether the received certificate chain contains a certificate with a fitting public key of the list above. This way, certificates for api.twitter.com issued by possibly untrusted CAs should be blocked. However, this approach lacks a very important verification: The domain name of the leaf certificate is not verified by iOS, as TwitterKit for iOS implemented an own delegate method for its public key pinning functionality. In this case, iOS only verifies, that the certificate chain is valid regarding signatures. All other checks have to be performed by the delegate method, to provide the flexibility for alternative verification methods. A simple fix would have been additionally calling the iOS method secTrustEvaluate and utilize its result value to reject certificates for other domains.

Because of the missing domain name verification, any valid certificate chain containing a certificate with a public key hash of that list is accepted by the app. An attacker with a valid certificate for his own domain, issued by one of these CAs, can use this certificate for man-in-the-middle-attacks against apps communicating via the Twitter Kit for iOS with api.twitter.com. As the implementation does not check the position inside the chain, the matching public key could also be in the middle of the chain, such as in case of an intermediate certificate.

We used a matching legitimate certificate, issued by DigiCert for a domain under our control to verify the impact of the vulnerability. So we redirected the traffic for api.twitter.com to our server, that answers the request with our own certificate. The received content is logged and transmitted to the ‘real’ Twitter servers. The server’s response is also logged and transmitted back to the app. However, as the login process for Twitter involves a WebView, which does not use the vulnerable pinning functionality, it would not accept our certificate. As the WebView loads its content via the same domain name, we had to distinguish TLS connections based on differences in ALPN extension of the TLS Client Hello and route WebView connections without interception, to create a fully working proof of concept attack.

During the Login with Twitter process, our man-in-the-middle proxy recorded for a vulnerable news app the OAuth 1.0 oauth_token_secret together with the authorized oauh_token. This enabled us to fully use the provided Twitter API with these long term secrets. Attackers could perform actions like changing content of the profile, creating fake tweets and direct messages or abusing the account to push tweets via fake likes. It would also be possible to read private direct messages sent or received within the last 30 days. We could not retrieve the password nor set it to a known value, so an attacker could not use the vulnerability to lock out a user from his account. However, by changing the Twitter password a victim would also not be able to invalidate the sniffed OAuth tokens. For this it is required to revoke the app’s authorization within the Twitter settings.

Further, on every app start the vulnerable app checks the validity of the Twitter account by invoking the Twitter API account/verify_credentials.json. In case the credentials are valid, the response contains detailed information about the victims Twitter profile, such as ID, name, location and last activities. As the response can be read in our attack scenario, the information can be used to collect information about the victim to track him or dynamically create targeted phishing attacks.

We will demonstrate the vulnerability and its detection at it-sa 2019 fair in Nuremberg, Germany at Hall 9, Booth 234.