文章插圖

文章插圖
翻譯:shan66
預估稿費:300RMB
投稿方式:發送郵件至linwei##,或登陸網頁版在線投稿
前言
本文將為讀者詳細介紹QuickZip v4.60緩沖區溢出漏洞方面的知識 。由于漏洞在2010年就出現了,所以它的設計僅適用于32位Windows XP 。所以,我決定嘗試在64位Windows 7上重現該漏洞,這將是一個(有趣的)挑戰!
PoC
為此,我從exploit-db中抓取了QuickZip v4.60 Windows XP漏洞,并將用它創建了一個簡單的PoC來觸發崩潰 。
如果您在QuickZip中打開剛創建的ZIP文件,并嘗試提取其內容(或只需雙擊文件名),那么QuickZip就會崩潰 。
了解崩潰詳情
好的,我們來運行PoC,看看到底發生了什么 。
使用上面的Python腳本創建ZIP文件,使用QuickZip打開它,啟動ImmunityDebugger,附加到QuickZip進程,并在QuickZip中雙擊文件名以觸發崩潰 。注意:我們將不斷重復這個過程!
下面,我們來研究一下SEH鏈 。
偏移量
一如既往,我要借助mona(https://github.com/corelan/mona )來完成許多工作 。
首先,我們生成一個4064個獨特字符的模版,并將其放在PoC漏洞利用代碼的有效載荷中:
此外,似乎我們無法控制SEH了 。
使用以下命令讓mona計算所有偏移量:
讓我們用偏移信息更新PoC,并嘗試再次觸發崩潰 。
找到這樣的指令是很容易的,但首先,我們必須知道允許使用哪些字符 。這就是我們需要關注的下一個問題 。
壞字符
總的來說,大部分是這樣的 。為什么?因為我們的溢出是針對filename參數的,而文件名用到的字符類型是相當有限的: 通常只有ASCII可打印的字符 。
如果使用手動方式的話,那么使用mona通過遍歷方法找到所有壞的字符將需要太長的時間,所以這里簡單假設除了0x00、0x0a和0x0d(分別代表NULL、換行和回車)之外,我可以使用ASCII表中所有的字符(最高值為0x7F的字符) 。
這個假設可能會比事情比實際情況要更困難(因為我需要避免使用實際可以使用的字符)一些,或者可能會導致更多的問題,如果我的假設范圍內的某些字符其實是錯誤的話 。
我不喜歡這樣做假設,但為了進行這個練習,這里例外一次 。
我只需要記住,要格外小心,如果有情況,則需要再次檢查壞的字符 。這有點冒險,但很好玩,繼續!
POP-POP-RET
讓我們通過mona來尋找一個易于使用的POP-POP-RET指令:
這里唯一的問題是0x00字節,但是由于程序的地址空間的原因,每個地址都以0x00開頭,所以我們來嘗試一下,看看是否會影響我們的漏洞利用代碼 。
更新PoC漏洞利用代碼,用 x33x28x42x00替換目前代表SEH的CCCC,再次觸發崩潰并考察SEH鏈 。
shellcode去哪里了?
好的,我們分析一下,看看我們進展情況 。
我們設法讓它崩潰了,并且能控制SEH,這非常好! 問題是我們的有效載荷受制于一個非常有限的字符集,并且因為我們必須使用NULL字節的地址來調用POP-POP-RET指令,我們的有效載荷被切斷了,并且留給shellcode的空間也不是很大 。
那么它究竟有多大呢? 別忘了,為了獲得SEH,我們還在有效負載開始部分進行了填充:
不過,這個問題好像可以用egghunter來解決!
Egghunter只是一堆指令,在程序的內存空間中查找一個特定的、已知的字節序列(“egg”),一旦找到,將重定向到該區域 。
這樣我們就不用擔心我們的shellcode在哪里結束了,我們可以調用eghtunter例程,它會為我們找到它們!
聽起來不錯,但下一個問題是,有效載荷的“截止”部分真的位于在內存中嗎? 我們來看看吧 。
讓我們生成3764個單字符的模版(在NULL字節之后填寫我們的有效負載),并用它替換現有的A 。
Egghunter
現在我們能夠使用egghunter來獲取我們的shellcode,但是我們只有292個字節可供使用 。實際上,我們可以用292字節空間做許多事情,但是別忘了,我們只能使用非常有限的字符集 。
我們試著用metasploit的x86 / alpha_mixed編碼器對egghunter進行編碼,看看在這之后還剩下多少空間 。
首先,讓我們生成egghunter有效載荷 。請記住,我們正在使用64位操作系統,因此還需要使用相應的egghunter例程(有關更多詳細信息,請訪問https://www.corelan.be/index.php/2011/11/18/WOW64-egghunter/ ):
指定bufferregister選項基本上就是告訴編碼器不用擔心如何在內存中找到自己的位置,我們會事先做好這件事情,我們將其地址放在EAX寄存器中 。這樣,我們的編碼后的egghunter就是純ASCII字符(更多關于生成字母數字shellcode的信息可以在這里找到) 。
我們更新我們的PoC漏洞利用代碼,以反映我們迄今為止所做的工作的成效 。
跳轉回來
現在我們還有更多的事情需要考慮——這里最重要的一點是,我們需要把egghunter的地址放在EAX中,然后跳轉到那里 。
我們如何在空間有限的情況下做到這一點? 首先,我們有多少空間? 簡單計算一下就知道是146字節(nseh偏移減去egghunter的大?。?。
146字節可以做什么? 我們只需要寫幾個指令,但是它們必須屬于允許使用的有限的字符集 。在這種情況下,我們不能使用已經用于egghunter的通用編碼器,因為我們根本沒有足夠的空間來滿足它 。
所以,我們需要創建自己的編碼器! 這聽起來很讓人頭疼,但實際上比看起來要簡單得多 。
首先,我們來看看目前在程序中的位置 。
在這方面,可以參考TheColonial分享的相關技巧:http://buffered.io/posts/jumping-with-bad-chars/ 。
簡而言之,我們可以簡單地使用JO和JNO指令來調用近轉移指令到我們的有效載荷 。但我們能跳多遠? 通過用一些允許的字符的包裹后,我發現一些壞的字符會被轉換為A2,它轉換成十進制就是92,這應該能給我們提供足夠的空間,以創建我們的自定義編碼器 。
定制編碼器
為了跳到eghunter,我們需要寫許多條指令,因為不使用“壞”字符的話,就沒有直接的方法 。
要解決這個問題,我們需要執行以下操作:
找出我們想要寫的指令的操作代碼
使用簡單的數學指令(即ADD和SUB),通過允許的字符將來自上述步驟的操作碼的值放入我們選擇的寄存器(例如EAX)中
我們將這個寄存器的值寫入堆棧,從而將我們想要的指令寫入ESP指向的內存區域
聽起來很復雜? 但實際上并不是那么糟糕 。
首先,我們需要調整堆棧才能寫入我們控制的內存區域 。通過觀察ESP的值和我們目前的位置(上面的截圖),可以發現,我們需要將ESP偏移0x62C(0x0018FB58(EIP的值)減去0x0018F528(ESP的值)再減去0x4(用于填充的空字節)) 。
注意:由于pop esp指令( x5c)的緣故,ZIP文件的內容看起來會有點不同 。x5c表示一個反斜杠,由QuickZip解釋為一個文件夾…這可能在以后有一些影響,但現在沒什么 。
為了避免“壞”字符,我們將在EAX寄存器中設置我們需要的操作碼的值,并將其壓入我們調整的堆棧上 。這樣,我們需要的指令將寫到我們控制的內存區域中 。
下面用一個例子來解釋 。
讓我們對所有剩余的字節做同樣的處理 。
完成上述處理后,新的PoC應該如下所示:
跳轉
不幸的是,我們沒有太多的空間可用于跳轉:在我們的編碼器代碼之后只有5個字節,編碼器代碼之前是4個字節 。所以,我們需要找到相應的指令,讓我們跳轉到剛寫的代碼 。
事實證明,由于字符限制,實際上我們無法做太多的事情 。任何短的向后跳轉指令都包含無效的字符,無法跳轉至恰當的地方 。所以,應該考慮是否重用之前用過的跳轉 。
下面來看看我們目前擁有的有效載荷 。
【0x0eedfade開不了機 0x0eedfade無法開機】哎,這樣行得通嗎?讓我解釋一下 。
我們需要使用的跳轉指令本來可以是簡單的JMP $ -16( xebxee),不幸的是它包含了無效的字符,因此不適用于我們… 。但是,任何帶有有效的字符的跳轉指令都會讓我們離的太遠 。
然而!我們可以使用自定義的編碼器來處理它們,就像我們將egghunter的地址放置到EAX一樣,只需要調整偏移量并修改代碼即可 。
首先,添加我們的JMP指令 。然后,修改我們的原始堆棧,使SEH跳轉能夠準確到達我們的初始位置 。最后,在編碼器的開頭部分添加一些NOP,它們之后將被所覆蓋 。下面我們具體介紹其工作原理 。
這里,讓我們先從自定義的編碼器前面的NOP開始 。由于我們要求使用有效的字符集,因此可以使用 x41x41(INC ECX)作為NOP 。
接下來,進行堆棧調整 。從目前的狀態來看,我們需要進一步偏移6個字節,以便寫入到要覆蓋的區域 。為此,我們可以進行相應的調整 。
最后,我們需要用編碼器寫入JNZ $ -16( x75xee)指令 。讓我們用新的指令來替換最后兩個 x90(記住這里使用的是little – endianness,所以我們需要反過來寫入) 。
最后,代碼將變成這樣:
崩潰被觸發
POP-POP-RET指令被調用
獲得JNO $ -92的跳轉地址
從頭開始執行自定義編碼器
代碼最終將到達第3步中跳轉的JNO指令
再次取得JNO的跳轉地址,但這次,我們登陸的第一條指令是剛剛寫入的16個字節的跳轉指令
獲取跳轉指令的跳轉地址
使用自定義編碼器寫入要執行的指令
我們來看看到底發生了什么 。
執行自定義的編碼器后:
讓我們來計算一下——ESP的當前值是0x0018FB4E,而egghunter代碼從0x0018FA90開始,這意味著我們需要將EAX減去0xBE,讓EAX指向我們的目的地 。
我們開始修改漏洞利用代碼,這里不是從EAX中減去0xDEADBEEF,而是減去0xBE 。PoC應進行以下修改:
讓我們觸發崩潰,看看這一次我們是否可以在內存中找到這個模版 。
Shellcode
現在,我們只需安裝常規流程來處理一下shellcode就行了——我們需要找出壞字符,然后在shellcode之前插入一個“egg”(w00tw00t)并對齊堆棧 。
我不會詳細介紹尋找壞字符的細枝末節,因為我已經在這里詳細介紹過了 。幸運的是,對于我們來說,這部分有效負載中僅有的壞字符是 x00, x0a和 x0d 。
我們還需要在shellcode的開頭插入w00tw00t字符,以確保egghunter可以定位它,并將執行權重定向到“egg”之后的第一個指令 。
最后,我們需要對齊堆棧,以確保ESP指向一個16字節倍數的地址 。這樣做的原因是有一些“SIMD”(單指令,多數據)指令可以并行處理內存中的多個字,所以要求這些字的起始地址是16字節的倍數 。
如果我們沒有正確對齊堆棧,那么shellcode根本不起作用 。我們可以輕松地利用單個指令AND esp,0xFFFFFFF0來對齊堆棧,也就是讓它正好在w00tw00t“蛋”之后,在實際shellcode之前 。
對于這個概念驗證來說,我們將使用msfvenom生成一個簡單的、彈出計算器的shellcode,具體如下所示:
在本文中,我們已經成功地重新創建了QuickZip漏洞利用代碼的64位版本,它已經可以在Windows 7上運行了!
總而言之,我們通過使用非常有限的、被允許的字符集(幾乎可以ASCII打?。﹦摻艘粋€egghunter漏洞利用代碼,編寫了我們自己的編碼器,并通過在內存中的跳轉,到達egghunter代碼,最終到達shellcode 。
需要注意的是:
找出允許使用的字符,并在發生錯誤時記住這些字符
如果緩沖區大小不夠,不要氣餒——發揮你的創造性!
確保您使用正確的egghunter代碼(32位與64位),具體取決于您正在開發漏洞的平臺
編寫自己的編碼器不是那么難,但需要大量的練習和耐心
確保在執行shellcode之前對齊堆棧
- iOS開發人員招聘 iOS開發招聘
- 接受駐場開發是什么意思 駐場開發好不好
- 一家企業可以申請幾個服務號 一個公司可以開通幾個服務號
- 開塞露怎么用 如何正確使用開塞露
- java哪個培訓學校好 java開發技術培訓哪家好
- 怎樣能開通信用卡收款 收款怎么能用信用卡
- 加濕器可以加開水嗎
- 加濕器一定只有在空調開時才能用嗎
- 新砂鍋用之前怎么開鍋
- eclipse怎么打開工程文件 用eclipse打開文件
