《網絡對抗技術》Exp1 PC平台逆向破解——20184303邢超遠


前期准備

一、逆向及Bof基礎實踐說明

1.1實踐目的

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

1.2實踐內容

  • 手工修改可執行文件,改變程序執行流程,直接跳轉到getShell函數。
  • 利用foo函數的Bof漏洞,構造一個攻擊輸入字符串,覆蓋返回地址,觸發getShell函數。
  • 注入並運行一段指定的shellcode。

1.3基礎知識

  • 熟悉Linux基本操作。掌握用戶切換命令,知道如何獲取root權限;掌握文件下載命令;懂得絕對路徑、相對路徑的使用方法;能查找指定的文件的路徑,並通過路徑操作進入到相應的文件夾,運行一個指定的文件;掌握管道“|”的含義和用法;掌握輸入、輸出重定向的知識;遇到陌生的命令,要掌握通過help、man和info等命令獲得相應命令的介紹和幫助的方法;會使用gdb、vi;掌握其他一些必備的命令,包括反匯編等。
  • 理解緩沖區溢出(BufferOverflow,Bof)的原理。能看得懂匯編、機器指令、EIP、指令地址、ELF文件格式。
  • 掌握機器指令與匯編語言的關系,認識並理解常用的匯編語言,包括MOV、SUB、NOP, JNE, JE, JMP, CMP等。匯編語言和機器碼是一一對應的,我們在Intel硬件手冊里面可以輕松找到這些對應關系。詳見https://wenku.baidu.com/view/eeb46ed184254b35eefd34bf.html。
  • 掌握堆棧的含義、概念和用法,知道函數調用和堆棧的關系,看到一段反匯編代碼,要能夠理解堆棧在其中的運行變化過程。

二、pwn文件

先在主機上下載實驗所需的Linux可執行文件,可以通過地址 https://gitee.com/wildlinux/NetSec/attach_files 在碼雲中下載;也可以如下圖所示在雲班課作業附件中找到pwn1.zip進行下載,下載完成后將壓縮包中的pwn1解壓出來。

圖1

將pwn1通過共享文件夾導入到kali中,在我的實驗中,單獨設置了一個文件夾“exp1”作為pwn1的路徑,專門用於完成實驗一。

圖2

實踐步驟

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

Step1:打開kali,在命令行中進入文件所在目錄,輸入

 objdump -d pwn1 | more

進行反匯編,得到如下圖所示結果。

圖3

objdump命令是Linux下的反匯編目標文件或者可執行文件的命令,它以一種可閱讀的格式讓你更多地了解二進制文件可能帶有的附加信息;-d參數表示disassembly——反匯編;pwn1表示要進行反匯編操作的文件名;|表示管道服務,意指將反匯編所得到的內容通過管道輸送到一個可執行文件,該文件通過more命令分頁顯示。

我們通過輸入/getShell可以找到我們需要關注的幾個函數,因為它們是挨着的,所以找到getShell即可找到全部三個函數,如下圖所示

圖4
  • 地址為80484b5處,call 8048491是匯編指令
    • 執行一條call指令相當於執行了兩條指令:PUSH和JMP,這條指令將調用位於地址8048491處的foo函數;
    • 其對應機器指令為e8 d7ffffffe8即call指令對應的機器指令;
    • 本來正常流程,此時此刻EIP的值應該是下條指令的地址,即80484ba,但如一解釋e8這條指令呢,CPU就會轉而執行 EIP + d7ffffff這個位置的指令。d7ffffff是補碼,表示-41,41=0x29,80484ba +d7ffffff= 80484ba-0x29=8048491,這正是foo函數的首地址。
  • main函數調用foo,對應機器指令為e8 d7ffffff
    • 由此可以發現,80484ba加上一個值,所得的就是CPU會跳轉到的地址,那我們想讓它調用getShell,只要修改d7ffffffgetShell-80484ba對應的補碼就行;
    • 用Windows計算器,直接 47d-4ba就能得到補碼,是c3ffffff

圖5

如上圖所示,HEX是16進制表示,我們在這種環境下用getShell的首地址減去執行call指令時EIP的值,即804847d減去80484ba,所得結果如上。在32位環境下,結果是ffffffc3,我們要把ffffffd7改為ffffffc3,即可實現main函數不再調用foo轉而調用getShell。改之前我們要明確一點就是,正常來說一個數是高位在前(左)低位在后(右),然而我們在反匯編內容里則是低位在前高位在后,即小端優先。以字節為單位划分,一個16進制數是4bit,一字節就是兩個16進制數,所以我們寫起來是兩個16進制數在一起算作一個字節,那么就要把call指令里面的偏移值改為c3ffffff。接下來我們研究如何實現上面的更改操作。

圖6

上圖所示的步驟,選自碼雲上的講義,我們按這個步驟做下去,即可完成修改操作。

Step2:輸入“ctrl+c”退出當前的反匯編分頁顯示界面。用cp命令備份一下pwn1文件,然后使用vi命令編輯備份文件。

圖7

Step3:由於vi編輯器編輯的對象是文本文件,所以對於一個可執行文件進入編輯模式的話,會出現大片亂碼。所以我們要輸入 :%!xxd ,以使文件內容以16進制形式顯示。效果如下:

圖8

圖9

Step4:我們要修改的對象是d7 ff ff ff,要將其改成c3 ff ff ff,簡單來說就是把d7改成c3。在vi編輯模式下我們可以輕松更改,關鍵是要找到這個d7在哪里。我們輸入 /e8 d7 既可以定位到這里,如果找到多個查詢結果,那么就對比着前面的反匯編結果,看看前后一定長度的字節內容是否匹配,一定要確保改的是正確的地方。

圖10

Step5:把光標移動到d,按一下 r 鍵,再輸入 c ,然后按一下方向鍵 → ,再按一下 r 鍵然后輸入 3 。完成修改。

圖11

Step6:修改完成后不能立即退出,有一套“退出機制”。首先是把當前的16進制形式轉換為原形式:%!xxd -r;然后是存盤退出 :wq 。如此便完成修改了,main函數可以成功調用到getShell函數。

圖12


Step7:驗證。我們可以用兩種方法來驗證是否修改成功了,第一種是反匯編,針對剛剛修改的文件進行反匯編,通過反匯編結果驗證。截圖如下:

圖13

由上圖可知,main函數通過call指令調用了首地址位於80847d的getShell函數,證明剛剛的修改是成功有效的。

另一種方法就是直接運行了,剛剛修改的文件名叫pwn2,那么就在文件所在的文件夾下輸入./pwn2來執行這個文件。./表示當前目錄。運行結果如下圖所示:

圖14

由上圖可知,運行過pwn2以后,即可執行命令行語句了,比如執行ls,就可以顯示出當前路徑下的所有文件:pwn1(原始文件)和pwn2(攻擊過后的文件)。輸入exit命令,就退出了shellcode。由此我們看到了攻擊效果,程序的功能被改變了。程序本來的功能是什么呢?我們運行一下pwn1就知道了,如上圖所示,pwn1運行過后,功能是回顯用戶輸入的字符串,這正是foo函數的效果,也正是程序被攻擊前的執行流程。

二、通過構造輸入參數,造成BOF攻擊,改變程序執行流

Step1:在這里,我們首先要發現程序的漏洞,然后針對漏洞實施攻擊。這就要求我們對程序的功能有足夠的了解。經過研究可以發現,本程序3個函數中foo函數存在BOF漏洞,可以實施緩沖區溢出攻擊。

圖15

