fix CVE-2018-1000805

(cherry picked from commit 1f0ac9e75ded34b70de136d745d1a62270586342)
This commit is contained in:
jzm369 2021-02-22 11:07:01 +08:00 committed by openeuler-sync-bot
parent dbc945cc97
commit 833285fbe0
2 changed files with 162 additions and 3 deletions

View File

@ -0,0 +1,155 @@
From 56c96a659658acdbb873aef8809a7b508434dcce Mon Sep 17 00:00:00 2001
From: Jeff Forcier <jeff@bitprophet.org>
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

View File

@ -1,6 +1,6 @@
Name: python-paramiko
Version: 2.4.1
Release: 8
Release: 9
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
Patch6000: backport-CVE-2018-1000805.patch
BuildArch: noarch
@ -66,8 +67,11 @@ PYTHONPATH=%{buildroot}%{python3_sitelib} pytest-%{python3_version}
%doc html/ demos/ NEWS README.rst
%changelog
* Sat Jan 30 2021 jinzhimin <jinzhimin2@huawei.com> - 2.4.1-8
- remove python2-paramiko subpackage
* Mon Feb 22 2021 jinzhimin <jinzhimin2@huawei.com> - 2.4.1-9
- fix CVE-2018-1000805
* Mon Aug 10 2020 lingsheng <lingsheng@huawei.com> - 2.4.1-8
- Remove python2-paramiko subpackage
* Wed Nov 06 2019 Lijin Yang <yanglijin@huawei.com> - 2.4.1-7
- init package