Decrypting HTTP2 TLS traffic in Wireshark
HTTP2 is a new protocol for serving web-pages. It is fundamentally different from HTTP1.1 which is used by most today. Chiefly, it is a binary protocol instead of a plain-text one.
What does this mean? A plain-text protocol is very easy for us humans to interact with, you can easily open a telnet session to a server and type in your GET request and read the response in plain old ASCII. But the world has moved on and wants to do more funky things with HTTP, and given the push recently to get everything encrypted, plain-text means little as TLS/SSL are binary anyway - you're not going to be typing encryption out by hand!
On the subject of encryption, HTTP2 is largely only supported over TLS (as it's predecessor SPDY was restricted to this), which means if you want to serve it up, you need to use a x509 certificate ("SSL" certificate). You can get one of these for free from LetsEncrypt (there are plenty of blogs and guides out there to deal with using these as they expire every 90 days).
Apache
You can enable HTTP2 on Apache quite easily by ensuring the relevant mod has been loaded:
a2enmod http2
And then updating your virtual host config file to support the protocol:
Protocols h2 http/1.1
And don't forget to restart apache... But that's it. If you check your browser's developer console you should see quietly somewhere that there is something mentioning it was http2 and not 1.1 in the response. Smashing.
Intercepting with Wireshark
You might want to start looking at what is going over the wire, to debug things (like, why doesn't push seem to be working for me), which is now frightfully complicated, given that the stream is binary, and most likely to be encrypted. Wireshark comes to the rescue though, that amazing packet capture tool that has got me out of many a jam. It's not the most intuitive tool, but definitely the most powerful and flexible.
First off, you're not going to be doing this against somebody else's website, as because it's encrypted, you need the all powerful private-key from the server to decrypt your traffic. This needs to be in RSA PEM format, the file will look something like:
-----BEGIN RSA PRIVATE KEY----- VGhlIEdlcm1hbiBHdW5zDQoNCkJvb20sIEJvb20sIEJvb20sIEJvb20 sDQoNCkJvb20sIEJvb20sIEJvb20sDQoNCkJvb20sIEJvb20sIEJvb2 0sIEJvb20sDQoNCkJvb20sIEJvb20sIEJvb20NCg0KDQpVbnRpdGxlZ CBTZWNvbmQgUG9lbQ0KDQpIZWFyIHRoZSB3b3JkcyBJIHNpbmcsDQoN CldhcidzIGEgaG9ycmlkIHRoaW5nLA0KDQpTbyBJIHNpbmcgc2luZyB zaW5nLi4uZGluZy1hLWxpbmctYS1saW5nLiA= -----END RSA PRIVATE KEY-----
If you're not using this format, then convert it (plenty of guides on how to get OpenSSL to do your bidding, another must have tool).
It is also likely you're using a fancy cutting edge cipher, in my test I used TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (which is reasonably cutting edge at the time of writing, lets see how long that lasts). These sorts of ciphers cannot be trivially intercepted and the encryption reversed with the private key, oh no, they implement fancy technologies such as Perfect Forward Secrecy to prevent hackers doing exactly this. You need to get your browser to get involved with the capture too and dump out pre-handshake information.
This example uses Firefox on Windows, you'll have to look up how to do the same on other browsers if you want to use a different one.
Getting down to it
- Close down Firefox
- Set the environment variable SSLKEYLOGFILE with a path to a convenient location
- In Windows navigate to Control Panel / System
- Select Advanced system settings
- Under the Advanced tab, select Environment Variables...
- Add a User variable as above
- Start up Firefox and when you go to any HTTPS website it'll start writing out very sensitive secret information. Make sure you delete this environment variable when done.
- Punch up Wireshark and head to the SSL Protocol preferences
- Jab the Edit button and enter in the details of the server you want to decode, being sure to add http2 as the protocol:
- Enter the path of the preshared key debug file from your browser in the relevant box
- Capture traffic on the relevant interface using a filter such as tcp port 443
That should be it, Wireshark should take care of the rest. You can tell it is working because there will be green entries listed as HTTP2 and not TLS / "Application Data".
You can then start to inspect the details of the HTTP traffic. The actual data that is sent as binary will look familiar, but with some extra gubbins new to HTTP2.