( 點擊圖片便可撥放音樂
最近窩在上CEH的課程,
結(jié)果學到了不少酷酷的新東東,
也順便補足了我自學所產(chǎn)生的盲點與誤解。
其中,就有包含一個有趣的主題,
是我至今為止都一直不敢去接觸的,
那就是:「如何挖掘、並開發(fā)出攻擊腳本」
該怎麼講呢,
主要是我認為自己的能力仍然有所不足,
並沒有那個底子或本事去學習這方面的知識,
所以遲遲不敢去研究這領(lǐng)域的技巧。
但!是!呢!
由於在CEH的課程中被迫學習這個領(lǐng)域的技術(shù),
我發(fā)現(xiàn),我居然意外的聽得懂欸!?
真的是超開心的說,
所以就整理成這一篇文章作為紀念,
並給未來的後輩們有一些參考的資料。
[#]前情提要:
1. 要會 Python3
2. 要會 socket 模組的 TCP 傳輸方法
3. 要會基礎的 32 位元的 Assembly
4. 要了解 stack push pop 的原理
5. 要會如何用 Asm 創(chuàng)造跟毀滅 stack frame
上面那幾點,
5項裡面建議至少要會3項,
否則等一下你真的會看的很痛苦~ (^ ^)
還有,
上面的那首歌我建議你先開始播放,
配合本文服用效果更佳。
因為你等一下你會看到一堆恐怖的東東,
來點歌舒緩內(nèi)心WTF的情緒肯定是必須的。
————————————————————
[#]你會用到的工具與靶機:
1. 一臺 Win10 電腦
2. 一臺 Kali 或 Parrot Os
4. mona.py
5. Vulnserver
把 3、4、5 都先下載好,
然後放在 Windows10 裡面,
而 Windows 10 的防火牆不用關(guān),
domain、private 、public 全部都打開就行了,
因為等一下我們可以直接打穿防火牆,
所以不用擔心。( ̄? ̄)
至於 Mona.py 嘛 ,
他是一個 Immunity Debugger 的模組,
所以就請諸君在安裝完 Immunity 後,
把他拉進 c:\Program File (x86)\Immunity Inc\Immunity Debugger\PyCommands 裡面。
————————————————————
[#] 觀念整理:
首先,
先幫各位複習一下stack的概念,
理論上,所有會需要參數(shù)的 function,
為了節(jié)省程式本體的檔案大小,
都會用到 stack frame 來傳遞/暫存變數(shù)給 function,
而不是定義出大量固定的 buffer 來放變數(shù)。
畢竟 stack frame 是一種動態(tài)儲存的概念,
因此只有在 runtime 時才會存在,
用完後就會直接:
mov esp, ebp
pop ebp
來毀滅掉所有暫存在裡面的資料。
而 buffer overflow 就是用超級大量的資料,
把 stack 裡面 callee 的 args buffer 通通灌滿,
造成覆寫到 callee 的 stack frame 資料。
而詳細的利用方法則如同下圖:
先用垃圾資料蓋掉 main var 的 stack frame,
再讓特定的資料複寫掉Return Addr(EIP),
讓程式執(zhí)行完後跳到惡意程式碼的區(qū)塊。
一言以蔽之,
就是太大了,所以難以抗拒。
只要你小時候32位元組語有學好,
這一切都會很簡單易懂,對吧?(′▽`)
————————————————————
[#] 實際演練:
在 windows 10 裡面,
先把 vulnserver 以管理員的身分啟動。
接著,
一樣以管理員的身份開啟 Immunity,
選擇 File 裡面的 Attach:
選擇裡面表示為 vulnserver 的程序,
並把他掛上去分析:
按一下左上角的播放按鈕,
右下角的狀態(tài)欄位就會變成 Running,
代表著開始觀測伺服器在記憶體中的狀況。
只要一但系統(tǒng)崩潰,或是執(zhí)行到 breakpoint,
左下角的狀態(tài)就會變回 Paused,
並紀錄暫存器中最後的資料與數(shù)值。
然後,在攻擊的那臺 Linux 中,
叫出 nmap 掃描一下到底新開了什麼 port。
由以下的圖片中,不難發(fā)現(xiàn),
他開了一個詭異的 port 9999。
我們先連上去瞭解一下狀況,
以及伺服器所提供的指令與互動模式。
至於伺服器所提供的指令是三小意思,
看不懂也沒關(guān)係,因為他們不是很重要。
我們只需要了解,
所有的指令後面都可以接著一個參數(shù),
而伺服器則會對你的輸入的參數(shù)做出回應。
而我們這邊就需要去 fuzz 他,
看看伺服器會不會因為奇葩的輸入資料而崩潰,
這邊我們將使用的是SPIKE。
所以我們就先寫一個簡單的腳本,
帶入各種指令(如:Stats、Rtime……),
加上SPIKE自動產(chǎn)生的奇怪參數(shù),
試圖讓伺服器產(chǎn)生錯誤並崩潰。
接著就使用Generic_tcp_send送出資料,
觀察 Immunity 中的伺服器有沒有被我們幹停。
而在不斷的嘗試之中,
可以發(fā)現(xiàn) TRUN 後面的參數(shù)可以造成崩潰,
而右下角的狀態(tài)也會隨之轉(zhuǎn)成 Paused。
我們可以寫一個簡單的程式,
用遞增的資料量試圖估計出造成崩潰的零界點,
也就是找出能覆寫 callee var 空間的約略大小。
重啟伺服器與 Immunity,
並執(zhí)行剛剛寫的 fuzz.py。
在 immunity 轉(zhuǎn)成 Paused 的那一刻,
立刻按下 Linux 的 Ctrl-C 終止程式,
我們可以發(fā)現(xiàn)造成崩潰的大小大落在 2400。
為了找出能夠剛好蓋過 EIP 的大小,
我們可以透過 msf-pattern_create 產(chǎn)生一組彼此不重複特殊的資料,
用來定位恰巧能夠覆寫掉 EIP 的切確大小。
接著再寫出一個 Python 腳本,
把剛產(chǎn)生的 2400 byte 的資料一次全部塞進去。
由下圖的暫存器狀況,
我們可以發(fā)現(xiàn)覆寫 EIP 的數(shù)值為:386F3337
丟進去 msf-pattern_offset 後,
我們可以發(fā)現(xiàn)那組數(shù)字是第 2003 個 byte。
也就是代表 var 的 buffer 大小為 1999,
往後推 4 byte 就是上一個 ebp 的暫存數(shù)值。
再往後推 4 byte 就是 return address,
之後的空間就是 callee 的 stack frame ㄌ。
我們可以寫一個簡單的小程式,
測試看看先前計算的offset是否正確。
如下圖,
先丟 2003 byte 的 C,加上 4 byte 的 D。
理論上大小 32 bit 的 EIP 就會變成 DDDD。
執(zhí)行後,可以發(fā)現(xiàn) EIP 變成了 44444444,
也就是代表了我們成功覆寫了原本的數(shù)值。
( D 的 ASCII 值為 44
接著,我們要來尋找看看,
是否有設定上不安全的模組,
裡面剛好有能讓我們完成 jmp esp 的 opcode,
讓我們待會兒可以把 EIP 導向那邊,
再間接跳進從 EBP 開始的 shellcode。
所以請再次打開 Immunity,
並 attach vulnserver 上去,
打入 “!mona modules” ,
而這個指令會列出所有模組的記憶體保護設定。
其中,下圖中的 essfunc.dll,
全部的記憶體保護設定都是 off 的,
所以,我們就拿它來測試看看裡面有沒有含有 jmp esp 的相關(guān)操作。
為了了解 jmp esp 的 opcode 為何,
我們先回到 linux 中叫出 msf-nasm_shell,
往裡面打入 jmp esp 後,
我們就能看到對應的 opcode 是 \xFF\xE4。
接著回到 Windows 的 Immunity 中,
打入 !mona find -s “\xff\xe4” -m essfunc.dll,
搜尋裡面含有 jmp esp 的 offset 位置。
裡面回傳了9筆資料,
為了方便起見,我就用第一個的 0x625011af。
這個時候,
我們就來實驗看看是否能夠透過該位置,
把程式 jmp 到 esp。
寫一個 python 程式,
測試看看是否透過覆寫 Return Address,
把 EIP 導到 0x625011af 的 jmp esp。
這個時候,
再次打開 Immunity 與 vulnserver,
並按下左上角的 goto 按鈕,
跳到 0x625011af 去檢視看看那邊的程式碼。
點擊 jmp esp 再按下 F2 ,
就可以在此處設置一個 breakpoint。
然後再按下播放按鍵,
開始繼續(xù)監(jiān)控 vulnserver。
再執(zhí)行剛剛寫的程式後,
immunity 再次變成 paused 了,
而且此時此刻的 EIP 為 0x625011af,
代表者 jmp esp 到 shellcode 的手法是可行的。
然而,
再開心的用 shellcode 把他灌滿滿之前,
我們?nèi)皂毩私馑欧髦惺欠裼?badchar 的問題。
至於該如何測試呢?
簡單來說就是把各種已知的 badchar 傳過一輪,( 網(wǎng)路上就查得到ㄌ
並觀察記憶體中的資料是否會產(chǎn)生錯誤。
關(guān)於這部分的測試,
我們一樣也可以透過 python 來完成。
再執(zhí)行程式後,
Immunity 就會再次被我們幹停ㄌ。
點擊右上角的暫存器那區(qū),
並點擊 ESP 再按下 Follow in dump,
就能夠把左下角的 memory dump 轉(zhuǎn)跳至該位置。
不難發(fā)現(xiàn),資料都亂掉了,
唯有第一個的 0x00 是正常的,
而這代表著 0x00 是 badchar,
需要在產(chǎn)生 payload 時刻意被迴避。
總之,
再不斷的反覆嘗試與調(diào)整後,
直到剩餘的數(shù)字都能夠正常且連續(xù)的顯示時,
就代表你已經(jīng)排除了所有的 badchar ㄌ。
這時候,
我們就可以開始準備攻擊用的 shellcode 了!
這邊我就用 msfvenom 處理這部分,
並把 format 選擇為 C。
準備好 shellcode 後,
我們就可以開始構(gòu)築我們的攻擊腳本ㄌ。
在這邊我先簡單整理一下,
我們要向伺服器丟出的資料為:
「 2003 bytes 的垃圾資料用來覆寫 buffer
+ 4 bytes 用來覆寫 RA 讓 EIP 指向 jmp esp
+ 一段任意大小的 NOP Sled 用來緩衝
+ Shellcode 本體。」
我簡單講解一下 NOP Sled 的用意,
主要是因為結(jié)束 stack frame 前,
我們無法預知 function 會不會使用 stack ,
因此無法準確預知 ESP 最後的位置。
( 我們只知道 EBP 的位置
所以就只能用 NOP(\x90) 當作一個緩衝區(qū),
讓 EIP 可以在這個區(qū)段內(nèi)滑行到 Shellcode。
因此 ESP 只要在 NOP Sled 的保留緩衝內(nèi),
攻擊都不會失敗。
重新再啟動一次在 Win10 上的 vulnserver,
並在 Linux 中執(zhí)行 nc -lvp 53 監(jiān)聽,
再執(zhí)行完我們精心設計的攻擊腳本後,
我們就可以拿到一個與 vulnserver 相同權(quán)限(系統(tǒng)管理員)的 reverse tcp shell,
並且可以執(zhí)行任何你想要的指令與程式。
————————————————————
..….
……
……
……
……
……
……
很簡單對吧?
諸君,你們學會了嗎?