CVE-2020-0601 is a major security issue affecting recent versions of Microsoft Windows. In a nutshell, NSA found a vulnerability in core Windows libraries that perform certificate validation. This vulnerability can be used to craft certificates that are accepted as valid by Windows - even though they do not have a valid signature of a trusted certificate authority. The vulnerability can, for example, be used to impersonate TLS servers, to fake signature, or to fake email and file signatures.
I will not go into exactly how the vulnerability works; however if you are interested in the mathematical background, check out this post.
Hours after the announcement of the vulnerability, we published the first package that can detect TLS exploit attempts. This was followed by a second package, that gives a slightly higher quality signal, 24 hours day later.
In this blog post, I will provide a high-level overview of some of the basics of the exploit,and how Zeek can be used to detect it.
Elliptic Curve Certificates
Elliptic Curve Cryptography (ECC) is a public-key cryptographic scheme. From a user perspective, it works similarly to RSA - there is a public key as well as a private key. In addition, for ECC the participants need to agree on the domain parameters making up the elliptic curve - typically these domain parameters are just referred to as “the curve.” These curves are generally not made up by the participants - instead they are chosen from lists of published curves. For example, a typical curve that is used is secp384r1, which was standardized by NIST in FIPS 186-4 (note: to make things slightly confusing NIST curves have two names - secp384r1 is referred to as P-384 in the NIST publication).
When creating a certificate that uses Elliptic Curve DSA (ECDSA) as the signature scheme, the curve is typically just referred to by name - meaning that in the ASN.1 representation of the X.509 certificate just the name of the curve is given. It is expected that all participants know the parameters of the well-known curves. An example certificate using ECDSA from the Zeek test suite looks like this (unnecessary details omitted):
Note the line saying “ASN1 OID: sec384r1” which defines the curve.
There is a second way to share the curve parameters in certificates: by defining them explicitly. Instead of just giving a curve name, in this case all parameters are included in the certificate. This feature nowadays is rarely used for a variety of reasons - and it is also not supported by most software. Indeed RFC 5840, which specifies the use of ECC in X.509 certificates in the Internet, specifically states that “specifiedCurve, which is of type SpecifiedECDomain type (defined in [X9.62]), allows all of the elliptic curve domain parameters to be explicitly specified. This choice MUST NOT be used.”
The following is the OpenSSL output for a certificate that contains an explicitly defined curve.
Note that the generator, order, etc., of the curve is given directly in the certificate. Without going into specifics, the exploit requires a certificate containing such an explicitly defined curve. In addition, the curves that are used by the exploit are manipulated, meaning that they will not be from the list of standard curves.
Detecting CVE-2020-0601 using a Zeek scriptTo detect if someone is trying to exploit CVE-2020-0601, we need to determine if someone is trying to use a EC-certificate using a non-standard curve. It turns out that this is rather easy to do in a Zeek script. We can just use the x509_certificate event. The X509::Certificate parameter of this event contains both the key algorithm that is used by the certificate - which tells us that the certificate has an elliptic curve key - as well as the curve that is used in a certificate.
So, we can just write a simple test to check if a certificate is an EC-certificate but does not use a named curve and output a notice:
This is the exact code that is used by our detection script.
This is the exact code that is used by our detection script.
This just leaves us with one question: what happens when a certificate contains a standard curve, but encodes the parameters explicitly?
It turns out that the answer to this question is a bit complex with different OpenSSL installations behaving in various ways. Some OpenSSL versions will automatically convert well-known explicit curves back to their named equivalent. In this case, the Zeek code above will work as expected - and certificates with well-known curves that are explicitly specified will not generate a warning. Other versions will not do this; in this case you will get a false positive with this code when encountering such a certificate. Please note, however, that explicitly defined parameters are highly unusual, so the danger of false positives is very low.
To address this potential of false positives, we added a test to our package which determines if your OpenSSL installation behaves as expected. If not, you will get a test failure. You can still use the package, you just have to be aware that there is a small risk of false positives.
Furthermore, we have a second version of our package, which completely mitigates this issue. In this version, we created a C plugin that uses OpenSSL functionality to test if the curve contained in a certificate matches one of the well-known curves. The source is split across two files, a bif-file which creates a function that can test a certificate from script-land, and a second file that performs the test. The code in the second file is very long (more than 3,000 lines) - because it contains all curve definitions. This code is mostly a copy from the OpenSSL source code - which contains the functionality that we need - but does sadly not expose it directly in their API.
The drawback of this package is the higher complexity. Furthermore the package requires OpenSSL 1.1.1 - which might not be available for your Zeek installation if you are on an older release of your Linux distribution.
Getting InvolvedIf you have any questions about this script - or if you use it and find exploit attempts - we would love to hear from you. The best way to contact us is to share feedback on our mailing list, or you can email me directly.
The Zeek community is always interested in package contributions! If you write an interesting package that can detect an attack, adds a feature, etc., add it to the package manager and let the mailing list know.