def test_6_gex_server_with_old_client(self): transport = FakeTransport() transport.server_mode = True kex = KexGex(transport) kex.start_kex() self.assertEquals((paramiko.kex_gex._MSG_KEXDH_GEX_REQUEST, paramiko.kex_gex._MSG_KEXDH_GEX_REQUEST_OLD), transport._expect) msg = Message() msg.add_int(2048) msg.rewind() kex.parse_next(paramiko.kex_gex._MSG_KEXDH_GEX_REQUEST_OLD, msg) x = '1F0000008100FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF0000000102' self.assertEquals(x, hexlify(str(transport._message)).upper()) self.assertEquals((paramiko.kex_gex._MSG_KEXDH_GEX_INIT,), transport._expect) msg = Message() msg.add_mpint(12345) msg.rewind() kex.parse_next(paramiko.kex_gex._MSG_KEXDH_GEX_INIT, msg) K = 67592995013596137876033460028393339951879041140378510871612128162185209509220726296697886624612526735888348020498716482757677848959420073720160491114319163078862905400020959196386947926388406687288901564192071077389283980347784184487280885335302632305026248574716290537036069329724382811853044654824945750581L H = 'B41A06B2E59043CEFC1AE16EC31F1E2D12EC455B' x = '210000000866616B652D6B6579000000807E2DDB1743F3487D6545F04F1C8476092FB912B013626AB5BCEB764257D88BBA64243B9F348DF7B41B8C814A995E00299913503456983FFB9178D3CD79EB6D55522418A8ABF65375872E55938AB99A84A0B5FC8A1ECC66A7C3766E7E0F80B7CE2C9225FC2DD683F4764244B72963BBB383F529DCF0C5D17740B8A2ADBE9208D40000000866616B652D736967' self.assertEquals(K, transport._K) self.assertEquals(H, hexlify(transport._H).upper()) self.assertEquals(x, hexlify(str(transport._message)).upper()) self.assert_(transport._activated)
def test_6_gex_server_with_old_client(self): transport = FakeTransport() transport.server_mode = True kex = KexGex(transport) kex.start_kex() self.assertEquals((paramiko.kex_gex._MSG_KEXDH_GEX_REQUEST, paramiko.kex_gex._MSG_KEXDH_GEX_REQUEST_OLD), transport._expect) msg = Message() msg.add_int(2048) msg.rewind() kex.parse_next(paramiko.kex_gex._MSG_KEXDH_GEX_REQUEST_OLD, msg) x = '1F0000008100FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF0000000102' self.assertEquals(x, hexlify(str(transport._message)).upper()) self.assertEquals((paramiko.kex_gex._MSG_KEXDH_GEX_INIT, ), transport._expect) msg = Message() msg.add_mpint(12345) msg.rewind() kex.parse_next(paramiko.kex_gex._MSG_KEXDH_GEX_INIT, msg) K = 67592995013596137876033460028393339951879041140378510871612128162185209509220726296697886624612526735888348020498716482757677848959420073720160491114319163078862905400020959196386947926388406687288901564192071077389283980347784184487280885335302632305026248574716290537036069329724382811853044654824945750581L H = 'B41A06B2E59043CEFC1AE16EC31F1E2D12EC455B' x = '210000000866616B652D6B6579000000807E2DDB1743F3487D6545F04F1C8476092FB912B013626AB5BCEB764257D88BBA64243B9F348DF7B41B8C814A995E00299913503456983FFB9178D3CD79EB6D55522418A8ABF65375872E55938AB99A84A0B5FC8A1ECC66A7C3766E7E0F80B7CE2C9225FC2DD683F4764244B72963BBB383F529DCF0C5D17740B8A2ADBE9208D40000000866616B652D736967' self.assertEquals(K, transport._K) self.assertEquals(H, hexlify(transport._H).upper()) self.assertEquals(x, hexlify(str(transport._message)).upper()) self.assert_(transport._activated)
def _request(self, expects, cmd, *args): """ Build an SSH FTP packet and send it to the server Args: expects (type): a type we expect back from server, if any cmd (int): SSH FTP packet type args: additional contents of packet """ with self._lock: if getattr(g, "req_num", False): req_num = g["req_num"] else: g["req_num"] = req_num = 0 msg = Message() msg.add_int(req_num) [_add_to_message(msg, a) for a in args] g["req_num"] += 1 self._sftp._send_packet(cmd, msg) return req_num
def test_1_write(self): rsock = LoopSocket() wsock = LoopSocket() rsock.link(wsock) p = Packetizer(wsock) p.set_log(util.get_logger('paramiko.transport')) p.set_hexdump(True) encryptor = Cipher(algorithms.AES(zero_byte * 16), modes.CBC(x55 * 16), backend=default_backend()).encryptor() p.set_outbound_cipher(encryptor, 16, sha1, 12, x1f * 20) # message has to be at least 16 bytes long, so we'll have at least one # block of data encrypted that contains zero random padding bytes m = Message() m.add_byte(byte_chr(100)) m.add_int(100) m.add_int(1) m.add_int(900) p.send_message(m) data = rsock.recv(100) # 32 + 12 bytes of MAC = 44 self.assertEqual(44, len(data)) self.assertEqual( b'\x43\x91\x97\xbd\x5b\x50\xac\x25\x87\xc2\xc4\x6b\xc7\xe9\x38\xc0', data[:16])
def test_1_write(self): rsock = LoopSocket() wsock = LoopSocket() rsock.link(wsock) p = Packetizer(wsock) p.set_log(util.get_logger("paramiko.transport")) p.set_hexdump(True) encryptor = Cipher( algorithms.AES(zero_byte * 16), modes.CBC(x55 * 16), backend=default_backend(), ).encryptor() p.set_outbound_cipher(encryptor, 16, sha1, 12, x1f * 20) # message has to be at least 16 bytes long, so we'll have at least one # block of data encrypted that contains zero random padding bytes m = Message() m.add_byte(byte_chr(100)) m.add_int(100) m.add_int(1) m.add_int(900) p.send_message(m) data = rsock.recv(100) # 32 + 12 bytes of MAC = 44 self.assertEqual(44, len(data)) self.assertEqual( b"\x43\x91\x97\xbd\x5b\x50\xac\x25\x87\xc2\xc4\x6b\xc7\xe9\x38\xc0", data[:16], )
def test_1_write(self): rsock = LoopSocket() wsock = LoopSocket() rsock.link(wsock) p = Packetizer(wsock) p.set_log(util.get_logger("paramiko.transport")) p.set_hexdump(True) cipher = AES.new(b"\x00" * 16, AES.MODE_CBC, b"\x55" * 16) p.set_outbound_cipher(cipher, 16, SHA, 12, b"\x1f" * 20) # message has to be at least 16 bytes long, so we'll have at least one # block of data encrypted that contains zero random padding bytes m = Message() m.add_byte(chr(100).encode()) m.add_int(100) m.add_int(1) m.add_int(900) p.send_message(m) data = rsock.recv(100) # 32 + 12 bytes of MAC = 44 self.assertEquals(44, len(data)) self.assertEquals(b"\x43\x91\x97\xbd\x5b\x50\xac\x25\x87\xc2\xc4\x6b\xc7\xe9\x38\xc0", data[:16])
def test_3_closed(self): if sys.platform.startswith("win"): # no SIGALRM on windows return rsock = LoopSocket() wsock = LoopSocket() rsock.link(wsock) p = Packetizer(wsock) p.set_log(util.get_logger("paramiko.transport")) p.set_hexdump(True) encryptor = Cipher( algorithms.AES(zero_byte * 16), modes.CBC(x55 * 16), backend=default_backend(), ).encryptor() p.set_outbound_cipher(encryptor, 16, sha1, 12, x1f * 20) # message has to be at least 16 bytes long, so we'll have at least one # block of data encrypted that contains zero random padding bytes m = Message() m.add_byte(byte_chr(100)) m.add_int(100) m.add_int(1) m.add_int(900) wsock.send = lambda x: 0 from functools import wraps import errno import os import signal class TimeoutError(Exception): def __init__(self, error_message): if hasattr(errno, "ETIME"): self.message = os.sterror(errno.ETIME) else: self.messaage = error_message def timeout(seconds=1, error_message="Timer expired"): def decorator(func): def _handle_timeout(signum, frame): raise TimeoutError(error_message) def wrapper(*args, **kwargs): signal.signal(signal.SIGALRM, _handle_timeout) signal.alarm(seconds) try: result = func(*args, **kwargs) finally: signal.alarm(0) return result return wraps(func)(wrapper) return decorator send = timeout()(p.send_message) self.assertRaises(EOFError, send, m)
def test_3_closed(self): if sys.platform.startswith("win"): # no SIGALRM on windows return rsock = LoopSocket() wsock = LoopSocket() rsock.link(wsock) p = Packetizer(wsock) p.set_log(util.get_logger("paramiko.transport")) p.set_hexdump(True) encryptor = Cipher( algorithms.AES(zero_byte * 16), modes.CBC(x55 * 16), backend=default_backend(), ).encryptor() p.set_outbound_cipher(encryptor, 16, sha1, 12, x1f * 20) # message has to be at least 16 bytes long, so we'll have at least one # block of data encrypted that contains zero random padding bytes m = Message() m.add_byte(byte_chr(100)) m.add_int(100) m.add_int(1) m.add_int(900) wsock.send = lambda x: 0 from functools import wraps import errno import os import signal class TimeoutError(Exception): def __init__(self, error_message): if hasattr(errno, "ETIME"): self.message = os.sterror(errno.ETIME) else: self.messaage = error_message def timeout(seconds=1, error_message="Timer expired"): def decorator(func): def _handle_timeout(signum, frame): raise TimeoutError(error_message) def wrapper(*args, **kwargs): signal.signal(signal.SIGALRM, _handle_timeout) signal.alarm(seconds) try: result = func(*args, **kwargs) finally: signal.alarm(0) return result return wraps(func)(wrapper) return decorator send = timeout()(p.send_message) self.assertRaises(EOFError, send, m)
def test_3_closed(self): rsock = LoopSocket() wsock = LoopSocket() rsock.link(wsock) p = Packetizer(wsock) p.set_log(util.get_logger('paramiko.transport')) p.set_hexdump(True) cipher = AES.new(zero_byte * 16, AES.MODE_CBC, x55 * 16) p.set_outbound_cipher(cipher, 16, sha1, 12, x1f * 20) # message has to be at least 16 bytes long, so we'll have at least one # block of data encrypted that contains zero random padding bytes m = Message() m.add_byte(byte_chr(100)) m.add_int(100) m.add_int(1) m.add_int(900) wsock.send = lambda x: 0 from functools import wraps import errno import os import signal class TimeoutError(Exception): pass def timeout(seconds=1, error_message=os.strerror(errno.ETIME)): def decorator(func): def _handle_timeout(signum, frame): raise TimeoutError(error_message) def wrapper(*args, **kwargs): signal.signal(signal.SIGALRM, _handle_timeout) signal.alarm(seconds) try: result = func(*args, **kwargs) finally: signal.alarm(0) return result return wraps(func)(wrapper) return decorator send = timeout()(p.send_message) self.assertRaises(EOFError, send, m)
def test_3_closed(self): rsock = LoopSocket() wsock = LoopSocket() rsock.link(wsock) p = Packetizer(wsock) p.set_log(util.get_logger('paramiko.transport')) p.set_hexdump(True) cipher = AES.new(zero_byte * 16, AES.MODE_CBC, x55 * 16) p.set_outbound_cipher(cipher, 16, sha1, 12, x1f * 20) # message has to be at least 16 bytes long, so we'll have at least one # block of data encrypted that contains zero random padding bytes m = Message() m.add_byte(byte_chr(100)) m.add_int(100) m.add_int(1) m.add_int(900) wsock.send = lambda x: 0 from functools import wraps import errno import os import signal class TimeoutError(Exception): pass def timeout(seconds=1, error_message=os.strerror(errno.ETIME)): def decorator(func): def _handle_timeout(signum, frame): raise TimeoutError(error_message) def wrapper(*args, **kwargs): signal.signal(signal.SIGALRM, _handle_timeout) signal.alarm(seconds) try: result = func(*args, **kwargs) finally: signal.alarm(0) return result return wraps(func)(wrapper) return decorator send = timeout()(p.send_message) self.assertRaises(EOFError, send, m)
def test_1_write(self): rsock = LoopSocket() wsock = LoopSocket() rsock.link(wsock) p = Packetizer(wsock) p.set_log(util.get_logger('paramiko.transport')) p.set_hexdump(True) cipher = AES.new('\x00' * 16, AES.MODE_CBC, '\x55' * 16) p.set_outbound_cipher(cipher, 16, SHA, 12, '\x1f' * 20) # message has to be at least 16 bytes long, so we'll have at least one # block of data encrypted that contains zero random padding bytes m = Message() m.add_byte(chr(100)) m.add_int(100) m.add_int(1) m.add_int(900) p.send_message(m) data = rsock.recv(100) # 32 + 12 bytes of MAC = 44 self.assertEquals(44, len(data)) self.assertEquals( '\x43\x91\x97\xbd\x5b\x50\xac\x25\x87\xc2\xc4\x6b\xc7\xe9\x38\xc0', data[:16])
def run(self): """ Run function from paramiko.Transport. This function was copied from Paramiko (paramiko.Transport) in order to implement the CVE-2018-10933 vulnerability. The only change in this function is where we added if ptype == MSG_USERAUTH_SUCCESS. """ # noqa: W503, E722 # (use the exposed "run" method, because if we specify a thread target # of a private method, threading.Thread will keep a reference to it # indefinitely, creating a GC cycle and not letting Transport ever be # GC'd. it's a bug in Thread.) # Hold reference to 'sys' so we can test sys.modules to detect # interpreter shutdown. self.sys = sys # active=True occurs before the thread is launched, to avoid a race _active_threads.append(self) tid = hex(long(id(self)) & xffffffff) if self.server_mode: self._log(DEBUG, "starting thread (server mode): {}".format(tid)) else: self._log(DEBUG, "starting thread (client mode): {}".format(tid)) try: try: self.packetizer.write_all(b(self.local_version + "\r\n")) self._log( DEBUG, "Local version/idstring: {}".format(self.local_version), ) # noqa self._check_banner() # The above is actually very much part of the handshake, but # sometimes the banner can be read but the machine is not # responding, for example when the remote ssh daemon is loaded # in to memory but we can not read from the disk/spawn a new # shell. # Make sure we can specify a timeout for the initial handshake. # Re-use the banner timeout for now. self.packetizer.start_handshake(self.handshake_timeout) self._send_kex_init() self._expect_packet(MSG_KEXINIT) while self.active: if self.packetizer.need_rekey() and not self.in_kex: self._send_kex_init() try: ptype, m = self.packetizer.read_message() except NeedRekeyException: continue # START - This is the part the implements the detection of CVE-2018-10933 if ptype == MSG_USERAUTH_SUCCESS: self.alert(self.sock) continue # END - This is the part the implements the detection of CVE-2018-10933 if ptype == MSG_IGNORE: continue elif ptype == MSG_DISCONNECT: self._parse_disconnect(m) break elif ptype == MSG_DEBUG: self._parse_debug(m) continue if len(self._expected_packet) > 0: if ptype not in self._expected_packet: raise SSHException( "Expecting packet from {!r}, got {:d}".format( self._expected_packet, ptype)) # noqa self._expected_packet = tuple() if (ptype >= 30) and (ptype <= 41): self.kex_engine.parse_next(ptype, m) continue if ptype in self._handler_table: error_msg = self._ensure_authed(ptype, m) if error_msg: self._send_message(error_msg) else: self._handler_table[ptype](self, m) elif ptype in self._channel_handler_table: chanid = m.get_int() chan = self._channels.get(chanid) if chan is not None: self._channel_handler_table[ptype](chan, m) elif chanid in self.channels_seen: self._log( DEBUG, "Ignoring message for dead channel {:d}". format( # noqa chanid), ) else: self._log( ERROR, "Channel request for unknown channel {:d}". format( # noqa chanid), ) break elif (self.auth_handler is not None and # noqa: W504 ptype in self.auth_handler._handler_table): handler = self.auth_handler._handler_table[ptype] handler(self.auth_handler, m) if len(self._expected_packet) > 0: continue else: # Respond with "I don't implement this particular # message type" message (unless the message type was # itself literally MSG_UNIMPLEMENTED, in which case, we # just shut up to avoid causing a useless loop). name = MSG_NAMES[ptype] warning = "Oops, unhandled type {} ({!r})".format( ptype, name) self._log(WARNING, warning) if ptype != MSG_UNIMPLEMENTED: msg = Message() msg.add_byte(cMSG_UNIMPLEMENTED) msg.add_int(m.seqno) self._send_message(msg) self.packetizer.complete_handshake() except SSHException as e: self._log(ERROR, "Exception: " + str(e)) self._log(ERROR, util.tb_strings()) self.saved_exception = e except EOFError as e: self._log(DEBUG, "EOF in transport thread") self.saved_exception = e except socket.error as e: if type(e.args) is tuple: if e.args: emsg = "{} ({:d})".format(e.args[1], e.args[0]) else: # empty tuple, e.g. socket.timeout emsg = str(e) or repr(e) else: emsg = e.args self._log(ERROR, "Socket exception: " + emsg) self.saved_exception = e except Exception as e: self._log(ERROR, "Unknown exception: " + str(e)) self._log(ERROR, util.tb_strings()) self.saved_exception = e _active_threads.remove(self) for chan in list(self._channels.values()): chan._unlink() if self.active: self.active = False self.packetizer.close() if self.completion_event is not None: self.completion_event.set() if self.auth_handler is not None: self.auth_handler.abort() for event in self.channel_events.values(): event.set() try: self.lock.acquire() self.server_accept_cv.notify() finally: self.lock.release() self.sock.close() except: # noqa: E722 # Don't raise spurious 'NoneType has no attribute X' errors when we # wake up during interpreter shutdown. Or rather -- raise # everything *if* sys.modules (used as a convenient sentinel) # appears to still exist. if self.sys.modules is not None: raise