Stack Overflow example using GDB

Download Report

Transcript Stack Overflow example using GDB

CAP6135: Malware and Software
Vulnerability Analysis
Buffer Overflow : Example of Using GDB to
Check Stack Memory
Cliff Zou
Spring 2016
A Stack Frame
BP
SP+offset
Parameters
Return Address
Calling Stack Pointer
Added Protection
SP
Local Variables
Addresses
00000000
SP: stack pointer BP: base/frame pointer
Calling stack pointer: previous function’s SP
2
Using GDB to Check Stack

GDB tutorial:




http://sunsite.ualberta.ca/Documentation/Gnu/gdb-4.18/html_chapter/gdb_toc.html
http://www.yolinux.com/TUTORIALS/GDB-Commands.html#GDB_COMMAND_LINE_ARGS
When compile the c code, use “gcc –g …..” so that Gdb can match
source code line number with code
Some knowledge: http://en.wikipedia.org/wiki/X86_assembly_language


Register eip: instruction pointer, the current position of next executable instruction
Register ebp: stack pointer, the top of the current stack, used for addressing local
variable
3

Related Gdb Commands:







List: list the source code and each execution’s corresponding line
number
Break linenumber: set breakpoint at the linenumber
Break test.c:foo break when program run in the foo() function in test.c
file.
Run argv: run the execution code with the parameter argv
Next: execute the next line of code
Backtrace: show trace of all function calls in stack
Info frame: List address, language, address of arguments/local
variables and which registers (eip, ebp) were saved in frame.





This will show where the return address is saved
Return address is in Register EIP
Calling stack pointer is in Register EBP
x &variable: show the address and value of a local variable (in hex
format)
x address: print binary representation of 4 bytes of memory pointed to
by address.
4
Example of Using GDB
#include <stdio.h>
void foo(char * input){
int a1=11;
int a2=22;
char buf[7];
strcpy(buf, input);
}
void main(int argc, char **argv){
foo(argv[1]);
}
Question: What does the stack look like before strcpy()?
5
7
czou@eustis:~/buffer-code$ setarch i686 –R gdb ./gdb-example
(gdb) list
1
#include <stdio.h>
Remove address randomization
2
void foo(char * input){
used in Unix (will talk in next lecture)
3
int a1=11;
4
int a2=22;
5
char buf[7];
6
strcpy(buf, input);
7
}
8
void main(int argc, char **argv){
9
foo(argv[1]);
10
}
(gdb) break 6
Breakpoint 1 at 0x8048459: file gdb-example.c, line 6.
(gdb) run “what is this? a book”
Starting program: /home/czou/buffer-code/gdb-example “what is this? a book"
Breakpoint 1, foo (input=0xbffff838 "1234567890") at gdb-example.c:
6
strcpy(buf, input);
6
(gdb) info frame
Stack level 0, frame at 0xbffff620:
eip = 0x8048459 in foo (gdb-example.c:6); saved eip 0x8048497
called by frame at 0xbffff640
source language c.
Arglist at 0xbffff618, args: input=0xbffff82d "what is this? a book"
Locals at 0xbffff618, Previous frame's sp is 0xbffff620
Saved registers:
ebp at 0xbffff618, eip at 0xbffff61c
(gdb) x &a1
0xbffff5fc: 0x0000000b
(gdb) x &a2
0xbffff600: 0x00000016
(gdb) x buf
0xbffff605: 0xf4000000
7
Two Techniques for
Generating Stack Overflow
Codes
NOPs



Most CPUs have a No-Operation
instruction – it does nothing but advance
the instruction pointer.
Usually we can put a bunch of these
ahead of our program (in the string).
As long as the new return-address points
to a NOP we are OK.
Using NOPs
new return address
Real program
(exec /bin/ls or whatever)
nop instructions
Estimating the stack size

We can also guess at the location of the
return address relative to the overflowed
buffer.

Put in a bunch of new return addresses!
Estimating the Location
new
new
new
new
new
new
return
return
return
return
return
return
address
address
address
address
address
address
Real program
nop instructions
Explanation of Project 1
• In the exploit.c code:
•
#define TARGET “/home/czou/cap6135-project1/targets/target”
• Need to be changed to point to your own target executable code
• Your main task is to:
• Find out where in stack stores the return address
• Find out where is the starting address of ‘buffer’ in foo()
in target code
• Fill the shellcode[] into the large buffer in your exploit
code (which will fill the ‘buffer’ variable in target code)
• Assign the starting address of buffer to the right place in
the large buffer in your exploit code in order to
overwrite the return address, then CPU will run the
shellcode you put at the start of buffer variable.
13
Several Tips on Project 1
1. Be sure to use the Makefile to generate executable of both
exploit program and target program
• At both ./exploit and ./target directory, run “make”
2. Be sure to use “setarch i686 -R” in front of every
execution, including both Gdb and direct execution of
./exploit
3. You can use “break target.c:foo” to set breakpoint upon
entering foo() function.
4. Fill the shell executable code (in the string array
shellcode[]) byte-by-byte into the buffer for your modified
return address to execute, do not use strcpy() because
shellcode[] is not an ASCII string.
Several Tips on Project 1
As an example, suppose we know that:
1. The address of ‘buffer’ in target.c is: 0xbfff0000
2. The address of the function’s return address (eip) is
0xbfff0100
3. We put the shellcode[] at the beginning of ‘buffer’.
How to Overwrite the return address to execute shellcode?
1. 0xbfff0100 – 0xbfff0000 = 0x100 = 256 in decimal
2. Since address in 32-bit machine is 4 bytes and Eustis is a
little-endian machine:
buffer[256] = 0x00; buffer[257] = 0x00;
buffer[258] = 0xff; buffer[259] = 0xbf;
In this way, we have changed the flow to the beginning of
shellcode!
15