我們知道foo函數的功能是回顯用戶輸入的字符串,由上圖的反匯編結果可知,函數內兩條call指令中前面那個讀入字符串,后面那個輸出輸入的字符串。輸入字符串按地址遞增的順序自然增長覆蓋,系統預留的緩沖區大小只有0x1c,即28字節,地址自然增長填滿28字節的區域是正常的,一旦輸入字符串過大,超過了28字節,那么接下來4個字節會覆蓋到EBP寄存器上,再來4個字節會覆蓋到EIP寄存器上,這4個字節,也就是第33、34、35和36個字節是我們關注的重點。因為EIP寄存器存放的是下一條要執行的指令的地址,我們若是能控制這個寄存器的值,那么就可以自由控制程序的走向了。正常來說,foo函數會回顯輸入的字符串,這其中有輸入和輸出兩步,一旦我們通過緩沖區溢出攻擊輸入了一個長度較大(不少於36字節)的字符串,那么EIP寄存器的值就有可能被修改,程序的走向就被帶偏了。我們可以輸入一長段字符串,指定第33、34、35、36個字節的內容就是getShell函數的首地址,那么這段字符串一覆蓋到堆棧上,程序的走向就被更改了,foo函數不會回顯剛剛輸入的字符串,而是會跳轉到getShell函數的首地址執行該函數。

另外,除了分析反匯編結果外,我們還可以通過gdb調試工具確定字符串中的哪些字節可以進入到EIP寄存器中。首先我們是為我們的kali下載安裝gdb工具,如果沒有的話。

圖16
如上圖所示,我們通過`apt-get install gdb`命令即可完成gdb的安裝。如果提示權限不足,就在命令前面加上`sudo`。安裝的全過程包括成功的界面截圖如上,有上面那些步驟應該就是是安裝成功了。

圖17

上圖有兩個紅框,第一個紅框以上的部分是gdb調試pwn1的過程,到第一個紅框開始才能輸入命令。這里我們輸入r,表示運行。下面第二個紅框里有兩行一模一樣的內容,這正是pwn1本來的面目,它會調用foo函數回顯輸入的字符串。我輸入了一條測試字符串,長度為42字節,111111112222222233333333444444441234567890。可以正常回顯,所以就有了第二行的輸出,但下面緊接着就給出了segmentation fault,即段錯誤,因為是發生了緩沖區溢出。那么此時各個寄存器狀態如何呢?我們通過info r來查詢一下,結果如下圖所示:

圖18

由上圖可以看出,EIP寄存器對應的內容是0x34333231,這正是16進制下的1、2、3和4。這更加說明,我們上面輸入的42字節的數據中,1234被寫入了EIP寄存器,即第33、34、35、36個字節是會被寫入EIP寄存器的。

前面通過反匯編可以知道,getShell函數的首地址是0804847d,根據小端優先的規則,再加上2個16進制數算作1個字節,我們要輸入的地址是\x7d\x84\x04\x08。那么攻擊字符串就可以構造為11111111222222223333333344444444\x7d\x84\x04\x08\x0a\x0a表示回車。

Step2:在上述思路的指引下,接下來我們需要確定用什么樣的方法注入攻擊字符串。我們無法直接通過鍵盤輸入有效的16進制字符,可以通過生成包含這樣一個字符串的文件然后經由管道注入到目標文件來實現注入攻擊字符串的目的,這需要用到Perl語言。

perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input-20184303

這樣,我們就通過Perl語言把攻擊字符串寫入到了input-20184303文件中,它在當前文件夾中生成。生成代碼及效果截圖如下:

圖19
由上圖可知,我們在使用Perl語言生成了存有攻擊字符串的目標文件后,使用ls指令顯示當前路徑下的全部文件,果然顯示出了剛剛生成的文件**input-20184303**。然后用**xxd**命令驗證一下文件里面的內容是否是剛剛寫入的攻擊字符串。由上圖可知文件內容是正確的,地址為00000020的存儲單元存儲的正是getShell的首地址。

Step3:我們將input的輸入,通過管道符“|”,作為pwn1的輸入。輸入命令為

(cat input-20184303; cat) | ./pwn1

效果如下圖所示:

圖20

