TUD Logo

TUD Home » ... » Teaching » Distributed Operating Systems » Buffer Overflows

Operating Systems

Excercise: Buffer Overflows

  1. Working with GNU binutils

    Download the sample binary and use GNU binutils to solve the following tasks:

    1. The binary contains a function named grant_rights(). Use the nm tool to determine the function's address.
    2. Use the objdump utility to disassemble the binary. Find the main() function and determine, which functions are called by main().
    3. Use strace to find out if (and with which arguments) the write system call is called.
    4. 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.
    5. 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.
  2. 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().

  3. 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.

  4. 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.

  5. 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?

Last modified: 6th Jan 2020, 2.15 PM
Author: Dr.-Ing. Carsten Weinhold

Contact
Dipl.-Inf.
Michael Raitza

Regulations
  • ModuleModules: INF-BI-1, INF-BAS4, INF-VERT4, DSE-E3
  • Credits6 Credit Points
  • 2/1/0 = 3 SWS
Time and Place
  • Lecture, weekly
    TimeMon, 11.10 AM PlaceAPB E008
  • Exercise, biweekly
    TimeMon, 9.20 AM PlaceAPB 3105
Mailing List