A1: Exploiting Buffer Overflows

Authored by Professor Gang Tan of Penn State University. Slightly adjusted by Jie Zhou for this course.

This assignment requires a good understanding of the lectures and assigned readings of August 29th to September 3rd.

Part 1

We will use the vlab machine as specified in lecture 3. Make sure you have access to the machine.

Part 2 (5 points)

We have the following program lucky.c that generates lucky numbers. It takes a password as input, but always refuses to generate a lucky number. Luckily, the program is vulnerable to a buffer overrun in the goodPassword() procedure. The goal is to take advantage of the vulnerability so that it can generate lucky numbers for us.

#include <stdio.h>
#include <sys/time.h>
#include <stdlib.h>

long *ret;

void generateLuckyNumber() {
  struct timeval t;

  gettimeofday(&t, 0);
  srand((unsigned int) t.tv_usec);
  printf("Your lucky number today is %d!\n", rand()%100);
}

char goodPassword() {
  int good='N';
  char Password[50]; // Memory storage for the password
  gets(Password); // Get input from keyboard

  return (char)good;
}

int main() {
  struct timeval t;
  printf("Enter your password:");

  if (goodPassword() == 'Y') {
    generateLuckyNumber();
  }
  else {
    printf("No lucky numbers for you today.\n");
    exit(-1);
  }

  return 0;
}

Figure out a password that can make the program output a lucky number. Explain how your password works. Hint: no need to overwrite the return address for Part 2; there is another easy target to overwrite in this program.

Compile the above program using clang lucky.c -o lucky (in particular, without compiler optimizations) and verify your password works on the generated executable; ignore the warning about gets from clang.

Part 3 (5 points)

Suppose you are allowed to add some code between gets(Password); and return (char)good; in the goodPassword() procedure. We intend to use the following code template to modify the return address on the stack so that the program jumps directly to the THEN branch without checking the result of goodPassword():

ret = (long *) ((long) Password+?);
*ret = *ret + ?;

Each ? above represents an integer constant. Figure out these constants. You’d need the help of a debugger such as gdb or ddd to figure out the offset between the Password buffer and the return address on the stack. On-paper calculation probably won’t work, as the stack layout depends on the compiler.

Part 4 (5 points)

Assume we cannot insert extra code as in Part 4. Figure out a password that makes the program luck.c to call the generateLuckNumber function so that a lucky number can be generated. Basically, your attack should overflow the Password buffer and overwrite the return address so that the new return address points to the address of the generateLuckNumber function.

Tools you may need

  • clang -S lucky.c -o lucky.s compiles the C program to assembly code.
  • clang -ggdb lucky.c -o lucky produces an executable with debugging information, which is used by a debugger like gdb.
  • gdb is a tool that you can use to figure out the difference between the original return address and the new return address for Part 3. You may also use vscode as an IDE to examine memory in vscode’s GUI.
  • x86 uses the little-endian format for storing addresses.
  • You can pipe your payload to lucky instead of manually typing it, which is error-prone and even impossible for certain payload. You can use python to generate your payload, e.g., python3 -c 'print("f"*30)' | ./lucky.

What you need to submit

Submit your work through Blackboard. The deadline is September 19th by midnight. The submission should be a PDF file that contains the answers to the required parts and also explanations of the process you took to get your answers and how your answers work to achieve the desired results. Screenshots of important steps, such as memory/register status shown by gdb or other tools, are not required, but you can include them if they think they facilitate your answers. Do not include screenshots for all steps. Note that it’s not enough to just give answers, you need to explain in detail how you got the answers.