Exemple #1
0
 def test_handle_13(self):
     # Test handling a SSH2_AGENTC_SIGN_REQUEST
     msg = Message()
     # Please sign some data
     msg.add_byte(byte_chr(13))
     # The id of the key to sign with
     key = list(self.agent.identities.values())[0][0].asbytes()
     msg.add_int(len(key))
     msg.add_bytes(bytes(key))
     # A blob of binary to sign
     blob = b'\x0e' * 10
     msg.add_int(len(blob))
     msg.add_bytes(blob)
     # Go go go
     mtype, msg = self.send(msg)
     self.assertEqual(mtype, 14)
     self.assertEqual(binascii.hexlify(msg.get_binary()), force_bytes((
         '000000077373682d7273610000010031d4c2bfad183557a7055f005c3d0d838d5'
         '701bd7b8a09d6d7f06699c691842c18e2bb62504a4beba0fbf5aeaf62f8106352'
         'b99f60d1fdc2dac1f5ad29566022eff25f62fac38cb2db849ed6b862af5e6bd36'
         '09b249a099848aa6fcfdfe1d93d2538ab4e614ecc95a4282abf8742c7bb591db9'
         '3e049e70a559d29134d207018a650b77fd9a7b6be8a2b1f75efbd66fa5a1e9e96'
         '3a5245ebe76294e0d150dfa2348bc7303203263b11952f0300e7b3a9efab81827'
         'b9e53d8c1cb8b2a1551c22cbab9e747fcff79bf57373f7ec8cb2a0dc9b42a7264'
         'afa4b7913693b709c5418eda02175b0a183549643127be92e79936ffc91479629'
         'c2acdc6aa5c83250a8edfe'
     )))
Exemple #2
0
    def test_encode(self):
        msg = Message()
        msg.add_int(23)
        msg.add_int(123789456)
        msg.add_string('q')
        msg.add_string('hello')
        msg.add_string('x' * 1000)
        self.assertEqual(msg.asbytes(), self.__a)

        msg = Message()
        msg.add_boolean(True)
        msg.add_boolean(False)
        msg.add_byte(byte_chr(0xf3))

        msg.add_bytes(zero_byte + byte_chr(0x3f))
        msg.add_list(['huey', 'dewey', 'louie'])
        self.assertEqual(msg.asbytes(), self.__b)

        msg = Message()
        msg.add_int64(5)
        msg.add_int64(0xf5e4d3c2b109)
        msg.add_mpint(17)
        msg.add_mpint(0xf5e4d3c2b109)
        msg.add_mpint(-0x65e4d3c2b109)
        self.assertEqual(msg.asbytes(), self.__c)
Exemple #3
0
    def test_1_encode(self):
        msg = Message()
        msg.add_int(23)
        msg.add_int(123789456)
        msg.add_string("q")
        msg.add_string("hello")
        msg.add_string("x" * 1000)
        self.assertEqual(msg.asbytes(), self.__a)

        msg = Message()
        msg.add_boolean(True)
        msg.add_boolean(False)
        msg.add_byte(byte_chr(0xf3))

        msg.add_bytes(zero_byte + byte_chr(0x3f))
        msg.add_list(["huey", "dewey", "louie"])
        self.assertEqual(msg.asbytes(), self.__b)

        msg = Message()
        msg.add_int64(5)
        msg.add_int64(0xf5e4d3c2b109)
        msg.add_mpint(17)
        msg.add_mpint(0xf5e4d3c2b109)
        msg.add_mpint(-0x65e4d3c2b109)
        self.assertEqual(msg.asbytes(), self.__c)
Exemple #4
0
 def test_handle_13_failure(self):
     # Test handling a SSH2_AGENTC_SIGN_REQUEST (where no identity)
     msg = Message()
     msg.add_byte(byte_chr(13))
     # The id of the key to sign with - in this case it doesn't exist
     key = b'\x0e' * 10
     msg.add_int(len(key))
     msg.add_bytes(bytes(key))
     # A blob of binary to sign
     blob = b'\x0e' * 10
     msg.add_int(len(blob))
     msg.add_bytes(blob)
     mtype, msg = self.send(msg)
     self.assertEqual(mtype, 5)
Exemple #5
0
    def add_key(self, key, comment='', lifetime=None, confirm=False):
        """
        Add a key to the SSH agent.

        :raises SSHException: if adding the key fails
        """
        msg = Message()
        if lifetime or confirm:
            msg.add_byte(cSSH_AGENTC_ADD_ID_CONSTRAINED)
        else:
            msg.add_byte(cSSH_AGENTC_ADD_IDENTITY)
        msg.add_bytes(key.asagentbytes())
        msg.add_string(comment)
        if lifetime:
            msg.add_byte(cSSH_AGENT_CONSTRAIN_LIFETIME)
            msg.add_int(lifetime)
        if confirm:
            msg.add_byte(cSSH_AGENT_CONSTRAIN_CONFIRM)
        ptype, result = self._send_message(msg)
        if ptype != SSH_AGENT_SUCCESS:
            raise paramiko.SSHException("Unable to add key to agent")
Exemple #6
0
    def sign(self, ca_key, nonce):
        """
        Sign this certificate with the specified ``ca_key``. The ``ca_key``
        must include a private key and be able to sign data. The ``nonce``
        must be provided. Usually this would be something random, i.e. from
        os.urandom(32), but can any string. Testing re-used the nonce from
        the existing certificate to verify that re-signing results in the
        same certificate

        :param .PKey ca_key:
            The key to use as a CA for signing the certificate
        :param str nonce:
            A string to random data to use in the signing of the certificate

        :raises SSHException:
            If the ca_key cannot be used for signing.
        """
        if not ca_key.can_sign():
            err = "Provided key cannot be used for signing"
            raise SSHException(err)

        new_bytes = self.generate_body(ca_key, nonce)
        sig = ca_key.sign_ssh_data(new_bytes)
        # If the key used to sign the data was a paramiko.Agent.AgentKey, the
        # results are a string/binary sequence. If a paramiko.pkey.PKey was
        # used, then the result is a Message. Convert to a string as needed.
        if type(sig) == Message:
            sig = sig.asbytes()

        msg = Message()
        msg.add_bytes(new_bytes)
        msg.add_string(sig)

        # Set new values on self after the signing process has been completed
        # and the new certificate is ready.
        self.nonce = nonce
        self.signature = sig
        self.signature_key = ca_key.asbytes()
        self._body_bytes = new_bytes
        self._bytes = msg.asbytes()
Exemple #7
0
    def test_1_encode(self):
        msg = Message()
        msg.add_int(23)
        msg.add_int(123789456)
        msg.add_string("q")
        msg.add_string("hello")
        msg.add_string("x" * 1000)
        self.assertEquals(str(msg), self.__a)

        msg = Message()
        msg.add_boolean(True)
        msg.add_boolean(False)
        msg.add_byte("\xf3")
        msg.add_bytes("\x00\x3f")
        msg.add_list(["huey", "dewey", "louie"])
        self.assertEquals(str(msg), self.__b)

        msg = Message()
        msg.add_int64(5)
        msg.add_int64(0xF5E4D3C2B109L)
        msg.add_mpint(17)
        msg.add_mpint(0xF5E4D3C2B109L)
        msg.add_mpint(-0x65E4D3C2B109L)
        self.assertEquals(str(msg), self.__c)
