Impact of the c-ares TCP Use-After-Free Vulnerability: A Deep Dive into the calc-poc RCE
The c-ares TCP use-after-free vulnerability enables remote code execution by manipulating DNS-over-TCP response sequences to trigger a memory corruption condition in ares_getaddrinfo(), allowing attackers to hijack internal allocator hooks and redirect execution to arbitrary functions.
The bikini/exploitarium repository hosts a proof-of-concept demonstrating a critical use-after-free (UAF) flaw in the c-ares asynchronous DNS library. This vulnerability specifically impacts the TCP code path and can be exploited to achieve full remote code execution (RCE) in any application processing attacker-controlled DNS responses through a vulnerable c-ares version.
How the c-ares TCP UAF Vulnerability Works
The attack exploits a race condition in the resolver's TCP implementation when handling specific EDNS retry sequences. Successful exploitation requires precise control over the DNS response timing and the ability to shape heap memory through custom allocation hooks.
Triggering the Vulnerable Code Path
The vulnerability activates only when the application initializes c-ares with flags that force TCP-based resolution. In poc/cares_tcp_uaf_calc_poc.c, the PoC configures the resolver at lines 64-70 using ARES_FLAG_EDNS combined with ARES_FLAG_USEVC:
/* Minimal trigger: configure c‑ares to use TCP+EDNS and force the
vulnerable code path. */
struct ares_options opts = {0};
opts.flags = ARES_FLAG_EDNS | ARES_FLAG_USEVC; // enable TCP & EDNS
opts.lookups = "b"; // DNS‑only
ares_init_options(&channel, &opts, ARES_OPT_FLAGS);
This configuration forces the resolver into the vulnerable TCP retry logic where the use-after-free occurs during connection reset handling.
The Malicious DNS Response Sequence
The exploit relies on a specific sequence of DNS responses that manipulate the resolver's internal state machine. According to the repository's README.md (lines 41-53), the attack server transmits a FORMERR response immediately followed by a successful empty response using the same query ID. This sequence induces the resolver to retry the EDNS exchange, then reset the TCP connection before completing the next write operation, leaving a dangling pointer in the ares_query_t tracking structures.
Allocator Manipulation and Control Flow Hijacking
The PoC demonstrates sophisticated heap shaping by overriding c-ares' internal memory allocator via ares_library_init_mem. This allows the attacker to force a stale ares_query_t.node_queries_by_timeout pointer to reference a crafted skip-list node allocated at a predictable location.
When the resolver's cleanup routine eventually calls ares_slist_node_destroy(), the node's destruct function pointer has been overwritten to reference proof_marker(). As implemented in poc/cares_tcp_uaf_calc_poc.c (lines 68-99), this payload function executes when the stale pointer is dereferenced:
/* proof_marker() - the payload function that executes when the UAF
is successfully triggered */
static void proof_marker(void *arg) {
(void)arg;
FILE *f = fopen("/tmp/cares_rce_proof", "w");
if (f) {
fprintf(f, "CARES_RCE_PAYLOAD_TRIGGERED\n");
fclose(f);
}
/* Attempts to launch calculator as proof of code execution */
system("calc.exe || gnome-calculator || xcalc");
}
Exploitation Impact and Real-World Scope
When successfully exploited, this vulnerability transitions from a memory corruption bug to arbitrary code execution within the victim process context. The PoC conclusively proves that attackers can redirect control flow to execute shell commands rather than merely crashing the application.
The practical impact depends on three strict conditions:
- The target must exercise the vulnerable
ares_getaddrinfo()code path - The resolver must accept DNS-over-TCP with EDNS retry logic enabled
- The attacker must control or spoof the DNS response sequence
Affected Software Ecosystems
Because c-ares serves as the asynchronous DNS backend for numerous high-level frameworks, the vulnerability surface extends across multiple language ecosystems and critical infrastructure software:
- Node.js: Bundles c-ares in
deps/cares; DNS resolution APIs may trigger the vulnerable path - gRPC: Uses c-ares as the default resolver on many platforms
- Envoy Proxy: Configurable DNS resolver defaults to c-ares
- libcurl: Optional async DNS backend implemented through c-ares
- Wireshark: Uses c-ares for asynchronous name resolution during packet capture analysis
- Python async DNS stacks:
pycaresandaiodnswrap the c-ares library - Rust wrappers: The
c-arescrate exposes vulnerable interfaces to Rust applications
Mitigation Strategies
Organizations should implement the following countermeasures to eliminate exposure to this vulnerability:
- Upgrade c-ares immediately: Deploy versions containing the upstream fix (referenced in
README.mdlines 17-20) - Rebuild statically linked binaries: Recompile applications after upgrading the embedded library
- Disable DNS-over-TCP: Configure resolvers to use UDP transport only, removing the vulnerable code path
- Implement network segmentation: Restrict DNS resolution to trusted servers that cannot be influenced by attackers
- Audit binary dependencies: Use
ldd,readelf,strings, orotoolto identify bundled c-ares versions (see operational triage guidance inREADME.mdlines 87-103)
Building and Testing the Proof-of-Concept
Security researchers can reproduce the vulnerability using the helper scripts provided in the repository. First, compile the PoC against a specific c-ares version:
# Build the PoC against the latest c-ares release (v1.34.6)
git clone --depth 1 --branch v1.34.6 https://github.com/c-ares/c-ares.git /tmp/c-ares-v1.34.6
./scripts/build_from_checkout.sh /tmp/c-ares-v1.34.6 /tmp/c-ares-v1.34.6-build ./cares_tcp_uaf_calc_poc
Execute the binary using the provided retry wrapper, as heap layout stability may require multiple attempts:
# Run the PoC – it will retry until the allocator‑shaped layout hits
chmod +x ./cares_tcp_uaf_calc_poc
./scripts/run_until_hit.sh ./cares_tcp_uaf_calc_poc
# Expected output (proof marker)
CARES_RCE_PAYLOAD_TRIGGERED
run=N rc=77
c-ares control‑flow payload reached pid=...
Summary
- The c-ares TCP use-after-free vulnerability in
ares_getaddrinfo()enables remote code execution through crafted DNS-over-TCP response sequences - Exploitation requires specific initialization flags (
ARES_FLAG_EDNS | ARES_FLAG_USEVC) and attacker-controlled DNS servers to trigger the race condition - The PoC in
poc/cares_tcp_uaf_calc_poc.cdemonstrates full control-flow hijacking by overwriting skip-list node destructors - High-impact targets include Node.js, gRPC, Envoy, libcurl, and any applications bundling vulnerable c-ares versions
- Immediate remediation requires upgrading the library and auditing statically linked binaries for embedded vulnerable versions
Frequently Asked Questions
What versions of c-ares are affected by this TCP UAF vulnerability?
The vulnerability affects c-ares versions prior to the upstream security patch. Organizations should consult the official c-ares project release page and upgrade to the latest stable version that contains the specific fix for this use-after-free condition in the TCP resolver path. Statically linked applications must be recompiled against the patched library.
Can this vulnerability be exploited without DNS-over-TCP enabled?
No. The attack specifically requires the ARES_FLAG_USEVC flag to force TCP transport and typically requires ARES_FLAG_EDNS to trigger the retry logic that creates the race condition. Applications using UDP-only DNS resolution do not exercise the vulnerable code path described in this vulnerability.
How can I detect if my application is using a vulnerable c-ares library?
You can audit binaries using standard system tools: ldd identifies dynamically linked libraries, while strings or readelf can extract version symbols from static binaries. The README.md in the bikini/exploitarium repository provides specific operational triage questions and shell commands to verify whether your DNS resolution stack includes the vulnerable library version.
Does this vulnerability affect applications behind a firewall or using internal DNS?
Yes, if the application processes DNS responses from any source, including internal resolvers that might be compromised or spoofed. The vulnerability depends on processing malicious DNS responses rather than direct internet exposure, meaning insider threats or DNS cache poisoning attacks could trigger the condition even in firewalled environments.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →