Smashing The Stack in 2020

There are great tutorials on stack-based buffer overflows but in 2020 a lot times the software used in those examples isn’t available anymore. This makes it difficult to follow along. For this series, I’ll mine ExploitDB for the latest exploits to share walk-throughs of.

Requiring The Basics

There are some basic requirements when starting off in exploit development.

A Windows and Linux based box with appropriate tools.

http://zeroknights.com/getting-started-exploit-lab/

http://zeroknights.com/getting-started-exploit-lab/ A basic understanding of Python, Perl, Ruby or another scripting language

A basic understanding of x86 assembly language (don’t worry, you’ll learn as you go)

Some strongly caffeinated beverages, a passion to pwn and tunnel vision

A Short Intro To Assembly

Every piece of software uses memory to store/retrieve information and instructions. This information can be the graphical design of the current screen you see, functions in the software’s code or input you give to the application.

The part of memory we are going to focus on in this series is the stack segment. This is the part of memory that stores functions, variables and user input. The stack operates on a Last-In First-Out (LIFO) architecture. This means the data contained in the last register that we push onto the stack is the first data to be popped into a register. Our focus will revolve around these registers in the x86 stack:

EAX : accumulator : used for performing calculations, and used to store return values from function calls. Basic operations such as add, subtract, compare use this general-purpose register

: accumulator : used for performing calculations, and used to store return values from function calls. Basic operations such as add, subtract, compare use this general-purpose register EBX : base (does not have anything to do with base pointer). It has no general purpose and can be used to store data.

: base (does not have anything to do with base pointer). It has no general purpose and can be used to store data. ECX : counter : used for iterations. ECX counts downward.

: counter : used for iterations. ECX counts downward. EDX : data : this is an extension of the EAX register. It allows for more complex calculations (multiply, divide) by allowing extra data to be stored to facilitate those calculations.

: data : this is an extension of the EAX register. It allows for more complex calculations (multiply, divide) by allowing extra data to be stored to facilitate those calculations. ESP : stack pointer

: stack pointer EBP : base pointer

: base pointer ESI : source index : holds location of input data

: source index : holds location of input data EDI : destination index : points to location of where result of data operation is stored

: destination index : points to location of where result of data operation is stored EIP : instruction pointer

Important Register Info

The registers we want to look more at are EIP, ESP, EBP and the location of the return address. By controlling these registers we can control the flow of execution within the application.

EIP holds the memory address to the next set of instructions to be executed.

ESP is the current location in the stack. The stack always grows toward lower memory addresses and ESP always points to the top.

EBP – When an application enters a function or subroutine it will create a new stack frame. The starting memory address of the function/subroutine will be stored in EBP. The memory address just prior to entering the function/subroutine will be stored on top of EBP (EBP + 4 byte) and this is called the Return Address. Once the function/subroutine completes, the instruction RET is called, the Return Address is placed in EIP and then executed.

What is a Stack-Based Buffer Overflow?

A stack-based buffer overflow is a vulnerability where the software is not correctly validating the length of user input. With this in hand a malicious user can enter a larger amount of input than the program is expecting which results in a chunk of memory being overwritten.

With carefully crafted input the malicious user can control the flow of the application by overwriting instructions in memory that are then executed. This malicious input will almost always contain shellcode which is a specially crafted set of CPU instructions that have a desired outcome such as binding a port on the target machine or popping calculator.

Enough Talk. Let’s Hack Something

Break out your Windows XP machine and download Streamripper 2.6. You can find an existing exploit for this vulnerability here, but we are going to walk through the process of creating this exploit from scratch.

Once you have installed Streamripper on your Windows XP machine, open Immunity Debugger and attach (File->Attach) to the Streamripper process. Press the play button in Immunity to continue running the program. Next open Notepad++ and let’s start trying to trigger this vuln. Write out your exploit code like it is below.

We are creating a file, evil.txt, that contains 500 As. Run your Python script, open evil.txt and copy the data. In Streamripper where you see Station/Song Matching, click add and then add then paste your 500 As and press OK. You just successfully crashed the program, go to Immunity Debugger to see what’s going on.

We Have The Control!

Looking at our registers in the top right corner of Immunity we can see we have overwritten EIP as well as ESP and EBP with our As. Now that we control EIP we can place a memory address of our choosing into it and direct execution to that address in memory.

Remember that the instructions contained at a given memory address in EIP are executed on the stack next. If we know where in memory our shellcode will be, we can set that location in EIP and execute it.

Let’s Call On Mona For Help

Now that we know we can overwrite a chunk of memory. Let’s dig further. We know we control EIP, but now we need to know exactly where EIP is. This is where Mona comes into play. On the bottom of Immunity Debugger is a command line input field (if you can see in the pic above mine says !mona findmsp). On this command line type the command !mona pattern_create 500. This creates a 500 character Metasploit pattern that Mona can use to help identify the location of registers in the stack.

Once Mona has generated the pattern go to C:\Program Files\Immunity Inc\Immunity Debugger and open pattern.txt. You can use the ASCII or the hex values. For this example, I’ll use the ASCII set. Copy the ASCII characters and replace the “A”*500 in your exploit code with these.

Run your exploit and copy the contents of evil.txt. In Immunity Debugger you can press the rewind button to restart Streamripper and press play to run it. Just like before in Streamripper under Station/Song matching click add, paste your evil payload and press OK.

In Immunity Debugger on the command line, enter the command !mona findmsp to find the Metasploit pattern you just used as a payload. Mona will now tell you where EIP is located. In this example, EIP is located 256 bytes into our payload.

Let’s update our exploit with this information. We will use 256 As to get us next to EIP which we will fill with 4 Bs (4 bytes) and then we’ll top it off with 230 Cs to keep our same 500 byte payload.

Same as before, run your exploit, copy the contents of evil.txt, press rewind and play in Immunity Debugger, paste the payload into the Add Station/Songs Matching and go back to Immunity Debugger for the results.

We can see that our 4 Bs are in EIP (42424242 is hex for BBBB) and ESP contains our Cs. If we can place our shellcode in ESP and jump to ESP it’s game over for Streamripper. First we need to find an address that we can place into EIP that will jump to ESP. Mona to the rescue again. In the command line of Immunity Debugger use the command !mona jmp -r esp. This will give us a list of addresses in Streamripper that have the instruction to jump to ESP (jmp esp).

When we are looking for addresses there are certain characteristics we have to look out for. We can’t use addresses that have bad characters in them. For this example we have to avoid addresses that contain 00. 00 is a no no for most exploit development because 0x00, a null byte, signifies string termination and a program will stop reading the data at that point. Mona will help with this issue and tell you if an address contains a null byte.

We prefer addresses that are apart of the application and not the OS. Using OS addresses limit our ability to use the exploit across multiple platforms. This is not always a choice we have and sometimes we must use OS addresses. We also want to stick to addresses that have ASLR off, SafeSEH off, Rebase off, etc. Mona will help detail all of this information for you. So lets get back to it and see the results.

For this example, we don’t have a choice and have to use an address from the OS and one with SafeSEH on. Since this isn’t an SEH exploit, we aren’t worried about SafeSEH. The address we will use is 0x773f36f8. We will replace our BBBB with this address. Because the stack moves from high to low, we will place this address in our buffer backwards.

This time, press rewind and play to start Streamripper with Immunity attached. In the disassembler in the top right of Immunity, right click and goto expression 0x773f36f8 and press F2 to set a breakpoint. Like before run your exploit, copy your payload and paste it into Streamripper. In Immunity you will see you are stopped at your breakpoint. By pressing F7 you can execute the next instruction which is your jmp ESP. This will take you into the start of your Cs.

Let’s Finish This. Pwn Streamripper

I will use a piece of shellcode, which is a set of instructions that once executed will open calculator.exe to complete the pwnage. Because ESP contains our Cs, we will replace these with a small 10 byte nopsled and our shellcode, then finish it off with Cs to keep the 500 byte length.

A NOP (0x90) is a no-operation instruction so these act as padding when needed. A nopsled helps by giving us a smooth transition into the shellcode. Ok, enough about that, let’s see some code and finish this!

Just as before, start Streamripper, run your exploit, copy the payload and paste into Streamripper. There pops the calculator! PWND! You have just completed a vanilla buffer overflow!

I hope you enjoyed this walk-through and I’ll be writing more advanced articles on buffer overflow exploits so keep checking back! If you have any questions or comments feel free to leave a comment or hit me up on Twitter!