Certificate pinning
What happens when an android app connects to a remote https server?
So, by default the app match the certificate provided by the server with the device’s trust store and check that the certificate has been generated for the expected hostname. It doesn’t do additional checks, and this of course can be a security hole as any unsafe certificate can be installed by mistake by the user or by malicious apps, allowing man-in-the-middle attacks.
The solution adopted by developers is the certificate pinning, which consists in embed and forcing the app to use a specific certificate, which match the one used by the server, ignoring the device’s trust store and thus allowing the mobile application to successfully connect only to the legitimate server.
This is a very good practice but unfortunately it prevents to debug or reverse engineer the app using tools such Burp Suite.
Replace the embedded certificate
For the demostration I will use Dyson Link, andoid app from Dyson, which I was interested to reverse engineer.
The app uses a series of embedded certificates to verify the authenticity of the remote API server. So let’s start decompiling the app using apktool.
andrea@system:~/demo$ java -jar apktool_2.2.2.jar d ./DysonLink_v3.3.1.apk
I: Using Apktool 2.2.2 on DysonLink_v3.3.1.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /home/andrea/.local/share/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...
The result will be the folder DysonLink_v3.3.1 containing the decompiled code and the app resources. The folder DysonLink_v3.3.1/assets/ contains our SSL certificates.
andrea@system:~/demo$ ls -l DysonLink_v3.3.1/assets/
total 120
-rw-rw-r-- 1 3189 Mar 16 16:46 DysonConnectedProductsCNServerAuthenticationIssuingCA.crt.bundle.pem
-rw-rw-r-- 1 3505 Mar 16 16:46 DysonMockServerAuthenticationIssuingCA.crt.cer
-rw-rw-r-- 1 3188 Mar 16 16:46 DysonProdEnvsConnectedProductsCNServerAuthenticationIssuingCA.crt.bundle.pem
-rw-rw-r-- 1 2518 Mar 16 16:46 DysonProdEnvsConnectedProductsServerAuthenticationIssuingCA.crt.bundle.pem
drwxrwxr-x 2 4096 Mar 16 16:46 fonts
drwxrwxr-x 2 4096 Mar 16 16:46 images
-rw-rw-r-- 1 andrea andrea 38457 Mar 16 16:46 register_configuration.json
-rw-rw-r-- 1 6543 Mar 16 16:46 timezones.json
Now let’s fire up Burp Suite, export the CA certificate using the GUI or pointing the browser to http://burp/. The certificate is in DER format, which we need to convert to PEM.
openssl x509 -inform der -in cacert.der -out cacert.pem
We will use the new generated certificate to replace all the pem files in the assets folder.
Repack the app
Recreate the apk from the sorce folder:
andrea@system:~/demo$ java -jar apktool_2.2.2.jar b -o DysonLink_new.apk DysonLink_v3.3.1
I: Using Apktool 2.2.2
I: Checking whether sources has changed...
I: Smaling smali folder into classes.dex...
I: Checking whether resources has changed...
I: Building resources...
W: warning: string 'connection_connect_ap_app_to_robot_description_single' has no default translation.
W: warning: string 'connection_connect_ap_app_to_robot_title_single' has no default translation.
W: warning: string 'connection_journey_carousel_no_blue_light' has no default translation.
W: warning: string 'connection_journey_carousel_robot_blue_light_description' has no default translation.
W: warning: string 'connection_journey_carousel_robot_dock_description' has no default translation.
W: warning: string 'connection_journey_carousel_robot_title' has no default translation.
W: warning: string 'connection_journey_carousel_robot_wifi_light_description' has no default translation.
I: Copying libs... (/lib)
I: Building apk file...
I: Copying unknown files/dir...
Sign the apk
Generate a new keytore for the signing procedure:
keytool -genkey -keystore test.keystore -validity 10000 -alias test
Sign the forged apk:
jarsigner -keystore test.keystore -verbose DysonLink_new.apk test
Test it!
Now we are ready to install it in our emulator. First let’s start it, with the correct proxy settings to point to Burp Suite:
./emulator -netdelay none -netspeed full -http-proxy http://127.0.0.1:8118 -avd Nexus_5_API_23
Install the forged apk (remember to uninstall the original one before):
adb install DysonLink_new.apk
And… as soon we will try to open the app we will see the https traffing passing through Burp Suite!