CNIT 127: Exploit Development
Ch 2: Stack Overflows in Linux
Stack-based Buffer Overflows
• Most popular and best understood
exploitation method
• Aleph One's "Smashing the Stack for Fun and
Profit" (1996)
– Link Ch 2a
• Buffer
– A limited, contiguously allocated set of memory
– In C, usually an array
C and C++ Lack Bounds-Checking
• It is the programmer's responsibility to ensure
that array indices remain in the valid range
#include <stdio.h>
#include <string.h>
int main() {
int array[5] = {1, 2, 3, 4, 5};
printf("%d\n", array[5]);
}
Using gdb (GNU Debugger)
• Compile with symbols
– gcc -g -o ch2a ch2a.c
• Run program in debugger
– gdb ch2a
• Show code, place breakpoint, run to it
– list
– break 7
– run
• Examine the memory storing "array"
– x/10x &array
Reading Past End of Array
Reading Past End of Array
• array[5] = 0xb7fb63c4
Writing Past End of Array
Compile and Run, Crash
Debug
• Open in debugger
– gdb ch2b
• Run
– run
• Examine the memory storing "array"
– x/50x &array
Buffer Overflow
• Many RAM locations now contain 0xa
• But why, precisely, did that cause a crash?
Debug
• Examine registers
– info registers
• Examine assembly code near eip
– x/10i $eip-10
10 (0xa) is not in any register
Last Command Writes $0xa to RAM
• Evidently we went so far we exited the RAM
allocated to the program
Intel v. AT&T Format
• gdb uses AT&T format by default, which is
popular with Linux users
– mov source, destination
• Windows users more commonly use Intel
format
– MOV DESTINATION, SOURCE
Jasmin
Assembly Language Simulator
The Stack
LIFO (Last-In, First-Out)
• ESP (Extended Stack Pointer) register points to
the top of the stack
• PUSH puts items on the stack
– push 1
– push addr var
Stack
• POP takes items off the stack
– pop eax
– pop ebx
EBP (Extended Base Pointer)
• EBP is typically used for calculated addresses
on the stack
– mov eax, [ebp+10h]
• Copies the data 16 bytes down the stack into
the EAX register
Functions and the Stack
Purpose
• The stack's primary purpose is to make the
use of functions more efficient
• When a function is called, these things occur:
– Calling routine stops processing its instructions
– Saves its current state
– Transfers control to the function
– Function processes its instructions
– Function exits
– State of the calling function is restored
– Calling routine's execution resumes
Example
Using gdb (GNU Debugger)
• Compile with symbols
– gcc -g -o ch2d ch2d.c
• Run program in debugger
– gdb ch2d
• Show code, place breakpoint, run to it
– list 1,12
– break 9
– break 11
– break 4
Using gdb (GNU Debugger)
• Run to breakpoint after line 9
• run
• Examine registers
– info reg
• Run to breakpoint after line 4
• continue
• Examine registers
– info reg
In main() before calling function()
• esp 0xbffff460
• ebp 0xbffff468 (start of stack frame)
• eip 0x8048414 <main+17>
In function()
• esp 0xbffff430
• ebp 0xbffff450 (start of stack frame)
• eip 0x8048401 <function+6>
Examine the Stack
– x/12x $esp
• Highlight is function()'s stack frame
• Outlined area shows these items
– Return address
– Arguments of function(1,2)
• Next to the left is the original value of $ebp
Using gdb (GNU Debugger)
• Run to breakpoint after line 11
• continue
• Examine registers
– info reg
In main() after calling function()
• esp 0xbffff460
• ebp 0xbffff468
• eip 0x8048420 <main+29>
Functions and the Stack
• Primary purpose of the stack
– To make functions more efficient
• When a function is called
– Push function's arguments onto the stack
– Call function, which pushes the return address RET
onto the stack, which is the EIP at the time the
function is called
Functions and the Stack
– Before function starts, a prolog executes, pushing
EBP onto the stack
– It then copies ESP into EBP
– Calculates size of local variables
– Reserves that space on the stack, by subtracting
the size from ESP
– Pushes local variables onto stack
Functions and the Stack
#include <stdio.h>
void function(int a, int b)
{
int array[5];
}
main()
{
function(1,2);
printf("This is where the
return address points\n");
}
• <main+3> puts a's value, 1, onto the stack
• <main+5> puts b's value, 2, onto the stack
• <main+7> calls function, which implicitly
pushes RET (EIP) onto the stack
• Prolog
– Push EBP onto stack
– Move ESP into EBP
– Subtract 0x14 from stack to reserve space for
array
• leave restores the original stack, same as
– mov esp, ebp
– pop ebp
Stack Buffer Overflow Vulnerability
Compile and Run
Disassemble return_input
Set Breakpoints
• At call to gets
• And at ret
Disassemble main
• Next instruction after the call to return_input
is 0x08048453
Run Till First Breakpoint
• Highlighted values are the saved EBP and the
RET address
Continue and Input 40 Characters
• 30 characters are stored correctly
• Next four overwrite stored EBP with
0x44444444 ('DDDD')
• Next four overwrite RET
Examine $eip, Step One Instruction
• x/1i means "Examine one instruction"
• stepi executes one machine language
instruction
Observe Overwritten Registers
• ebp and eip are 0x44444444 = 'DDDD'
Stack Overflow
Controlling eip
• 0x44444444 is invalid and causes the program
to halt
• We can put any valid memory address there
• However, at the point of the crash we have
returned to main() so we should choose an
instruction in main()
Call to return_input
• 0x0804844e
– stored backwards in a string
– "\x4e\x84\x04\x08"
Python Exploit Code
• sys.stdout.write doesn't put a space or
linefeed at end
How to Debug with Arguments