This repo contains an (attempted) implementation of the timing attack on OpenSSL 0.9.7 described in "Remote Timing Attacks are Practical", a 2003 paper by David Brumley and Dan Boneh [1]. The attack works against OpenSSL 0.9.7, and was the motivation for turning on blinding by default in 2003 [2].
I haven't got the attack to work yet (see current project status). Hopefully this repo is a good resource for anyone trying to replicate the paper. If you have any advice, or have spotted an error, please do get in touch. I'm keen to get this working!
The general gist of the attack is that the time taken to decrypt g
with a private key d
, g^d % N
, is dependant on the relationship between g
and the factors of N=p*q
. The paper combines two time leaks sourced from implementation details of this modular exponentiation. The first is from their use of Montgomery multiplication, and the second from Karatsuba multiplication.
To get this to work in practice, we need a way to send a variety of g
values to the server, and time their decryption. The paper accomplishes this by sending specially crafted g
's in place of the pre-master secret in the TLS handshake. This causes the handshake to fail. The time between sending the pre-master secret, and receiving failure message from the server is recorded as the decryption time.
There's quite a bit more to this attack than Ive explained here, but thats a high-level overview of the core parts. The papers explanations are clearer than what I've written above, and relatively short. It's definitely worth a read.
If you've read it and aren't 100% sure what they mean by zero-one gap, take a look at slide 7 in this presentation from Johns Hopkins' "Selected Topics in Network Security (Spring 05)" course. It helped clear things up for me.
This project consists of two key components:
This is an Ubuntu container running Apache 1.3.27 built with mod_ssl
2.8.12 and using OpenSSL 0.9.7 (the versions used in the paper). The Dockerfile
contains instructions on how this is built and is the primary piece of code in the server component.
Upon build, the OpenSSL source code is patched to add two pieces of functionality:
RSA_private_decrypt
routine to calculate the g^d % N
decryption.A pre-generated 1024-bit RSA keypair is located in ./server/ssl-certificate
and contains the secrets that the client aims to extract. The certificate is baked in to the image at build time, so a docker-compose build server
is needed if you want to change them.
Differences to the original paper:
This container includes some Python modules that implement the actual attack (attack.py
, tls.py
, and timed_messenger.*
), and an environment for statistical analysis (Jupyter, scipy, etc).
The attack.ipynb
Jupyter notebook is a good starting point, providing a high-level overview of the attack. It uses the implementations in attack.py
and tls.py
to take measurements and infer information about the private key. Its worth diggin into these if you're more curious about what's going on. Since I haven't got this working yet, it's quite likely that the narrative around the code cells is out-of-date at any particular point.
The attack.py
module contains the actual attack, handshake_attack()
, and its caller, sample()
. These build upon the helper functions in tls.py
and timed_messenger.*
.
The majority of the attack code is written in Python, with the exception of timed_messenger.*
in C. This module sends a message over an open socket, waits for a response, and times how long the whole thing takes. It does this using the guidance in the "How to Benchmark Code Execution Times" whitepaper from Intel [3].
This project relies heavily on Docker and docker-compose
. This has only been tested on Linux but I imagine it'll work on Windows and Mac presuming the aforementioned tools are installed and working.
Open up a terminal in the root directory and run docker-compose up
. This will build (if necessary) then start up the server and client containers. This gives you a vulnerable Apache, mod_ssl
& OpenSSL running on port 443, and a Jupyter notebook with which to mount the attack on port 8080.
There's a little bash script for executing the client notebooks from the command line:
$ docker-compose run --entrypoint=bash execute-notebook <notebook_name>
The results will be saved in a separate copy named <notebook_name>.YYYY-MM-DDTHH-MM-SS.ipynb
.
I use the above to gather new measurements, like so:
$ # Delete existing measurement files, to signal that new ones must be generated
$ rm client/measurements/bit-samples.txt \
client/measurements/internal-measurements.txt \
client/measurements/bruteforce-top-bits.txt
$ # Run the attack.ipynb notebook
$ docker-compose run --detach --entrypoint=bash client execute-notebook attack
$ # Gather internal OpenSSL time measurements from the servers stdout:
$ docker-compose logs --no-color --tail=all --follow server \
| grep "djwj: internal measurement: " \
> client/measurements/internal-measurements.txt
Log:
mod_ssl
has blinding enabled by default from version 2.8.13 onwards. I've been using 2.8.14 ๐คฆ. The paper uses 2.8.12, which is the version I should have been using all along, I'm not sure how I ended up at 2.8.14. Rebuilding the server with 2.8.12 and taking new measurements didn't seem to help. Still, it's progress.