Exemple #8
0
    def test_1_encode(self):
        msg = Message()
        msg.add_int(23)
        msg.add_int(123789456)
        msg.add_string('q')
        msg.add_string('hello')
        msg.add_string('x' * 1000)
        self.assertEquals(str(msg), self.__a)

        msg = Message()
        msg.add_boolean(True)
        msg.add_boolean(False)
        msg.add_byte('\xf3')
        msg.add_bytes('\x00\x3f')
        msg.add_list(['huey', 'dewey', 'louie'])
        self.assertEquals(str(msg), self.__b)

        msg = Message()
        msg.add_int64(5)
        msg.add_int64(0xf5e4d3c2b109L)
        msg.add_mpint(17)
        msg.add_mpint(0xf5e4d3c2b109L)
        msg.add_mpint(-0x65e4d3c2b109L)
        self.assertEquals(str(msg), self.__c)
Exemple #9
0
    def test_1_encode(self):
        msg = Message()
        msg.add_int(23)
        msg.add_int(123789456)
        msg.add_string(b'q')
        msg.add_string(b'hello')
        msg.add_string(b'x' * 1000)
        self.assertEquals(bytes(msg), self.__a)

        msg = Message()
        msg.add_boolean(True)
        msg.add_boolean(False)
        msg.add_byte(b'\xf3')
        msg.add_bytes(b'\x00\x3f')
        msg.add_list([b'huey', b'dewey', b'louie'])
        self.assertEquals(bytes(msg), self.__b)

        msg = Message()
        msg.add_int64(5)
        msg.add_int64(0xf5e4d3c2b109)
        msg.add_mpint(17)
        msg.add_mpint(0xf5e4d3c2b109)
        msg.add_mpint(-0x65e4d3c2b109)
        self.assertEquals(bytes(msg), self.__c)
