Memory Corruption Vulnerabilities

December 28, 2017

In the previous post, some brief information on analyzing memory corruption issues was given. In the following post, a few prevalent issues in this category that can lead to security impacts will be addressed.

Introduction:

It all starts with a runtime error leading to a crash, but in the end, it all boils down to one question: whether a memory corruption issue can be exploited or not. The exploitability of a memory corruption vulnerability depends on lot of factors and exploit developers generally face a lot of challenges (and frustrations due to exploit mitigations and countermeasures) while developing a `reliable` exploit. Sometimes a vulnerability that is not exploitable at the moment may become exploitable in the upcoming releases; sometimes a reliable exploit can be developed by chaining multiple low level vulnerabilities. The price of a `reliable` exploit normally ranges from $10,000 to $1 Million or more; depending on the target and respective `market’s` business model. Hence, such vulnerabilities are usually treated as exploitable by default.

Got SIGSEGV / SIGABRT?

The memory corruption issues in a software are identified if a crash has occurred during its `runtime`  when accessing the contents at an arbitrary memory location that was not programmatically intended. Such vulnerabilities in the open source software we’ve analyzed (in C, C++, Ruby, Golang packages) were identified primarily through fuzzing (mostly AFL) the application binary - basically, a new issue in its source code repositories was created with the respective crash reports as attachments.

Manually identifying them is quite challenging due to the fact that a range of typical scenarios or boundary conditions have to addressed just by reading the source code. Some vulnerabilities are easy to find at the assembly level but not at the source code level. For example, integer errors like sign extensions can be identified easily using disassemblers by observing `movsx` instructions (in Intel platforms); however, it is usually hard to interpret the value changing type conversions causing sign-extensions (eg: signed char to unsigned int) that are performed by the compiler, just by reading the source code.

A few scenarios addressing a software’s operations that leads to memory corruptions are mentioned below.

Exploitability Factors:

There are number of factors that are considered while developing a fully functional and reliable exploit. However, we’ll address a few while tackling the vulnerable scenarios mentioned in the previous section that are essential for a developer to contextualize the impact of a memory corruption in her/his code.

There are complex cases as well, for example:

Summary:

A motivated attacker can compromise the software with a multitude of techniques. For example, if the buffer’s size is not enough to hold the required shell code or if the stack segments are non-executable (NX), or even if the program is dropping the privileges upon executing an argument (`/bin/sh`) to `system()` function call; the attacker still find a way by chaining up the required trampolines and conduct a ret2libc style attacks, even restoring the privileges by invoking `setreuid()`.

Hence, memory corruption issues shouldn’t be regarded as low priority issues even if they cannot be exploited at that moment. The developers must treat all memory corruption issues as exploitable by default.

Credit: ACE Team - Loginsoft

Get notified

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

BLOGS AND RESOURCES

Latest Articles