Testing SSL Pinning in a mobile Application

David Arteaga Grigoriev
Globant
Published in
9 min readJul 20, 2020

Summary

This document describes the concept of SSL Pinning and the importance of its implementation in mobile projects to prevent the interception of TLS/SSL requests made by an application on a private network using a proxy.

Description

OWASP defines SSL pinning as “Users and developers expect end-to-end security when sending and receiving data in their applications, especially sensitive data on channels protected by either VPN, SSL, or TLS. While organizations that control DNS (Domain Name System) and CA (Certificate Authority) have reduced the risk to trivial levels in most threat models, users and developers subject to the DNS of others and to a hierarchy of public CA they are exposed to non-trivial amounts of risk”. In the case of mobile applications, one of the priorities that should be taken into account is that the calls or requests made to services that are consumed by the application should not be intercepted. If a user, or in the specific case of a malicious user, can capture the requests of the application to the back-end / service and the parameters that it passes to it, the attacker can manipulate the requests made, either by manipulating the parameters sent in the request, the request headers, the type of request that you make, passing parameters of different types to those expected that are validated in the front-end layer and not in the back-end layer, among others.

One of the ways in which a malicious user can capture the requests of an application, even if they are protected by secure channels, is by installing signed certificates by his/her own CA and configuring a proxy that using that certificate captures the requests sent by the application. By relying on the proxy certificate, it is possible to capture the requests even if they go through a secure channel, and to expose parameters, headers, URLs and types of requests sent to the service consumed by the application. One way to avoid these types of non-trivial threats is through the implementation of SSL Pinning in the application.

That said, SSL Pinning takes the certificate or public key hash of a host or service; which can be added to an application at the time of development and compared with the published service every time the application sends a request. It can also be added in the first handshake between the application and the service. It is preferable to choose the first method, since preloading the certificate or the out-of-band public key usually means that the attacker cannot spot the pin. If the certificate or public key is added in the first encounter, it could be pinning the attacker certificate.

SSL Pinning leverages on the existing relationship between the user and an organization or service to help make better security-related decisions. Since you already have information about the server or service, you don’t need to rely on generalized mechanisms to solve the key distribution problem. That is, you don’t need to go to DNS for name / address or CA assignments for links and status.

Every time the application sends a request to the host or service, it compares the certificate in the application with the one received from the service, if they match means there is a secure connection between them, otherwise the application will not send the data and will inform the user of a connection error. Pinning can be done against the Leaf, Intermediate or Root Certificate. Each type and difference and implementation are widely explained by Mathew Dolan in his Android Security: SSL Pinning article.

The following Proof of Concept (PoC) is an example about the importance of SSL pinning. The example captures a request with a login form and exposes credentials in plain text and modifies them through a proxy tool. The second example includes an implementation of SSL Pinning which prevents the interception of the login form. This PoC includes Burp Suite Community Edition to capture the application request, which contains a proxy that can be set in order to do the captures.

Proof of Concept Development

Topology

Image 1: Topology Context Diagram

Proxy settings

For this specific case, the Burp Suite Community Edition tool was used. This tool comes with an integrated proxy function. Different tools can be used for this purpose such as: Charles, MitM Proxy, ZAP, etc.

For this WLAN the IP of the Burp proxy was set as 10.30.6.134 on port 8080. These configurations must be set on the phone which have the application that is going to be tested.

Image 2: Burp Proxy configuration

Mobile configuration

For the WLAN, the client/phone (iPhone 7 v13.3.1) in which the application will be tested, has a private IP set to 10.30.6.133. Then, we also need to configure the proxy used by the phone with the IP defined in the previous step.

Image 3: Mobile IP Topology configuration
Image 4: Mobile Proxy Topology configuration

If you are using the Android Studio emulator you must configure the proxy in the extended controls of the emulator in the setting menu and proxy tab. For this example the IP is set as is shown in the topology.

Image 5: Android Studio emulator proxy configuration

Mobile Certificate configuration

Burp certificate (Portswigger CA) must be set as “full trust” in order for Burp to intercept the requests. All the steps of installation of the certificate could be found in the official Portswigger documentation for iOS and Android.

Image 6: Mobile certificate configuration full trust
Image 7: Mobile certificate configuration verified

Capturing Requests

At this step, we can start testing and intercepting requests. Note that when intercepting requests, the proxy captures the request for a URL protected by SSL, and even though it travels through a secure channel, the parameters of the request can be seen in plain text.

Login incorrect credentials test

The first test is done for an application which has a form that sends an email and password for authenticating a user inside the application. In this test, in order to show in plain text the parameters sent on the request, it was tested with incorrect credentials on the form and were captured on Burp.

  • Sending credentials through mobile application
Image 8 Mobile application login test
  • Proxy Interception of requests incorrect credentials

