|
Excercise: Buffer Overflows
Working with GNU binutils
Download the sample binary and use GNU binutils to solve the following tasks:
- The binary contains a function named grant_rights(). Use
the nm tool to determine the function's address.
- Use the objdump utility to disassemble the binary. Find the main() function
and determine, which functions are called by main().
- Use strace to find out if (and with which arguments) the write system call
is called.
- Make yourself comfortable with the gdb debugger. Run the sample binary using gdb
and:
- Single-step through the do_work() function.
- Determine the return address stored in do_work()'s stack frame.
- The binary uses fread() to read data into a buffer within the function
do_work. Using gdb, determine the address and the maximum size
of the buffer.
- Write a C program that takes 32-bit hexadecimal numbers from the command line and prints
them byte-wise to stdout. Use hexdump to verify the results.
Redirecting control flow
Use the knowledge obtained in exercise 1 to modify the do_work() function's
return address so that it returns to the function grant_rights().
Executing shell code
Download the 32-byte shell code binary. Use ndisasm to disassemble
the shell code and find out, what it does. Place it in the sample binary's
buffer and overflow the buffer, so that the do_work() function returns into
the shell code.
Return into libC
Let's assume the existence of non-executable stacks. The method from exercise 3 doesn't
work under these circumstances. However, return-into-libC attacks still work. Overflow the
buffer in a way that makes do_work() return into the libC's execve() function
and uses this function to start /bin/date.
Safe string functions?
The following program sn.c passes its first command line argument to the
function do_work, which then uses strncpy() to make sure that the
buffer buf cannot be overflown.
#include <string.h>
#include <stdio.h>
int do_work(char *str)
{
char buf[32];
strncpy(buf, str, 32);
return strlen(buf);
}
int main( int argc, char **argv)
{
if (argc != 2) return -1;
printf("ret: %d\n", do_work(argv[1]));
return 0;
}
Compile the program in the following ways:
- $> gcc -fno-stack-protector -o sn_noprot sn.c
- $> gcc -fstack-protector -o sn_prot sn.c
How predictable is the output of the program in both cases? Why?
|
Contact
Dipl.-Inf. Michael Raitza
Regulations
-
Modules: INF-BI-1, INF-BAS4, INF-VERT4, DSE-E3
-
6 Credit Points
-
2/1/0 = 3 SWS
Time and Place
-
Lecture, weekly
Mon, 11.10 AM
APB E008
-
Exercise, biweekly
Mon, 9.20 AM
APB 3105
Mailing List
|