Decrypting DebIan-Vulnerable SSH Traffic
Decrypting DebIan-Vulnerable SSH Traffic
Tuesday, February 3, 2009
My favorite security flaw from 2008 is the Debian OpenSSL vulnerability. Lots of analysis work has been done to understand the ramifications of this flaw, interesting because the effect of the flaw lasts long after vulnerable systems have been patched. Full recovery requires that all keys generated on a vulnerable system be replaced.
Lots of folks have experimented with HD Moore's precomputed SSH keys, allowing an attacker to quickly identify the private key of a vulnerable Debian OpenSSL implementation. If you haven't looked at these tools, I recommend you setup a vulnerable VM, generate a SSH key with "ssh-keygen -t dsa" and use some of the scripts on the OpenSSL Toys page to attack the system (on the vulnerable system, remember to "mv .ssh/id_pub.dsa .ssh/authorized_keys2").
What got less attention is the ability to decrypt SSH traffic by brute-forcing the Diffie-Hellman (DH) session key of a vulnerable OpenSSL system, implemented by the great guys at cr0.org. Two of their tools can be used in tandem; ssh_kex_keygen which recovers the DH key when at least one system in the SSH exchange is running a vulnerable OpenSSL, and ssh_decoder which parses TCP stream information from the SSH exchange automatically.
The folks at cr0 wrote their tools with the intention of recovering password-based authentication credentials against a vulnerable system, but it can also be used to decrypt an SSH packet capture when public/private key authentication is used. In order to get the TCP stream information in a form useful for ssh_decoder to parser, we can use the tcpick tool on a packet capture file.
To decrypt an OpenSSH session of a vulnerable OpenSSL implementation:
1. Capture the OpenSSH exchange. Unfortunately, tcpick has a bug which prevents it from correctly parsing 802.11 packet captures. I've sent the tcpick author a patch that fixes this flaw, but until that gets merged, you can convert an 802.11 packet capture to an Ethernet/802.3 packet capture using wlan2eth, available at http://www.willhackforsushi.com/code/wlan2eth/wlan2eth-0.1-src.tgz.
2. Extract the session you want to decrypt. If you have a big packet capture, it's best if you target the exchange you want to attack. Wireshark's Statistics -> Conversations feature will allow you to select any of the TCP sessions in the capture. Applying the session as a display filter (right-click on the TCP conversation, click Apply as Filter -> Selected -> A <-> B). Save the display filter results as a new packet capture (when clicking Save As, select "Displayed" in the Packet Range group in the "Save file as" dialog box.
3. Convert the packet capture into two data streams representing the client and server communications using tcpick:
$ tcpick -wRC -wRS -r ssh-sess.dump
Starting tcpick 0.2.1 at 2009-02-02 23:00 EST
Timeout for connections is 600
tcpick: reading from ssh-sess.dump
1 SYN-SENT 172.16.0.6:44388 > 172.16.0.99:ssh
1 SYN-RECEIVED 172.16.0.6:44388 > 172.16.0.99:ssh
1 ESTABLISHED 172.16.0.6:44388 > 172.16.0.99:ssh
1 FIN-WAIT-1 172.16.0.6:44388 > 172.16.0.99:ssh
1 TIME-WAIT 172.16.0.6:44388 > 172.16.0.99:ssh
1 CLOSED 172.16.0.6:44388 > 172.16.0.99:ssh
tcpick: done reading from ssh-sess.dump
$ ls
eth-sess.dump
tcpick_172.16.0.6_172.16.0.99_ssh.clnt.dat
tcpick_172.16.0.6_172.16.0.99_ssh.serv.dat
4. Grab ssh_kex_keygen from cr0.org. Compile the tool by running "make".
5. I ended up running into problems with the ssh_decoder tool causing it to fail in parsing the tcpick SSH session data. I chatted with the guys at cr0.org about it, but for some reason the only mailing address I have for them is only returning undeliverable. These hacks aren't a 100% fix, but it works fairly reasonably. In the ssh_kex_keygen-1.1/ directory, grab my version of ssh_decoder.rb:
www.willhackforsushi.com/code/ssh_decoder.rb
6. Ready to go; run ssh_decoder specifying the number of CPU's available to brute-force the DH key with the -n argument, specify -s if the server is vulnerable or -c if the client is vulnerable and the tcpick .dat files. On my Core Duo laptop, I run the script like this:
$ ruby ssh_decoder.rb -s -n2 ../tcpick*.dat
* read handshake
cipher: aes128-cbc, mac: hmac-md5, kex_hash: sha256, compr: none
* bruteforce DH
DH shared secret : 480a7ee6d32d09fb5a6a931ba0fca33e ... <trimmed> ...
* derive keys
* decipher streams
* successful authentication packet
{:testic=>1,
:username=>"username",
:keytype=>"ssh-dss",
:key=>
{:type=>"ssh-dss",
<trimmed>
:nextservice=>"ssh-connection",
:auth_method=>"publickey"}
* deciphered streams saved to "sshdecrypt.0.client.dat" & "sshdecrypt.0.server.dat"
The output files sshdecrypt* represent the plaintext data of the vulnerable OpenSSH/OpenSSL implementation. If both the client and server are vulnerable, then you'll have plaintext data in both. If only one end of the session is vulnerable, then one file will be encrypted and the other will be plaintext.
One sesiously missing tool to round out this vulnerability is a mechanism to decrypt a non-vulnerable OpenSSH server implementation when the public/private keypair is known. Unfortunately, to the best of my knowledge, there is no method to decrypt a non-vulnerable OpenSSH session. This is something I'm working on, and will post more information here as I get things working.
-Josh