Exemple #10
0
     desired_mech = m.get_string()
     mech_ok = sshgss.ssh_check_mech(desired_mech)
     # if we don't support the mechanism, disconnect.
     if not mech_ok:
         self._log(
             INFO,
             "Disconnect: Received an invalid GSS-API OID mechanism",
         )
         self._disconnect_no_more_auth()
     # send the Kerberos V5 GSSAPI OID to the client
     supported_mech = sshgss.ssh_gss_oids("server")
     # RFC 4462 says we are not required to implement GSS-API error
     # messages. See section 3.8 in http://www.ietf.org/rfc/rfc4462.txt
     m = Message()
     m.add_byte(cMSG_USERAUTH_GSSAPI_RESPONSE)
     m.add_bytes(supported_mech)
     self.transport.auth_handler = GssapiWithMicAuthHandler(
         self, sshgss
     )
     self.transport._expected_packet = (
         MSG_USERAUTH_GSSAPI_TOKEN,
         MSG_USERAUTH_REQUEST,
         MSG_SERVICE_REQUEST,
     )
     self.transport._send_message(m)
     return
 elif method == "gssapi-keyex" and gss_auth:
     mic_token = m.get_string()
     sshgss = self.transport.kexgss_ctxt
     if sshgss is None:
         # If there is no valid context, we reject the authentication
    def _parse_userauth_request(self, m):
        if not self.transport.server_mode:
            # er, uh... what?
            m = Message()
            m.add_byte(cMSG_USERAUTH_FAILURE)
            m.add_string('none')
            m.add_boolean(False)
            self.transport._send_message(m)
            return
        if self.authenticated:
            # ignore
            return
        username = m.get_text()
        service = m.get_text()
        method = m.get_text()
        self.transport._log(
            DEBUG, 'Auth request (type=%s) service=%s, username=%s' %
            (method, service, username))
        if service != 'ssh-connection':
            self._disconnect_service_not_available()
            return
        if (self.auth_username
                is not None) and (self.auth_username != username):
            self.transport._log(
                WARNING,
                'Auth rejected because the client attempted to change username in mid-flight'
            )
            self._disconnect_no_more_auth()
            return
        self.auth_username = username
        # check if GSS-API authentication is enabled
        gss_auth = self.transport.server_object.enable_auth_gssapi()

        if method == 'none':
            result = self.transport.server_object.check_auth_none(username)
        elif method == 'password':
            changereq = m.get_boolean()
            password = m.get_binary()
            try:
                password = password.decode('UTF-8')
            except UnicodeError:
                # some clients/servers expect non-utf-8 passwords!
                # in this case, just return the raw byte string.
                pass
            if changereq:
                # always treated as failure, since we don't support changing passwords, but collect
                # the list of valid auth types from the callback anyway
                self.transport._log(
                    DEBUG, 'Auth request to change passwords (rejected)')
                newpassword = m.get_binary()
                try:
                    newpassword = newpassword.decode('UTF-8', 'replace')
                except UnicodeError:
                    pass
                result = AUTH_FAILED
            else:
                result = self.transport.server_object.check_auth_password(
                    username, password)
        elif method == 'publickey':
            sig_attached = m.get_boolean()
            keytype = m.get_text()
            keyblob = m.get_binary()
            try:
                key = self.transport._key_info[keytype](Message(keyblob))
            except SSHException as e:
                self.transport._log(INFO,
                                    'Auth rejected: public key: %s' % str(e))
                key = None
            except:
                self.transport._log(
                    INFO, 'Auth rejected: unsupported or mangled public key')
                key = None
            if key is None:
                self._disconnect_no_more_auth()
                return
            # first check if this key is okay... if not, we can skip the verify
            result = self.transport.server_object.check_auth_publickey(
                username, key)
            if result != AUTH_FAILED:
                # key is okay, verify it
                if not sig_attached:
                    # client wants to know if this key is acceptable, before it
                    # signs anything...  send special "ok" message
                    m = Message()
                    m.add_byte(cMSG_USERAUTH_PK_OK)
                    m.add_string(keytype)
                    m.add_string(keyblob)
                    self.transport._send_message(m)
                    return
                sig = Message(m.get_binary())
                blob = self._get_session_blob(key, service, username)
                if not key.verify_ssh_sig(blob, sig):
                    self.transport._log(INFO,
                                        'Auth rejected: invalid signature')
                    result = AUTH_FAILED
        elif method == 'keyboard-interactive':
            lang = m.get_string()
            submethods = m.get_string()
            result = self.transport.server_object.check_auth_interactive(
                username, submethods)
            if isinstance(result, InteractiveQuery):
                # make interactive query instead of response
                self._interactive_query(result)
                return
        elif method == "gssapi-with-mic" and gss_auth:
            sshgss = GSSAuth(method)
            # Read the number of OID mechanisms supported by the client.
            # OpenSSH sends just one OID. It's the Kerveros V5 OID and that's
            # the only OID we support.
            mechs = m.get_int()
            # We can't accept more than one OID, so if the SSH client sends
            # more than one, disconnect.
            if mechs > 1:
                self.transport._log(
                    INFO,
                    'Disconnect: Received more than one GSS-API OID mechanism')
                self._disconnect_no_more_auth()
            desired_mech = m.get_string()
            mech_ok = sshgss.ssh_check_mech(desired_mech)
            # if we don't support the mechanism, disconnect.
            if not mech_ok:
                self.transport._log(
                    INFO,
                    'Disconnect: Received an invalid GSS-API OID mechanism')
                self._disconnect_no_more_auth()
            # send the Kerberos V5 GSSAPI OID to the client
            supported_mech = sshgss.ssh_gss_oids("server")
            # RFC 4462 says we are not required to implement GSS-API error
            # messages. See section 3.8 in http://www.ietf.org/rfc/rfc4462.txt
            while True:
                m = Message()
                m.add_byte(cMSG_USERAUTH_GSSAPI_RESPONSE)
                m.add_bytes(supported_mech)
                self.transport._send_message(m)
                ptype, m = self.transport.packetizer.read_message()
                if ptype == MSG_USERAUTH_GSSAPI_TOKEN:
                    client_token = m.get_string()
                    # use the client token as input to establish a secure
                    # context.
                    try:
                        token = sshgss.ssh_accept_sec_context(
                            self.gss_host, client_token, username)
                    except Exception:
                        result = AUTH_FAILED
                        self._send_auth_result(username, method, result)
                        raise
                    if token is not None:
                        m = Message()
                        m.add_byte(cMSG_USERAUTH_GSSAPI_TOKEN)
                        m.add_string(token)
                        self.transport._send_message(m)
                else:
                    result = AUTH_FAILED
                    self._send_auth_result(username, method, result)
                    return
                # check MIC
                ptype, m = self.transport.packetizer.read_message()
                if ptype == MSG_USERAUTH_GSSAPI_MIC:
                    break
            mic_token = m.get_string()
            try:
                sshgss.ssh_check_mic(mic_token, self.transport.session_id,
                                     username)
            except Exception:
                result = AUTH_FAILED
                self._send_auth_result(username, method, result)
                raise
            # TODO: Implement client credential saving.
            # The OpenSSH server is able to create a TGT with the delegated
            # client credentials, but this is not supported by GSS-API.
            result = AUTH_SUCCESSFUL
            self.transport.server_object.check_auth_gssapi_with_mic(
                username, result)
        elif method == "gssapi-keyex" and gss_auth:
            mic_token = m.get_string()
            sshgss = self.transport.kexgss_ctxt
            if sshgss is None:
                # If there is no valid context, we reject the authentication
                result = AUTH_FAILED
                self._send_auth_result(username, method, result)
            try:
                sshgss.ssh_check_mic(mic_token, self.transport.session_id,
                                     self.auth_username)
            except Exception:
                result = AUTH_FAILED
                self._send_auth_result(username, method, result)
                raise
            result = AUTH_SUCCESSFUL
            self.transport.server_object.check_auth_gssapi_keyex(
                username, result)
        else:
            result = self.transport.server_object.check_auth_none(username)
        # okay, send result
        self._send_auth_result(username, method, result)
 def _parse_service_accept(self, m):
     service = m.get_text()
     if service == 'ssh-userauth':
         self.transport._log(DEBUG, 'userauth is OK')
         m = Message()
         m.add_byte(cMSG_USERAUTH_REQUEST)
         m.add_string(self.username)
         m.add_string('ssh-connection')
         m.add_string(self.auth_method)
         if self.auth_method == 'password':
             m.add_boolean(False)
             password = bytestring(self.password)
             m.add_string(password)
         elif self.auth_method == 'publickey':
             m.add_boolean(True)
             m.add_string(self.private_key.get_name())
             m.add_string(self.private_key)
             blob = self._get_session_blob(self.private_key,
                                           'ssh-connection', self.username)
             sig = self.private_key.sign_ssh_data(blob)
             m.add_string(sig)
         elif self.auth_method == 'keyboard-interactive':
             m.add_string('')
             m.add_string(self.submethods)
         elif self.auth_method == "gssapi-with-mic":
             sshgss = GSSAuth(self.auth_method, self.gss_deleg_creds)
             m.add_bytes(sshgss.ssh_gss_oids())
             # send the supported GSSAPI OIDs to the server
             self.transport._send_message(m)
             ptype, m = self.transport.packetizer.read_message()
             if ptype == MSG_USERAUTH_BANNER:
                 self._parse_userauth_banner(m)
                 ptype, m = self.transport.packetizer.read_message()
             if ptype == MSG_USERAUTH_GSSAPI_RESPONSE:
                 # Read the mechanism selected by the server. We send just
                 # the Kerberos V5 OID, so the server can only respond with
                 # this OID.
                 mech = m.get_string()
                 m = Message()
                 m.add_byte(cMSG_USERAUTH_GSSAPI_TOKEN)
                 m.add_string(
                     sshgss.ssh_init_sec_context(
                         self.gss_host,
                         mech,
                         self.username,
                     ))
                 self.transport._send_message(m)
                 while True:
                     ptype, m = self.transport.packetizer.read_message()
                     if ptype == MSG_USERAUTH_GSSAPI_TOKEN:
                         srv_token = m.get_string()
                         next_token = sshgss.ssh_init_sec_context(
                             self.gss_host, mech, self.username, srv_token)
                         # After this step the GSSAPI should not return any
                         # token. If it does, we keep sending the token to
                         # the server until no more token is returned.
                         if next_token is None:
                             break
                         else:
                             m = Message()
                             m.add_byte(cMSG_USERAUTH_GSSAPI_TOKEN)
                             m.add_string(next_token)
                             self.transport.send_message(m)
                 else:
                     raise SSHException("Received Package: %s" %
                                        MSG_NAMES[ptype])
                 m = Message()
                 m.add_byte(cMSG_USERAUTH_GSSAPI_MIC)
                 # send the MIC to the server
                 m.add_string(sshgss.ssh_get_mic(self.transport.session_id))
             elif ptype == MSG_USERAUTH_GSSAPI_ERRTOK:
                 # RFC 4462 says we are not required to implement GSS-API
                 # error messages.
                 # See RFC 4462 Section 3.8 in
                 # http://www.ietf.org/rfc/rfc4462.txt
                 raise SSHException("Server returned an error token")
             elif ptype == MSG_USERAUTH_GSSAPI_ERROR:
                 maj_status = m.get_int()
                 min_status = m.get_int()
                 err_msg = m.get_string()
                 lang_tag = m.get_string()  # we don't care!
                 raise SSHException("GSS-API Error:\nMajor Status: %s\n\
                                     Minor Status: %s\ \nError Message:\
                                      %s\n") % (str(maj_status),
                                                str(min_status), err_msg)
             elif ptype == MSG_USERAUTH_FAILURE:
                 self._parse_userauth_failure(m)
                 return
             else:
                 raise SSHException("Received Package: %s" %
                                    MSG_NAMES[ptype])
         elif self.auth_method == 'gssapi-keyex' and\
                 self.transport.gss_kex_used:
             kexgss = self.transport.kexgss_ctxt
             kexgss.set_username(self.username)
             mic_token = kexgss.ssh_get_mic(self.transport.session_id)
             m.add_string(mic_token)
         elif self.auth_method == 'none':
             pass
         else:
             raise SSHException('Unknown auth method "%s"' %
                                self.auth_method)
         self.transport._send_message(m)
     else:
         self.transport._log(DEBUG,
                             'Service request "%s" accepted (?)' % service)