從上圖可以看出,經過管道注入后,再運行pwn1文件時,它的功能已經不再是回顯輸入的字符串了,而是調用了getShell函數,可以輸入命令行指令。我先后測試了ls和pwd,結果都是符合預期的,前面那個是顯示出了當前文件夾里面的全部文件,包括input-20184303、pwn1和pwn2;后面那個顯示出了當前所處的路徑。都是沒問題的。

圖21

三、注入Shellcode並執行

Step1:准備一段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\

Step2:做好准備工作。為了讓本操作沒那么復雜,本操作是有一些限制條件的,本步驟就是要落實這些限制條件。

圖22

上圖截自碼雲上的實驗講義。但在實際操作中,由於種種原因還是不會和上圖完全一致,這與用戶權限有關。

還未安裝execstack的話,可以通過apt-get install execstack命令安裝,為避免權限不夠,我還在命令前面加上了sudo。安裝過程如下圖所示:

sudo apt-get install execstack

圖23

安裝成功后,接下來我們通過execstack -s pwn4303設置堆棧可執行,本實驗中,我備份pwn1,並重命名為pwn4303,方便之后的運行。通過execstack -q pwn4303查詢文件的堆棧是否可用。如下圖所示,出現X的話就表示可用了。

圖24

下面要關閉地址隨機化。我們通過 more /proc/sys/kernel/randomize_va_space來查詢地址隨機化的狀態。我們用more來查看的這個文件有3個值,分別是0、1、2,每個值都有不同的含義。當且僅當它的值為2時才表明關閉了地址隨機化。下圖所示的3段有效指令中,第一段是查詢randomize_va_space的值,發現不是0,然后就通過第二段指令將0覆蓋進去,最后通過第三段指令重新查看一下該文件的值,驗證一下第二段指令的修改是否有效。結果是0,這是正確的、符合預期的!

如下圖所示,當我輸入第二段指令時,可以看,出連續兩次被提示權限不夠,即使我已經加了sudo。后來查閱資料才知道,還要加上sh -c才可以。利用 "sh -c" 命令,它可以讓 bash 將一個字串作為完整的命令來執行,這樣就可以將 sudo 的影響范圍擴展到整條命令。詳見 https://blog.csdn.net/tangtang_yue/article/details/78030658

圖25

Step3:使用輸出重定向將perl生成的字符串存儲到文件input_shellcode-4303中,效果如下圖所示:

圖26

上面這一大段字符串也是事先規定好的,粘貼過來直接用就可以。

Step4:下面我們通過(cat input_shellcode-4303;cat) | ./pwn4303注入攻擊緩沖區buffer。效果如下圖所示:

圖27

Step5:使用gdb調試進程。


保持當前的命令行終端不變,另外打開一個命令行,通過ps -ef | grep pwn4303查詢pwn4303的進程號,結果如下圖所示:

圖28
我們開啟了兩個終端,要查詢的是第一個終端也就是pts/0里面的pwn4303的進程號,可以看出這是2262。接下來我們要使用gdb工具來調試該進程。

圖29

如上圖所示,我們首先輸入gdb來開啟調試工具。然后等到圖中一個紅框所示的位置以后可以輸入內容,我們就輸入attach加上剛剛查詢到的進程號,在此我輸入了attach 2262

然后輸入disassemble foo,針對foo函數進行反匯編,得到如下結果:

圖30

從上圖可知,ret的地址為0x080484ae,所以我們就在這個地址設置斷點,指令為break *0x080484ae。效果如下圖所示:

圖31

此時系統會提示自己說,Breakpoint 1 at 0x80484ae,這表明斷點設置完畢。

現在,我們在第一個命令行終端按下一次回車鍵,然后回到第二個終端按下c鍵繼續運行。

圖32

圖33

經歷過上面的操作后,我們在第二個終端輸入info r esp查看棧頂指針所在的位置及其存放的數據。

圖34

