From d14565c89b3238f4c0aa6f925b97bb432029782b Mon Sep 17 00:00:00 2001 From: yeah_wang Date: Mon, 1 Feb 2021 16:23:44 +0800 Subject: [PATCH] fix CVE --- backport-CVE-2018-1000805.patch | 155 ++++++++++++++++++++++++++++++++ python-paramiko.spec | 8 +- 2 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 backport-CVE-2018-1000805.patch diff --git a/backport-CVE-2018-1000805.patch b/backport-CVE-2018-1000805.patch new file mode 100644 index 0000000..faa6859 --- /dev/null +++ b/backport-CVE-2018-1000805.patch @@ -0,0 +1,155 @@ +From 56c96a659658acdbb873aef8809a7b508434dcce Mon Sep 17 00:00:00 2001 +From: Jeff Forcier +Date: Tue, 18 Sep 2018 19:59:16 -0700 +Subject: [PATCH] Fix and changelog re #1283 + +Conflict:NA +Reference:https://github.com/paramiko/paramiko/commit/56c96a65 +--- + paramiko/auth_handler.py | 36 ++++++++++++++++++++++++---- + tests/test_transport.py | 52 +++++++++++++++++++++++++++++++++++++--- + 2 files changed, 81 insertions(+), 7 deletions(-) + +diff --git a/paramiko/auth_handler.py b/paramiko/auth_handler.py +index a1ce5e3..137330e 100644 +--- a/paramiko/auth_handler.py ++++ b/paramiko/auth_handler.py +@@ -664,17 +664,39 @@ Error Message: {} + self.auth_event.set() + return + +- _handler_table = { ++ # TODO: do the same to the other tables, in Transport. ++ # TODO 3.0: MAY make sense to make these tables into actual ++ # classes/instances that can be fed a mode bool or whatever. Or, ++ # alternately (both?) make the message types small classes or enums that ++ # embed this info within themselves (which could also then tidy up the ++ # current 'integer -> human readable short string' stuff in common.py). ++ # TODO: if we do that, also expose 'em publicly. ++ ++ # Messages which should be handled _by_ servers (sent by clients) ++ _server_handler_table = { + MSG_SERVICE_REQUEST: _parse_service_request, +- MSG_SERVICE_ACCEPT: _parse_service_accept, + MSG_USERAUTH_REQUEST: _parse_userauth_request, ++ MSG_USERAUTH_INFO_RESPONSE: _parse_userauth_info_response, ++ } ++ ++ # Messages which should be handled _by_ clients (sent by servers) ++ _client_handler_table = { ++ MSG_SERVICE_ACCEPT: _parse_service_accept, + MSG_USERAUTH_SUCCESS: _parse_userauth_success, + MSG_USERAUTH_FAILURE: _parse_userauth_failure, + MSG_USERAUTH_BANNER: _parse_userauth_banner, + MSG_USERAUTH_INFO_REQUEST: _parse_userauth_info_request, +- MSG_USERAUTH_INFO_RESPONSE: _parse_userauth_info_response, + } + ++ # NOTE: prior to the fix for #1283, this was a static dict instead of a ++ # property. Should be backwards compatible in most/all cases. ++ @property ++ def _handler_table(self): ++ if self.transport.server_mode: ++ return self._server_handler_table ++ else: ++ return self._client_handler_table ++ + + class GssapiWithMicAuthHandler(object): + """A specialized Auth handler for gssapi-with-mic +@@ -767,9 +789,15 @@ class GssapiWithMicAuthHandler(object): + self._restore_delegate_auth_handler() + return self._delegate._parse_userauth_request(m) + +- _handler_table = { ++ __handler_table = { + MSG_SERVICE_REQUEST: _parse_service_request, + MSG_USERAUTH_REQUEST: _parse_userauth_request, + MSG_USERAUTH_GSSAPI_TOKEN: _parse_userauth_gssapi_token, + MSG_USERAUTH_GSSAPI_MIC: _parse_userauth_gssapi_mic, + } ++ ++ @property ++ def _handler_table(self): ++ # TODO: determine if we can cut this up like we did for the primary ++ # AuthHandler class. ++ return self.__handler_table +diff --git a/tests/test_transport.py b/tests/test_transport.py +index 9474acf..17db1f4 100644 +--- a/tests/test_transport.py ++++ b/tests/test_transport.py +@@ -30,18 +30,19 @@ import threading + import random + from hashlib import sha1 + import unittest ++from mock import Mock + + from paramiko import ( + Transport, SecurityOptions, ServerInterface, RSAKey, DSSKey, SSHException, +- ChannelException, Packetizer, Channel, ++ ChannelException, Packetizer, Channel, AuthHandler, + ) + from paramiko import AUTH_FAILED, AUTH_SUCCESSFUL + from paramiko import OPEN_SUCCEEDED, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED + from paramiko.common import ( + MSG_KEXINIT, cMSG_CHANNEL_WINDOW_ADJUST, MIN_PACKET_SIZE, MIN_WINDOW_SIZE, +- MAX_WINDOW_SIZE, DEFAULT_WINDOW_SIZE, DEFAULT_MAX_PACKET_SIZE, ++ MAX_WINDOW_SIZE, DEFAULT_WINDOW_SIZE, DEFAULT_MAX_PACKET_SIZE, MSG_NAMES, MSG_UNIMPLEMENTED, MSG_USERAUTH_SUCCESS, cMSG_UNIMPLEMENTED, + ) +-from paramiko.py3compat import bytes ++from paramiko.py3compat import bytes, byte_chr + from paramiko.message import Message + + from .util import needs_builtin, _support, slow +@@ -974,3 +975,48 @@ class TransportTest(unittest.TestCase): + assert "forwarding request denied" in str(e) + else: + assert False, "Did not raise SSHException!" ++ ++ def _send_client_message(self, message_type): ++ self.setup_test_server(connect_kwargs={}) ++ self.ts._send_message = Mock() ++ # NOTE: this isn't 100% realistic (most of these message types would ++ # have actual other fields in 'em) but it suffices to test the level of ++ # message dispatch we're interested in here. ++ msg = Message() ++ # TODO: really not liking the whole cMSG_XXX vs MSG_XXX duality right ++ # now, esp since the former is almost always just byte_chr(the ++ # latter)...but since that's the case... ++ msg.add_byte(byte_chr(message_type)) ++ self.tc._send_message(msg) ++ # No good way to actually wait for server action (see above tests re: ++ # MSG_UNIMPLEMENTED). Grump. ++ time.sleep(0.1) ++ ++ def _expect_unimplemented(self): ++ # Ensure MSG_UNIMPLEMENTED was sent (implies it hit end of loop instead ++ # of truly handling the given message). ++ # NOTE: When bug present, this will actually be the first thing that ++ # fails (since in many cases actual message handling doesn't involve ++ # sending a message back right away). ++ assert self.ts._send_message.call_count == 1 ++ reply = self.ts._send_message.call_args[0][0] ++ reply.rewind() # Because it's pre-send, not post-receive ++ assert reply.get_byte() == cMSG_UNIMPLEMENTED ++ ++ def test_server_transports_reject_client_message_types(self): ++ # TODO: handle Transport's own tables too, not just its inner auth ++ # handler's table. See TODOs in auth_handler.py ++ for message_type in AuthHandler._client_handler_table: ++ self._send_client_message(message_type) ++ self._expect_unimplemented() ++ # Reset for rest of loop ++ self.tearDown() ++ self.setUp() ++ ++ def test_server_rejects_client_MSG_USERAUTH_SUCCESS(self): ++ self._send_client_message(MSG_USERAUTH_SUCCESS) ++ # Sanity checks ++ assert not self.ts.authenticated ++ assert not self.ts.auth_handler.authenticated ++ # Real fix's behavior ++ self._expect_unimplemented() +-- +2.19.1 + diff --git a/python-paramiko.spec b/python-paramiko.spec index 5a83a80..0776342 100644 --- a/python-paramiko.spec +++ b/python-paramiko.spec @@ -1,6 +1,6 @@ Name: python-paramiko Version: 2.4.1 -Release: 7 +Release: 8 Summary: Python SSH module License: LGPLv2+ URL: https://github.com/paramiko/paramiko @@ -8,6 +8,7 @@ Source0: https://github.com/paramiko/paramiko/archive/%{version}/paramiko- Patch0: paramiko-2.3.1-disable-gssapi-on-unsupported-version.patch Patch1: paramiko-2.4.1-drop-pytest-relaxed.patch +Patch2: backport-CVE-2018-1000805.patch BuildArch: noarch @@ -90,5 +91,10 @@ PYTHONPATH=%{buildroot}%{python3_sitelib} pytest-%{python3_version} %doc html/ demos/ NEWS README.rst %changelog +* Mon Feb 01 2021 yeah_wang - 2.4.1-8 +- Type:CVE-2018-1000805 +- ID:NA +- SUG:NA +- DESC:fix CVE-2018-1000805 * Wed Nov 06 2019 Lijin Yang - 2.4.1-7 - init package -- Gitee