SSL Pinning Workaround for Android Uber Apps

August 31, 2016
ssl mitm android uber notes

Overview

Viewing encrypted SSL/TLS traffic from mobile devices has become more difficult to do with the introduction of certificate pinning, sometimes also call SSL pinning. Normally there is a set of trusted certificate authorities (CAs) on a system that is used to validate a certificate, so as long as the certificate was signed by a trusted CA then it is trusted. This was easy to workaround as you could just add a self signed certificate to your trusted certs and use that self signed certificate to decrypt the traffic being sent and received. Certificate pinning adds an extra layer of security to this by bundling the expected certificate public key with the app and verifying the certificate on the endpoint being connected to matches this.

While attempting to view traffic being sent by the Uber app on Android with Burp Suite, I couldn’t get it to pass any traffic and came to the realization that it was using certificate pinning.

Workaround

Here are some very rough notes describing how to workaround the certificate pinning that is implemented in Uber’s Android app. The general idea is that we’ll decompile the APK, find the password for certificate keystore, add the self signed Burp certificate into the password protected keystore for the app, and finally recompile a new version of the app. This guide assumes you are using Burp Suite Community Edition as the tool to sniff traffic.

Environment Setup

Decompiling Uber App

First you’ll need to decompile the Uber app with apktool

java -jar apktool.jar decode uber.apk

Modify Network Security configuration

The first step we’ll take is to modify the network security settings for the app to allow user provided system certificates. For apps that don’t implement certificate pinning, this may be all that is required to be able to start sniffing TLS traffic.

Finding Password for Keystore

Since certificate pinning is in use here, we also need to find the place where the expected certificates are being stored. In this case, a password protected keystore named ssl_pinning_certs_bk146.bks is where this can be found. Of course the plaintext version of the password has to live somewhere in the app or else it wouldn’t be able to access the keystore either. You’ll need to find this password in order to unlock the keystore and add in a custom certificate. To find this password, I used jd-gui to decompile APK back into Java files and searched for ssl_pinning_certs_bk146 in the code. For example, in v4.214.10002 of the Uber app, the password is sMdqVqJBdBmmkDMp6BK7EVeEkHcNbJ - this may of course change in future version of the app.

Adding Certificate into Keystore

Execute java keytool to import burp certificate into the Uber keystore, enter the discovered password to unlock, and then say yes to add it as a trusted certificate.

cd ~/uber/uber/res/raw
keytool -import -v -trustcacerts -alias workaround -file ~/uber/burp.pem -keystore ssl_pinning_certs_bk146.bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath ~/uber/bc.jar
Enter keystore password: <enter this password from above and hit enter>
Owner: CN=PortSwigger CA, OU=PortSwigger CA, O=PortSwigger, L=PortSwigger, ST=PortSwigger, C=PortSwigger
Issuer: CN=PortSwigger CA, OU=PortSwigger CA, O=PortSwigger, L=PortSwigger, ST=PortSwigger, C=PortSwigger
Serial number: 53af3569
Valid from: Sat Jun 28 14:36:41 PDT 2014 until: Sun Jun 28 14:36:41 PDT 2037
Certificate fingerprints:
	 MD5:  EF:F9:D6:60:38:A5:29:C2:F5:2D:28:0F:52:88:AE:49
	 SHA1: 69:1A:25:34:CE:CF:DC:CC:19:76:9E:99:97:14:30:E4:97:77:3E:AB
	 SHA256: E7:0C:93:EF:8F:5D:14:92:78:73:DC:78:94:67:3D:E9:10:61:A1:9D:E7:7B:A3:CF:AA:73:BA:7A:40:6E:C4:16
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3

Extensions:

#1: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
  CA:true
  PathLen:0
]

#2: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 49 12 56 F4 D7 B1 EB BD   BE AC BA 67 0B 23 D9 3B  I.V........g.#.;
0010: 57 8E 12 B5                                        W...
]
]

Trust this certificate? [no]:  yes
Certificate was added to keystore
[Storing ssl_pinning_certs_bk146.bks]

Create Keystore for Signing New APK

Use keytool to create a signing key that will be used to sign the modified APK. This prompts you to enter a password for the keystore and key (this can be any password), and to provide the Distinguished Name fields for your key. It then generates the keystore as a file called my-release-key.jks, saving it in the current directory. The keystore contains a single key that is valid for 10,000 days.

cd ~/uber
keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-alias
Enter keystore password:
Re-enter new password:
What is your first and last name?
  [Unknown]:
What is the name of your organizational unit?
  [Unknown]:
What is the name of your organization?
  [Unknown]:
What is the name of your City or Locality?
  [Unknown]:
What is the name of your State or Province?
  [Unknown]:
What is the two-letter country code for this unit?
  [Unknown]:
Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
  [no]:  yes

Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 10,000 days
	for: CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
Enter key password for <my-alias>
	(RETURN if same as keystore password):
[Storing my-release-key.jks]

Warning:
The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore my-release-key.jks -destkeystore my-release-key.jks -deststoretype pkcs12".

Building Modified APK

Move back to main directory, use apktool to build, jarsigner to sign the APK and zipalign to align it.

cd ~/uber/uber
java -jar ../apktool.jar build . -o ../modified_uber.apk
cd ~/uber
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.jks modified_uber.apk my-alias
jarsigner -verify -verbose -certs modified_uber.apk
./zipalign -v 4 modified_uber.apk modified_uber-aligned.apk
Now copy this modified APK to your Android phone, install it, and setup Burp to intercept traffic as usual. Note that the Google maps don’t load in this case as Google doesn’t trust the Burp self signed certificate, but everything else should still be functional in the app.

CopperheadOS: Feature Review Part 1

May 14, 2018
android security copperheados review

Let's Encrypt CloudFront Cert Renewal with Lambda

January 2, 2016
aws lambda cloudfront letsencrypt ssl

VMware CLI Dockerized

August 28, 2014
vmware cli docker notes