Skip to main content

Frida SSL intercept

Overview

The output from these Frida scripts should be entered into Wirehark's '(Pre)-Master-Secret log filename' field under 'TLS' in 'Protocol Preferences'. The files should contain one set of keys per line. The window is shown below.

To quickly navigate to this window, right click on a TLS frame and follow the screenshot below.

SSLv3 and TLSv1.0

In order to decrypt SSLv3 and TLSv1.0, we need the 'client random' and 'master key'.

An SSL context object is passed to several functions, including SSL_read(SSL *ssl, char *buf, int num) and SSL_write(SSL *ssl, char *buf, int num).

⚠️ Coincidentally, the char *buf field in each of the two functions listed above contains the plaintext data before and after encryption/decryption. Use this if you can't be bothered to use Wireshark. ⚠️

This SSL object contains two further objects, which contain the required values. These are an ssl3_state_st object called s3 (offset (*ssl)+128) and an SSL_SESSION object called session (offset (*ssl)+304), and are shown in the diagram below. It should be noted that these will likely change between OpenSSL versions, so you may need to check in Ghidra for new offsets.

Inside of the ssl3_state_st object is the client_random at an offset of (*s3)+196.

Inside of the SSL_SESSION object is the master_key at an offset of (*session)+20.

Once these offsets have been determined, the following script can be updated and used to extract the keys in the correct format.

const S3_OFFSET = 128
const CLIENT_RANDOM_OFFSET = 196

const SESSION_OFFSET = 304
const MASTER_KEY_OFFSET = 20

function buf2hex(buffer) { // buffer is an ArrayBuffer
  return [...new Uint8Array(buffer)]
      .map(x => x.toString(16).padStart(2, '0'))
      .join('');
}

const cb = {
  onEnter(args) {
    const ssl = ptr(args[0])

    const s3 = ssl.add(S3_OFFSET).readPointer()
    const client_random = s3.add(CLIENT_RANDOM_OFFSET).readByteArray(32)

    const session = ssl.add(SESSION_OFFSET).readPointer()
    const master_key = session.add(MASTER_KEY_OFFSET).readByteArray(48)

    console.log(`CLIENT_RANDOM ${buf2hex(client_random)} ${buf2hex(master_key)}`)
  }
}

Interceptor.attach(Module.findExportByName('libssl.so.1.0.0', 'SSL_read'), cb)
Interceptor.attach(Module.findExportByName('libssl.so.1.0.0', 'SSL_write'), cb)