The request is intercepted in the Burp proxy and we can see the URL of the exposed end-point and the user’s credentials sent in the parameters are shown in plain text. These parameters are sent to the application back-end and can be manipulated on the repeater tool that has Burp.

Image 9: Proxy request intercepted incorrect credentials
  • Proxy History Request incorrect credentials

For this test we can also see the status of the response of the request in the proxy HTTP history tab.

Image 10: Proxy history request incorrect credentials
  • Proxy History Response incorrect credentials

Also we can see the response of the request that has been received from the end-point.

Image 11: Proxy history response incorrect credentials

Login with correct credentials test

The next example was done with correct credentials for the same application form and intercepting the response of the back-end service of the application.

  • Proxy History Request correct credentials
Image 12: Proxy history request correct credentials
  • Proxy History Response correct credentials

As you can see in this test, the response shows an access_token and more information about the user. This information and the one that was shown in the first test, could be used to automate a brute force attack against this application back-end or perform a DDoS attack against it.

Image 13: Proxy history request correct credentials

SSL Pinning Implementation

iOS

Swift 5.2 provides a relatively simple way of implementing SSL pinning for an iOS application. The certificate of the end-point must be downloaded. Once the certificate is downloaded, the certificate must be put as a file in the resource folder so that it can be recognized within the classes of the project that wish to invoke it. For this example it was called “certificade-file-name” and has .der extension. The existing certificate is compared and the “challenge” from the service is resolved. Every time the application sends a request, it uses the developed method. In this case, the “urlSession” method.

Image 14: Swift code SSL pinning, credits to Ivan Rapoport

Android

In the case of Android, it is not required to download the entire certificate, just include the hash and compare it with the one from the service. In the extras section you can find a bash code to extract the hash of public certificates. The OkHttp3 library has a method in the client that deals with the verification of hashes with each request made. On the next Kotlin code example, it performs the pinning in the part where the okHttpClientBuilder object is built, a separate object of type CertificadePinner is created that contains the hash as sha256. The CertificadePinner object is sent as a parameter in the certificatePinner method of the okHttpClientBuilder object:

//OkHttp3 Client
val okHttpClientBuilder = OkHttpClient.Builder()
.authenticator(CustomAuthenticator.getInstance(context))
//SSL Pinning
val certPin = CertificatePinner.Builder()
.add(BuildConfig.PATTERN, "sha256/YOUR-HASH-HERE")
.build() okHttpClientBuilder.certificatePinner(certPin)

For more implementation methods in Android:

Testing request capture with SSL Pinning implemented

After the implementation is done is time to check again the procedures done in previous sections and compare the results.

In the first place it could be seen on the event log on the dashboard of Burp that the connection SSL, when requests are sent on the application, can’t be done because it fails on the exchange of certificates.

Image 15: Burp certificate negotiation error

In the same way, if you have the possibility to debug the application with Logcat, for the case of the Okhttp3 library you can see an error that informs you an SSL handshake exception that the certificate pin that has been configured doesn’t match with the one that is currently trading between the application and the end-point. In other words, the library can’t find the path of the certificate that was received in the current request, and doesn’t allow the connection to be established between the pairs.

Image 16: Android logcat Okhttp3 pinning error

A bad or null configuration of SSL Pinning in an application leaves exposed the calls that a mobile application makes to its back-end. A malicious user can use this as an attack vector.

Risks

SSL Pinning is a prevention method, however there are still ways to avoid this protection, for example using programs such as Frida that allows the injection of snipes that allows you to bypass this measure. Another example could be performing a reverse engineering over the application, changing the hash (on Android) and re-building it. It is recommended to use encryption algorithms for sensitive information in the communication between the application and its back-end so if someone could see the request would not be in plain text.

Extras

Install burp certificate on iOS
Installing Burp’s CA Certificate in an iOS Device

Install burp certificate on Android
Installing Burp’s CA Certificate in an Android Device

Bash code for extraction of hash in sha256 of a public certificate (extracted from: Android Security: SSL Pinning. Using SSL in an Android app is easy… | by Matthew Dolan)

#!/bin/bash
certs=`openssl s_client -servername $1 -host $1 -port 443 -showcerts </dev/null 2>/dev/null | sed -n '/Certificate chain/,/Server certificate/p'`
rest=$certs
while [[ "$rest" =~ ' - - -BEGIN CERTIFICATE - - -' ]]
do
cert="${rest%% - - -END CERTIFICATE - - -*} - - -END CERTIFICATE - - -"
rest=${rest#* - - -END CERTIFICATE - - -}
echo `echo "$cert" | grep 's:' | sed 's/.*s:\(.*\)/\1/'`
echo "$cert" | openssl x509 -pubkey -noout |
openssl rsa -pubin -outform der 2>/dev/null |
openssl dgst -sha256 -binary | openssl enc -base64
Done

--

--