Binary Exploitation ELI5 — Part 2

Daniel A. Bloom
12 min readMay 2, 2018

--

Binary Exploitation ELI5 — Part 2

“ Wait a minute. Using an RX modulator, I might be able to conduct a mainframe cell direct and hack the uplink to the download.” — Hackerman, Kung Fury

0x00 — Preface

This article is part 2 to the Binary Exploitation ELI5 article series. For Part 1, please follow the below link:

Binary Exploitation ELI5 — Part 1

Throughout this article, we will be covering:

0x01 — Prerequisite Knowledge: Privilege and Exception Handling
0x02 — Defense: Stack Canaries
0x03 — Attack: Format String Vulnerabilities
0x04 — Attack: SEH Overwrites
0x05 — Defense: DEP / NX

Let’s get started!

0x01 — Prerequisite Knowledge: Privilege and Exception Handling

As you get more and more into computers, you’ll likely hear the terms Kernel and userland thrown around pretty often. If we try to search for a definition for the kernel here’s what we’ll find:

The Kernel is the core of an operating system and has complete control over everything (processor, memory, chips, etc.) on the system. Whenever a program needs to do anything (i.e. write to files, open network connections, etc.), it hands control of user-space processing to the kernel temporarily.

While this definition gives us a pretty good understanding as to what the kernel is, let’s take a quick look at an analogy I used for my Explain Spectre and Meltdown Like I’m 5 article:

Whenever Batman and the rest of the Justice League are out fighting mega-criminals, Alfred (the kernel) is handed control of the Batcave (the processor) so that he can provide important information and help the group win. When the team defeats the bad guys, Batman relieves Alfred of his control and takes the Batcave back.

To break it down, the kernel is simply the back-end of your operating system that does all the heavy lifting (i.e. memory management, etc.) for your applications. The userland, on the other hand, is the memory space where regular applications run. Much like Batman and the Justice League, userland applications need to hand over control to the kernel (alfred) whenever privileged information is needed.

This sort of privilege separation is used heavily within computers. However, while Batman and the Justice League only really have 2 categories of privilege, computers have 4 separate “Rings” of privilege.

The Rings of Privilege

As you can see, Applications run in the least-privileged ring. However, obviously sometimes applications need to access some privileged information or functions (i.e. Making network connections, memory management functions, etc.). In this case, the application will use specific functions called syscalls, which act as a bridge between the different privilege rings.

One easy way to think of privilege rings could be levels in a video game:

To increase general ability throughout the game (whether it be upgrading armor or weapons, getting to different worlds, or finally rescuing the princess from the spiky turtle man) the player has to navigate through different environments. If the player tries to skip a level he/she won’t have the strength or resources to defeat the boss in the level they skipped to! They’ll fail!

Mario Failing with a Fall-Into-Pit Exception

When a userland application tries to access privileged information, the application will fail with an exception. This means that the application will crash and output a crash report. In addition to attempting to access privileged memory or functions from an unprivileged (userland) environment, programs can fail with an exception for lots of reasons. For example, if a program tries to divide something by 0 (which, as we all know, doesn’t work), the program will fail with an ArithmeticException.

Now, while simply understanding that programs can fail is important, we need to discuss what actually happens when a program fails. This is where Structured Exception Handlers (SEH) comes in. Before we talk about what Structured Exception Handlers are and how they work, let’s use Indiana Jones as an example:

In the 1981 movie “Indiana Jones and the Raiders of the Lost Ark”, Jones and his small group go on a quest to locate the lost Ark of the Covenant. Along his route, Jones and his team encounter many traps, such as poison darts and giant boulders, that are triggered by secret pressure plates or switches. Indiana and his team have to try to survive all these traps and more to achieve their goals.

In Indiana Jones and the Raiders of the Lost Ark, traps are set all throughout the dungeons and caves that Indiana and his team have to navigate. These traps, which were planted years before Indiana Jones was even alive, serve to protect the Golden Statue at the heart of the adventure. Along the same vein, Programs have their own sort of traps, from privilege mismatches and access denial to logic and arithmetic errors, programs have lots of ways to prevent (handle) errors or bad operations. Furthermore, programmers are able to implement custom exception handlers through function such as try-catch blocks which try a block of code and catch any errors or exceptions in order to handle them.

In many operating systems (we’ll be talking more specifically about Microsoft’s structured exception handlers), there are systems in place to handle any exceptions that weren’t originally caught by an exception handler. This is to say, if an error is caught but isn’t properly handled, the operating system will escalate the exception handling and redirect the caught exception to a separate structured exception handler. If the exception continues to not be properly handled, the application will just crash.

