OpenSSL 3.0.7 - Otherwise Known As, The Hype That Was Not
Finally, it is midnight (in my timezone, at least) and the wait is over - OpenSSL have published details of their second ever critical severity, nope high-severity (**amended after disclosure), security vulnerability - tracked as CVE-2022-3786 and CVE-2022-3602.
The details published by OpenSSL can be found here:
At watchTowr, we were fearful that the new bugs could be similar to the 'Heartbleed' vulnerability that caused defenders so much headache in the past. Fortunately, however, they aren't as severe as this - and you wouldn't be blamed for suggesting that this may have been a lot of drama for.. not very much.
Read on for our analysis of the (two!) vulnerabilities and why we think we won't see them being used to breach external perimeters any time soon.
Ground Zero: The Changelog
The details of the bugs first surfaced in OpenSSL 3.0.7's changelog. Here's an excerpt:
* Fixed two buffer overflows in punycode decoding functions.
A buffer overrun can be triggered in X.509 certificate verification,
specifically in name constraint checking. Note that this occurs after
certificate chain signature verification and requires either a CA to
have signed the malicious certificate or for the application to continue
certificate verification despite failure to construct a path to a trusted
issuer.
In a TLS client, this can be triggered by connecting to a malicious
server. In a TLS server, this can be triggered if the server requests
client authentication and a malicious client connects.
An attacker can craft a malicious email address to overflow
an arbitrary number of bytes containing the `.` character (decimal 46)
on the stack. This buffer overflow could result in a crash (causing a
denial of service).
([CVE-2022-3786])
An attacker can craft a malicious email address to overflow four
attacker-controlled bytes on the stack. This buffer overflow could
result in a crash (causing a denial of service) or potentially remote code
execution depending on stack layout for any given platform/compiler.
([CVE-2022-3602])
So there are two different bugs - CVE-2022-3786 and CVE-2022-3602. Let's tackle them both in turn.
CVE-2022-3786
Firstly, CVE-2022-3786. The changelog states that this bug is DoS-only, although the presence of "an arbitrary number of bytes .. on the stack" is worrying. Since source is available, we can analyse the code ourselves - the following is from the crypto/punycode.c
file, heavily edited for readability.
int ossl_a2ulabel(const char *in, char *out, size_t *outlen)
{
char *outptr = out;
const char *inptr = in;
size_t size = 0;
int result = 1;
while (1) {
char *tmpptr = strchr(inptr, '.');
...
if (tmpptr != NULL) {
*outptr = '.';
outptr++;
size++;
if (size >= *outlen - 1)
result = 0;
}
if (tmpptr == NULL)
break;
inptr = tmpptr + 1;
}
return result;
}
We can see here a while
loop, which searches for instances of a .
via the C strchr
function. If a .
is present, then tmpptr
becomes non-NULL, and a .
is written to outptr
. Note that the size check if (size >= *outlen - 1)
does not terminate the loop on overflow - it simply sets the result
flag to indicate that an error has occurred, and then the loop iterates again, writing another .
even if the output buffer is full.
Since the only data that can be written is, indeed, the .
character, it is unlikely that there is a way to use this bug to alter program execution and achieve RCE.
CVE-2022-3602
The more interesting of the two bugs, CVE-2022-3602 is a four-byte stack overflow. Looking through the code, we can see a likely candidate for the responsible code snippet in the function ossl_punycode_decode
, in the same source file. The following code is present:
if (written_out >= max_out)
return 0;
While looking at the previous version shows:
if (written_out > max_out)
return 0;
Looking around that line, we can see that it is part of a copy operation.
if (written_out >= max_out)
return 0;
memmove(pDecoded + i + 1, pDecoded + i,
(written_out - i) * sizeof(*pDecoded));
pDecoded[i] = n;
It appears that pDecoded
, a stack-based buffer of type unsigned int
, becomes overflowed by a single element. Fortunately, however, the memory range which is overflowed is likely to contain non-critical data, even in software built with no mitigations in place. Software built with even the most rudimentary of mitigation mechanisms, such as static stack cookies, makes exploitation even harder (if not impossible).
Further Mitigating Factors
So we have two bugs - one which appears to be DoS-only, and one which is unlikely to allow code execution. Fortunately, this gets even better, and exploitation is further constrained.
It turns out that the vulnerable code is executed only after various other checks on the certificate have taken place. Recall the calming words of the changelog:
Note that this occurs after
certificate chain signature verification and requires either a CA to
have signed the malicious certificate or for the application to continue
certificate verification despite failure to construct a path to a trusted
issuer.
In a TLS client, this can be triggered by connecting to a malicious
server. In a TLS server, this can be triggered if the server requests
client authentication and a malicious client connects.
So an attacker needs a malformed certificate which has been signed by the victim, or to already be ignoring signing! This further constrains the usefulness of the bug to an attacker.
The second part of the changelog advises that a TLS server (for example, a VPN server using client authentication) could be vulnerable when it is exposed to a malformed certificate presented to it by a client. Again, however, this certificate must be signed by the CA itself, which makes exploitation improbable.
Readers who are concerned about this scenario are advised to examine their audit logs for certificates which could trigger the vulnerable code paths.
Summary
Any bug in OpenSSL is cause for an amount of concern, and these two are no different. Those running a vulnerable version of OpenSSL (<=3.0.6) are advised to update to 3.0.7 at their earliest convenience, while those running the older 1.1.x branch are unaffected and need take no action.
Readers, and watchTowr clients alike, are reminded that the requirements for successful exploitation are unusually high:
- An attacker must be in possession of a signed certificate, from a trusted CA.
- The certificate must contain a malformed email address.
- The software into which OpenSSL is built must store some critical data structure immediately after the
pDecoded
array in memory. - The software into which OpenSSL must also have no compile-time mitigations enabled which can prevent exploitation.
Brief FAQ
- Is this a remotely-exploitable bug, that will have trivial direct impact on my infrastructure?
No!
- Are we likely to see this vulnerability used for mass-exploitation across the Internet?
No!
- Is watchTowr aware of any in-the-wild exploitation?
No!
- Is this comparable to Heartbleed?
No!
- Should I be patching and what versions are affected?
Yes, you should! This affected code was first introduced in OpenSSL 3.0.0. OpenSSL 1.0.2, 1.1.1 and other earlier versions are not affected. OpenSSL 3.0.7 and above is not affected.
As we've said - please exercise caution and apply patches to systems you identify internally as running an affected version of OpenSSL - but, luckily(?) this is not the end-of-the-world moment it was purported to be.
If you'd like to learn more about how the watchTowr Platform, our Attack Surface Management and Continuous Automated Red Teaming solution, can support your organisation, please get in touch.