由上圖可知,esp寄存器放的是存0xffffd18c,緊接着我們用x/16x 0xffffd18c查看該地址的及其臨近地址所存放內容。我們找到了0x01020304,這也正是返回地址的位置。shellcode就挨着,加上4就是了,所以shellcode的地址是 0xffffd190。

Step6:修改shellcode的值,完成攻擊。

圖35

如上圖所示,我們可以先退出gdb調試工具,然后向剛才生成的input_shellcode-4303文件中覆蓋修改后的Perl代碼,地址0xffffd319在寫入文件時遵循小端優先的原則,按\x19\xd3\xff\xff......的形式寫入,每一個16進制數表示一個字節。

​ 我們也可以用xxd命令來驗證一下剛剛的文件input_shellcode-4303有沒有被正確寫入,如下圖所示:

圖36

Step7:最后,我們針對getShell函數進行調用,通過管道將input_shellcode-4303的輸入作為pwn4303的輸入,結果如下圖所示:

圖37

在上圖中,輸完管道命令后下面第一行的ls是無效的,因為此時程序尚未執行完畢。當出現接下來的代碼以后,就可以成功調用命令行了。在此我先后輸入了ls、pwd、exit這三個有效命令進行測試,結果都是符合預期的。

實驗總結

一、實驗收獲與感想

本次實驗圍繞緩沖區溢出攻擊進行了三個操作,分別是直接修改程序機器指令、利用foo函數的BOF漏洞和注入shellcode

  • 關於實驗操作:碼雲講義上有着非常詳細的實驗講義,視頻也針對實驗內容進行了逐步的分析,在思考的過程中完成本次實驗,使我理解了BOF原理,學會了怎么運行原本不可訪問的代碼片段,強行修改程序執行流以及注入運行任意代碼,了解了如何通過修改棧所存儲的指令地址,跳轉到想運行的指令。作為網絡對抗的第一次實驗,接觸到了很多之前僅僅只是了解的知識,並在實際的操作中完成這些指令的編譯,操作非常簡單,但如何去理解這些內容成為了一個難點,只能不斷地去回顧視頻內容,查閱相關資料。
  • 關於實驗中出現的問題:實驗中出現的問題非常多,花費時間最長的是GDK工具不能使用,execstack的安裝,指令權限等,我所使用的KALI是導入相關源漢化后的版本,出現的問題更加多了,這時只有不斷的查閱資料,查閱相關博客,解決這些問題,逐步熟悉Linus系統。

二、什么是漏洞?漏洞有什么危害?

  • 漏洞:是在硬件、軟件、協議的具體實現上存在的缺陷,從而可以使攻擊者能夠訪問或破壞系統。配置不當的問題都可能被攻擊者使用,威脅到系統的安全。具體舉例來說,比如在 Intel Pentium芯片中存在的邏輯錯誤,在Sendmail早期版本中的編程錯誤,在NFS協議中認證方式上的弱點,在Unix系統管理員設置匿名Ftp服務時配置不當的問題都可能被攻擊者使用,威脅到系統的安全。因而這些都可以認為是系統中存在的安全漏洞。

  • 漏洞的危害:漏洞會影響到的范圍很大,包括系統本身及其軟件等。在這些不同的軟硬件設備中都可能存在不同的安全漏洞問題。這個缺陷或錯誤可以被不法者或者電腦黑客利用,通過植入木馬、病毒等方式來攻擊或控制整個電腦,從而竊取電腦中的重要資料和信息,甚至破壞系統。聯想電腦管家經常會更新一些漏洞補丁,我們無法在如此繁雜的代碼中找到所有的漏洞,只能由用戶使用、發現最后回饋給系統,系統再動態的更新代碼,彌補漏洞。針對本實驗的緩沖區溢出攻擊,也是有很多規避方法的,如GCC堆棧保護技術、設置堆棧不可執行、啟用地址隨機化、加強代碼質量檢查等,避免緩沖區溢出漏洞。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM