CVE-2024-6197: freeing stack buffer in utf8asn1str
Medium
C
curl
Submitted None
Actions:
Reported by
z2_
Vulnerability Details
Technical details and impact analysis
Libcurl at commit [04739054cdac5a0614fb94e3655e313c03399f35](https://github.com/curl/curl/tree/04739054cdac5a0614fb94e3655e313c03399f35) contains an invalid invocation of `free()` in the function `utf8asn1str()` at [lib/vtls/x509asn1.c:397](https://github.com/curl/curl/blob/04739054cdac5a0614fb94e3655e313c03399f35/lib/vtls/x509asn1.c#L397).
The relevant code can be seen below:
```c
static CURLcode
utf8asn1str(struct dynbuf *to, int type, const char *from, const char *end)
{
// --- snip ---
if(type == CURL_ASN1_UTF8_STRING) {
// --- snip ---
}
else {
while(!result && (from < end)) {
char buf[4]; /* decode buffer */
// --- snip ---
if(wc >= 0x00200000) {
free(buf);
/* Invalid char. size for target encoding. */
return CURLE_WEIRD_SERVER_REPLY;
}
}
}
}
```
`buf` is located on the stack and not the heap, which means that `buf` will be falsely treated as a heap chunk.
This poses a security risk because the address of `buf` can be returned in subsequent calls to `malloc()`, which causes
the stack contents at that point to be overwritten.
The stack holds data that determines the control flow of the application. This can either be local variables that indirectly
determine the control flow of their corresponding functions or security-critical metadata liked saved framepointers or return addresses.
If an attacker manages to overwrite these kinds of stack contents he/she can gain control over the control flow of the application.
# Exploit Scenario
Consider the following scenario that demonstrates how to leverage the invalid `free()` to overwrite return addresses:
1. The attacker sets up a malicious server with a TLS certificate that triggers the invalid `free()`
2. An application using libcurl connects to the server and during the connect() phase parses the invalid certificate.
This causes the stack address to be put into the freelist of the allocator.
3. The attacker interacts with the client in a way that causes the stack address to be returned by a `malloc()` call
and used to store data from the attacker
4. Depending on the state of the stack, the attacker can now overwrite local variables, pointers or security-critical metadata.
The worst case would be that a return address gets overwritten with a [ROP-chain](https://en.wikipedia.org/wiki/Return-oriented_programming) in order to
gain control over the execution of the program
One environment where that scenario could work out is Ubuntu bionic, where the glibc does not check whether the argument to `free()` actually refers to a valid heap chunk.
# Patch
The fix for this vulnerability is pretty straight forward, just remove the call to `free()`:
```diff
diff --git a/lib/vtls/x509asn1.c b/lib/vtls/x509asn1.c
index cea88e668..ddfb65344 100644
--- a/lib/vtls/x509asn1.c
+++ b/lib/vtls/x509asn1.c
@@ -394,7 +394,6 @@ utf8asn1str(struct dynbuf *to, int type, const char *from, const char *end)
if(wc >= 0x00000800) {
if(wc >= 0x00010000) {
if(wc >= 0x00200000) {
- free(buf);
/* Invalid char. size for target encoding. */
return CURLE_WEIRD_SERVER_REPLY;
}
```
## Impact
I assess the impact of this vulnerability to be "High" because
1. The invalid `free()` is easy to trigger since it happens during the TLS handshake
2. An overwrite of memory contents with attacker-controlled data poses a great security risk
Report Details
Additional information and metadata
State
Closed
Substate
Resolved
Submitted
Weakness
Free of Memory not on the Heap