Buffer overflow in "named" related to stats channel
Summary
The stats channel website used by named has a buffer overflow in the "process_request" function related to large HTTP headers. This could theoretically lead to a remote attacker gaining code execution but in practice simply crashes the "named" process due to a number of mitigations,both intentional and unintentional.
Vulnerability & Source Code Analysis
The named process has an optional stats channel webserver. This makes use of the picohttpparser in order to parse the request details, notably the headers of the request. These headers can have any name and length, despite the expectation of certain headers being a certain length. This leads to a security issue when the "If-Modified-Since" header is parsed in "process_request" as defined in "httpd.c", currently on 456 ( https://gitlab.isc.org/isc-projects/bind9/-/blob/main/lib/isc/httpd.c#L456) and on line 450 in the following commit ( beecde71) which introduced the vulnerability around 10 months ago.
The snippet of code in question with the buffer overflow.
} else if (name_match(header, "If-Modified-Since")) { char timestamp[ISC_FORMATHTTPTIMESTAMP_SIZE + 1]; memmove(timestamp, header->value, header->value_len); timestamp[header->value_len] = 0;
/* Ignore the value if it can't be parsed */ (void)isc_time_parsehttptimestamp( timestamp, &httpd->if_modified_since); }
While any reasonable timestamp will be smaller than what is defined in "ISC_FORMATHTTPTIMESTAMP_SIZE", the header can be of any size. By setting the header value for "If-Modified-Since" to be sufficiently long, we can overwrite values on the stack, theoretically leading to remote code execution in a worse case scenario.
Existing Mitigations
There are luckily some mitigating circumstances that limit the impact of this vulnerability, altering it from appearing to be fully unrestricted stack-based buffer overflow as exists in the source code.
- The stats channel is not enabled by default and the best practices for running it suggest blocking external IPs. However, a quick search on shodan shows several dozen of these web servers being public. I have not verified if they are vulnerable or not beyond connecting to verify they were indeed public. Additionally, to perform this attack, the attacker does not need to receive any data from the server and simply needs to send data to it, which increases the possible number of exploitation scenarios.
- The use of FORTIFY_SOURCE includes the automated replacing of memmove with memmove_chk, which will end the program if the buffer is overflowed. This means with default compilation settings, or at least as tested with the bind9 package on debian, the buffer overflow should always lead to a crash rather than leading to remote code execution. This changes the nature of the vulnerability from remote code execution to causing a server crash.
Bypass of Mitigations for 1 null byte overflow
However, mitigation number 2 has a slight caveat. When examining the compiled library "/lib/x86_64-linux-gnu/libisc-9.18.16-1-Debian.so" which contains the httpd code in question, I found that there is still the ability to cause a 1 byte buffer overflow without triggering a crash. The following code snippet is how the code is actually compiled, as seen in the decompiler GHIDRA and cleaned up by myself.
else if ((name_size == 17) && (match = strncasecmp(header,"If-Modified-Since",17), match == 0)) { __memmove_chk(timestamp,header->value,header->value_len,51); timestamp[len] = 0; isc_time_parsehttptimestamp(timestamp,&httpd->if_modified_since); }
FORTIFY only protects against insecure use of memmove, and will allow the target buffer to be entirely filled, terminating the program if the source length is just 1 larger than the length of the destination buffer. Since the last character of the timestamp is set to 0 to ensure a proper string null terminator. This means a buffer overflow can still occur if the length of the header value is exactly the size of the buffer it is being copied into, 51. 1 byte overflows on the stack have been shown to have potential to lead to full RCE in some scenarios, such as when the last byte of a pointer can be overwritten. However, in this specific compiled library, that does not appear to be the case due to padding for byte alignment reasons.
We cannot strictly guarantee how the compiler will order values on the stack, so some compilation may lead to the "timestamp" variable being able to overflow into a critical area. However, based on my own knowledge of compiler internals, I believe this to be a very unlikely scenario with the current value of ISC_FORMATHTTPTIMESTAMP_SIZE being 50. Since 50 + 1 is not a multiple of 4, it will normally have some "padding" bytes which exist to ensure alignment of variables.
Reproducing
Enable the stats channel server in named.conf, as described in current bind9 documentation. For me this meant appending "statistics-channels { inet 127.0.0.1 port 8080 ; };" to /etc/bind/named.conf
Run named, the easiest way I found to do this for testing the crash was "sudo /usr/sbin/named -f -u bind".
To trigger the crash, I used curl.
A request that won't overflow, only 50 bytes in the header. curl 'http://127.0.0.1:8080/' -H 'If-Modified-Since: 01234567890123456789012345678901234567890123456789'
A request that will overflow with a null byte and not crash, 51 bytes in the header. curl 'http://127.0.0.1:8080/' -H 'If-Modified-Since: 0123456789012345678901234567890123456789012345678901'
A request that will overflow the buffer and trigger FORTIFY protections, crashing named, 52 (could be more) bytes in the header. curl 'http://127.0.0.1:8080/' -H 'If-Modified-Since: 012345678901234567890123456789012345678901234567890'
This last curl command caused the following error to be printed by named as it exited.
*** buffer overflow detected ***: terminated zsh: IOT instruction sudo /usr/sbin/named -f -u bind
Version
Based on the releases found at https://www.isc.org/bind/
BIND 9.16.18 uses the old version httpd.c before the switch over to the current model with picohttpparser. Does NOT contain this vulnerability
BIND 9.18.17 affected by the crash as well as the 1 byte overflow due to mitigations. Verified my compiler assumptions discussed above.
BIND 9.19.15 affected by the crash as well as the 1 byte overflow due to mitigations. Verified my compiler assumptions discussed above.
Recommendations
I'd advise capping the length of header->value_len at the same length as ISC_FORMATHTTPTIMESTAMP_SIZE when the header is an "If-Modified-Since" header. This project seems to be actively maintained and I'm hesitant to submit a pull request myself as I don't fully understand enough of the codebase.
Final Notes
I do not know of this vulnerability being exploited in the wild, and to my knowledge, the only exploit of it has been performed by myself on my own machine.
While remote code execution is possible if bind-9 is compiled in certain ways, to my knowledge, there are no publicly available copies (such as in package managers) which are vulnerable. I have not checked every version ever released.
If any other projects use "isc_httpdmgr", such as internal ISC projects or simply other products I've not found, there is the potential for other similar vulnerabilities.
I'm Cameron Whitehead, a grad student doing some independent vulnerability research in open source software, primarily as I work on methods to better automate the detection and validation of vulnerabilities. I check this email fairly regularly, so if you need further assistance feel free to reach out.
Regards, Cameron