Developers forgot that arrays start at 0. An off-by-one error in `libstring-c`'s concatenation logic permits a single byte overflow on the heap. This allows attackers to corrupt chunk metadata, leading to Remote Code Execution (RCE) in any application linking this library—which is basically half the IoT world.
A critical off-by-one vulnerability in the widely used `libstring-c` library allows remote attackers to execute arbitrary code via malformed string concatenation requests. This bug creates a classic heap overflow scenario, turning simple text processing into a gateway for complete system compromise.
You probably haven't heard of libstring-c, but your toaster has. It's one of those foundational C libraries that gets statically linked into everything from smart fridges to enterprise routers because nobody wants to write their own string concatenation logic (and honestly, who can blame them?).
The library's selling point was 'safety and speed'. Irony is dead. It turns out that when you prioritize speed over basic arithmetic, you get CVE-2024-80085. This isn't just a denial of service; it's a full-blown invitation to take over the instruction pointer.
What makes this juicy is the attack surface. Since this library handles input parsing for HTTP headers in several lightweight web servers, the vulnerability is reachable remotely, often without authentication. It’s the kind of bug that keeps sysadmins awake at night and exploit developers grinning from ear to ear.
At its core, this is a textbook off-by-one error, the kind usually reserved for CS 101 failures. The function sc_concat_safe() takes a destination buffer, a source buffer, and a maximum length. The logic is supposed to prevent writing past the end of the destination.
The developers implemented a check: if (current_index <= max_length). Do you see the problem? In C, if your buffer is max_length bytes long, the valid indices are 0 to max_length - 1. By allowing writing at max_length, they allow exactly one byte to be written outside the allocated chunk.
On the heap, one byte is all we need. By overwriting the size field of the next chunk header, we can trick the memory allocator (specifically ptmalloc in glibc) into consolidating chunks that shouldn't be touched. This leads to the 'House of Spirit' or similar heap grooming techniques, eventually giving us an arbitrary write primitive.
Let's look at the diff. It’s almost insulting how simple the fix is. The vulnerability lived in src/concat.c.
Vulnerable Code:
// The loop that doomed us all
for (size_t i = 0; i <= max_len; i++) {
if (src[i] == '\0') break;
dest[dest_offset + i] = src[i];
}See that <=? That acts as the red carpet for our exploit. It allows the loop to execute one extra time when i equals max_len, writing a byte into the abyss.
Patched Code:
// The loop, now with basic math skills applied
for (size_t i = 0; i < max_len; i++) {
if (src[i] == '\0') break;
dest[dest_offset + i] = src[i];
}
// Ensure null termination explicitly if needed
dest[max_len - 1] = '\0';The fix simply changes the operator to <. It’s a one-character change that separates 'secure software' from 'remote root shell'.
Exploiting this requires finesse. We can't just smash the stack; we have to massage the heap. Here is the attack chain:
Heap Spray: Send multiple HTTP requests with specific header lengths to force the allocator to arrange memory chunks contiguously. We want our vulnerable chunk to sit right before a chunk containing a function pointer or a C++ vtable.
Trigger the Overflow: Send a request that triggers sc_concat_safe with a length exactly matching the buffer size. This writes our malicious byte into the metadata of the next chunk.
Chunk Corruption: We modify the size field of the next chunk. When that chunk is free()'d (which happens when the request ends), the allocator gets confused about where the chunk ends and merges it with a fake chunk we created in step 1.
The Overwrite: The next allocation will return a pointer to memory we already control. We overwrite a function pointer (like a destructor or a GOT entry) with the address of system().
Execution: Trigger the function we overwrote. Boom. Shell.
If you are running a standard Linux server, you have ASLR and NX bit protections. These make the exploit harder, but not impossible. The real victims here are IoT devices.
Many embedded systems run without full ASLR, or with binaries compiled without stack canaries. On these systems, this exploit is 100% reliable. An attacker can scan the internet for devices exposing the affected web interface, send a single malformed packet, and gain root access.
Once inside, they can add the device to a botnet, steal credentials, or pivot to the internal network. Given libstring-c is used in several OpenWRT packages, the blast radius is massive.
The only real fix is to update the library. If you are a developer using libstring-c, upgrade to version 1.4.2 immediately.
If you are a sysadmin and can't patch (because the vendor went out of business in 2019), you have limited options:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
libstring-c OpenSourceLib | < 1.4.2 | 1.4.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-193 (Off-by-one Error) |
| Attack Vector | Network (Remote) |
| CVSS | 9.8 (Critical) |
| Impact | Remote Code Execution (RCE) |
| Exploit Status | PoC Available |
| Privileges | None Required |
A product calculates or uses an incorrect maximum or minimum value that is 1 more, or 1 less, than the correct value.
Get the latest CVE analysis reports delivered to your inbox.