This week, the SSH protocol made the news due to the now infamous xz-utils backdoor. One of my favorite detection techniques is network traffic analysis. Protocols like SSH make this, first of all, more difficult. However, as I did show in the discussion of SSH identification strings earlier this year, some information is still to be gained from SSH traffic [1].
Let's look at the SSH handshake of a normal SSH client and a normal SSH server in a bit more detail to learn what is normal when it comes to SSH.
1 - Client Identification
The first payload packet sent from the client to the server should only contain the client identification string. Note that the format is standardized. The important part is in the beginning:
SSH-2.0-OpenSSH_9.6
This means we are going to use SSH-2.0.
2 - Server Identification
In reply, the server will send its identification string. As for the client, the beginning of the string identifies the SSH version.
SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u3
3 - Client Key Exchange Init
This is a bit like the "Client Hello" for TLS. It lists all the ciphers the client supports.
4 - Server Key Exchange Init
In the case of TLS, the server would pick the cipher. But for SSH, the server responds with its list of supported ciphers
5 - The client now responds with the selected cipher and its public key
6 - The server now responds to complete the key exchange.
7 - In the end, the client acknowledges the complete exchange with a "New Keys" message.
Everything beyond this point will be encrypted.
For the xz-utils backdoor, Step 5, where the client sends its public key, is the interesting spot. This is where the attacker would send the exploit. However, the key is derived for specific connections and implementations, so I doubt this will be useful for detection.
The zeek documentation dedicates a chapter to understanding SSH and suggests several ways to leverage the zeek ssh.log. The log does not log public keys.
To experiment, we luckily have Anthony Weems' implementation of the backdoor [2]. I ran his "xzbot", and got the following lines in my syslog for a regular, non-backdoored (I hope) Ubuntu 22.04 system:
Connection closed by 10.128.0.11 port 38682 [preauth]
User root from 10.128.0.11 not allowed because none of user's groups are listed in AllowGroups
error: userauth_pubkey: parse key: error in libcrypto [preauth]
Connection closed by invalid user root 10.128.0.11 port 38780 [preauth]
I highlighted the third line. It is unique in that I have not seen it before. This could indicate someone is attempting a technique like the one implemented in the backdoor to execute code. Or is it just me using the xzbot wrong? I used the default ed448 seed of 0.
The packet capture appears to be similar.
Please let me know if you have other ideas to detect this backdoor or similar backdoors (better!) via network traffic.
[1] https://isc.sans.edu/diary/30520
[2] https://github.com/amlweems
---
Johannes B. Ullrich, Ph.D. , Dean of Research, SANS.edu
Twitter|