SSH2: implement terrapin attack countermeasures

This commit is contained in:
terrafrost 2023-12-28 06:27:57 -06:00
parent 23f117e32b
commit c8e3ab9317

View File

@ -1099,6 +1099,14 @@ class Net_SSH2
*/ */
var $smartMFA = true; var $smartMFA = true;
/**
* Extra packets counter
*
* @var bool
* @access private
*/
var $extra_packets;
/** /**
* Default Constructor. * Default Constructor.
* *
@ -1512,7 +1520,7 @@ class Net_SSH2
$preferred['client_to_server']['comp'] : $preferred['client_to_server']['comp'] :
$this->getSupportedCompressionAlgorithms(); $this->getSupportedCompressionAlgorithms();
$kex_algorithms = array_merge($kex_algorithms, array('ext-info-c')); $kex_algorithms = array_merge($kex_algorithms, array('ext-info-c', 'kex-strict-c-v00@openssh.com'));
// some SSH servers have buggy implementations of some of the above algorithms // some SSH servers have buggy implementations of some of the above algorithms
switch (true) { switch (true) {
@ -1576,6 +1584,7 @@ class Net_SSH2
return false; return false;
} }
$this->extra_packets = 0;
$kexinit_payload_server = $this->_get_binary_packet(); $kexinit_payload_server = $this->_get_binary_packet();
if ($kexinit_payload_server === false) { if ($kexinit_payload_server === false) {
$this->bitmap = 0; $this->bitmap = 0;
@ -1600,6 +1609,12 @@ class Net_SSH2
} }
$temp = unpack('Nlength', $this->_string_shift($response, 4)); $temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length'])); $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
if (in_array('kex-strict-s-v00@openssh.com', $this->kex_algorithms)) {
if ($this->session_id === false && $this->extra_packets) {
user_error('Possible Terrapin Attack detected');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
}
if (strlen($response) < 4) { if (strlen($response) < 4) {
return false; return false;
@ -1986,6 +2001,10 @@ class Net_SSH2
return false; return false;
} }
if (in_array('kex-strict-s-v00@openssh.com', $this->kex_algorithms)) {
$this->get_seq_no = $this->send_seq_no = 0;
}
$this->encrypt = $this->_encryption_algorithm_to_crypt_instance($encrypt); $this->encrypt = $this->_encryption_algorithm_to_crypt_instance($encrypt);
$this->decrypt = $this->_encryption_algorithm_to_crypt_instance($decrypt); $this->decrypt = $this->_encryption_algorithm_to_crypt_instance($decrypt);
@ -3780,9 +3799,11 @@ class Net_SSH2
$this->bitmap = 0; $this->bitmap = 0;
return false; return false;
case NET_SSH2_MSG_IGNORE: case NET_SSH2_MSG_IGNORE:
$this->extra_packets++;
$payload = $this->_get_binary_packet($skip_channel_filter); $payload = $this->_get_binary_packet($skip_channel_filter);
break; break;
case NET_SSH2_MSG_DEBUG: case NET_SSH2_MSG_DEBUG:
$this->extra_packets++;
$this->_string_shift($payload, 2); $this->_string_shift($payload, 2);
if (strlen($payload) < 4) { if (strlen($payload) < 4) {
return false; return false;
@ -3794,6 +3815,7 @@ class Net_SSH2
case NET_SSH2_MSG_UNIMPLEMENTED: case NET_SSH2_MSG_UNIMPLEMENTED:
return false; return false;
case NET_SSH2_MSG_KEXINIT: case NET_SSH2_MSG_KEXINIT:
// this is here for key re-exchanges after the initial key exchange
if ($this->session_id !== false) { if ($this->session_id !== false) {
$this->send_kex_first = false; $this->send_kex_first = false;
if (!$this->_key_exchange($payload)) { if (!$this->_key_exchange($payload)) {