Merge branch '3.0'

This commit is contained in:
terrafrost 2023-12-28 07:55:37 -06:00
commit cc2d773b7d

View File

@ -936,6 +936,16 @@ class SSH2
*/ */
private $errorOnMultipleChannels; private $errorOnMultipleChannels;
/**
* Terrapin Countermeasure
*
* "During initial KEX, terminate the connection if any unexpected or out-of-sequence packet is received"
* -- https://github.com/openssh/openssh-portable/commit/1edb00c58f8a6875fad6a497aa2bacf37f9e6cd5
*
* @var int
*/
private $extra_packets;
/** /**
* Default Constructor. * Default Constructor.
* *
@ -1260,7 +1270,7 @@ class SSH2
$c2s_compression_algorithms = $preferred['client_to_server']['comp'] ?? $c2s_compression_algorithms = $preferred['client_to_server']['comp'] ??
SSH2::getSupportedCompressionAlgorithms(); SSH2::getSupportedCompressionAlgorithms();
$kex_algorithms = array_merge($kex_algorithms, ['ext-info-c']); $kex_algorithms = array_merge($kex_algorithms, ['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) {
@ -1316,6 +1326,7 @@ class SSH2
if ($kexinit_payload_server === false) { if ($kexinit_payload_server === false) {
$this->send_binary_packet($kexinit_payload_client); $this->send_binary_packet($kexinit_payload_client);
$this->extra_packets = 0;
$kexinit_payload_server = $this->get_binary_packet(); $kexinit_payload_server = $this->get_binary_packet();
if ( if (
@ -1347,6 +1358,11 @@ class SSH2
$this->languages_server_to_client, $this->languages_server_to_client,
$first_kex_packet_follows $first_kex_packet_follows
] = Strings::unpackSSH2('L10C', $response); ] = Strings::unpackSSH2('L10C', $response);
if (in_array('kex-strict-s-v00@openssh.com', $this->kex_algorithms)) {
if ($this->session_id === false && $this->extra_packets) {
throw new \UnexpectedValueException('Possible Terrapin Attack detected');
}
}
$this->supported_private_key_algorithms = $this->server_host_key_algorithms; $this->supported_private_key_algorithms = $this->server_host_key_algorithms;
@ -1605,6 +1621,10 @@ class SSH2
throw new UnexpectedValueException('Expected SSH_MSG_NEWKEYS'); throw new UnexpectedValueException('Expected SSH_MSG_NEWKEYS');
} }
if (in_array('kex-strict-s-v00@openssh.com', $this->kex_algorithms)) {
$this->get_seq_no = $this->send_seq_no = 0;
}
$keyBytes = pack('Na*', strlen($keyBytes), $keyBytes); $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
$this->encrypt = self::encryption_algorithm_to_crypt_instance($encrypt); $this->encrypt = self::encryption_algorithm_to_crypt_instance($encrypt);
@ -3435,9 +3455,11 @@ class SSH2
$this->bitmap = 0; $this->bitmap = 0;
return false; return false;
case MessageType::IGNORE: case MessageType::IGNORE:
$this->extra_packets++;
$payload = $this->get_binary_packet($skip_channel_filter); $payload = $this->get_binary_packet($skip_channel_filter);
break; break;
case MessageType::DEBUG: case MessageType::DEBUG:
$this->extra_packets++;
Strings::shift($payload, 2); // second byte is "always_display" Strings::shift($payload, 2); // second byte is "always_display"
[$message] = Strings::unpackSSH2('s', $payload); [$message] = Strings::unpackSSH2('s', $payload);
$this->errors[] = "SSH_MSG_DEBUG: $message"; $this->errors[] = "SSH_MSG_DEBUG: $message";
@ -3446,6 +3468,7 @@ class SSH2
case MessageType::UNIMPLEMENTED: case MessageType::UNIMPLEMENTED:
return false; return false;
case MessageType::KEXINIT: case MessageType::KEXINIT:
// this is here for key re-exchanges after the initial key exchange
if ($this->session_id !== false) { if ($this->session_id !== false) {
if (!$this->key_exchange($payload)) { if (!$this->key_exchange($payload)) {
$this->bitmap = 0; $this->bitmap = 0;