9

I would like to be able to decrypt my server's https traffic for debugging and analysis. My server is a debian 9 Apache2 server running mod_wsgi and django.

I have seen this post: Extract pre-master keys from an OpenSSL application

and I figured out I might be able to use https://httpd.apache.org/docs/2.4/mod/mod_ssl.html#sslopensslconfcmd

to get apache to output those dh keys, but I can't figure out how to do it.

I know it is possible, because it is done by many security applications and vendors (IPS/IDS systems for example).

Any ideas?

Yotam Alon
  • 93
  • 1
  • 3
  • I don't think this is possible. First, you don't need to *"those dh keys"* but you need to have the pre-master secrets of the specific connection. And you have no way of associating a specific secret to a specific running connection. *"... it is done by many security applications and vendors (IPS/IDS systems for example)..."* - I doubt this (unproven) claim. These systems either do active man in the middle or have the private key of the server to passively intercept SSL connections, which can be done only if RSA key exchange (which is considered obsolete) is used. – Steffen Ullrich Aug 15 '19 at 13:32
  • 1
    @SteffenUllrich: through 1.2 for ciphersuites using DHE or ECDHE keyexchanges the DH-agreement _is_ the TLS premaster, and Wireshark can use either premaster or master linked to either sessionid or clientrandom. I haven't tested if Wireshark is updated for 1.3, where clientrandom should still work but 'ticketid' links (if at all) to a future-only PSK. Though I agree IDS/IPS/WAF/etc are likelier to do active or possibly RSA rather than rely on tight realtime integration with the (often numerous and varied) servers. – dave_thompson_085 Aug 16 '19 at 02:27
  • 1
    Wireshark uses the Client Random only as identifier for the master secret (TLS 1.2) or one of the derived secrets (TLS 1.3). And yes, it does support TLS 1.3 as does the sslkeylog.so library :) – Lekensteyn Aug 16 '19 at 09:29

1 Answers1

13

Apache om Debian 9 (Stretch) uses OpenSSL 1.0.2 (see apache2-bin dependency on libssl1.0), so you can use the approaches documented in that linked post. You can modify the startup script to export LD_PRELOAD=/path/to/libsslkeylog.so and SSLKEYLOGFILE=/tmp/your.keys.

How to do so is dependent on the application. For systemd you could try systemctl edit apache2 to create an override. If it is still a classic sysvinit init script like Apache, try modifying /etc/init.d/apache2 with the above two environment variables. Don't forget the export keyword. Apache no longer seems to use sysvinit scripts, so you must modify the systemd unit file.

This will result in the master secret being written to the file specified by the SSLKEYLOGFILE environment variable. It is not exactly the premaster secret, but you can use it to enable decryption in Wireshark. For more details about the latter, see also https://wiki.wireshark.org/TLS

Depending on your use case, it might be easier to skip modification of the server and tap keys on the client side instead. Firefox and Chromium have built-in support for the SSLKEYLOGFILE environment variable. Newer versions of curl do support that too, but older versions of curl or other applications using OpenSSL require something like the above sslkeylog.sh approach.

Walkthrough

The sslkeylog.so library is specific to the OpenSSL version. Version 1.0.2 (libssl1.0.2 in Debian Stretch) is not compatible with OpenSSL 1.1.0 (libssl1.1 in Debian Stretch). In order to build the library, you need corresponding development header files. These are available through the libssl1.0-dev or libssl-dev packages for respective versions.

Fetching the sources and building the library should be straightforward:

sudo apt install git make gcc libssl1.0-dev
git clone --depth=1 https://git.lekensteyn.nl/peter/wireshark-notes
cd wireshark-notes/src
make
# Optional: install to a specific location. Adjust paths below if you skip this.
sudo install libsslkeylog.so /usr/local/lib/

This produces a libsslkeylog.so file in your current directory. To test whether it works:

$ ./sslkeylog.sh curl https://example.com -sI
CLIENT_RANDOM ... ...    <-- expected for TLS 1.2
HTTP/2 200 
...
$ ldd /usr/bin/curl | grep ssl
libssl.so.1.0.2 => /usr/lib/x86_64-linux-gnu/libssl.so.1.0.2 (0x00007fc5a088d000)

The last command shows which libssl version the program was linked against. We can do something similar for Apache. The primary program (apache2) loads TLS support through a different library though, so we have to check that:

$ ldd /usr/lib/apache2/modules/mod_ssl.so | grep ssl
libssl.so.1.0.2 => /usr/lib/x86_64-linux-gnu/libssl.so.1.0.2 (0x00007f8dbb6ed000)

If this shows libssl.so.1.1 for whatever reason, then you would have to sudo apt install libssl-dev instead and rebuild with make -B.

The next step is to modify the systemd unit file for the apache2 service. Execute systemctl edit apache2, this opens an editor for /etc/systemd/system/apache2.service.d/override.conf where you should add:

[Service]
Environment=LD_PRELOAD=/usr/local/lib/libsslkeylog.so
Environment=SSLKEYLOGFILE=/tmp/your.keys

After restarting (sudo systemctl restart apache2) your keys will now be created somewhere in /tmp/systemd-private-*-apache2.service-*/tmp/your.keys. If you would like a shorter path, you could enter something like /home/user/your.keys, but make sure the file is writable by the www-data user.

Make sure to remove this once your testing has completed. I recommend temporarily modifying the client instead to perform this kind of testing. As shown above, sslkeylog.sh also works with clients.

Lekensteyn
  • 5,958
  • 5
  • 38
  • 62
  • Thanks for the answer, where do you find sslkeylog.so? Also, getting pre-master secrets from the clients is not possible, as I don't have access to them. – Yotam Alon Aug 18 '19 at 06:36
  • I found a the sslkeylog.so file that should work, but adding it to both /lib/systemd/system/apache2.service and /etc/init.d/apache2 does not seem to work, as the sslkeylogfile is not written. – Yotam Alon Aug 18 '19 at 07:26
  • I have added commands and instructions that I just validated with a fresh Stretch installation. To test it locally, I additionally did `sudo apt install apache2 && sudo a2ensite default-ssl && sudo a2enmod ssl` and ran `curl https://localhost -k` to trigger traffic. – Lekensteyn Aug 18 '19 at 12:06
  • You are a beautiful person. I really appreciate the time and effort you put into this. – Yotam Alon Aug 18 '19 at 14:13
  • First: Awesome answer! I built this and tried to use with apache and it kept crashing. After a bit of debugging I confirmed that I was using 1.0.2.k openssl. (no SSL_CTX_set_keylog_callback) support. However, that symbol was found at runtime. "(gdb) info symbol SSL_CTX_set_keylog_callback SSL_CTX_set_keylog_callback in section .text of /usr/lib64/mysql/libmysqlclient.so.18". I commented out the calls that were looking for that symbol dynamically, and everything worked. It turned out that a module for mysql support in php was contributing the problematic libary. – Chris Holt Feb 21 '20 at 21:10
  • @ChrisHolt By default libsslkeylog.so will be built for whatever version `libssl.so` is for. If you know that an application is linking with 1.0.2, you could try `make CFLAGS=-DOPENSSL_SONAME=\"libssl.so.1.0.0\"` to ensure that it tries to load OpenSSL 1.0.0 at runtime. And be sure to install libssl1.0-dev on some Ubuntu or Debian versions to ensure matching header files. – Lekensteyn Feb 22 '20 at 00:32