systemd Vulnerability Leads to Denial of Service on Linux
Many Linux distributions are at risk due to a recently disclosed flaw in systemd: a flaw in its DNS resolver could cause a denial-of-service attack on vulnerable systems. The vulnerability is exploited by having the vulnerable system send a DNS query to a DNS server controlled by the attackers. The DNS server would then return a specially crafted query, causing systemd to enter an infinite loop that pins the system’s CPU usage to 100%. This vulnerability was assigned CVE-2017-15908.
There are multiple ways to get the user to query a DNS server under the control of a threat actor, but the easiest would be to get the user’s system to visit a domain controlled by the attacker. This could be done using malware or social engineering.
The most effective fix for this flaw is to patch the underlying flaw in systemd. We first discovered this flaw in July of this year and reported it to the appropriate vendors via the Zero-Day Initiative (ZDI) in the same month. Independent researchers found the same vulnerability in October of this year and reported it to Canonical. Fixes were rolled out to various Linux distributions such as Ubuntu in late October as well. Fortunately, no attacks against this vulnerability are known to be in the wild yet.
Analysis of the Vulnerability
New functions have been added to DNS over time, both to add new features and make it more secure. One of the new types of resource records added in DNS Security Extensions (DNSSEC), as defined in RFC 4034, was the NSEC (Next Secure) record.
The vulnerability lies in the processing of the bits representing pseudo-types in the NSEC bitmap. The image below shows the code section and stack frame. The highlighted line “continue” shows where the “while loop” enters an infinite loop. The dns_packet_read_type_window() implementation is in the file resolved-dns-packet.c.
Figure 1. Source code of infinite loop and stack frame
Note that the above function dns_packet_read_type_window() is called from dns_packet_read_rr()when the record type is DNS_TYPE_NSEC. The image below shows the code section of dns_packet_read_rr() in the file resolved-dns-packet.c.
Figure 2. Source code of reading DNS packets
Proof of Concept
To test this vulnerability, we created a custom DNS server which would send back maliciously formed replies. This reply contained an NSEC record designed to trigger the vulnerability, as seen below:
Figure 3. Packet capture of specially crafted DNS reply
Once a system running systemd uses it for DNS resolution, it will receive this specially crafted DNS packet, and the CPU utilization would hit 100%, as seen here:
Figure 4. Maximized CPU utilization
As we noted earlier, fixes to this vulnerability have been released. We recommend applying these to systems at risk as soon as possible.
System administrators may also opt to block potentially malicious packets manually. Incoming DNS responses should be checked to see if they contain resource records as specified in section 4 of RFC 4034.
Monitor incoming DNS response traffic and detect if the DNS RRs in the answer section contains DNS and record of types as specified in the RFC 4034 section 4, which defines NSEC RRs. If the attached bitmap is processed and contains pseudo-types, it should be blocked.