Assignment #2: The Buffer Bomb

Pre-assignment due by 11:59pm, Wednesday, February 18.
Full assignment due by 11:59pm, Wednesday, February 25.

Assignment Overview:

This assignment helps you develop a detailed understanding of the assembly/machine codes and the calling stack organization on an x86 processor. It involves applying a series of buffer overflow attacks on an executable file.

Note: In this lab, 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 run-time 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 computer systems. There are criminal statutes governing such activities.

The managing TA for this assignment is Sean Wang (swang73@u.rochester.edu). Please first direct your questions about this assignment to the managing TA who has the most intimate knowledge about the assignment setup and specific details. The TA's office hours for this assignment are:

The office hours are held at Hylan 301.

You can form a group of two for this assignment. You can also choose to work alone. You are able to choose to work in a group of two for four assignments (assignments #2/#3/#4/#5). However, it is our policy that you can NOT work with the same team partner for more than two assignments. If you do, we will apply 50% penalty on your third and fourth assignments with the same grouping.

Location of the Bomb:

To obtain a bomb, point your browser at http://cycle3.csug.rochester.edu:18213/. (This will work only for browsers running on a URCS machine.) You'll end up downloading a tar file which, when unpacked, will give you a set of three programs:

makecookie
Generates a "cookie" based on your team name.
bufbomb
The code you will attack.
hex2raw
A utility to help convert between string formats.
All of these programs are compiled to run on the CSUG machines.

Team Name and Cookie:

You should create a team name for the one or two people in your group of the following form:

"name"
where name is your username, if you are working alone, or
"name1:name2"
where name1 is the username of the first team member and name2 is the username of the second team member.
You should choose a consistent ordering of the IDs in the second form of team name. Teams "bob:jane" and "jane:bob" are considered distinct. You must follow this scheme for generating your team name. Our grading program will only give credit to those people whose username can be extracted from the team names.

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

    unix> makecookie bob:jane
    0x7da0a20b
      
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: 

    int getbuf()
    {
	char input[12];
        char buf[NORMAL_BUFFER_SIZE];
        Gets(buf);
        return 1;
    }
      
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 32 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 31 characters long, it is clear that getbuf will return 1, as shown by the following execution example:

    unix> bufbomb -u bob:jane
    Type string: howdy doody
    Dud: getbuf returned 0x1
      
If we type a longer string, typically an error occurs:
    unix> bufbomb -u bob:jane
    Type string: This string is too long
    Ouch!: You caused a segmentation fault!
      
As the error message indicates, overrunning the buffer typically causes the program state to be corrupted, leading to a memory access error. Your task is to be more clever with the strings you feed bufbomb so that it does more interesting things. These are called exploit strings.

Note: This version of the lab has been specially modified to defeat the stack randomization techniques used by newer versions of Linux. It works by using mmap() and a bit of in-line assembly code to move the stack pointed at by %esp to an otherwise unused part of your address space. You may need to use gdb to figure out where that is.

Bufbomb takes several command line arguments:

–u TEAM
Operate the bomb for the indicated team. You should always provide this argument for several reasons:
–h
Print list of possible command line arguments.
–n
Operate in "Nitro" mode, as is used in Level 4 below.
–s
Submit your solution exploit string to the grading server.
Your exploit strings will typically contain byte values that do not correspond to the ASCII values for printing characters. The program hex2raw can help you generate these raw strings. It takes as input a hex-formatted string. In this format, each byte value is represented by two hex digits. For example, the string "012345" could be entered in hex format as "30 31 32 33 34 35" since the ASCII code for decimal digit 0 is 0x30 and so forth.

The hex characters you pass hex2raw should be separated by whitespace (blanks or newlines). We recommend separating different parts of your exploit string with newlines while you're working on it. hex2raw also supports C-style block comments, so you can mark off sections of your exploit string. For example:

    bf 66 7b 32 78 /* mov    $0x78327b66,%EDF */
      
Be sure to leave space around both the starting and ending comment strings (/*, */) so they will be properly ignored.

If you place a hex-formatted exploit string in the file exploit.txt, you can apply the raw string to bufbomb in at least two different ways:

  1. You can set up a series of pipes to pass the string through hex2raw.
        unix> cat exploit.txt | ./hex2raw | ./bufbomb -u bob:jane
    	  
  2. You can store the raw string in a file and use I/O redirection to supply it to bufbomb
        unix> ./hex2raw < exploit.txt > exploit-raw.txt
        unix> ./bufbomb -u bob:jane < exploit-raw.txt
    	  
    This approach can also be used when running bufbomb from within gdb:
        unix> gdb bufbomb
        (gdb) run -u bob:jane < exploit-raw.txt
    	  

Important points:

When you have correctly solved one of the levels, say level 0:

    unix> ./hex2raw < smoke-bob:jane.txt | ./bufbomb -u bob:jane
    Userid: bob:jane
    Cookie: 0x7da0a20b
    Type string:Smoke!: You called smoke()
    VALID
    NICE JOB!
      
then you can submit your solution to the grading server using the -s option:
    unix> ./hex2raw < smoke-bob:jane.txt | ./bufbomb -u bob:jane -s
    Userid: bob:jane
    Cookie: 0x7da0a20b
    Type string:Smoke!: You called smoke()
    VALID
    Sent exploit string to server to be validated.
    NICE JOB!
      
The server will test your exploit string to make sure it really works, and it will update the Buffer Lab scoreboard page indicating that your userid (listed by your cookie for anonymity) has completed this level.

You can view the scoreboard by pointing your browser at http://cycle3.csug.rochester.edu:18213/scoreboard

Important note on the frame pointer: Examples in the class and textbook use the frame pointer %ebp to reference data on the current function's stack frame (including return address, local variables, and function arguments). The latest GCC compiler may have optimized away the frame pointer %ebp so it can be used for general purpose computing. We recommend that you instead use the stack pointer %esp to inspect the stack frame data when needed.

Pre-Assignment:

By Wednesday, February 18, send email to TA Sean Wang (swang73@u.rochester.edu) with the subject line "[CSC252] Assign#2 Pre-assignment - uname1 uname2" (without the quotes, where uname is your login name) containing answers to the following questions (a single email per team is expected):

  1. (1 pt) Where is the return address of a calling function stored relative to the callee function's frame pointer?
  2. (1 pt) Where is the return value of a function stored when control returns to the calling function?
  3. (1 pt) In gdb, how do you print a string whose base address is 0x01234567? (Hint: Something similar to C.)
  4. (1 pt) Please copy the executable file /u/cs252/labs15/bombpreassign. Run it and you will be asked to provide a secret phrase to defuse the bomb. What is the secret phrase? Hint: You should disassemble the program using objdump -d bombpreassign and direct the output to a file. We advise that you start by focusing your attention on function phase_1. Note: This question has no direct relation with the full assignment, aside from asking you to understand assembly code and make logical analysis. You should put aside this file after completing the pre-assignment (since it is not used in any way in the full assignment). Furthermore, this question is much more challenging than the other pre-assignment questions even though it is worth the same 1 point.
  5. (1 pt) Run the program makecookie with your team name as a parameter. What is the output?
  6. (1 pt) What is the purpose of the hex2raw program?
Please keep your answer to be as brief as possible. Your answer to each question should be no more than one line.

Full Assignment Description:

This assignment contains multiple levels. The levels can be done in any order. Feel free to fire away at bufbomb with any string you like.

Tools:

There are some very useful tools that can help you understand how certain programs work and behave. They include:

Looking for a particular tool? Don't forget, the commands man and apropos are your friends. In particular, man ascii might come in useful. The web may also be a treasure trove of information.

Hint on Generating Byte Codes:

Using gcc as an assembler and objdump as a disassembler makes it convenient to generate the byte codes for instruction sequences. For example, suppose we write a file example.s containing the following assembly code:

    # Example of hand-generated assembly code
        pushl $0x89abcdef       # Push value onto stack
        addl $17,%eax           # Add 17 to %eax
        .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 0s) as:

    68 ef cd ab 89 83 c0 11 98 ba dc fe
      
This string can then be passed through hex2raw to generate a proper input string we can give to bufbomb. Alternatively, we can edit example.d to look like this:
    68 ef cd ab 00  /* push   $0xabcdef */
    83 c0 11        /* add    $0x11,%eax */
    98
    ba dc fe
      
which is also a valid input we can pass through hex2raw before sending to bufbomb.

Turn-in:

There is no explicit turn-in. The bomb will notify us automatically whenever you correctly solve a level and use the -s option. Upon receiving your solution, the server will validate your string and update the Buffer Lab scoreboard Web page, which you can view by pointing your Web browser at http://cycle3.csug.rochester.edu:18213/scoreboard. You should be sure to check this page 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.

Late Turn-in Policy:

No late turn-in is allowed for the pre-assignment. If you do not email the TA your pre-assignment by its deadline, you will earn no point for the pre-assignment.

For the full assignment, late turn-ins will be accepted for up to three days, with 10% penalty for each late day. Note that the score board will not reflect the late penalty, which we will manually apply after the assignment closes. No turn-ins more than three-day late will be accepted.