{"id":11103,"date":"2018-01-12T16:40:06","date_gmt":"2018-01-13T00:40:06","guid":{"rendered":"http:\/\/www.palada.net\/index.php\/2018\/01\/12\/news-4874\/"},"modified":"2018-01-12T16:40:06","modified_gmt":"2018-01-13T00:40:06","slug":"news-4874","status":"publish","type":"post","link":"https:\/\/www.palada.net\/index.php\/2018\/01\/12\/news-4874\/","title":{"rendered":"An Analysis of the OpenSSL SSL Handshake Error State Security Bypass (CVE-2017-3737)"},"content":{"rendered":"<p><strong>Credit to Author: Dehui Yin| Date: Fri, 12 Jan 2018 11:39:59 +0000<\/strong><\/p>\n<div class=\"entry\">\n<p>OpenSSL is a widely used library for SSL and TLS protocol implementation that secures data using encryption and decryption based on cryptographic functions. However, a <em>Security Bypass<\/em> vulnerability &ndash; recently addressed in a <a href=\"https:\/\/www.openssl.org\/news\/secadv\/20171207.txt\">patch<\/a> by the OpenSSL Project &ndash;can be exploited to make vulnerable SSL clients or remote SSL servers send clean application data without encryption.<\/p>\n<p>This <em>Security Bypass <\/em>vulnerability (CVE-2017-3737) is caused by an error when the SSL_read or SSL_write function handles an &quot;error state&quot; during an SSL handshake. In this paper the FortiGuard Labs team examines the root cause of this vulnerability.<\/p>\n<p>The &quot;error state&quot; mechanism was introduced in OpenSSL beginning with version 1.0.2b, It is used to make OpenSSL move into an error state whenever a fatal error occurs during the SSL handshake that would fail if the SSL handshake continued. If SSL_read or SSL_write function is called directly, it checks the SSL handshake state and performs a new SSL handshake automatically if no handshake has been initiated. If a fatal error occurs during the SSL handshake, OpenSSL moves into the error state and returns an error message to the caller. However, the problem occurs if the caller doesn&#39;t check the error state and simply calls the SSL_read or SSL_write function again, because it then sends application data without encryption. &nbsp;&nbsp;<\/p>\n<p>The following code snippet was taken from OpenSSL 1.0.2m. (Comments added by me have been highlighted.)<\/p>\n<p><em>ssl\/s3_pkt.c:<\/em><\/p>\n<p><em>638&nbsp;&nbsp;&nbsp;&nbsp; int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)<\/em><\/p>\n<p><em>639&nbsp;&nbsp;&nbsp;&nbsp; {<\/em><\/p>\n<p><em>640&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const unsigned char *buf = buf_;<\/em><\/p>\n<p><em>641&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int tot;<\/em><\/p>\n<p><em>642&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int n, nw;<\/em><\/p>\n<p><em>643&nbsp;&nbsp;&nbsp;&nbsp; #if !defined(OPENSSL_NO_MULTIBLOCK) &amp;&amp; EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK<\/em><\/p>\n<p><em>644&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int max_send_fragment;<\/em><\/p>\n<p><em>645&nbsp;&nbsp;&nbsp;&nbsp; #endif<\/em><\/p>\n<p><em>646&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSL3_BUFFER *wb = &amp;(s-&gt;s3-&gt;wbuf);<\/em><\/p>\n<p><em>647&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<\/em><\/p>\n<p><em>648&nbsp;&nbsp;&nbsp;&nbsp; <\/em><\/p>\n<p><em>649&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s-&gt;rwstate = SSL_NOTHING;<\/em><\/p>\n<p><em>650&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OPENSSL_assert(s-&gt;s3-&gt;wnum &lt;= INT_MAX);<\/em><\/p>\n<p><em>651&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tot = s-&gt;s3-&gt;wnum;<\/em><\/p>\n<p><em>652&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s-&gt;s3-&gt;wnum = 0;<\/em><\/p>\n<p><em>653&nbsp;&nbsp;&nbsp;&nbsp; <\/em><\/p>\n<p><em>654&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (SSL_in_init(s) &amp;&amp; !s-&gt;in_handshake) { \/\/checks to see if the SSL handshake state is initiated. The state will be SSL_ST_INIT the first time.<\/em><\/p>\n<p><em>655&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = s-&gt;handshake_func(s);&nbsp; \/\/performs a new SSL handshake if no handshake has been initiated.<\/em><\/p>\n<p><em>656&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (i &lt; 0)<\/em><\/p>\n<p><em>657&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (i);<\/em><\/p>\n<p><em>658&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (i == 0) {<\/em><\/p>\n<p><em>659&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSLerr(SSL_F_SSL3_WRITE_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE);<\/em><\/p>\n<p><em>660&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<\/em><\/p>\n<p><em>661&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/em><\/p>\n<p><em>662&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/em><\/p>\n<p>ssl3_write_bytes() is called by the SSL_write function to send the application data. It checks the SSL handshake state and performs the SSL handshake if needed.<\/p>\n<p><em>ssl\/s3_clnt.c:<\/em><\/p>\n<p><em>898&nbsp;&nbsp;&nbsp;&nbsp; int ssl3_get_server_hello(SSL *s)<\/em><\/p>\n<p><em>899&nbsp;&nbsp;&nbsp;&nbsp; {<\/em><\/p>\n<p><em>900&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; STACK_OF(SSL_CIPHER) *sk;<\/em><\/p>\n<p><em>901&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const SSL_CIPHER *c;<\/em><\/p>\n<p><em>902&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CERT *ct = s-&gt;cert;<\/em><\/p>\n<p><em>903&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned char *p, *d;<\/em><\/p>\n<p><em>904&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i, al = SSL_AD_INTERNAL_ERROR, ok;<\/em><\/p>\n<p><em>&#8230;.<\/em><\/p>\n<p><em>1077&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (i &lt; 0) {<\/em><\/p>\n<p><em>1078&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/* we did not say we would use this cipher *\/<\/em><\/p>\n<p><em>1079&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; al = SSL_AD_ILLEGAL_PARAMETER;<\/em><\/p>\n<p><em>1080&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);<\/em><\/p>\n<p><em>1081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto f_err;&nbsp; \/\/a fatal error occurs<\/em><\/p>\n<p><em>1082&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/em><\/p>\n<p><em>&#8230;.<\/em><\/p>\n<p><em>1170&nbsp;&nbsp;&nbsp;&nbsp; f_err:<\/em><\/p>\n<p><em>1171&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ssl3_send_alert(s, SSL3_AL_FATAL, al); \/\/sends an SSL alert packet<\/em><\/p>\n<p><em>1172&nbsp;&nbsp;&nbsp;&nbsp; err:<\/em><\/p>\n<p><em>1173&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s-&gt;state = SSL_ST_ERR; \/\/moves into an error state<\/em><\/p>\n<p><em>1174&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (-1);<\/em><\/p>\n<p><em>1175&nbsp;&nbsp;&nbsp; }<\/em><\/p>\n<p>We used a vulnerable SSL client as a target during the test. During the SSL handshake it received a malformed server hello message from the SSL server controlled by the attacker. ssl3_get_server_hello() is called to handle this server hello message and a fatal error occurs, causing OpenSSL to move into an error state by setting s-&gt;state from <em>SSL_ST_INIT<\/em> to SSL_ST_ERR.<\/p>\n<p><em>ssl\/s3_pkt.c:<\/em><\/p>\n<p><em>638&nbsp;&nbsp;&nbsp;&nbsp; int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)<\/em><\/p>\n<p><em>639&nbsp;&nbsp;&nbsp;&nbsp; {<\/em><\/p>\n<p><em>640&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const unsigned char *buf = buf_;<\/em><\/p>\n<p><em>641&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int tot;<\/em><\/p>\n<p><em>642&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int n, nw;<\/em><\/p>\n<p><em>643&nbsp;&nbsp;&nbsp;&nbsp; #if !defined(OPENSSL_NO_MULTIBLOCK) &amp;&amp; EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK<\/em><\/p>\n<p><em>644&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int max_send_fragment;<\/em><\/p>\n<p><em>645&nbsp;&nbsp;&nbsp;&nbsp; #endif<\/em><\/p>\n<p><em>646&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSL3_BUFFER *wb = &amp;(s-&gt;s3-&gt;wbuf);<\/em><\/p>\n<p><em>647&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<\/em><\/p>\n<p><em>648&nbsp;&nbsp;&nbsp;&nbsp; <\/em><\/p>\n<p><em>649&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s-&gt;rwstate = SSL_NOTHING;<\/em><\/p>\n<p><em>650&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OPENSSL_assert(s-&gt;s3-&gt;wnum &lt;= INT_MAX);<\/em><\/p>\n<p><em>651&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tot = s-&gt;s3-&gt;wnum;<\/em><\/p>\n<p><em>652&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s-&gt;s3-&gt;wnum = 0;<\/em><\/p>\n<p><em>653&nbsp;&nbsp;&nbsp;&nbsp; <\/em><\/p>\n<p><em>654&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (SSL_in_init(s) &amp;&amp; !s-&gt;in_handshake) { \/\/ SSL_in_init is called again to check the state<\/em><\/p>\n<p>If the vulnerable SSL client doesn&#39;t check the error state and call SSL_write function to send application data again, ssl3_write_bytes() is called and uses SSL_in_init() to check the handshake state again.<\/p>\n<p><em>include\/openssl\/ssl.h:<\/em><\/p>\n<p><em>1749&nbsp;&nbsp;&nbsp; # define SSL_in_init(a)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (SSL_state(a)&amp;SSL_ST_INIT) \/\/s-&gt;state is now SSL_ST_ERR, and check returns are false.<\/em><\/p>\n<p>This time the check fails, the SSL handshake is bypassed&nbsp; and the application data will be sent without encryption.<\/p>\n<p>&nbsp;<\/p>\n<p>The following traffic dump shows how the clean application data is sent:<\/p>\n<p>&nbsp;<img decoding=\"async\" alt=\"traffic\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/updatedimage.jpg\" style=\"border-width: 0px; border-style: solid; width: 800px; height: 425px;\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>During this attack, the attacker entices the vulnerable SSL client to connect to a malicious SSL server. The SSL client may bypass the handshake process and send the application data without encryption. The SSL server may also have the same vulnerability if SSL_read or SSL_write function is called directly.<\/p>\n<p>NOTE: authentication is NOT required to exploit this vulnerability.<\/p>\n<p>&nbsp;<\/p>\n<h3>IPS Signature<\/h3>\n<p>FortiGuard released IPS signature OpenSSL.Handshake.Error.State.Security.Bypass to address this vulnerability.<\/p>\n<p>&nbsp;<\/p>\n<p><i>Sign up for our weekly FortiGuard Labs&nbsp;<a href=\"https:\/\/www.fortinet.com\/fortiguard\/threat-intelligence\/threat-research.html\">intel briefs<\/a>&nbsp;or to be a part of our&nbsp;<a href=\"https:\/\/www.fortinet.com\/fortiguard\/threat-intelligence\/threat-research.html\">open beta<\/a>&nbsp;of Fortinet&rsquo;s FortiGuard Threat Intelligence Service.<\/i><\/p>\n<\/div<br \/><a href=\"https:\/\/blog.fortinet.com\/2018\/01\/12\/an-analysis-of-the-openssl-ssl-handshake-error-state-security-bypass-cve-2017-3737\" target=\"bwo\" >https:\/\/blog.fortinet.com\/feed<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p><img decoding=\"async\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/updatedimage.jpg\"\/><\/p>\n<p><strong>Credit to Author: Dehui Yin| Date: Fri, 12 Jan 2018 11:39:59 +0000<\/strong><\/p>\n<p>OpenSSL is a widely used library for SSL and TLS protocol implementation that secures data using encryption and decryption based on cryptographic functions. However, a Security Bypass vulnerability \u2013 recently addressed in a patch by the OpenSSL Project \u2013can be exploited to make vulnerable SSL clients or remote SSL servers send clean application data without encryption.    This Security Bypass vulnerability (CVE-2017-3737) is caused by an error when the SSL_read or SSL_write function handles an &quot;error state&quot; during an SSL handshake&#8230;.<\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"colormag_page_container_layout":"default_layout","colormag_page_sidebar_layout":"default_layout","footnotes":""},"categories":[10424,10378],"tags":[],"class_list":["post-11103","post","type-post","status-publish","format-standard","hentry","category-fortinet","category-security"],"_links":{"self":[{"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts\/11103","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/comments?post=11103"}],"version-history":[{"count":0,"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts\/11103\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/media?parent=11103"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/categories?post=11103"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/tags?post=11103"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}