Various technical and personal blog articles I've written.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5.5 KiB

The Importance of Exploit Mitigations

When an operating system ships without exploit mitigations, attackers will have an easy time exploiting systems. Over the past sixteen years, grsecurity has been raising the bar for attackers, providing innovative solutions to extremely difficult problems. The goal of exploit mitigations is to drive the costs up for an attacker such that they are outside the economics of the attacker.

FreeBSD is the only enterprise operating system today that lacks exploit mitigations. Attackers can reuse exploits without modification against FreeBSD systems. Exploitation of vulnerable applications is relatively easy and painless.

HardenedBSD, a fork of FreeBSD, is porting the grsecurity patchset in order to frustrate attackers and drive up their costs. As we will see in this article, the bar has been raised drastically. HardenedBSD’s exploit mitigations provide excellent security for the FreeBSD community.

The NTP CVEs

On 21 March 2017, the NTP project announced several CVEs. Some of those CVEs apply only to Windows systems, others involve injecting malcious configurations from a malicious NTP server to an unwitting NTP client. We’ll be focusing on one of the two NTP vulnerabilities applicable to FreeBSD that involved stack-based buffer overflows (CVE-2017-6458).

About CVE-2017-6458

CVE-2017-6458 is a classic stack-based buffer overflow. There are several affected functions, but they all generally follow the same pattern as ctl_putstr below.

/*
 * ctl_putstr - write a tagged string into the response packet
 *		in the form:
 *
 *		tag="data"
 *
 *		len is the data length excluding the NUL terminator,
 *		as in ctl_putstr("var", "value", strlen("value"));
 */
static void
ctl_putstr(
	const char *	tag,
	const char *	data,
	size_t		len
	)
{
	char buffer[512];
	char *cp;
	size_t tl;

	tl = strlen(tag);
	memcpy(buffer, tag, tl); /* <- here's your buffer overflow */
	cp = buffer + tl;
	if (len > 0) {
		INSIST(tl + 3 + len <= sizeof(buffer));
		*cp++ = '=';
		*cp++ = '"';
		memcpy(cp, data, len);
		cp += len;
		*cp++ = '"';
	}
	ctl_putdata(buffer, (u_int)(cp - buffer), 0);
}

The length of tag is not checked prior to copying the contents of tag into buffer. tag could be larger than 512 bytes. An attacker can make use of this by crafting malicious data that overflows buffer, spilling into the stack canary and return address. Stack canaries are extremely easy to bypass these days, so having it is moot point.

Applicable Exploit Mitigations

Without any exploit mitigations, crafting malicious payload to trigger the exploit and gain arbitrary code execution would be simple. An attacker only needs to follow the call path and deduce the memory layout. The attacker would be able to craft a reusable payload that works reliably 100% of the time, given a predictable and reproducable memory layout.

Thus, Address Space Layout Randomization (ASLR), would prevent an attacker from knowing where the buffer lies in memory. The attacker would still be able to overflow the buffer, but he or she should not know the addresses needed for successful exploitation without a second vulnerability: an information leak. HardenedBSD’s implementation of ASLR follows the PaX design and is enabled by default on all architectures.

SafeStack, which is enabled by default in HardenedBSD 12-CURRENT/amd64, would mitigate this vulnerability. By placing the unsafe data (the buffer) on the unsafe stack, the vulnerability turns from an arbitrary code execution vulnerability into a data-only vulnerability. The attacker would only be able to overflow into other buffers and data considered unsafe.

The current implementation of SafeStack requires ASLR at a minimum to be effective. The unsafe stack is placed in a random spot in memory. However, SafeStack relies on the operating system’s virtual memory subsystem to perform the randomized mapping. If an attacker could deduce where the unsafe stack in memory lies, the attacker could bypass SafeStack.

Additionally, SafeStack is enhanced by W^X. If an attacker could reliably create memory mappings that were both writable and executable (or upgrade a writable page to executable (RW -> RX)), the attacker would be able to bypass SafeStack.

HardenedBSD 12-CURRENT/amd64 also ships with non-Cross-DSO Control-Flow Integrity (CFI) by default. If an attacker was able to overflow the buffer and modify a function pointer, CFI would disallow calling the function pointer as the function pointer would not point to a valid code path determined by the compiler and runtime for that function pointer.

Cross-DSO CFI, which is not yet available in HardenedBSD, also builds on top of ASLR and W^X. Cross-DSO CFI requires storing in memory metadata about loaded shared objects and function references. Even though Cross-DSO CFI is still a work-in-progress in HardenedBSD, non-Cross-DSO CFI would still be effective against CVE-2017-6458 since the code in question resides in the application code, not in a shared library.

Conclusion

With ASLR, W^X, SafeStack, and CFI enabled in HardenedBSD 12-CURRENT/amd64, attackers will have an extremely difficult time successfully exploiting CVE-2017-6458. When multiple exploit mitigations are enabled and a holistic approach to security is taken, the cost of exploitation is driven upwards. Exploitation on FreeBSD, given its complete lack of meaningful exploit mitigations, would be relatively simple.