Buffer Overflows Flashcards
What is the highest and lowest memory address used by Windows?
- lowest = 0x00000000
- highest = 0x7FFFFFFF
Define the Stack
- When a thread is running, it executes code from within the Program Image or from various DLLs (Dynamic Link Libraries)
- The thread requires short-term data areas for functions, local variables, and program control information….this short-term data area is the STACK
- To facilitate independent execution of multiple threads, each thread in a running application has its own STACK
Explain LIFO and the Stack
- Stack memory is “viewed” by the CPU as a Last-In First-Out structure
- Items put (“PUSHED”) onto the top of the Stack are removed (“POPPED”) first
- x86 architecture implements dedicated PUSH and POP assembly instructions in order to ADD or REMOVE data on the STACK
Explain Return Address
- When code within a Thread calls a Function, it must know which address to return to once the function completes
- This “RETURN ADDRESS” (along with the functions parameters and local variables) is stored on the Stack
- When a Function ends, the “RETURN ADDRESS” is taken from the Stack and used to restore the execution flow back to the main program or the “calling function”
CPU Registers
- To perform efficient code execution, the CPU maintains and uses a series of nine 32-bit registers
- Registers are small, extremely high-speed CPU storage locations where data can be efficiently read and manipulated.
What are the general purpose registers?
- EAX
- EBX
- ECX
- EDX
- ESI
- EDI
EAX
- Accumulator
- - Arithmetical and logical instructions
EBX
- Base
- - Base pointer for memory addresses
ECX
- Counter
- - Loop, shift, and rotation counter
EDX
- Data
- - I/O port addressing, multiplication, and division
ESI
- Source Index
- - Pointer addressing of data and source in string copy operations
EDI
- Destination Address
- - Pointer addressing of data and destination in string copy operations
ESP
- Stack Pointer
- - Keeps ‘track’ of the most recently referenced location on the Stack (top of the Stack) by storing a pointer to it
What does “pointer” mean?
- reference to an address (or location) in memory
- stores the target address
EBP
- Base Pointer
- stores a pointer to the top of the Stack when a function is called
- By accessing EBP, a function can easily reference information from its own Stack
EIP
- Instruction Pointer
- One of the most important registers because it points to the next code to be executed
- EIP directs the flow of a program
- ** The attacker’s primary target when exploiting any memory corruption vulnerability such as a buffer overflow ***
- ** Holy Grail for shellcoding ***
What is the goal of Fuzzing?
- provide the target application with input that is not handled correctly, resulting in an application crash
What are the summary steps of exploiting a Win32 Buffer Overflow?
- Validate EIP register fills with A’s
- Fill EIP with msf-pattern-create
- Locate EIP with msf-pattern-offset
- Locate space for the shellcode
- Check for Bad Characters
- Find a Return Address for our shellcode
- Generate Shellcode
- Add NOP Sled
- Run Netcat
- Get Reverse Shell
What is the first goal of exploiting a Win32 Buffer Overflow?
- gaining control of the EIP register
- EIP is like the reins of a horse
- We can use it to control the direction or flow of the application
What is the first step to knowing if we have modified the EIP register?
- Overflow the buffer with A’s
- See the EIP address value comprised of 41414141 (A’s from our Buffer)
What is the next thing we need to do to gain control of the EIP register? How do you do this?
- find out the exactly what part of the Fuzzing Input (Buffer of A’s) are hitting the EIP register
- Use a long string of non-repeating 4-byte chunks as our fuzzing input
- msf-pattern-create -l 800
- Place the generated pattern in the python script and rerun exploit
- EIP will now contain a new string (ex. 42306142
- msf-pattern-offset -l 800 -q 42306142
- This will tell you were exactly the offset is located (ex. 780)
- Adjust the fuzzer/filler string in python script to the offset value and add EIP and Buffer values
- filler = “A” * 780
- eip = “B” * 4
- buffer = “C” * 16
- inputBuffer = filler + eip + buffer
- resend the python exploit and you should now see the EIP value = 42424242 (4 B’s)
- ** The second set of C’s land at ESP
- ** We will want the next part to test for control of ESP
How do you locate space for the shellcode?
- A standard reverse shell payload requires approximately 350-400 bytes of space
- We need to run our test from 800 bytes to 1500 bytes and see if this allows enough space for our shellcode without breaking the buffer overflow condition or changing the nature of the crash.
- We need to update our python code to include 1500 D’s, less the length of the other 3 variables:
- filler = “A” * 700
- eip = “B” *4
- offset = “C” * 4
- buffer = “D” * (1500 - len(filler) -len(eip) - len(offset))
- This test works and shows us we have approximately 700 bytes of space for our shellcode
Which Bad Characters should always be excluded?
- 0x00 = null byte; this character is considered bad because a null byte is also used to terminate a string in low level languages such as C/C++
- this will cause the string copy (strcopy) operation to end, effectively truncating our buffer at the first instance of a null byte
- 0x0D = return character; should be avoided when sending the exploit as part of an HTTP POST request
- this signifies the end of an HTTP field
How do you determine which characters are bad for a given application?
- Send all possible characters, from 0x00 to 0xFF, as part of the buffer, and see how the application deals with these characters after the crash
- In the python script, replace the D’s with all possible hex characters, except 0x00
- badchars = ( “\x01\x02\x03\x04…….”)
- filler = “A” * 700
- eip = “B” *4
- offset = “C” * 4
- inputBuffer = filler + eip + offset + badchars
- ** After executing the python exploit, right-click on the ESP and select “Follow in Dump”, to show the input buffer hex characters in memory
- ** The output shows hex values 0x01 through 0x09 made it into the stack memory buffer…but 0x0A did not
- ** We remove 0x0A from our test script and resend the payload, resulting in the next bad character terminating in the stack memory buffer
- ** Keep doing this until all bad characters are discovered