Exemple #13
0
    def _parse_service_accept(self, m):
        service = m.get_text()
        if service == "ssh-userauth":
            self._log(DEBUG, "userauth is OK")
            m = Message()
            m.add_byte(cMSG_USERAUTH_REQUEST)
            m.add_string(self.username)
            m.add_string("ssh-connection")
            m.add_string(self.auth_method)
            if self.auth_method == "password":
                m.add_boolean(False)
                password = b(self.password)
                m.add_string(password)
            elif self.auth_method == "publickey":
                m.add_boolean(True)
                # Use certificate contents, if available, plain pubkey
                # otherwise
                if self.private_key.public_blob:
                    m.add_string(self.private_key.public_blob.key_type)
                    m.add_string(self.private_key.public_blob.key_blob)
                else:
                    m.add_string(self.private_key.get_name())
                    m.add_string(self.private_key)
                blob = self._get_session_blob(
                    self.private_key, "ssh-connection", self.username
                )
                sig = self.private_key.sign_ssh_data(blob)
                m.add_string(sig)
            elif self.auth_method == "keyboard-interactive":
                m.add_string("")
                m.add_string(self.submethods)
            elif self.auth_method == "gssapi-with-mic":
                sshgss = GSSAuth(self.auth_method, self.gss_deleg_creds)
                m.add_bytes(sshgss.ssh_gss_oids())
                # send the supported GSSAPI OIDs to the server
                self.transport._send_message(m)
                ptype, m = self.transport.packetizer.read_message()
                if ptype == MSG_USERAUTH_BANNER:
                    self._parse_userauth_banner(m)
                    ptype, m = self.transport.packetizer.read_message()
                if ptype == MSG_USERAUTH_GSSAPI_RESPONSE:
                    # Read the mechanism selected by the server. We send just
                    # the Kerberos V5 OID, so the server can only respond with
                    # this OID.
                    mech = m.get_string()
                    m = Message()
                    m.add_byte(cMSG_USERAUTH_GSSAPI_TOKEN)
                    try:
                        m.add_string(
                            sshgss.ssh_init_sec_context(
                                self.gss_host, mech, self.username
                            )
                        )
                    except GSS_EXCEPTIONS as e:
                        return self._handle_local_gss_failure(e)
                    self.transport._send_message(m)
                    while True:
                        ptype, m = self.transport.packetizer.read_message()
                        if ptype == MSG_USERAUTH_GSSAPI_TOKEN:
                            srv_token = m.get_string()
                            try:
                                next_token = sshgss.ssh_init_sec_context(
                                    self.gss_host,
                                    mech,
                                    self.username,
                                    srv_token,
                                )
                            except GSS_EXCEPTIONS as e:
                                return self._handle_local_gss_failure(e)
                            # After this step the GSSAPI should not return any
                            # token. If it does, we keep sending the token to
                            # the server until no more token is returned.
                            if next_token is None:
                                break
                            else:
                                m = Message()
                                m.add_byte(cMSG_USERAUTH_GSSAPI_TOKEN)
                                m.add_string(next_token)
                                self.transport.send_message(m)
                    else:
                        raise SSHException(
                            "Received Package: {}".format(MSG_NAMES[ptype])
                        )
                    m = Message()
                    m.add_byte(cMSG_USERAUTH_GSSAPI_MIC)
                    # send the MIC to the server
                    m.add_string(sshgss.ssh_get_mic(self.transport.session_id))
                elif ptype == MSG_USERAUTH_GSSAPI_ERRTOK:
                    # RFC 4462 says we are not required to implement GSS-API
                    # error messages.
                    # See RFC 4462 Section 3.8 in
                    # http://www.ietf.org/rfc/rfc4462.txt
                    raise SSHException("Server returned an error token")
                elif ptype == MSG_USERAUTH_GSSAPI_ERROR:
                    maj_status = m.get_int()
                    min_status = m.get_int()
                    err_msg = m.get_string()
                    m.get_string()  # Lang tag - discarded
                    raise SSHException(
                        """GSS-API Error:
Major Status: {}
Minor Status: {}
Error Message: {}
""".format(
                            maj_status, min_status, err_msg
                        )
                    )
                elif ptype == MSG_USERAUTH_FAILURE:
                    self._parse_userauth_failure(m)
                    return
                else:
                    raise SSHException(
                        "Received Package: {}".format(MSG_NAMES[ptype])
                    )
            elif (
                self.auth_method == "gssapi-keyex"
                and self.transport.gss_kex_used
            ):
                kexgss = self.transport.kexgss_ctxt
                kexgss.set_username(self.username)
                mic_token = kexgss.ssh_get_mic(self.transport.session_id)
                m.add_string(mic_token)
            elif self.auth_method == "none":
                pass
            else:
                raise SSHException(
                    'Unknown auth method "{}"'.format(self.auth_method)
                )
            self.transport._send_message(m)
        else:
            self._log(
                DEBUG, 'Service request "{}" accepted (?)'.format(service)
            )
Exemple #14
0
    def _parse_userauth_request(self, m):
        if not self.transport.server_mode:
            # er, uh... what?
            m = Message()
            m.add_byte(cMSG_USERAUTH_FAILURE)
            m.add_string('none')
            m.add_boolean(False)
            self.transport._send_message(m)
            return
        if self.authenticated:
            # ignore
            return
        username = m.get_text()
        service = m.get_text()
        method = m.get_text()
        self.transport._log(DEBUG, 'Auth request (type=%s) service=%s, username=%s' % (method, service, username))
        if service != 'ssh-connection':
            self._disconnect_service_not_available()
            return
        if (self.auth_username is not None) and (self.auth_username != username):
            self.transport._log(WARNING, 'Auth rejected because the client attempted to change username in mid-flight')
            self._disconnect_no_more_auth()
            return
        self.auth_username = username
        # check if GSS-API authentication is enabled
        gss_auth = self.transport.server_object.enable_auth_gssapi()

        if method == 'none':
            result = self.transport.server_object.check_auth_none(username)
        elif method == 'password':
            changereq = m.get_boolean()
            password = m.get_binary()
            try:
                password = password.decode('UTF-8')
            except UnicodeError:
                # some clients/servers expect non-utf-8 passwords!
                # in this case, just return the raw byte string.
                pass
            if changereq:
                # always treated as failure, since we don't support changing passwords, but collect
                # the list of valid auth types from the callback anyway
                self.transport._log(DEBUG, 'Auth request to change passwords (rejected)')
                newpassword = m.get_binary()
                try:
                    newpassword = newpassword.decode('UTF-8', 'replace')
                except UnicodeError:
                    pass
                result = AUTH_FAILED
            else:
                result = self.transport.server_object.check_auth_password(username, password)
        elif method == 'publickey':
            sig_attached = m.get_boolean()
            keytype = m.get_text()
            keyblob = m.get_binary()
            try:
                key = self.transport._key_info[keytype](Message(keyblob))
            except SSHException as e:
                self.transport._log(INFO, 'Auth rejected: public key: %s' % str(e))
                key = None
            except:
                self.transport._log(INFO, 'Auth rejected: unsupported or mangled public key')
                key = None
            if key is None:
                self._disconnect_no_more_auth()
                return
            # first check if this key is okay... if not, we can skip the verify
            result = self.transport.server_object.check_auth_publickey(username, key)
            if result != AUTH_FAILED:
                # key is okay, verify it
                if not sig_attached:
                    # client wants to know if this key is acceptable, before it
                    # signs anything...  send special "ok" message
                    m = Message()
                    m.add_byte(cMSG_USERAUTH_PK_OK)
                    m.add_string(keytype)
                    m.add_string(keyblob)
                    self.transport._send_message(m)
                    return
                sig = Message(m.get_binary())
                blob = self._get_session_blob(key, service, username)
                if not key.verify_ssh_sig(blob, sig):
                    self.transport._log(INFO, 'Auth rejected: invalid signature')
                    result = AUTH_FAILED
        elif method == 'keyboard-interactive':
            lang = m.get_string()
            submethods = m.get_string()
            result = self.transport.server_object.check_auth_interactive(username, submethods)
            if isinstance(result, InteractiveQuery):
                # make interactive query instead of response
                self._interactive_query(result)
                return
        elif method == "gssapi-with-mic" and gss_auth:
            sshgss = GSSAuth(method)
            # Read the number of OID mechanisms supported by the client.
            # OpenSSH sends just one OID. It's the Kerveros V5 OID and that's
            # the only OID we support.
            mechs = m.get_int()
            # We can't accept more than one OID, so if the SSH client sends
            # more than one, disconnect.
            if mechs > 1:
                self.transport._log(INFO,
                                    'Disconnect: Received more than one GSS-API OID mechanism')
                self._disconnect_no_more_auth()
            desired_mech = m.get_string()
            mech_ok = sshgss.ssh_check_mech(desired_mech)
            # if we don't support the mechanism, disconnect.
            if not mech_ok:
                self.transport._log(INFO,
                                    'Disconnect: Received an invalid GSS-API OID mechanism')
                self._disconnect_no_more_auth()
            # send the Kerberos V5 GSSAPI OID to the client
            supported_mech = sshgss.ssh_gss_oids("server")
            # RFC 4462 says we are not required to implement GSS-API error
            # messages. See section 3.8 in http://www.ietf.org/rfc/rfc4462.txt
            while True:
                m = Message()
                m.add_byte(cMSG_USERAUTH_GSSAPI_RESPONSE)
                m.add_bytes(supported_mech)
                self.transport._send_message(m)
                ptype, m = self.transport.packetizer.read_message()
                if ptype == MSG_USERAUTH_GSSAPI_TOKEN:
                    client_token = m.get_string()
                    # use the client token as input to establish a secure
                    # context.
                    try:
                        token = sshgss.ssh_accept_sec_context(self.gss_host,
                                                              client_token,
                                                              username)
                    except Exception:
                        result = AUTH_FAILED
                        self._send_auth_result(username, method, result)
                        raise
                    if token is not None:
                        m = Message()
                        m.add_byte(cMSG_USERAUTH_GSSAPI_TOKEN)
                        m.add_string(token)
                        self.transport._send_message(m)
                else:
                    raise SSHException("Client asked to handle paket %s"
                                       %MSG_NAMES[ptype])
                # check MIC
                ptype, m = self.transport.packetizer.read_message()
                if ptype == MSG_USERAUTH_GSSAPI_MIC:
                    break
            mic_token = m.get_string()
            try:
                sshgss.ssh_check_mic(mic_token,
                                     self.transport.session_id,
                                     username)
            except Exception:
                result = AUTH_FAILED
                self._send_auth_result(username, method, result)
                raise
            # TODO: Implement client credential saving.
            # The OpenSSH server is able to create a TGT with the delegated
            # client credentials, but this is not supported by GSS-API.
            result = AUTH_SUCCESSFUL
            self.transport.server_object.check_auth_gssapi_with_mic(username, result)
        elif method == "gssapi-keyex" and gss_auth:
            mic_token = m.get_string()
            sshgss = self.transport.kexgss_ctxt
            if sshgss is None:
                # If there is no valid context, we reject the authentication
                result = AUTH_FAILED
                self._send_auth_result(username, method, result)
            try:
                sshgss.ssh_check_mic(mic_token,
                                     self.transport.session_id,
                                     self.auth_username)
            except Exception:
                result = AUTH_FAILED
                self._send_auth_result(username, method, result)
                raise
            result = AUTH_SUCCESSFUL
            self.transport.server_object.check_auth_gssapi_keyex(username, result)
        else:
            result = self.transport.server_object.check_auth_none(username)
        # okay, send result
        self._send_auth_result(username, method, result)
