How to bypass Instagram SSL Pinning on Android (v78)

My goal was to take a look at the HTTP requests that Instagram was making but, after setting an HTTP proxy, I couldn’t see anything. Turns out that Instagram is protected against MITM attacks using a technique called certificate validation (SSL Pinning) which compares the certificate provided by server in the TLS handshake with a trusted one embedded in APK.

Instagram refuses to complete TLS handshake if certificate doesn’t match

This article is based on Instagram APK version 78.0.0.11.104 (x86) which you can download here. I am also using an Android 8.0 emulator with adb running as root.


Disclaimer

The sole purpose of this article is educational and for testing of your own applications. This is not intended for piracy or any other non-legal use.


Setting up Burp to work with TLS 1.3

Facebook deployed TLS 1.3 at very large scale with their open source library Fizz. It doesn’t surprise me that they decided to use it on their Instagram application to make internet traffic more secure.

This time I decided to use Burp to capture requests that Instagram app is making. After setting up the proxy, some weird alert appears in the Alerts tab.

What is this weird “no cipher suites in common” message? Looks like this version of Burp does not support TLSv1.3 cipher suites. We can verify this by going to Project Options > SSL and list all ciphers.

A simple solution to this problem is to run Burp with the latest version of JDK. At that point, you can run burpsuite_community.jar with the newly extracted java binary taken from JDK:

./Downloads/jdk-11.0.2.jdk/Contents/Home/bin/java -jar burpsuite_community.jar

This time after opening Instagram app we get a different message from Alerts tab.


Now we get a different (fatal) alert: bad_certificate which tells us that the certificate provided by Burp is not accepted by the client. We have to dig deeper into the app internals to get around this issue.

Patching Native Layer

Android applications can interact with native (C/C++) code using Java Native Interface (JNI). You can read more about it here. Instagram loads many native libraries from /data/data/com.instagram.android/lib-zstd which is created after the first app launch.

~ adb pull /data/data/com.instagram.android/lib-zstd
~ grep lib-zstd -re fizz
Binary file lib-zstd/libliger.so matches

Bingo! Let’s launch IDA Pro to take a look at this shared object file. After reading source code, I spotted the exception which was causing this bad_certificate issue.

Let’s search for strings using IDA (View > Open Subviews > Strings).
At offset 002831F4 on read-only section (.rodata) we can see the constant we were looking for.

IDA is pointing us to the subroutine sub_3C864 which using it. After analysing the flow, we can apply a simple patch at offset 0003CD4D patching JNZ to JZ so exception is no longer thrown!

Let’s apply the patches (Edit > Patch Program > Apply patches to input file) and push the newly patched libliger.so to the device.

adb push libliger.so /data/data/com.instagram.android/lib-zstd/libliger.so

Now Burp complains with a weird alert:

That’s weird. Analysing traffic with Wireshark didn’t help much and gave me no additional clues. Next step was to debug Android smali code using Android Studio (you can find an useful article here).

I followed this StackOverflow reply to catch any exception and this shows up shortly after:

This looks interesting. Let’s go back to IDA and search for the string constant “openssl cert verify error“. Match on offset 00295732 used by subroutine sub_176434. Similarly to what we’ve dove before, we can patch this subroutine to avoid throwing this exception.

Patch JNZ to JZ, apply to input file and open Burp.

Jackpot! We can now be the man in the middle and take a look at the “private” Instagram API.

18 Thoughts to “How to bypass Instagram SSL Pinning on Android (v78)”

  1. Oliver Martinez

    This is the most detailed and most understandable step by step reverse engineering tutorial for instagram apk. Thank you very much Marco!

    1. Marco Genovese

      Thanks, I’m glad you enjoyed it 🙂

      1. zamtara

        hi marco,

        “b”.i.instagram.com
        “graph”.instagram.com

        burp alert = unknown_ca

        solve?

        thank you.

  2. pashmak73

    Hi,
    Thanks, but I did everything you did with no success.
    Still can’t read all requests

  3. giacomo

    Thanks for your share! really good work!
    How do you intercept the request from emulator with burp? The only way I know is with linux and redirecting with iptables

    1. Marco Genovese

      Set up Burp to listen on the LAN interface and set the HTTP proxy on emulator (if you run the emulator with CLI, pass the -http-proxy flag)

  4. Raymond P Fore

    wooow. Thanks !!!!
    Can you patched APK here ? (Link For Download)

  5. I need patched apk sir.😊😊😊 thank you

  6. Dan

    Thank you so much for writing this! You have no idea how many months I’ve spent trying to find a solution to bypassing Instagram pinning to no avail. I didn’t even know they use TLS 1.3. I will try this out soon! You should consider making a tool that automatically patches the error message.

  7. Megro

    Can you upload your patched file?

  8. Manju Naik

    plz upload libliger.so patched file bro

  9. ALSW

    I have patched it, but it’s not worked

  10. Johnnie Smalls

    Bump on the upload of patched file ^^

  11. I patched same no traffic. Please share your libliger.so.

  12. Fran

    please can you share apk patched? thanks!

  13. Nicolas

    Would be awesome if you could share the libliger.so file indeed. Thanks for this tutorial!

  14. Peter

    Hi Marco Genovese,
    This is quite helpful to me. Could you leave a email? I want to have some communicate with you, thanks.

Leave a Comment