8

I am trying to learn how to hook into the browser memory. The Frida tool is a good start to this. My goal is to extract the client-random, server-random and symmetric session keys established at the end of a TLS handshake. By setting the SSLKEYLOGFILE environment I can extract the client-random and the master key, however it does not output the server-random key.

After going through the source code for Firefox, this can be fixed easily by printing out the server-random key in the function static void ssl3_RecordKeyLog(sslSocket *ss) at <firefox src/security/nss/lib/ssl/ssl3conn.c>

However, this is not a viable solution in my project as it makes deploy-ability poor, i.e. compiling Firefox every time there is a new update is generally not good practice to make changes to browser code and redistribute it.

Is there a better way to do this? More specifically, are any of these two options viable? I do not have much knowledge on the architecture of the browser.

  • A. Using native C++ calls in a Firefox extension to call this function/any function from the file src/security/nss/lib/ssl/ssl3conn.c.

  • B. Use a browser hook to call my own code every time this function is called in the browser.

Context: Using the three value of server random, client random and master secret, I want to generate the keyblock which is further used to generate encryption keys used in a TLS session.

I am aware wireshark has this feature, and with minimal change I can output the keys, but I would not like to use wireshark as it is would consume more resources on the host computer for a simple process like key generation.

I can write my own libpcap code to parse through traffic, but I would like to keep this as the last option.

Tsundoku
  • 127
  • 1
  • 5
  • Is this just for fun? – StackzOfZtuff Dec 24 '16 at 12:48
  • Not really. It is one of the ways I could have taken in a project Iwas working on –  Dec 25 '16 at 15:13
  • 2
    @AbhimanyuKhanna Be aware that the Client Hello Random, Server Hello Random and Master Secret are not always sufficient to calculate the session keys. With the [TLS Extended Master Secret](https://tools.ietf.org/html/rfc7627) extension you need to hash the full handshake. And with the upcoming TLS 1.3 you are given the client/server traffic secrets (which is sufficient to derive decryption keys). – Lekensteyn Jan 09 '17 at 10:46
  • Will you be publishing the project afterward or is it for personal use? – J.A.K. Jan 09 '17 at 19:38

1 Answers1

2

You may want to try this with frida:

import frida
import sys

session = frida.attach("firefox.exe")
script = session.create_script("""
"use strict";
const PR_Read = Module.findExportByName("nss3.dll", "PR_Read");

Interceptor.attach(PR_Read, {
    onEnter: function (args) {
        let length = args[2].toInt32();
        let buffer = Memory.readByteArray(args[1], length - 1);
        console.log(buffer);
    }
});
""")

script.load()
sys.stdin.read()

Note that I haven't tried this code, but as you seem to have managed to get the client-random and the master key, with PR_Write (which is what firefox outputs), you probably will get the server random with PR_Read (which is what the server responds).

Sources:


How I found that:

  • looked at the page you linked.
  • found that the way to get what firefox output is using PR_Write
  • looked at what the function is on MDN
  • guessed that if there's a write, there might be a read
  • searched PR_Read on MDN
  • found it has the same signature as PR_Write
  • replaced PR_Write with PR_Read
  • if the signature was different, I might have had to change some more things around (like the args[])
satibel
  • 433
  • 2
  • 8
  • Might I know what is wrong with my answer? I don't bite. – satibel Jan 16 '17 at 06:21
  • 1
    Hi satibel - I also haven't tested the code, but your answer seems reasonable to me, so I am not sure why the downvotes. Maybe people tested it and it didn't work? – Rory Alsop Feb 14 '17 at 15:05