Intercepting SSL on iOS

There are multiple ways to intercept SSL traffic on iOS. In this post, I will summarize a couple of ways to intercept SSL traffic. Some methods would be easy to execute but some of them would require a jailbroken device.

Basic SSL

SSL or TLS connection requires a bunch of steps to initiate a secure connection. I am not going to explain the details of those protocols but the important thing to remember is this. For a secure connection to happen, the client and the server must use public and private keys issued by the certificate provider. This is why it is hard to sniff those connections. Unless you’re a certificate provider, you can’t issue a forged certificate to listen to traffic. To listen to traffic, we must either create a self-signed certificate and force clients to accept this certificate or intercept the encryption keys in a jailbroken device and use those keys to decrypt the packets.

Proxy

There are multiple https proxies to intercept traffic. You can either use mitmproxy, Charles, or Proxyman. All those programs can issue a self-signed certificate and will allow you to sniff SSL traffic. You can check the documentation of these apps to see how you can create your certificate, add this certificate to your device, and finally trusting this certificate.

Pros:

  • Easy to use.
  • No Jailbreak required

Cons:

  • SSL pinning can be an issue.
  • Only HTTPS traffic.
  • Custom certificate must be installed

Sniffing with SSLKEYLOGFILE

Pros:

  • Can sniff SSL traffic without key installation.
  • SSL pinning can be bypassed

Cons:

  • Jailbreak only.
  • More steps.

SSLKEYLOGFILE is an environment variable that is being used by popular SSL libraries like OpenSSL or BoringSSL. When this variable is set, those libraries log pre-master secret keys to a file. So you can use those keys to decrypt encrypted packages. However, there is no easy way to set up this environment variable on iOS. We need Frida to hook into the process and set this parameter ourselves.

  • Jailbreak your device
  • Install Frida Server to your device and frida tools to your computer
  • Connect your iOS device to your computer with USB
  • Run the following command on your terminal
frida -U  -f BUNDLE.ID.OF.APP --codeshare andydavies/ios-tls-keylogger -o app.keylog

You can check the source code to see how this script is working. This script works for iOS 12.x but you may need to update it for other iOS versions due to its fragile hooking mechanism. If you need to update for future iOS versions, you need to update 0x2A8 constant in the script. Let’s see how we can find that constant for future iOS versions.

  • Get dyld_shared_cache_arm64 from your iOS ipsw file. Tutorial
  • Disassemble libboringssl.dylib
  • Search for CLIENT_RANDOM

You will get some disassembly like below

libboringssl:__text:0000000181D8835C                 LDRSW           X3, [X20,#0xC]
libboringssl:__text:0000000181D88360                 ADRP            X1, #aClientRandom@PAGE ; "CLIENT_RANDOM"
libboringssl:__text:0000000181D88364                 ADD             X1, X1, #aClientRandom@PAGEOFF ; "CLIENT_RANDOM"
libboringssl:__text:0000000181D88368                 MOV             X0, X19
libboringssl:__text:0000000181D8836C                 BL              sub_181D4CF90

sub_181D4CF90 represents our log function. Go inside that function and you’ll see something similar

libboringssl:__text:0000000181D4CF90                 SUB             SP, SP, #0x60
libboringssl:__text:0000000181D4CF94                 STP             X22, X21, [SP,#0x50+var_20]
libboringssl:__text:0000000181D4CF98                 STP             X20, X19, [SP,#0x50+var_10]
libboringssl:__text:0000000181D4CF9C                 STP             X29, X30, [SP,#0x50+var_s0]
libboringssl:__text:0000000181D4CFA0                 ADD             X29, SP, #0x50
libboringssl:__text:0000000181D4CFA4                 LDR             X8, [X0,#0x68]
libboringssl:__text:0000000181D4CFA8                 LDR             X8, [X8,#0x2A8]
libboringssl:__text:0000000181D4CFAC                 CBZ             X8, loc_181D4D0B4

As you see, if the logging function is defined which is at offset 0x2A8 then the library logs the key, otherwise, the function returns without logging anything. Our Frida script changes that pointer so we can log master keys to a file. Okay, now we learned how to dump master keys. How can we use this key file to decrypt packets?

We need to capture the network packages of your device with tcpdump. There are multiple ways of doing this.

  • Dump from the device by using tcpdump if you’re jailbroken
  • Share your Mac internet with Internet Sharing with USB or WiFi
  • Create a virtual network with rvictl
ideviceinfo | grep UniqueDeviceID
rvictl -s YOUR_UNIQUE_DEVICE_ID
tcpdump -i rvi0 -w capture.pcap -P
  • Open your captured pcap file with Wireshark,
  • Go to Preferences > Protocols > TLS > (Pre)-Master-Secret log filename and select the key file we created in the previous step.

Sniffing with SSLSPLIT

Pros:

  • Raw TLS traffic can be sniffed besides HTTPS
  • SSL pinning can be bypassed
  • No Jailbreak required

Cons:

  • Custom certificate must be installed.
  • SSL pinning can be an issue.

This is my favorite mode of sniffing because it is easier to configure and solves lots of issues. Instead of https, we can also sniff non-HTTP(s) protocols. It also allows us to sniff Flutter apps. Because by default Flutter, doesn’t respect system proxy settings.

  • Install Sslsplit with brew install sslsplit
  • Connect your device to Mac with USB and share your internet with USB only. Disable WiFi of your device.
  • Edit pf rules

    sudo vi /etc/pf.conf
  • Add following line just after rdr-anchor "com.apple/*"
rdr pass on bridge100 inet proto tcp from any to any port 443 -> 127.0.0.1 port 8000
  • Reload rules
sudo pfctl -F all -f /etc/pf.conf
  • Create key files and trust them on your device. I used Charles Proxy’s certificate. You can export p12 file by navigating to Help/SSL Proxying/Export Charles Root Certificate and Private Key menu. Use below commands to export private and public keys from charles-ssl-proxying.p12 file
openssl pkcs12 -in charles-ssl-proxying.p12 -nokeys -out ca.crt
openssl pkcs12 -in charles-ssl-proxying.p12 -nocerts -out ca.key

I prefer using an existing certificate so I can just go back to Charles for a light workload. If you want to create your keys, you can use the below commands

openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 1826 -key ca.key -out ca.crt
  • Run SSLSPLIT

    sudo sslsplit -X capture.pcap -M keyfile.log -S logdir/  -k ca.key -c ca.crt -D https 127.0.0.1 8000

If you have done it everything correctly, you should see packages flying around and everything is logged to the logdir directory. If you don’t see any packages, it means you either didn’t configure sharing well or your certificate isn’t created or trusted properly.

I am actively job-hunting and available
Interested? Feel free to reach