diff -Nru paramiko-1.10.1/debian/changelog paramiko-1.10.1/debian/changelog --- paramiko-1.10.1/debian/changelog 2018-03-16 19:48:48.000000000 +0000 +++ paramiko-1.10.1/debian/changelog 2018-10-16 15:22:15.000000000 +0000 @@ -1,3 +1,15 @@ +paramiko (1.10.1-1git1ubuntu0.2) trusty-security; urgency=medium + + * SECURITY UPDATE: server-side authentication vulnerability + - debian/patches/CVE-2018-1000805-pre.patch: fix MSG_UNIMPLEMENTED in + paramiko/transport.py, added tests to tests/test_transport.py. + - debian/patches/CVE-2018-1000805.patch: split messages dict in + paramiko/auth_handler.py, added tests to tests/test_transport.py. + - debian/control: added python-mock to Build-Depends. + - CVE-2018-1000805 + + -- Marc Deslauriers Tue, 16 Oct 2018 11:21:31 -0400 + paramiko (1.10.1-1git1ubuntu0.1) trusty-security; urgency=medium * SECURITY UPDATE: customized clients can skip auth diff -Nru paramiko-1.10.1/debian/control paramiko-1.10.1/debian/control --- paramiko-1.10.1/debian/control 2018-03-16 07:15:20.000000000 +0000 +++ paramiko-1.10.1/debian/control 2018-10-16 15:22:02.000000000 +0000 @@ -7,6 +7,7 @@ Build-Depends: debhelper (>> 8), python-all (>= 2.6.6-3~), python-crypto (>= 2.1.0-2), + python-mock, python-setuptools, python-epydoc Standards-Version: 3.9.4 diff -Nru paramiko-1.10.1/debian/patches/CVE-2018-1000805.patch paramiko-1.10.1/debian/patches/CVE-2018-1000805.patch --- paramiko-1.10.1/debian/patches/CVE-2018-1000805.patch 1970-01-01 00:00:00.000000000 +0000 +++ paramiko-1.10.1/debian/patches/CVE-2018-1000805.patch 2018-10-16 15:44:48.000000000 +0000 @@ -0,0 +1,124 @@ +Backport of: + +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 + +--- + paramiko/auth_handler.py | 36 ++++++++++++++++++++++++---- + sites/www/changelog.rst | 12 ++++++++++ + tests/test_transport.py | 51 +++++++++++++++++++++++++++++++++++++++- + 3 files changed, 94 insertions(+), 5 deletions(-) + +Index: paramiko-1.10.1/paramiko/auth_handler.py +=================================================================== +--- paramiko-1.10.1.orig/paramiko/auth_handler.py 2018-10-16 11:43:45.222765827 -0400 ++++ paramiko-1.10.1/paramiko/auth_handler.py 2018-10-16 11:43:45.222765827 -0400 +@@ -413,14 +413,36 @@ class AuthHandler (object): + self._send_auth_result(self.auth_username, 'keyboard-interactive', result) + + +- _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 ++ +Index: paramiko-1.10.1/tests/test_transport.py +=================================================================== +--- paramiko-1.10.1.orig/tests/test_transport.py 2018-10-16 11:43:45.222765827 -0400 ++++ paramiko-1.10.1/tests/test_transport.py 2018-10-16 11:44:41.919002492 -0400 +@@ -31,10 +31,11 @@ import random + from mock import Mock + + from paramiko import Transport, SecurityOptions, ServerInterface, RSAKey, DSSKey, \ +- SSHException, BadAuthenticationType, InteractiveQuery, ChannelException, Channel ++ SSHException, BadAuthenticationType, InteractiveQuery, ChannelException, Channel, AuthHandler + from paramiko import AUTH_FAILED, AUTH_PARTIALLY_SUCCESSFUL, AUTH_SUCCESSFUL + from paramiko import OPEN_SUCCEEDED, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED +-from paramiko.common import MSG_KEXINIT, MSG_CHANNEL_WINDOW_ADJUST, MSG_UNIMPLEMENTED ++from paramiko.common import MSG_KEXINIT, MSG_CHANNEL_WINDOW_ADJUST, \ ++ MSG_NAMES, MSG_UNIMPLEMENTED, MSG_USERAUTH_SUCCESS + from paramiko.message import Message + from loop import LoopSocket + from util import ParamikoTest +@@ -821,3 +822,48 @@ class TransportTest(ParamikoTest): + + def test_client_does_not_respond_to_MSG_UNIMPLEMENTED(self): + self._send_unimplemented(server_is_sender=True) ++ ++ 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(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() == chr(MSG_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() diff -Nru paramiko-1.10.1/debian/patches/CVE-2018-1000805-pre.patch paramiko-1.10.1/debian/patches/CVE-2018-1000805-pre.patch --- paramiko-1.10.1/debian/patches/CVE-2018-1000805-pre.patch 1970-01-01 00:00:00.000000000 +0000 +++ paramiko-1.10.1/debian/patches/CVE-2018-1000805-pre.patch 2018-10-16 15:19:02.000000000 +0000 @@ -0,0 +1,93 @@ +Backport of: + +From 852176d2d776b183a39e100009d3e18b6896323b Mon Sep 17 00:00:00 2001 +From: Jeff Forcier +Date: Tue, 18 Sep 2018 18:21:33 -0700 +Subject: [PATCH] Fix a pseudo-bug re: responding to MSG_UNIMPLEMENTED w/ + itself + +--- + dev-requirements.txt | 1 + + paramiko/transport.py | 23 ++++++++++++++++++----- + sites/www/changelog.rst | 5 +++++ + tests/test_transport.py | 25 +++++++++++++++++++++++++ + 4 files changed, 49 insertions(+), 5 deletions(-) + +Index: paramiko-1.10.1/paramiko/transport.py +=================================================================== +--- paramiko-1.10.1.orig/paramiko/transport.py 2018-10-16 11:14:37.930340430 -0400 ++++ paramiko-1.10.1/paramiko/transport.py 2018-10-16 11:15:56.930852015 -0400 +@@ -1639,11 +1639,22 @@ class Transport (threading.Thread): + elif (self.auth_handler is not None) and (ptype in self.auth_handler._handler_table): + self.auth_handler._handler_table[ptype](self.auth_handler, m) + else: +- self._log(WARNING, 'Oops, unhandled type %d' % ptype) +- msg = Message() +- msg.add_byte(chr(MSG_UNIMPLEMENTED)) +- msg.add_int(m.seqno) +- self._send_message(msg) ++ # Respond with "I don't implement this particular ++ # message type" message (unless the message type was ++ # itself literally MSG_UNIMPLEMENTED, in which case, we ++ # just shut up to avoid causing a useless loop). ++ name = MSG_NAMES[ptype] ++ self._log( ++ WARNING, ++ "Oops, unhandled type {} ({!r})".format( ++ ptype, name ++ ), ++ ) ++ if ptype != MSG_UNIMPLEMENTED: ++ msg = Message() ++ msg.add_byte(chr(MSG_UNIMPLEMENTED)) ++ msg.add_int(m.seqno) ++ self._send_message(msg) + except SSHException, e: + self._log(ERROR, 'Exception: ' + str(e)) + self._log(ERROR, util.tb_strings()) +Index: paramiko-1.10.1/tests/test_transport.py +=================================================================== +--- paramiko-1.10.1.orig/tests/test_transport.py 2018-10-16 11:14:37.930340430 -0400 ++++ paramiko-1.10.1/tests/test_transport.py 2018-10-16 11:18:48.939877963 -0400 +@@ -28,12 +28,13 @@ import time + import threading + import unittest + import random ++from mock import Mock + + from paramiko import Transport, SecurityOptions, ServerInterface, RSAKey, DSSKey, \ + SSHException, BadAuthenticationType, InteractiveQuery, ChannelException, Channel + from paramiko import AUTH_FAILED, AUTH_PARTIALLY_SUCCESSFUL, AUTH_SUCCESSFUL + from paramiko import OPEN_SUCCEEDED, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED +-from paramiko.common import MSG_KEXINIT, MSG_CHANNEL_WINDOW_ADJUST ++from paramiko.common import MSG_KEXINIT, MSG_CHANNEL_WINDOW_ADJUST, MSG_UNIMPLEMENTED + from paramiko.message import Message + from loop import LoopSocket + from util import ParamikoTest +@@ -797,3 +798,26 @@ class TransportTest(ParamikoTest): + assert "forwarding request denied" in str(e) + else: + assert False, "Did not raise SSHException!" ++ ++ def _send_unimplemented(self, server_is_sender): ++ self.setup_test_server() ++ sender, recipient = self.tc, self.ts ++ if server_is_sender: ++ sender, recipient = self.ts, self.tc ++ recipient._send_message = Mock() ++ msg = Message() ++ msg.add_byte(chr(MSG_UNIMPLEMENTED)) ++ sender._send_message(msg) ++ # TODO: I hate this but I literally don't see a good way to know when ++ # the recipient has received the sender's message (there are no ++ # existing threading events in play that work for this), esp in this ++ # case where we don't WANT a response (as otherwise we could ++ # potentially try blocking on the sender's receipt of a reply...maybe). ++ time.sleep(0.1) ++ assert not recipient._send_message.called ++ ++ def test_server_does_not_respond_to_MSG_UNIMPLEMENTED(self): ++ self._send_unimplemented(server_is_sender=False) ++ ++ def test_client_does_not_respond_to_MSG_UNIMPLEMENTED(self): ++ self._send_unimplemented(server_is_sender=True) diff -Nru paramiko-1.10.1/debian/patches/series paramiko-1.10.1/debian/patches/series --- paramiko-1.10.1/debian/patches/series 2018-03-16 19:35:50.000000000 +0000 +++ paramiko-1.10.1/debian/patches/series 2018-10-16 15:19:08.000000000 +0000 @@ -2,3 +2,5 @@ 0002-Allow-overriding-test-client-connect-kwargs-in-Trans.patch 0003-Initial-tests-proving-CVE-2018-7750-1175.patch 0004-Fixes-CVE-2018-7750-1175.patch +CVE-2018-1000805-pre.patch +CVE-2018-1000805.patch