Project 1 : Buffer Overflows
CIS 551


Due: Feb. 6th 2009 at 11:59 p.m.

Description

The blame service is a simple system for assigning blame, written by our hero, Feckless C. Coder, PostDoc. The program accepts on standard input the name of a scapegoat and prints on standard output a message asserting that person's universal culpability in a loop. For example:
        $ echo "Steve Zdancewic" | ./blame
        It's all Steve Zdancewic's fault.
        It's all Steve Zdancewic's fault.
        ...
        It's all Steve Zdancewic's fault.
or, if you prefer:
        $ echo "Bill Gates" | ./blame
        It's all Bill Gates's fault.
        ...
        It's all Bill Gates's fault.
        It's all Bill Gates's fault.
The program is designed to operate as a network service, e.g., from the "inetd" daemon under Unix.

Source code for blame.c is attached below and is also available at http://www.cis.upenn.edu/~cis551/blame.c.

Simple-minded string processing aside (it would be more correct, after all, to say that "It's all Bill Gates' fault"), there is a serious problem with the blame program. Despite Feckless' best efforts, a bug allows anyone who can provide input to this program to run arbitrary code on the target machine. (What might happen if it is run as a network service under inetd, as suggested in the comments?)

Your job is to create input that will cause the blame service to print out the helpful message "Now I pwn your computer" and terminate the loop. For example:

	$ cat exploit_file | ./blame
	...
	Now I pwn your computer

Here, the "..." may be additional output caused as a side-effect of your attack.

Deliverables

  1. Write a well documented program that generates exploit_file. (You can assume you'd have access to the object code for the instance of blame against which it will be run). Your program should work on the Linux platform available on the machines mod-l.seas.upenn.edu (note that minus.seas.upenn.edu, which are part of the eniac machine pool has buffer overflow protection turned on). The gcc compiler and gdb debugger are already installed. If, for some reason, you do not have an eniac login account, contact one of the course staff members.

    Submit the program that generates your exploit_file as well as any tools you use to generate parameters and constants. Your software should be sufficiently documented to allow a novice programmer to port your code to other platforms or to modify it to exploit similar weaknesses in other programs. In other words, your submission should be suitable as a tutorial on exploiting (and avoiding) this class of vulnerability.

  2. Fix the blame.c implementation so that it is not vulnerable to this buffer overflow attack, but still has the same behavior as the original program for inputs that fit into the buffer INPUT_BUFFER. How do you know your program is secure?

  3. Your submission should consist of a directory. The directory should include a README file containing your group information (including full names and e-mail addresses) and a list of the contents of the directory you submit.

    project1 should be submitted online on eniac by using the command turnin.

    There is also a turnin man page which explains the usage in more detail, including some additional arguments.

Extra credit:

Feckless C. Coder, PhD wrote another code culpability.c available at http://www.cis.upenn.edu/~cis551/culpability.c. Due to recent changes in gcc 4.1.*, it is harder to perform stack-smashing attacks to culpability.c.

Carry out the stack smashing attack to culpability.c assuming that culpability.c is compiled with the option -fno-stack-protector, and fix the implemetation so that it is not vulnerable to this buffer overflow attack, but still has the same behavior as the original program.
DO THIS ONLY AFTER COMPLETING THE PROJECT WITH blame.c*

Resources

You may find these links useful in your task. Feel free to use additional sources for learning about C, gdb, gcc, but do not submit code that you did not create entirely by yourself. Please see the course policies for acceptable use of external resources.

Grading guidelines

Blame server source code (blame.c)

/*
 * Blame server.  Assigns blame to the person of your choice.
 *
 * Usage: blame
 *	(reads one line from standard input)
 *
 * To compile:
 *	gcc blame.c -o blame
 *
 * Install under inetd as follows:
 *  blame	stream	tcp	nowait	root	/path/to/blame	blame
 *
 * Copyright 2009 by Feckless C. Coder, PostDoc.
 */

#include 
#include 
#include 
#define INPUT_BUFFER 256  /* maximum name size */

int buffer[INPUT_BUFFER]; /* storing input data */

/*
 * read input, copy into p 
 * gets() is insecure and prints a warning
 *    so we use this instead
 */
void saveinput(int *p)
{
	int c;
	
	while ((c=getchar()) != EOF)
		*p++ = c;
	*p = EOF;
}

/*
 * read data from p to s
 */
void getline(char *s, int *p)
{
	int c;
	
	for(; (c=*p++)!= EOF; *s++ = c);
	*s = '\0';
}

/*
 * convert newlines to nulls in place
 */
void purgenewlines(char *s)
{
	int l;

	l = strlen(s);

	while (l--)
		if (s[l] == '\n')
			s[l] = '\0';
}

/*
 * copy data from p to scapegoat
 *   print on the screen after reformatting
 */
int loop(int *p)
{
	char scapegoat[INPUT_BUFFER];

	getline (scapegoat, p);
	/* this check ensures there's no buffer overflow */
	if (strlen(scapegoat) < INPUT_BUFFER) {
		purgenewlines(scapegoat);
		printf("It's all %s's fault.\n", scapegoat);
		return 1;
	} else {
		return 0;
        }
}

/*
 * save input into buffer, then start loop
 */
int main()
{
        saveinput(buffer);
	while(loop(buffer));
	return 0;
}

Culpability server source code (culpability.c)

/*
 * Culpability server.  Assigns culpability to the person of your choice.
 *
 * Usage: culpability
 *	(reads one line from standard input)
 *
 * To compile:
 *	gcc culpability.c -o culpability
 *
 * Install under inetd as follows:
 *  culpability	stream	tcp	nowait	root	/path/to/culpability	culpability
 *
 * Copyright 2004 by Feckless C. Coder, PhD.
 */

#include 
#include 
#define INPUT_BUFFER 256  /* maximum name size */

/*
 * read input, copy into s 
 * gets() is insecure and prints a warning
 *    so we use this instead
 */
void getline(char *s)
{
	int c;
	
	while ((c=getchar()) != EOF)
		*s++ = c;
	*s = '\0';
}

/*
 * convert newlines to nulls in place
 */
void purgenewlines(char *s)
{
	int l;

	l = strlen(s);

	while (l--)
		if (s[l] == '\n')
			s[l] = '\0';
}


int main()
{
	char scapegoat[INPUT_BUFFER];

	getline(scapegoat);
	/* this check ensures there's no buffer overflow */
	if (strlen(scapegoat) < INPUT_BUFFER) {
		purgenewlines(scapegoat);
		printf("It's all %s's fault.\n", scapegoat);
	}
	return 0;
}

Last Revised: 15 Jan. 2009