Exemple #15
0
 def _parse_service_accept(self, m):
     service = m.get_text()
     if service == 'ssh-userauth':
         self.transport._log(DEBUG, 'userauth is OK')
         m = Message()
         m.add_byte(cMSG_USERAUTH_REQUEST)
         m.add_string(self.username)
         m.add_string('ssh-connection')
         m.add_string(self.auth_method)
         if self.auth_method == 'password':
             m.add_boolean(False)
             password = bytestring(self.password)
             m.add_string(password)
         elif self.auth_method == 'publickey':
             m.add_boolean(True)
             m.add_string(self.private_key.get_name())
             m.add_string(self.private_key)
             blob = self._get_session_blob(self.private_key, 'ssh-connection', self.username)
             sig = self.private_key.sign_ssh_data(blob)
             m.add_string(sig)
         elif self.auth_method == 'keyboard-interactive':
             m.add_string('')
             m.add_string(self.submethods)
         elif self.auth_method == "gssapi-with-mic":
             sshgss = GSSAuth(self.auth_method, self.gss_deleg_creds)
             m.add_bytes(sshgss.ssh_gss_oids())
             # send the supported GSSAPI OIDs to the server
             self.transport._send_message(m)
             ptype, m = self.transport.packetizer.read_message()
             if ptype == MSG_USERAUTH_BANNER:
                 self._parse_userauth_banner(m)
                 ptype, m = self.transport.packetizer.read_message()
             if ptype == MSG_USERAUTH_GSSAPI_RESPONSE:
                 # Read the mechanism selected by the server. We send just
                 # the Kerberos V5 OID, so the server can only respond with
                 # this OID.
                 mech = m.get_string()
                 m = Message()
                 m.add_byte(cMSG_USERAUTH_GSSAPI_TOKEN)
                 m.add_string(sshgss.ssh_init_sec_context(self.gss_host,
                                                          mech,
                                                          self.username,))
                 self.transport._send_message(m)
                 while True:
                     ptype, m = self.transport.packetizer.read_message()
                     if ptype == MSG_USERAUTH_GSSAPI_TOKEN:
                         srv_token = m.get_string()
                         next_token = sshgss.ssh_init_sec_context(self.gss_host,
                                                                  mech,
                                                                  self.username,
                                                                  srv_token)
                         # After this step the GSSAPI should not return any
                         # token. If it does, we keep sending the token to
                         # the server until no more token is returned.
                         if next_token is None:
                             break
                         else:
                             m = Message()
                             m.add_byte(cMSG_USERAUTH_GSSAPI_TOKEN)
                             m.add_string(next_token)
                             self.transport.send_message(m)
                 else:
                     raise SSHException("Received Package: %s" % MSG_NAMES[ptype])
                 m = Message()
                 m.add_byte(cMSG_USERAUTH_GSSAPI_MIC)
                 # send the MIC to the server
                 m.add_string(sshgss.ssh_get_mic(self.transport.session_id))
             elif ptype == MSG_USERAUTH_GSSAPI_ERRTOK:
                 # RFC 4462 says we are not required to implement GSS-API
                 # error messages.
                 # See RFC 4462 Section 3.8 in
                 # http://www.ietf.org/rfc/rfc4462.txt
                 raise SSHException("Server returned an error token")
             elif ptype == MSG_USERAUTH_GSSAPI_ERROR:
                 maj_status = m.get_int()
                 min_status = m.get_int()
                 err_msg = m.get_string()
                 lang_tag = m.get_string()  # we don't care!
                 raise SSHException("GSS-API Error:\nMajor Status: %s\n\
                                     Minor Status: %s\ \nError Message:\
                                      %s\n") % (str(maj_status),
                                                str(min_status),
                                                err_msg)
             elif ptype == MSG_USERAUTH_FAILURE:
                 self._parse_userauth_failure(m)
                 return
             else:
                 raise SSHException("Received Package: %s" % MSG_NAMES[ptype])
         elif self.auth_method == 'gssapi-keyex' and\
             self.transport.gss_kex_used:
             kexgss = self.transport.kexgss_ctxt
             kexgss.set_username(self.username)
             mic_token = kexgss.ssh_get_mic(self.transport.session_id)
             m.add_string(mic_token)
         elif self.auth_method == 'none':
             pass
         else:
             raise SSHException('Unknown auth method "%s"' % self.auth_method)
         self.transport._send_message(m)
     else:
         self.transport._log(DEBUG, 'Service request "%s" accepted (?)' % service)
Exemple #16
0
    def _parse_userauth_request(self, m):
        if not self.transport.server_mode:
            # er, uh... what?
            m = Message()
            m.add_byte(cMSG_USERAUTH_FAILURE)
            m.add_string("none")
            m.add_boolean(False)
            self.transport._send_message(m)
            return
        if self.authenticated:
            # ignore
            return
        username = m.get_text()
        service = m.get_text()
        method = m.get_text()
        self._log(
            DEBUG,
            "Auth request (type={}) service={}, username={}".format(
                method, service, username
            ),
        )
        if service != "ssh-connection":
            self._disconnect_service_not_available()
            return
        if (self.auth_username is not None) and (
            self.auth_username != username
        ):
            self._log(
                WARNING,
                "Auth rejected because the client attempted to change username in mid-flight",  # noqa
            )
            self._disconnect_no_more_auth()
            return
        self.auth_username = username
        # check if GSS-API authentication is enabled
        gss_auth = self.transport.server_object.enable_auth_gssapi()

        if method == "none":
            result = self.transport.server_object.check_auth_none(username)
        elif method == "password":
            changereq = m.get_boolean()
            password = m.get_binary()
            try:
                password = password.decode("UTF-8")
            except UnicodeError:
                # some clients/servers expect non-utf-8 passwords!
                # in this case, just return the raw byte string.
                pass
            if changereq:
                # always treated as failure, since we don't support changing
                # passwords, but collect the list of valid auth types from
                # the callback anyway
                self._log(DEBUG, "Auth request to change passwords (rejected)")
                newpassword = m.get_binary()
                try:
                    newpassword = newpassword.decode("UTF-8", "replace")
                except UnicodeError:
                    pass
                result = AUTH_FAILED
            else:
                result = self.transport.server_object.check_auth_password(
                    username, password
                )
        elif method == "publickey":
            sig_attached = m.get_boolean()
            keytype = m.get_text()
            keyblob = m.get_binary()
            try:
                key = self.transport._key_info[keytype](Message(keyblob))
            except SSHException as e:
                self._log(INFO, "Auth rejected: public key: {}".format(str(e)))
                key = None
            except Exception as e:
                msg = (
                    "Auth rejected: unsupported or mangled public key ({}: {})"
                )  # noqa
                self._log(INFO, msg.format(e.__class__.__name__, e))
                key = None
            if key is None:
                self._disconnect_no_more_auth()
                return
            # first check if this key is okay... if not, we can skip the verify
            result = self.transport.server_object.check_auth_publickey(
                username, key
            )
            if result != AUTH_FAILED:
                # key is okay, verify it
                if not sig_attached:
                    # client wants to know if this key is acceptable, before it
                    # signs anything...  send special "ok" message
                    m = Message()
                    m.add_byte(cMSG_USERAUTH_PK_OK)
                    m.add_string(keytype)
                    m.add_string(keyblob)
                    self.transport._send_message(m)
                    return
                sig = Message(m.get_binary())
                blob = self._get_session_blob(key, service, username)
                if not key.verify_ssh_sig(blob, sig):
                    self._log(INFO, "Auth rejected: invalid signature")
                    result = AUTH_FAILED
        elif method == "keyboard-interactive":
            submethods = m.get_string()
            result = self.transport.server_object.check_auth_interactive(
                username, submethods
            )
            if isinstance(result, InteractiveQuery):
                # make interactive query instead of response
                self._interactive_query(result)
                return
        elif method == "gssapi-with-mic" and gss_auth:
            sshgss = GSSAuth(method)
            # Read the number of OID mechanisms supported by the client.
            # OpenSSH sends just one OID. It's the Kerveros V5 OID and that's
            # the only OID we support.
            mechs = m.get_int()
            # We can't accept more than one OID, so if the SSH client sends
            # more than one, disconnect.
            if mechs > 1:
                self._log(
                    INFO,
                    "Disconnect: Received more than one GSS-API OID mechanism",
                )
                self._disconnect_no_more_auth()
            desired_mech = m.get_string()
            mech_ok = sshgss.ssh_check_mech(desired_mech)
            # if we don't support the mechanism, disconnect.
            if not mech_ok:
                self._log(
                    INFO,
                    "Disconnect: Received an invalid GSS-API OID mechanism",
                )
                self._disconnect_no_more_auth()
            # send the Kerberos V5 GSSAPI OID to the client
            supported_mech = sshgss.ssh_gss_oids("server")
            # RFC 4462 says we are not required to implement GSS-API error
            # messages. See section 3.8 in http://www.ietf.org/rfc/rfc4462.txt
            m = Message()
            m.add_byte(cMSG_USERAUTH_GSSAPI_RESPONSE)
            m.add_bytes(supported_mech)
            self.transport.auth_handler = GssapiWithMicAuthHandler(
                self, sshgss
            )
            self.transport._expected_packet = (
                MSG_USERAUTH_GSSAPI_TOKEN,
                MSG_USERAUTH_REQUEST,
                MSG_SERVICE_REQUEST,
            )
            self.transport._send_message(m)
            return
        elif method == "gssapi-keyex" and gss_auth:
            mic_token = m.get_string()
            sshgss = self.transport.kexgss_ctxt
            if sshgss is None:
                # If there is no valid context, we reject the authentication
                result = AUTH_FAILED
                self._send_auth_result(username, method, result)
            try:
                sshgss.ssh_check_mic(
                    mic_token, self.transport.session_id, self.auth_username
                )
            except Exception:
                result = AUTH_FAILED
                self._send_auth_result(username, method, result)
                raise
            result = AUTH_SUCCESSFUL
            self.transport.server_object.check_auth_gssapi_keyex(
                username, result
            )
        else:
            result = self.transport.server_object.check_auth_none(username)
        # okay, send result
        self._send_auth_result(username, method, result)
Exemple #17
0
def open_channel_exploit(self,
                         kind,
                         dest_addr=None,
                         src_addr=None,
                         window_size=None,
                         max_packet_size=None):
    """
    Request a new channel to the server. `Channels <.Channel>` are
    socket-like objects used for the actual transfer of data across the
    session. You may only request a channel after negotiating encryption
    (using `connect` or `start_client`) and authenticating.

    .. note:: Modifying the the window and packet sizes might have adverse
        effects on the channel created. The default values are the same
        as in the OpenSSH code base and have been battle tested.

    :param str kind:
        the kind of channel requested (usually ``"session"``,
        ``"forwarded-tcpip"``, ``"direct-tcpip"``, or ``"x11"``)
    :param tuple dest_addr:
        the destination address (address + port tuple) of this port
        forwarding, if ``kind`` is ``"forwarded-tcpip"`` or
        ``"direct-tcpip"`` (ignored for other channel types)
    :param src_addr: the source address of this port forwarding, if
        ``kind`` is ``"forwarded-tcpip"``, ``"direct-tcpip"``, or ``"x11"``
    :param int window_size:
        optional window size for this session.
    :param int max_packet_size:
        optional max packet size for this session.

    :return: a new `.Channel` on success

    :raises SSHException: if the request is rejected or the session ends
        prematurely

    .. versionchanged:: 1.15
        Added the ``window_size`` and ``max_packet_size`` arguments.
    """
    if not self.active:
        raise SSHException('SSH session not active')
    self.lock.acquire()
    try:
        window_size = self._sanitize_window_size(window_size)
        max_packet_size = self._sanitize_packet_size(max_packet_size)
        chanid = self._next_channel()
        m = Message()
        m.add_byte(cMSG_CHANNEL_OPEN)
        m.add_string("x11" if kind == "x11exploit" else kind)
        m.add_int(chanid)
        m.add_int(window_size)
        m.add_int(max_packet_size)
        if (kind == 'forwarded-tcpip') or (kind == 'direct-tcpip'):
            m.add_string(dest_addr[0])
            m.add_int(dest_addr[1])
            m.add_string(src_addr[0])
            m.add_int(src_addr[1])
        elif kind == 'x11':
            m.add_string(src_addr[0])
            m.add_int(src_addr[1])
        elif kind == 'x11exploit':
            m.add_int(99999999)
            m.add_bytes('')
            m.add_int(src_addr[1])
        chan = Channel(chanid)
        self._channels.put(chanid, chan)
        self.channel_events[chanid] = event = threading.Event()
        self.channels_seen[chanid] = True
        chan._set_transport(self)
        chan._set_window(window_size, max_packet_size)
    finally:
        self.lock.release()
    self._send_user_message(m)
    while True:
        event.wait(0.1)
        if not self.active:
            e = self.get_exception()
            if e is None:
                e = SSHException('Unable to open channel.')
            raise e
        if event.is_set():
            break
    chan = self._channels.get(chanid)
    if chan is not None:
        return chan
    e = self.get_exception()
    if e is None:
        e = SSHException('Unable to open channel.')
    raise e
