The Buffer Bomb - Computer Security - Homework 1 | ECS 153, Assignments of Computer Science

Material Type: Assignment; Professor: Chen; Class: Computer Security; Subject: Engineering Computer Science; University: University of California - Davis; Term: Winter 2000;

Typology: Assignments

Pre 2010

Uploaded on 09/17/2009

koofers-user-g8x
koofers-user-g8x 🇺🇸

8 documents

1 / 10

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
ECS 153, Winter 2009
Homework Assignment 1: The Buffer Bomb
Assigned: January 15. Due: Sunday, February 1, 10:00PM
Introduction
This assignment helps you develop a detailed understanding of the calling stack organization on an IA32
processor. It involves applying a series of buffer overflow attacks on an executable file
bufbomb
available at
the course web page.
Note: In this homework, you will gain firsthand experience with one of the methods commonly used to
exploit security weaknesses in operating systems and network servers. Our purpose is to help you learn
about the runtime operation of programs and to understand the nature of this form of security weakness so
that you can avoid it when you write system code. We do not condone the use of these or any other form
of attack to gain unauthorized access to any system resources. There are criminal statutes governing such
activities.
Logistics
You must work individually in solving the problems for this assignment. You must run the programs on one
of the Linux machines (
pc1
pc99
) in the CSIF labs. The only “hand-in” will be an automated logging of
your successful attacks. Any clarifications and revisions to the assignment will be posted on the course web
page.
Note: Some CSIF Linux machines may be unstable occasionally. If your attack does not work on one
machine but you think that the attack is correct, please try other machines.
Hand Out Instructions
Download
buflab-handout.tar
from
http://www.cs.ucdavis.edu/˜hchen/teaching/ecs153-w09/#hw1
Copy
buflab-handout.tar
to a (protected) directory in which you plan to do your work. Then give the
command
tar xvf buflab-handout.tar
”. This will cause a number of files to be unpacked in the
directory:
1
pf3
pf4
pf5
pf8
pf9
pfa

Partial preview of the text

Download The Buffer Bomb - Computer Security - Homework 1 | ECS 153 and more Assignments Computer Science in PDF only on Docsity!

ECS 153, Winter 2009

Homework Assignment 1: The Buffer Bomb

Assigned: January 15. Due: Sunday, February 1, 10:00PM

Introduction

This assignment helps you develop a detailed understanding of the calling stack organization on an IA processor. It involves applying a series of buffer overflow attacks on an executable file bufbomb available at the course web page.

Note: In this homework, you will gain firsthand experience with one of the methods commonly used to exploit security weaknesses in operating systems and network servers. Our purpose is to help you learn about the runtime operation of programs and to understand the nature of this form of security weakness so that you can avoid it when you write system code. We do not condone the use of these or any other form of attack to gain unauthorized access to any system resources. There are criminal statutes governing such activities.

Logistics

You must work individually in solving the problems for this assignment. You must run the programs on one of the Linux machines (pc1 – pc99) in the CSIF labs. The only “hand-in” will be an automated logging of your successful attacks. Any clarifications and revisions to the assignment will be posted on the course web page.

Note: Some CSIF Linux machines may be unstable occasionally. If your attack does not work on one machine but you think that the attack is correct, please try other machines.

Hand Out Instructions

Download buflab-handout.tar from http://www.cs.ucdavis.edu/˜hchen/teaching/ecs153-w09/#hw Copy buflab-handout.tar to a (protected) directory in which you plan to do your work. Then give the command “tar xvf buflab-handout.tar”. This will cause a number of files to be unpacked in the directory:

MAKECOOKIE : Generates a “cookie” based on your CSIF Unix user name.

BUFBOMB : The code you will attack.

SENDSTRING : A utility to help convert between string formats.

All of these programs are compiled to run on Linux machines.

In the following instructions, we will assume that you have copied the three programs to a protected local directory, and that you are executing them in that local directory.

Cookie

A cookie is a string of eight hexadecimal digits that is (with high probability) unique to you. You can generate your cookie with the makecookie program giving your CSIF Unix user name as the argument. For example:

unix> ./makecookie hchen 0x1b0e

In four of your five buffer attacks, your objective will be to make your cookie show up in places where it ordinarily would not.

The BUFBOMB Program

The BUFBOMB program reads a string from standard input with a function getbuf having the following C code:

1 int getbuf() 2 { 3 char buf[12]; 4 Gets(buf); 5 return 1; 6 }

The function Gets is similar to the standard library function gets—it reads a string from standard input (terminated by ‘\n’ or end-of-file) and stores it (along with a null terminator) at the specified destination. In this code, the destination is an array buf having sufficient space for 12 characters.

Neither Gets nor gets has any way to determine whether there is enough space at the destination to store the entire string. Instead, they simply copy the entire string, possibly overrunning the bounds of the storage allocated at the destination.

If the string typed by the user to getbuf is no more than 11 characters long, it is clear that getbuf will return 1, as shown by the following execution example:

