Hitting a CurveBall Like a Pro!
Last month (Jan 14th 2020), Microsoft has released a security update for Windows which includes a fix to a dangerous bug that would allow an attacker to spoof a certificate, making it look like it came from a trusted source. The vulnerability (CVE-2020–0601 , AKA CurveBall) was reported to Microsoft by the NSA. In this blog post, we will explore how defenders can detect the exploitation of this vulnerability.
Previously on CurveBall
This is our third blog post on CurveBall. In our first blog post, we explained the cryptography principles behind CurveBall, enabling attackers to create an “evil twin” of a legitimate certificate by changing the base point.
In the second blog post, we explained the SSL certificate validation process and shed some light on the bug in Windows10 that allowed it to accept this “evil twin” certificate as valid.
In this third blog post we will try to make this knowledge actionable, by creating detection rules to catch exploits of the CurveBall vulnerability.
Detection Recipe by NSA
The original NSA advisory suggests
Packet capture analysis tools such as Wireshark can be used to parse and extract certificates from network protocol data for additional analysis…
..Certificates containing explicitly-defined elliptic curve parameters which only partially match a standard curve are suspicious, especially if they include the public key for a trusted certificate, and may represent bona fide exploitation attempts.
Breaking down this advice into four steps (or “bases” as we are dealing with a curve ball):
- Wireshark can be used to parse and extract certificates from network protocol data.
- Certificates containing explicitly-defined elliptic curve parameters
- Elliptic curve parameters which only partially match a standard curve
- Include the public key for a trusted certificate
In the following sections, we will follow the NSA’s blueprint to detect such exploits, starting from first base all the way to a home-run!
First base: Capturing certificates with Wireshark
I assume you are already familiar with Wireshark, the Swiss army knife of network capture. For this blog we need to use Wireshark of version 3.3.0 (or newer) which is currently available only as a nightly build (or by building from source code)
As the exploit abuses certificates in SSL. The certificates are exchanged in the handshake stage of the SSL protocol, so the certificates information is available in plaintext and no decryption is needed. Sweet!
A basic Wireshark filter for the handshake message with certificate “(tls.handshake.type == 11)” would help us zoom in on that message.
To experiment in this stage any SSL traffic would do, so you can capture any browsing session to HTTPS site. However, for next stages real exploits traffic is needed. To obtain such, you can either browse to CurveBall testing sites curveballtest.com or testcve.kudelskisecurity.com or just download the capture files of SSL traffic we already recorded by and uploaded to GitHub.
Second Base: Identify explicitly-defined parameters
This is a real piece of cake with Wireshark. Normally, a certificate will use the name of a standard curve and will not define the curve parameters
However, for this exploit attackers need to use a specified curve. We will use the following Wireshark filter “(pkcs1.ECParameters == 0)” to catch it.
Note, that if you don’t have the luxury of having Wireshark to reconstruct the TCP session and parse the SSL protocol and certificate, a simpler signature may work. A simple signature that tries to match the hex value of the “prime-field” OID (Object IDentifier) 1.2.840.10045.1.1, on the wire “2a 86 48 ce 3d 01 01” can do a decent job in catching non-default elliptic curve parameters, as suggested in the tweet below (with some extra context to minimize false positives)
Third Base: Identify elliptic curve parameters which only partially match a standard curve
For the exploit to work the certificate must change the standard base point (AKA Generator) of the curve (see our first blog on CurveBall).
Since the parameters of curve are standard and known in advance, we can add a detection rule for the non-standard base points
Therefore, we can create such filter for curves supported by SSL and Windows for example secp384r1 (we will see in the next section that checking for secp256r1, secp384r1 is probably sufficient). The filter will match the “a” and “b” parameters of standard curves, with a non-standard base point.
“(pkcs1.ECParameters == 0) && (pkcs1.a == ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:fe:ff:ff:ff:ff:00:00:00:00:00:00:00:00:ff:ff:ff:fc) && (pkcs1.b == b3:31:2f:a7:e2:3e:e7:e4:98:8e:05:6b:e3:f8:2d:19:18:1d:9c:6e:fe:81:41:12:03:14:08:8f:50:13:87:5a:c6:56:39:8d:8a:2e:d1:9d:2a:85:c8:ed:d3:ec:2a:ef) && (pkcs1.base != 04:aa:87:ca:22:be:8b:05:37:8e:b1:c7:1e:f3:20:ad:74:6e:1d:3b:62:8b:a7:9b:98:59:f7:41:e0:82:54:2a:38:55:02:f2:5d:bf:55:29:6c:3a:54:5e:38:72:76:0a:b7:36:17:de:4a:96:26:2c:6f:5d:9e:98:bf:92:92:dc:29:f8:f4:1d:bd:28:9a:14:7c:e9:da:31:13:b5:f0:b8:c0:0a:60:b1:ce:1d:7e:81:9d:7a:43:1d:7c:90:ea:0e:5f)”
Home run: Include the public key for a trusted certificate
The crux of the exploit is that the rogue certificate public key matches a the public key of an already trusted Win10 certificate (check our second blog on CurveBall). But can we find them all?
Yes we can, and in fact Benjamin Delpy has done so in another CurveBall exploit tool used to sign binaries. (It might be a good opportunity to remind that although the detection rules here are network exploits oriented, I assume they are relevant, with the appropriate changes, to the detection of maliciously signed files)
To do so, we can search the repository of Microsoft supported Certificate Authorities (CAs) for elliptic curve based certificates (by the “Public Key Algorithm” column), download all 35 of them and extract the public key. (additionally you can see that Windows supported CAs only use secp256r1 and secp384r1 curves)
Then we can add all public keys to the filter:
“(pkcs1.ECParameters == 0) && (x509af.subjectPublicKey == 04:1a:ac:54:5a:a9:f9:68:23:e7:7a:d5:24:6f:53:c6:5a:d8:4b:ab:c6:d5:b6:d1:e6:73:71:ae:dd:9c:d6:0c:61:fd:db:a0:89:03:b8:05:14:ec:57:ce:ee:5d:3f:e2:21:b3:ce:f7:d4:8a:79:e0:a3:83:7e:2d:97:d0:61:c4:f1:99:dc:25:91:63:ab:7f:30:a3:b4:70:e2:c7:a1:33:9c:f3:bf:2e:5c:53:b1:5f:b3:7d:32:7f:8a:34:e3:79:79)”
Bonus: Exploit based detection
Detecting a specific exploit is a “Whack-a-mole” game, as the exploit can be easily changed. However, sometimes adding detection for a popular exploit on top of the solid vulnerability based detection (such as the aforementioned) can be worth the while as it can add some certainty to the detection.
A popular CurveBall exploit is using the “degenerate case” in which the private key equals to 1 to avoid elliptic curve arithmetics (see our first blog on CurveBall). As a result, the base point of the exploit certificate is equal to its public key. Using Wireshark you can detect it with the following filter “(pkcs1.base == x509af.subjectPublicKey)”.
Note, that it will only catch the exploit of curveballtest.com, as the testcve.kudelskisecurity.com exploit is doing some elliptic curve arithmetics to support non degenerate cases.
The ninth inning: Putting it all together
Are all of these detection elements actually needed? I am not sure. In detection, you don’t need to swing to the fences every time. My personal feeling is that checking for SSL certificates with explicit parameters might be enough.
I would not expect it to generate too many false positives as many implementations do not support explicit parameters (including Windows versions older than Win10) and updated standards (RFC 5480) ban the use of them.
Recently, there was (another) heated debate on publishing exploits. However, I believe that there is a broad consensus that sharing detection rules recipes is a good idea. Therefore, we encourage you to share your results of applying these rules. Please reply in the comments below or in twitter.
Be safe out there!