Unknown
CVE-2022-3786
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below:
Add References:
CVE-2022-3786
MITRE ATT&CK
Collection
Command and Control
Credential Access
Defense Evasion
Discovery
Execution
Exfiltration
Impact
Initial Access
Lateral Movement
Persistence
Privilege Escalation
Topic Tags
Description
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 a malicious certificate or for an application to continue certificate verification despite failure to construct a path to a trusted issuer. An attacker can craft a malicious email address in a certificate 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). 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.
Add Assessment
No one has assessed this topic. Be the first to add your voice to the community.
CVSS V3 Severity and Metrics
General Information
Vendors
- fedoraproject,
- nodejs,
- openssl
Products
- fedora 36,
- fedora 37,
- node.js,
- node.js 18.12.0,
- node.js 19.0.0,
- openssl
References
Advisory
Exploit
A PoC added here by the AKB Worker must have at least 2 GitHub stars.
Miscellaneous
Additional Info
Technical Analysis
Description
On November 1, 2022, the OpenSSL project released version 3.0.7 to address a pair of vulnerabilities – CVE-2022-3602 and CVE-2022-3786 – that they labeled as “critical” in their announcements, then downgraded to “high” when they were released. In their blog post, the OpenSSL developers explain that they downgraded the risk because exploitation seems unlikely:
During the week of prenotification, several organisations performed testing and gave us feedback on the issue, looking at the technical details of the overflow and stack layout on common architectures and platforms. […] the stack layout was such that the 4 bytes overwrote an adjacent buffer that was yet to be used and therefore there was no crash or ability to cause remote code execution.
Even though the OpenSSL team knew that the vulnerability was going to be downgraded before they released the patch, they did nothing in the hours leading up to the release to defuse the collective panic. We’d like to see future projects be more open with impact changes, particularly when upcoming releases are going to be less impactful than originally announced.
CVE-2022-3786 refers to an arbitrary-length overflow when parsing Punycode domain names utilizing OpenSSL’s Punycode library, which is part of libcrypto.so
and only accessible through certificate-validation functions after certificate validation. In a trusted certificate, this can potentially affect any client application running a vulnerable version of OpenSSL, or any server application that is configured to validate client certificates. Even on affected hosts, the likelihood of meaningful exploitation is low for reasons detailed below.
Affected products are:
- OpenSSL 3.0.0 – 3.0.6 (fixed in OpenSSL 3.0.7; other OpenSSL versions are not affected)
Technical analysis
CVE-2022-3786 is a parsing error in the ossl_a2ulabel
function in punycode.c, where period characters (.
or 0x2e
) can be infinitely appended to a buffer, which typically leads to denial of service conditions (i.e., crashing the process by flooding it with periods). In rare cases, if a useful memory address is stored right after the buffer, and changing the last byte two of the address to 0x2e
is useful, and nothing important gets overwritten in the process, a partial address overwrite (like this one) might lead to a exploitable memory corruption. That would have to be very carefully tailored to the target, and the memory layout of the target would need to be just right, making it unlikely to be widely exploited.
The diff for this issue is rather long, but let’s take a look at the vulnerable code to see what’s going on! A brief proof of concept that demonstrates the issue by directly calling the vulnerable function can be found in our Github repo, which overwrites the return address with 0x2e
bytes. We’ll use that in our examples below, but note that it’s a very contrived example. The only known path to real-world exploitation is through the certificate-validation function, which requires a signed and trusted certificate.
The function signature for ossl_a2label
is:
int ossl_a2ulabel(const char *in, char *out, size_t *outlen);
It’s designed to decode possibly-Punycode-encoded DNS names; for example, www.xn--n28haaaaaaaaaaaaa.com
would become www.😉😉😉😉😉😉😉😉😉😉😉😉😉😉.com
. The code is mostly contained in a while (1)
loop, which processes each label (ie, the portions of the name between periods) until it runs out:
while (1) { char *tmpptr = strchr(inptr, '.'); // [...] if (tmpptr == NULL) break; } return result;
If the label does not start with xn--
(ie, it’s a standard label), it’s basically copied directly into the output buffer. A length check sets the result
variable to 0
and stops copying memory when we run out of output space, but importantly this does not exit the parsing loop:
// [...] if (strncmp(inptr, "xn--", 4) != 0) { size += delta + 1; if (size >= *outlen - 1) result = 0; if (result > 0) { memcpy(outptr, inptr, delta + 1); outptr += delta + 1; } } else { // [...] }
If the label does start with xn--
, the else
executes, and it decodes using the ossl_punycode_decode
function (note that that function is vulnerable to CVE-2022-3602, which means we can write 4 bytes past the end of the stack-based buffer buf
, but the next element on the stack does not appear to be a useful target):
} else { unsigned int bufsize = LABEL_BUF_SIZE; unsigned int i; if (ossl_punycode_decode(inptr + 4, delta - 4, buf, &bufsize) <= 0) return -1; for (i = 0; i < bufsize; i++) { unsigned char seed[6]; size_t utfsize = codepoint2utf8(seed, buf[i]); if (utfsize == 0) return -1; size += utfsize; if (size >= *outlen - 1) result = 0; if (result > 0) { memcpy(outptr, seed, utfsize); outptr += utfsize; } } // [...] }
Once again, when it reaches the end of the output buffer, it sets result
to 0
, then stops writing to the output buffer (but, again, doesn’t stop processing). The following code, however, does write to the buffer:
if (tmpptr != NULL) { *outptr = '.'; outptr++; size++; if (size >= *outlen - 1) result = 0; } } // [...]
As long as tmpptr
isn’t NULL
(meaning, we haven’t reached the final label in the original string), it appends a period, even if result
has been set to 0
! That means that as long as there are Punycode-encoded labels to decode, we can keep adding periods. Note that the resulting string will look like it’s the correct length. In our contrived PoC, we use the string "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.xn--.xn--.xn--.xn--.xn--.xn--.xn--[...]"
, which appears to truncate when viewed as a string:
(gdb) x/s $rbp-0x20 0x7fffffffdea0: "a.b.c.d.e.f.g......."
But that’s because a 4-byte NULL
value is appended to the buffer at the end, before more period characters (0x2e
) are written as far past the buffer as the exploit desires:
(gdb) x/64xb $rbp-0x20 0x7fffffffdea0: 0x61 0x2e 0x62 0x2e 0x63 0x2e 0x64 0x2e 0x7fffffffdea8: 0x65 0x2e 0x66 0x2e 0x67 0x2e 0x2e 0x2e 0x7fffffffdeb0: 0x2e 0x2e 0x2e 0x2e 0x00 0x00 0x00 0x00 0x7fffffffdeb8: 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x7fffffffdec0: 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x7fffffffdec8: 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e [...]
Including overwriting the return address (again, this is contrived, not a real-world attack):
(gdb) cont [...] Program received signal SIGSEGV, Segmentation fault. 0x000000000040127e in main (argc=1, argv=0x7fffffffdfd8) at cve-2022-3786-periods.c:33 33 } (gdb) x/i $rip => 0x40127e <main+200>: ret (gdb) x/xg $rsp 0x7fffffffdec8: 0x2e2e2e2e2e2e2e2e
Exploiting this issue in real-world applications will be very dependent on how the vulnerable functions are called. At this point, nobody in the community (to our knowledge) has found an application where this overwrite leads to security implications. That doesn’t mean it’s impossible, however; this vulnerability permits us to perform a partial pointer overwrite, where we can change any number of bytes at the end of a memory address to 0x2e
, but only if the memory address is after the Punycode-output buffer and nothing else important is overwritten in between.
In the worst case scenario, a buffer overflow such as this could potentially lead to reading, writing, or executing code from the wrong place in memory. In practice, however, it’s unlikely that any targets are vulnerable to this.
Guidance
Organizations that are running an affected version of OpenSSL should update to 3.0.7 when practical, prioritizing operating system-level updates and public-facing shared services with direct dependencies on OpenSSL. Emergency patching is not indicated.
References
Report as Emergent Threat Response
Report as Exploited in the Wild
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below: