On December 4, Qualys released a security advisory for an authentication bypass vulnerability in OpenBSD, CVE-2019-19521. The vulnerability affects multiple services in OpenBSD including smtpd, sshd, ldapd, and radiusd. This immediately caught our attention as our recent v18 release included a package, part of our Encrypted Traffic Collection, which is capable of identifying successful authentication bypass exploits in the SSH protocol.
The Qualys advisory goes on to detail that the vulnerability in sshd does not allow for code execution given additional authentication checks which are part of the OpenSSH code base. This means the authentication bypass inference in our SSH Inference Package won’t trigger on this traffic. This is because the vulnerability does not succeed and allow SSH clients to bypass sshd’s authentication (but it does allow for clients to check to see if the server is vulnerable). Instead, the SSH session hangs. The reason for this is:
“…because sshd waits for login_passwd to send a challenge, while login_passwd waits for sshd to send a response…”
A question we are constantly considering is, “how can we identify something within Zeek?” A few hours after reading about this vulnerability, we had an OpenBSD 6.5 virtual machine up and pcap samples of this exploit recorded. Within the SSH connection’s sequence of lengths and inter-arrival time deltas, we noticed patterns which we thought could be used to build a detection. An additional hour later and we had an initial detection script. As the exploit occurs after encryption begins, traditional signature-based engines will have a difficult time identifying this traffic.
Below is a simple prototype script which identifies CVE-2019-19521 within SSH connections. This proof-of-concept script likely needs adjustments to run on large enterprise sites, however, it demonstrates possible detection strategies. We felt it important to get detection logic to the community quickly to facilitate testing. The general premise is that the script looks for connections which “hang” at a client authentication attempt and do not progress forward with a server authentication result message. Typically, server authentication responses are immediate, however, there are some scenarios where this doesn’t hold true.
This detection script is yet another demonstration of the power of Zeek’s scripting language for identifying threats in network traffic. Even though the exploit occurs within an encrypted tunnel, Zeek can still identify it.
If you’d like to learn more about Corelight, our Encrypted Traffic Collection, or this prototype script, feel free to reach out to us!
##! Detect CVE-2019-19521
# Record the timestamps of the first four client packets and check
# if a 10 second “hang” occurs after each
module SSH;
export {
global last_times: table[string] of time;
global pkt_counter: table[string] of count &default=0;
redef record SSH::Info += {
## A flag for marking a connection as analyzed.
checked_2019_19521: bool &default=F;
};
global do_check: event(c: connection);
}
redef SSH::disable_analyzer_after_detection = F;
event SSH::do_check(c: connection) {
if (c$ssh$checked_2019_19521 || SSH::pkt_counter[c$uid] > 4) {
if (c$uid in SSH::last_times) {
delete SSH::last_times[c$uid];
}
if (c$uid in SSH::pkt_counter) {
delete SSH::pkt_counter[c$uid];
}
return;
}
if (network_time() > 10 sec + SSH::last_times[c$uid] && “f” !in c$history && “r” !in c$history) {
print “possible exploit”;
delete SSH::pkt_counter[c$uid];
delete SSH::last_times[c$uid];
c$ssh$checked_2019_19521 = T;
}
}
event ssh_encrypted_packet (c: connection, orig: bool, len: count) &priority=10 {
if (c$ssh$checked_2019_19521 || !orig) {
return;
}
if (SSH::pkt_counter[c$uid] > 4) {
delete SSH::pkt_counter[c$uid];
delete SSH::last_times[c$uid];
c$ssh$checked_2019_19521 = T;
return;
}
SSH::pkt_counter[c$uid] += 1;
SSH::last_times[c$uid] = network_time();
schedule 10 sec {SSH::do_check(c)};
}
Anthony Kasza, Ben Reardon - Corelight Security Researchers