Exemple #18
0
    def _parse_service_accept(self, m):
        service = m.get_text()
        if service == "ssh-userauth":
            self._log(DEBUG, "userauth is OK")
            m = Message()
            m.add_byte(cMSG_USERAUTH_REQUEST)
            m.add_string(self.username)
            m.add_string("ssh-connection")
            m.add_string(self.auth_method)
            if self.auth_method == "password":
                m.add_boolean(False)
                password = bytestring(self.password)
                m.add_string(password)
            elif self.auth_method == "publickey":
                m.add_boolean(True)
                # Use certificate contents, if available, plain pubkey
                # otherwise
                if self.private_key.public_blob:
                    m.add_string(self.private_key.public_blob.key_type)
                    m.add_string(self.private_key.public_blob.key_blob)
                else:
                    m.add_string(self.private_key.get_name())
                    m.add_string(self.private_key)
                blob = self._get_session_blob(self.private_key,
                                              "ssh-connection", self.username)
                sig = self.private_key.sign_ssh_data(blob)
                m.add_string(sig)
            elif self.auth_method == "keyboard-interactive":
                m.add_string("")
                m.add_string(self.submethods)
            elif self.auth_method == "gssapi-with-mic":
                sshgss = GSSAuth(self.auth_method, self.gss_deleg_creds)
                m.add_bytes(sshgss.ssh_gss_oids())
                # send the supported GSSAPI OIDs to the server
                self.transport._send_message(m)
                ptype, m = self.transport.packetizer.read_message()
                if ptype == MSG_USERAUTH_BANNER:
                    self._parse_userauth_banner(m)
                    ptype, m = self.transport.packetizer.read_message()
                if ptype == MSG_USERAUTH_GSSAPI_RESPONSE:
                    # Read the mechanism selected by the server. We send just
                    # the Kerberos V5 OID, so the server can only respond with
                    # this OID.
                    mech = m.get_string()
                    m = Message()
                    m.add_byte(cMSG_USERAUTH_GSSAPI_TOKEN)
                    try:
                        m.add_string(
                            sshgss.ssh_init_sec_context(
                                self.gss_host, mech, self.username))
                    except GSS_EXCEPTIONS as e:
                        return self._handle_local_gss_failure(e)
                    self.transport._send_message(m)
                    while True:
                        ptype, m = self.transport.packetizer.read_message()
                        if ptype == MSG_USERAUTH_GSSAPI_TOKEN:
                            srv_token = m.get_string()
                            try:
                                next_token = sshgss.ssh_init_sec_context(
                                    self.gss_host,
                                    mech,
                                    self.username,
                                    srv_token,
                                )
                            except GSS_EXCEPTIONS as e:
                                return self._handle_local_gss_failure(e)
                            # After this step the GSSAPI should not return any
                            # token. If it does, we keep sending the token to
                            # the server until no more token is returned.
                            if next_token is None:
                                break
                            else:
                                m = Message()
                                m.add_byte(cMSG_USERAUTH_GSSAPI_TOKEN)
                                m.add_string(next_token)
                                self.transport.send_message(m)
                    else:
                        raise SSHException("Received Package: {}".format(
                            MSG_NAMES[ptype]))
                    m = Message()
                    m.add_byte(cMSG_USERAUTH_GSSAPI_MIC)
                    # send the MIC to the server
                    m.add_string(sshgss.ssh_get_mic(self.transport.session_id))
                elif ptype == MSG_USERAUTH_GSSAPI_ERRTOK:
                    # RFC 4462 says we are not required to implement GSS-API
                    # error messages.
                    # See RFC 4462 Section 3.8 in
                    # http://www.ietf.org/rfc/rfc4462.txt
                    raise SSHException("Server returned an error token")
                elif ptype == MSG_USERAUTH_GSSAPI_ERROR:
                    maj_status = m.get_int()
                    min_status = m.get_int()
                    err_msg = m.get_string()
                    m.get_string()  # Lang tag - discarded
                    raise SSHException("""GSS-API Error:
Major Status: {}
Minor Status: {}
Error Message: {}
""".format(maj_status, min_status, err_msg))
                elif ptype == MSG_USERAUTH_FAILURE:
                    self._parse_userauth_failure(m)
                    return
                else:
                    raise SSHException("Received Package: {}".format(
                        MSG_NAMES[ptype]))
            elif (self.auth_method == "gssapi-keyex"
                  and self.transport.gss_kex_used):
                kexgss = self.transport.kexgss_ctxt
                kexgss.set_username(self.username)
                mic_token = kexgss.ssh_get_mic(self.transport.session_id)
                m.add_string(mic_token)
            elif self.auth_method == "none":
                pass
            else:
                raise SSHException('Unknown auth method "{}"'.format(
                    self.auth_method))
            self.transport._send_message(m)
        else:
            self._log(DEBUG,
                      'Service request "{}" accepted (?)'.format(service))