This approach can also be used when running BUFBOMB from within GDB:

unix> gdb bufbomb (gdb) run -t hchen < exploit-raw.txt

One important point: your exploit string must not contain byte value 0x0A at any intermediate position, since this is the ASCII code for newline (‘\n’). When Gets encounters this byte, it will assume you intended to terminate the string. SENDSTRING will warn you if it encounters this byte value.

Hand In Instructions

When you correctly solve one of the levels, rerun BUFBOMB with an additional command line argument “-s”, which instructs BUFBOMB to automatically send an email notification to our grading server containing your user name (be sure to set the “-t” command line argument properly) and your exploit string. You will be informed of this by BUFBOMB. Upon receiving the email, the server will validate your string and update a web page linked from http://www.cs.ucdavis.edu/˜hchen/teaching/ecs153-s06/#hw You should check this page one minute after your submission to make sure your string has been validated. [If you really solved the level, your string should be valid.]

Note that each level is graded individually. You do not need to do them in the specified order, but you will get credit only for the levels for which the server receives a valid message.

There is no penalty for making mistakes in your experiment. Feel free to fire away at BUFBOMB with any string you like. However, send your successful exploit for each level to our grading server (i.e., run BUFBOMB with ”-s”) only once. Denial of service attempt on our server is strictly forbidden and will be prosecuted with cruel and unusual punishment.

Level 0: Candle (10 pts)

The function getbuf is called within BUFBOMB by a function test having the following C code:

1 void test() 2 { 3 int val; 4 volatile int local = 0xdeadbeef; 5 entry_check(3); /* Make sure entered this function properly / 6 val = getbuf(); 7 / Check for corrupted stack */ 8 if (local != 0xdeadbeef) { 9 printf("Sabotaged!: the stack has been corrupted\n"); 10 } 11 else if (val == cookie) { 12 printf("Boom!: getbuf returned 0x%x\n", val); 13 validate(3);

14 } 15 else { 16 printf("Dud: getbuf returned 0x%x\n", val); 17 } 18 }

When getbuf executes its return statement (line 5 of getbuf), the program ordinarily resumes execution within function test (at line 8 of this function). Within the file bufbomb, there is a function smoke having the following C code:

void smoke() { entry_check(0); /* Make sure entered this function properly */ printf("Smoke!: You called smoke()\n"); validate(0); exit(0); }

Your task is to get BUFBOMB to execute the code for smoke when getbuf executes its return statement, rather than returning to test. You can do this by supplying an exploit string that overwrites the stored return pointer in the stack frame for getbuf with the address of the first instruction in smoke. Note that your exploit string may also corrupt other parts of the stack state, but this will not cause a problem, since smoke causes the program to exit directly.

Some Advice :

  • All the information you need to devise your exploit string for this level can be determined by exam- ining a diassembled version of BUFBOMB.
  • Be careful about byte ordering.
  • You might want to use GDB to step the program through the last few instructions of getbuf to make sure it is doing the right thing.
  • The placement of buf within the stack frame for getbuf depends on which version of GCC was used to compile bufbomb. You will need to pad the beginning of your exploit string with the proper number of bytes to overwrite the return pointer. The values of these bytes can be arbitrary.

Level 1: Sparkler (30 pts)

Within the file bufbomb there is also a function fizz having the following C code:

void fizz(int val) { entry_check(1); /* Make sure entered this function properly */ if (val == cookie) {

  • You can use GDB to get the information you need to construct your exploit string. Set a breakpoint within getbuf and run to this breakpoint. Determine parameters such as the address of global_value and the location of the buffer.
  • Determining the byte encoding of instruction sequences by hand is tedious and prone to errors. You can let tools do all of the work by writing an assembly code file containing the instructions and data you want to put on the stack. Assemble this file with GCC and disassemble it with OBJDUMP. You should be able to get the exact byte sequence that you will type at the prompt. (A brief example of how to do this is included at the end of this writeup.)
  • Keep in mind that your exploit string depends on your machine, your compiler, and even your cookie. Do all of your work on a Fish machine, and make sure you include the proper user name on the command line to BUFBOMB.
  • Our solution requires 16 bytes of exploit code. Fortunately, there is sufficient space on the stack, because we can overwrite the stored value of %ebp. This stack corruption will not cause any problems, since bang causes the program to exit directly.
  • Watch your use of address modes when writing assembly code. Note that movl $0x4, %eax moves the value 0x00000004 into register %eax; whereas movl 0x4, %eax moves the value at memory lo- cation 0x00000004 into %eax. Since that memory location is usually undefined, the second instruction will cause a segfault!
  • Do not attempt to use either a jmp or a call instruction to jump to the code for bang. These instruc- tions uses PC-relative addressing, which is very tricky to set up correctly. Instead, push an address on the stack and use the ret instruction.

Level 3: Dynamite (30 pts)

The next two levels are for those who want to push themselves beyond our baseline expectations for the course, and who want to face challenges in designing buffer overflow attacks that arises in real life.

Our preceding attacks have all caused the program to jump to the code for some other function, which then causes the program to exit. As a result, it was acceptable to use exploit strings that corrupt the stack, overwriting the saved value of register %ebp and the return pointer.

The most sophisticated form of buffer overflow attack causes the program to execute some exploit code that patches up the stack and makes the program return to the original calling function (test in this case). The calling function is oblivious to the attack. This style of attack is tricky, though, since you must: 1) get machine code onto the stack, 2) set the return pointer to the start of this code, and 3) undo the corruptions made to the stack state.

