A2: Exploiting Format String Vulnerabilities

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

This assignment requires a good understanding of of TESO’s Format String paper as specified for the 9/17 lecture.

Part 1

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

Part 2 (10 points)

We continue our study of the lucky program in the last homework. For the convenience of performing a format string attack, we have modified the program slightly, as shown below.

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

char Password[100]; // Memory storage for the password

char goodPassword() {
  int good='N';
  int *p = &good;
  fgets(Password, sizeof(Password), stdin); // Get input from keyboard

  printf("Password=");
  printf(Password);
  printf("\n");

  return (char)(*p);
}

int main() {
  struct timeval t;

  printf("Enter your password:");

  char r = goodPassword();
  printf("r=%c\n", r);

  if (r == 'Y') {
    gettimeofday(&t, 0);
    srand((unsigned int) t.tv_usec);
    printf("Your lucky number today is %d!\n", rand()%100);
  }
  else {
    printf("No lucky number for you today.\n");
    exit(-1);
  }

  return 0;
}

Similar to the previous version, the program refuses to generate a lucky number. What is different is that it uses fgets() to get the user password instead of the insecure gets(). The fgets function takes the size of the Password buffer as the bound of the number of characters to read (more accurately, if the buffer size is n, fgets will read at most n-1 characters and will terminate the buffer with a null byte). Therefore, there is no possibility of overflowing the Password buffer through the fgets function.

However, there is a format-string vulnerability in the program. The program tries to echo the password in the goodPassword() function, but it uses printf in an insecure way. We would like to take advantage of this vulnerability so that the program generates lucky numbers for us.

Do this homework in the following steps:

  1. (1 point) Pinpoint which statement in the program has a format-string vulnerability. Explain why.
  2. (2 points) Try the password "%s%s%s%s%s%s%s%s%s". What is the behavior of the program? Explain why it behaves this way for this password.
  3. (2 points) Try the password "%16lx %16lx %16lx %16lx %16lx %16lx %16lx". What is the behavior of the program? Explain what happens.
  4. (1 point) Try the password "dddd%n". What is the behavior of the program? Explain what happens.
  5. (4 points) We would like to use a password of the form "%?c%?c...%?c%n" to attack the program. The password starts with a series of "%?c", where ? stands for a number we need to figure out. The purpose of this password is to 1) move the internal stack pointer (not rsp) of printf to point to the local variable p in goodPassword; 2) use the series of "%?c" to control the number of characters to print so that the number exactly equals the ASCII value of character ‘Y’; 3) use "%n" to write 'Y' to memory location with the address in p. In the last step, since p contains the address of variable good, the effect is to change the value of good from 'N' to 'Y'. Given this attack, your job is to figure out the number of "%?c" at the beginning of this password, and a number to replace "?" in each "$?c".

Notes

  • Compile the program by clang lucky.c -o lucky.
  • 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 gdb.
  • gdb might be useful for Part 5. Alternatively, manually inserting printf calls into the program might be sufficient to figure out which stack slot holds variable p and other information.

What you need to submit

Submit your work through Blackboard. The deadline is October 1st 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.