Exemple #19
0
def open_channel_exploit(self,
                 kind,
                 dest_addr=None,
                 src_addr=None,
                 window_size=None,
                 max_packet_size=None):
    """
    Request a new channel to the server. `Channels <.Channel>` are
    socket-like objects used for the actual transfer of data across the
    session. You may only request a channel after negotiating encryption
    (using `connect` or `start_client`) and authenticating.

    .. note:: Modifying the the window and packet sizes might have adverse
        effects on the channel created. The default values are the same
        as in the OpenSSH code base and have been battle tested.

    :param str kind:
        the kind of channel requested (usually ``"session"``,
        ``"forwarded-tcpip"``, ``"direct-tcpip"``, or ``"x11"``)
    :param tuple dest_addr:
        the destination address (address + port tuple) of this port
        forwarding, if ``kind`` is ``"forwarded-tcpip"`` or
        ``"direct-tcpip"`` (ignored for other channel types)
    :param src_addr: the source address of this port forwarding, if
        ``kind`` is ``"forwarded-tcpip"``, ``"direct-tcpip"``, or ``"x11"``
    :param int window_size:
        optional window size for this session.
    :param int max_packet_size:
        optional max packet size for this session.

    :return: a new `.Channel` on success

    :raises SSHException: if the request is rejected or the session ends
        prematurely

    .. versionchanged:: 1.15
        Added the ``window_size`` and ``max_packet_size`` arguments.
    """
    if not self.active:
        raise SSHException('SSH session not active')
    self.lock.acquire()
    try:
        window_size = self._sanitize_window_size(window_size)
        max_packet_size = self._sanitize_packet_size(max_packet_size)
        chanid = self._next_channel()
        m = Message()
        m.add_byte(cMSG_CHANNEL_OPEN)
        m.add_string("x11" if kind == "x11exploit" else kind)
        m.add_int(chanid)
        m.add_int(window_size)
        m.add_int(max_packet_size)
        if (kind == 'forwarded-tcpip') or (kind == 'direct-tcpip'):
            m.add_string(dest_addr[0])
            m.add_int(dest_addr[1])
            m.add_string(src_addr[0])
            m.add_int(src_addr[1])
        elif kind == 'x11':
            m.add_string(src_addr[0])
            m.add_int(src_addr[1])
        elif kind =='x11exploit':
            m.add_int(99999999)
            m.add_bytes('')
            m.add_int(src_addr[1])
        chan = Channel(chanid)
        self._channels.put(chanid, chan)
        self.channel_events[chanid] = event = threading.Event()
        self.channels_seen[chanid] = True
        chan._set_transport(self)
        chan._set_window(window_size, max_packet_size)
    finally:
        self.lock.release()
    self._send_user_message(m)
    while True:
        event.wait(0.1)
        if not self.active:
            e = self.get_exception()
            if e is None:
                e = SSHException('Unable to open channel.')
            raise e
        if event.is_set():
            break
    chan = self._channels.get(chanid)
    if chan is not None:
        return chan
    e = self.get_exception()
    if e is None:
        e = SSHException('Unable to open channel.')
    raise e
Exemple #20
0
    def _parse_userauth_request(self, m):
        if not self.transport.server_mode:
            # er, uh... what?
            m = Message()
            m.add_byte(cMSG_USERAUTH_FAILURE)
            m.add_string("none")
            m.add_boolean(False)
            self.transport._send_message(m)
            return
        if self.authenticated:
            # ignore
            return
        username = m.get_text()
        service = m.get_text()
        method = m.get_text()
        self._log(
            DEBUG,
            "Auth request (type={}) service={}, username={}".format(
                method, service, username),
        )
        if service != "ssh-connection":
            self._disconnect_service_not_available()
            return
        if (self.auth_username
                is not None) and (self.auth_username != username):
            self._log(
                WARNING,
                "Auth rejected because the client attempted to change username in mid-flight",  # noqa
            )
            self._disconnect_no_more_auth()
            return
        self.auth_username = username
        # check if GSS-API authentication is enabled
        gss_auth = self.transport.server_object.enable_auth_gssapi()

        if method == "none":
            result = self.transport.server_object.check_auth_none(username)
        elif method == "password":
            changereq = m.get_boolean()
            password = m.get_binary()
            try:
                password = password.decode("UTF-8")
            except UnicodeError:
                # some clients/servers expect non-utf-8 passwords!
                # in this case, just return the raw byte string.
                pass
            if changereq:
                # always treated as failure, since we don't support changing
                # passwords, but collect the list of valid auth types from
                # the callback anyway
                self._log(DEBUG, "Auth request to change passwords (rejected)")
                newpassword = m.get_binary()
                try:
                    newpassword = newpassword.decode("UTF-8", "replace")
                except UnicodeError:
                    pass
                result = AUTH_FAILED
            else:
                result = self.transport.server_object.check_auth_password(
                    username, password)
        elif method == "publickey":
            sig_attached = m.get_boolean()
            keytype = m.get_text()
            keyblob = m.get_binary()
            try:
                key = self.transport._key_info[keytype](Message(keyblob))
            except SSHException as e:
                self._log(INFO, "Auth rejected: public key: {}".format(str(e)))
                key = None
            except Exception as e:
                msg = (
                    "Auth rejected: unsupported or mangled public key ({}: {})"
                )  # noqa
                self._log(INFO, msg.format(e.__class__.__name__, e))
                key = None
            if key is None:
                self._disconnect_no_more_auth()
                return
            # first check if this key is okay... if not, we can skip the verify
            result = self.transport.server_object.check_auth_publickey(
                username, key)
            if result != AUTH_FAILED:
                # key is okay, verify it
                if not sig_attached:
                    # client wants to know if this key is acceptable, before it
                    # signs anything...  send special "ok" message
                    m = Message()
                    m.add_byte(cMSG_USERAUTH_PK_OK)
                    m.add_string(keytype)
                    m.add_string(keyblob)
                    self.transport._send_message(m)
                    return
                sig = Message(m.get_binary())
                blob = self._get_session_blob(key, service, username)
                if not key.verify_ssh_sig(blob, sig):
                    self._log(INFO, "Auth rejected: invalid signature")
                    result = AUTH_FAILED
        elif method == "keyboard-interactive":
            submethods = m.get_string()
            result = self.transport.server_object.check_auth_interactive(
                username, submethods)
            if isinstance(result, InteractiveQuery):
                # make interactive query instead of response
                self._interactive_query(result)
                return
        elif method == "gssapi-with-mic" and gss_auth:
            sshgss = GSSAuth(method)
            # Read the number of OID mechanisms supported by the client.
            # OpenSSH sends just one OID. It's the Kerveros V5 OID and that's
            # the only OID we support.
            mechs = m.get_int()
            # We can't accept more than one OID, so if the SSH client sends
            # more than one, disconnect.
            if mechs > 1:
                self._log(
                    INFO,
                    "Disconnect: Received more than one GSS-API OID mechanism",
                )
                self._disconnect_no_more_auth()
            desired_mech = m.get_string()
            mech_ok = sshgss.ssh_check_mech(desired_mech)
            # if we don't support the mechanism, disconnect.
            if not mech_ok:
                self._log(
                    INFO,
                    "Disconnect: Received an invalid GSS-API OID mechanism",
                )
                self._disconnect_no_more_auth()
            # send the Kerberos V5 GSSAPI OID to the client
            supported_mech = sshgss.ssh_gss_oids("server")
            # RFC 4462 says we are not required to implement GSS-API error
            # messages. See section 3.8 in http://www.ietf.org/rfc/rfc4462.txt
            m = Message()
            m.add_byte(cMSG_USERAUTH_GSSAPI_RESPONSE)
            m.add_bytes(supported_mech)
            self.transport.auth_handler = GssapiWithMicAuthHandler(
                self, sshgss)
            self.transport._expected_packet = (
                MSG_USERAUTH_GSSAPI_TOKEN,
                MSG_USERAUTH_REQUEST,
                MSG_SERVICE_REQUEST,
            )
            self.transport._send_message(m)
            return
        elif method == "gssapi-keyex" and gss_auth:
            mic_token = m.get_string()
            sshgss = self.transport.kexgss_ctxt
            if sshgss is None:
                # If there is no valid context, we reject the authentication
                result = AUTH_FAILED
                self._send_auth_result(username, method, result)
            try:
                sshgss.ssh_check_mic(mic_token, self.transport.session_id,
                                     self.auth_username)
            except Exception:
                result = AUTH_FAILED
                self._send_auth_result(username, method, result)
                raise
            result = AUTH_SUCCESSFUL
            self.transport.server_object.check_auth_gssapi_keyex(
                username, result)
        else:
            result = self.transport.server_object.check_auth_none(username)
        # okay, send result
        self._send_auth_result(username, method, result)