Your job for this level is to supply an exploit string that will cause getbuf to return your cookie back to test, rather than the value 1. You can see in the code for test that this will cause the program to go “Boom!.” Your exploit code should set your cookie as the return value, restore any corrupted state, push the correct return location on the stack, and execute a ret instruction to really return to test.

Some Advice :

  • In order to overwrite the return pointer, you must also overwrite the saved value of %ebp. However, it is important that this value is correctly restored before you return to test. You can do this by either
    1. making sure that your exploit string contains the correct value of the saved %ebp in the correct position, so that it never gets corrupted, or 2) restore the correct value as part of your exploit code. You’ll see that the code for test has some explicit tests to check for a corrupted stack.
  • You can use GDB to get the information you need to construct your exploit string. Set a breakpoint within getbuf and run to this breakpoint. Determine parameters such as the saved return address and the saved value of %ebp.
  • Again, let tools such as GCC and OBJDUMP do all of the work of generating a byte encoding of the instructions.
  • Keep in mind that your exploit string depends on your machine, your compiler, and even your cookie. Do all of your work on a Fish machine, and make sure you include the proper user name on the command line to BUFBOMB.

Once you complete this level, pause to reflect on what you have accomplished. You caused a program to execute machine code of your own design. You have done so in a sufficiently stealthy way that the program did not realize that anything was amiss. You may stop here, unless you want extra credit.

Extra Credit: Level 4: Nitroglycerin (20 pts)

From one run to another, especially by different users, the exact stack positions used by a given procedure will vary. One reason for this variation is that the values of all environment variables are placed near the base of the stack when a program starts executing. Environment variables are stored as strings, requiring different amounts of storage depending on their values. Thus, the stack space allocated for a given user depends on the settings of his or her environment variables. Stack positions also differ when running a program under GDB, since GDB uses stack space for some of its own state.

In the code that calls getbuf, we have incorporated features that stabilize the stack, so that the position of getbuf’s stack frame will be consistent between runs. This made it possible for you to write an exploit string knowing the exact starting address of buf and the exact saved value of %ebp. If you tried to use such an exploit on a normal program, you would find that it works some times, but it causes segmentation faults at other times. Hence the name “dynamite”—an explosive developed by Alfred Nobel that contains stabilizing elements to make it less prone to unexpected explosions.

For this level, we have gone the opposite direction, making the stack positions even less stable than they normally are. Hence the name “nitroglycerin”—an explosive that is notoriously unstable.

When you run BUFBOMB with the command line argument “-n,” it will run in “Nitro” mode. Rather than calling the function getbuf, the program calls a slightly different function getbufn:

int getbufn() { char buf[512];

.align 4 # Following will be aligned on multiple of 4 .long 0xfedcba98 # A 4-byte constant .long 0x00000000 # Padding

The code can contain a mixture of instructions and data. Anything to the right of a ‘#’ character is a comment. We have added an extra word of all 0s to work around a shortcoming in OBJDUMP to be described shortly.

We can now assemble and disassemble this file:

unix> gcc -c example.s unix> objdump -d example.o > example.d

The generated file example.d contains the following lines

0: 68 ef cd ab 89 push $0x89abcdef 5: 83 c0 11 add $0x11,%eax 8: 98 cwtl Objdump tries to interpret 9: ba dc fe 00 00 mov $0xfedc,%edx these as instructions

Each line shows a single instruction. The number on the left indicates the starting address (starting with 0), while the hex digits after the ‘:’ character indicate the byte codes for the instruction. Thus, we can see that the instruction pushl $0x89ABCDEF has hex-formatted byte code 68 ef cd ab 89.

Starting at address 8, the disassembler gets confused. It tries to interpret the bytes in the file example.o as instructions, but these bytes actually correspond to data. Note, however, that if we read off the 4 bytes starting at address 8 we get: 98 ba dc fe. This is a byte-reversed version of the data word 0xFEDCBA98. This byte reversal represents the proper way to supply the bytes as a string, since a little endian machine lists the least significant byte first. Note also that it only generated two of the four bytes at the end with value 00. Had we not added this padding, OBJDUMP gets even more confused and does not emit all of the bytes we want.

Finally, we can read off the byte sequence for our code (omitting the final 0’s) as:

68 ef cd ab 89 83 c0 11 98 ba dc fe