Frank DENIS random thoughts.

CVE-2015-7547: don't panic, don't spread fear

In case you missed it, a new vulnerability in the GNU C library was recently exposed. That one is in the stub resolver. The getaddrinfo() function has the ability to resolve A and AAAA queries simultaneously, but doesn’t properly manage the buffers receiving the responses. And more than 2048 bytes, the size of a stack-allocated buffer, can be overwritten. Exploitation beyond a DoS has been reported to be possible even with mitigations of modern Linux distributions.

Vulnerabilities in stub resolvers are actually fairly common. For example, Nginx had quite of few of them, but bugs in a C library sound more scary and deserve more press.

Stub resolvers never directly get responses from (potentially malicious, trying to exploit CVE-2015-7547) authoritative servers. They ask a recursive DNS server. Running BIND, Unbound, PowerDNS, whatever. Or, more likely, a fork of dnsmasq on your router. In this context, they all play the same role.

Resolvers receive quite a lot of untrusted DNS responses, so them being vulnerable to CVE-2015-7547 could be really bad. However, this is not going to happen. DNS resolvers just don’t use getaddrinfo(), a function that wouldn’t work at all for this purpose, as it doesn’t allow specifying where the query should be sent to, in addition to being limited to two query types and to being a blocking call.

According to the excellent patch description, there are different ways to trigger the vulnerability, using TCP or UDP.

Using TCP

Using TCP requires closing the connection or sending invalid, short responses. No matter the responses it is receiving or forwarding, a recursive server is very unlikely to ever have this behavior. So, the only realistic way to exploit this vulnerability using TCP is by a man-in-the-middle, namely an active attacker between the resolver and the client.

If an active attacker can read and inject arbitrary TCP packets, things are pretty bad already. But this can add the ability to run arbitrary code.

Using UDP

According to the advisory, it takes 3 specially-crafted UDP responses to exploit the vulnerability: one being a valid 2048-bytes long responses, one triggering a retry, and a last one being larger than 2048 bytes, smashing random things on the stack for fun and profit.

Lifting the restriction that the third packet must be valid opens more options for writing a working exploit, but this statement seems to have been overlooked by many:

A back of the envelope analysis shows that it should be possible to write correctly formed DNS responses with attacker controlled payloads that will penetrate a DNS cache hierarchy and therefore allow attackers to exploit machines behind such caches.

To recap:

A man-in-the-middle (your ISP or an active attacker on your local network) between your client and the resolver may easily exploit this. The DNS resolver you are using doesn’t make any difference at all. Without a MITM between the resolver and the vulnerable glibc stub resolver, responses have to be valid. There might be niche resolvers that pass responses as-is, but they are statistically insignificant. According to the patch/advisory, this may still exploitable.

Google DNS truncates UDP responses (to questions without the DO bit) to 512 bytes. This is useless against MITM attacks. So does djbdns (dnscache). OpenDNS runs it with a patch to send UDP responses up to 4 Kb (down from 16 Kb not so long ago). This does nothing against MITM attacks but also provides zero protection against exploits fitting in valid responses. Tweaking the Unbound settings to lower the maximum UDP size, or adding scripts to do it on other software doesn’t fix anything either. The limitation of the response size, if any, has to be done on the client.

A simple way to eliminate the man-in-the-middle case is to run a local resolver. The infamous systemd now has systemd-resolved.service that fits the bill. Unbound is another option. Most Ubuntu systems are installed with a local dnsmasq instance by default. On a residential network, the router is likely to be already intercepting queries to port 53, and redirecting them to its own local caching resolver.

If you are concerned about man-in-the-middle attacks, but don’t want to run a local caching resolver (why, oh why?), use DNSCrypt. Responses not coming from the resolver will be dropped. That’s exactly what it was made for.

The advisory mentions some mitigating factors: dropping UDP packets above 512 bytes, disabling edns0 like it’s the 1980s and limiting TCP responses to 1024 bytes.

With all due respect, these recommendations are terrible, and following them would be a significant regression in addition to breaking valid responses. It wouldn’t be surprising if these recommendations made more actual damage than the vulnerability itself.

So: don’t panic. Yes, there’s an PoC out there. Which doesn’t execute code. And requires an environment that probably doesn’t match yours. You should be afraid of two things: MITM attacks, that this vulnerability renders only slightly more powerful, and exploits fitting in valid responses, that haven’t been observed yet.

Just patch your system, and restart all the processes. Static binaries are likely to use NSS, which dynamically loads the libresolv library. So, relinking these should not be necessary.

Maybe take it as an opportunity to give distributions using a better C library a try.