ASCII Structured Exception Handling Diagram

One additional thing to note is that when a program fails with an exception it the program very briefly gains access to higher levels of privilege as information about the crash is retrieved.

0x02 — Defense: Stack Canaries

In the last article, we spoke about Stack Buffer Overflows and the danger (or benefit, depending on which side of the attack you’re on) of being able to overwrite data on the stack. Over the years, many types of defenses have been implemented into compilers and operating systems in order to defend against these attacks. In this section, we’ll be talking about Stack Canaries which are an extremely common, and extremely basic, form of overflow defense.

Stack Canaries are actually named after the analogy most commonly used to describe them, the canary in a coal mine.

In or around 1913, John Scott Haldane proposed the use of canaries or other warm blooded animals in deep mines in order to detect carbon monoxide. The theory was that, since birds were far more sensitive to carbon monoxide than humans, if miners saw the birds getting sick they would know that the air was polluted with carbon monoxide and, as such, would be able to get out of the cavern before being affected by the gas.

Much like the famed canary in the coal mine, stack canaries alert the program that something isn’t right, allowing the program to exit before any malicious operation could take place. This is done by placing a long random number on the stack at after space is allocated for local variables and then checking the long random number before the function returns. If the stack canary was overwritten by a stack buffer overflow attack, the program would exit.

ASCII Stack Canary Diagram

While Stack Canaries are common-sense defenses against overflow attacks, they are far from unbeatable. Let’s take a look at some attacks next.

0x03 — Attack: Format String Vulnerabilities

One method of defeating Stack Canaries would be to simply figure out where on the stack they are / what the random value is so that you could perfectly overwrite the canary during an overflow attack. However, as I mentioned earlier, Stack Canary values are large random numbers and, as such, it would be extremely difficult to just ‘know’ where a stack canary is. Furthermore, when developing exploits for applications, you are not able to debug (run the program through another special program that controls its operations and displays data and information as it passes through the program during runtime) the program and simply view the stack / manually search for the canary. So how on earth would we retrieve that information?

Well, that could be where Format String Vulnerabilities come in. Before we discuss the actual vulnerability, let’s talk a little about what a format string is.

In many programming languages (though we’ll be talking specifically about C in this article) there is an output function called printf (or something similar). printf is a function used to format and print data. To use this function, the programmer inputs:

printf(“formatting”, variables)

for example, if a programmer wanted to print out the value of the integer variable intvar, they would simply execute:

printf(“%i”, intvar)

In the above, the %i is called a format specifier and it simply specifies the format of the variable being printed out. While there are many useful format specifiers, such as %s which specifies a string value (general text, i.e. “hello”, “123”, etc. (just text within a double quote block (“ ”) ) ). However, the two format specifiers most important to us in this case are:

%x — The format specifier for hexadecimal values
%n —A special format specifier that allows us to actually write data to a variable, rather than read data from a variable

Some of you may be seeing where I’m going with this, but let’s take a look at a little example:

Bob just enrolled for some online banking through UHB (which stands for UnHackable Bank) When Bob goes onto the UHB website, he is met with an “Enter your account number” prompt. When Bob enters his account number, the bank displays his account information and he’s able to check on and move his money around freely. One day, Bob goes to his bank’s website but when prompted with “Enter your account number”, Bob accidentally mistypes his account number. Instead of saying “Incorrect Account”, Bob is brought to another customer’s account and is able to look at and move this other customer’s money.

Being able to display arbitrary information is a massive security hole. However, being able to display and manipulate arbitrary information is a catastrophic security hole, which is exactly what a format string vulnerability is.

If a user is able to directly input a string into a printf statement without any sort of checks occurring, they could simply enter %x to display the information on the stack since, as we know from the previous article, variables and other data are stored on the stack. Furthermore, if the malicious user continues to input %x’s, they could eventually leak extremely sensitive information such as exception handler pointers (the address in memory where a function should redirect an error for handling) or even stack canaries.

Furthermore, while simply being able to see arbitrary data from memory is a massive issue, if a malicious user has full access to the printf call they can also overwrite data using the %n format specifier. This means that a malicious user could copy and overwrite stack canaries with the correct value and then perform a ret2libc attack (discussed in the first article) or overwrite the function’s return pointer to some other malicious payload.

Let’s take a look at a little example:

ASCII Diagram of Format String Vulnerability Exploitation

Let’s break the above diagram down into sections.

please note: The above example’s stack is abridged and does not show the

First, the code:

Code Vulnerable to Format String Exploitation

First, we set up two string type variables — inputvar and stackvar.
Next, we read the user’s input through the readuserinput function and store said input in the inputvar variable. Then, we use a printf statement with the format specifier %s and pass in inputvar.

The vulnerability in the above code stems from the user’s ability to directly affect the printf statement without any checks for format specifiers.

Now, take a look at the above diagram of the entire attack. As you can see, when a user inputs regular, non format-specifier, input nothing special happens. However, when a user inputs “%x %x %x” the program outputs the contents of the stack (please note: %x outputs the contents of the stack in hexadecimal format. In this example I used just basic text and numbers so that it would be easier to understand). Furthermore, if a user uses %n to overwrite the stack cookie and the return pointer, he/she would be able to redirect the program to a malicious payload.

0x04 — Attack: SEH Overwrites

Much like ret2libc attacks, SEH (Structured Exception Handler) Overwrites are attacks that have to do with overwriting a pointer to a different function. However, while ret2libc attacks were based on overwriting a return pointer to redirect the program toward a specific libc function, SEH Overwrites function by overwriting an exception handler pointer and then triggering an exception so the program redirects to our malicious payload.

You can sort of think of SEH Overflows like insurance fraud:

Bob has a boat with a massive insurance policy that far outweighs how much he would get if he simply sold the boat. Bob, being the criminal that he is, decides that he’ll try to trick the insurance company by staging a gas leak and blowing the boat up so that he can claim the insurance money. After a couple weeks of planning, Bob blows his boat up. After some investigation, the insurance company is not able to definitively prove that Bob’s boat didn’t in fact blow up as a result of a gas leak and, as such, paid claim.

Much like Bob’s insurance fraud, SEH Overwrite attacks force an exception handler to navigate to a malicious user’s payload rather than properly handle the exception. These attacks can be done utilizing format string vulnerabilities or general stack buffer overflow attacks, as the exception handler pointer is simply an address that’s stored on the stack. To execute this vulnerability, a malicious agent would need to overwrite the exception handler pointer to point to a malicious payload rather than the actual exception handler and then the user would need to trigger an exception. Once that exception is caught, it will be redirected to the malicious function which can then discard the exception and execute it’s payload.

ASCII SEH Overwrite Diagram

0x05 — Defense: DEP / NX

By now, you’ve probably realized that unrestricted access to the stack is an extremely dangerous thing to allow. Furthermore, even with Stack Canaries acting as defenses, malicious users can redirect the program’s execution or even add malicious functions and features to the program easily with the help of format string exploits. However, as we progress through this series you’ll quickly learn that while there’s plenty of attacks, there’s plenty of defenses as well. In this section, we’ll be talking about Data Execution Prevention (DEP) and Non-Executable memory (NX).

A good way to think of DEP and NX could be the old dots and boxes game.

In dots and boxes, two players start with a grid of dots. During each turn, a player gets to draw one line connecting two dots. If a player closes a square, that player colors in the dot with Red (if player one) and Green(if player two). At the end of the game, whichever player has the most colored in squares wins.

Now, Imagine the box in your head (or see picture below from wikihow):

dots and boxes game

Instead of a grid of dots and boxes, let’s imagine each square to be a region of memory on your computer. The Red regions are regions that allow data execution and the Green regions do not allow data execution.

This is precisely what DEP and NX are. They’re simply mechanisms that block the execution of written memory (i.e. malicious code) in different memory areas. For example, most modern programs have DEP enabled on the stack so that malicious users can’t execute payloads through the stack.

In an ideal world, computers would use a write xor execute policy on all memory sections, however, there are a few large reasons why this cannot be the case. A write xor execute policy is one in which memory would be exclusively writeable or exclusively executable, but never both. This cannot be the case for all memory sections for a number of reasons, however, these will be covered in future articles. However, for some memory regions, such as the stack, DEP and NX make this possible.

0x05 — Part 2 Conclusion

In this article we covered:

0x01. The Kernel and the rings of privilege
0x02. Exceptions and Structured Exception Handlers
0x03. Structured Exception Handler Overwrite Attacks
0x04. Format Strings and the printf command
0x05. Format String Vulnerabilities and Exploitation
0x06. Data Execution Prevention and Non-Executable Memory

I hope this article was helpful. Please keep an eye out for the next part of this series, where we’ll be going over some more attacks and defenses.

If you haven’t yet, please read the first article in this series:

Binary Exploitation ELI5 — Part 1

string thanks = “”;
string for = “reading”;
readfromuser(thanks);
printf(“%s”, thanks)

--

--

Daniel A. Bloom

Daniel Bloom is a young, self taught, entrepreneur and the Founder of Bloom Cyber Defense, LLC — http://bcdefense.com — Twitter: @bcdannyboy