1. 程式人生 > >堆漏洞——實戰double free和unlink漏洞

堆漏洞——實戰double free和unlink漏洞

為什麽 來講 sub 添加 n+1 函數功能 lock 有關 長度

0ctf freenote:從逆向分析到exploit編寫

鄙人的上一篇文章中,還算較為詳細的講解了unlink漏洞的原理,在閱讀本篇文章之前建議先學習上一篇blog

現在我們開始學習,這道ctf題目現在已經掛在Jarvis OJ上了,下面給出nc的url和程序下載鏈接:

nc pwn2.jarvisoj.com 9886

https://files.cnblogs.com/files/Magpie/level6_x64.rar

首先分析程序功能:

程序是典型的記事本程序,功能上基本就是添加記錄、打印列出所有記錄、編輯記錄、刪除記錄。

各位既然已經開始接觸堆溢出類題目,相信入坑二進制應該已經有段時間的,基本的逆向分析能力應該都是有的,因此不一一講解IDA中的分析過程,在此本人只簡單地說一下各個函數的功能和程序的數據結構:

一、函數功能說明:

技術分享圖片

main函數如上,主要功能函數我們一一說一下(不按圖中順序,按邏輯順序):

0x01.sub_400a49:創建記錄索引表,具體就是分配一個大堆,堆裏面存了各條記錄存儲區的指針(看後面分析就知道各條記錄都malloc了一個堆來保存),就好像物業存了各個房間的鑰匙,每把鑰匙都對應了一個具體房間,掛鑰匙的板子就是這個大堆,鑰匙對應的房間就是存儲各個記錄的堆內存。

0x02.sub_400998:就是讓你輸入一個操作選項,沒什麽好說的,這裏沒有漏洞可以利用。

0x03.sub_400bc2:新建記錄,進去以後的具體實現就是,讓你輸入記錄內容長度和記錄內容,然後檢查長度有沒有超最大限制,正常的化就malloc一個存儲這條記錄的堆塊,然後以你輸入的長度為標準一個一個把記錄內容讀進這個堆塊。註意malloc堆塊時有這樣一個操作:技術分享圖片

,這表示分配堆塊的大小是0x80的整數倍。最後就是把這條記錄的有關信息寫進索引表;當然開始的時候也檢查了索引表中還有沒有空間,這個大家應該看的懂,待會看數據結構分析的時候會理解的更好一點。

0x04.sub_400b14:輸出功能,遍歷索引表,打印所有記錄的標號和記錄內容,標號從0開始。

0x05.sub_400d87:編輯功能,依據上述記錄標號找到相應記錄,然後edit。

0x06.sub_400f7d:刪除功能,仍舊依據上述標號找到相應記錄,然後重置其索引表為未使用態,並free掉對應的記錄堆塊。

二、數據結構分析:

索引表的數據結構:

技術分享圖片

head不用管,是索引表大堆塊的塊首,不屬於用戶區;

max_size表示能存儲的最大的記錄數量,exist_num表示已有的記錄個數;

再往後就是每三個數據構成一個索引項,索引項的結構體的三個數據分別代表:0/1是指該項有無記錄引用,0是沒有,1是有記錄,size_user是記錄的長度,ptr_heap是存儲記錄的堆塊的用戶區指針。

註意:

這裏有一點大家必須清楚,就是我們所說的記錄編號,並不是將所有已經存在的記錄進行編號,這個編號指的是,索引表中的每個索引項,無論是否存在記錄,都進行線性的、固定的編號,這個編號在索引表建立後就有了,和記錄是否存在無關,它是索引項的編號。

這就好像高中不可以自己配鑰匙的時候,宿管大爺的鑰匙板上無論是否掛了鑰匙,對應位置都會貼一個房間號標簽,即使不掛鑰匙也有,只不過沒掛鑰匙說明有人取走了,說明這個寢室裏有人,對應過來就是,沒掛鑰匙相當於第一個結構體成員值為1,對應的記錄堆塊已經存在!

但是也有一點不同,大家不要過度將兩個例子對號入座,鑰匙房間一一對應,鑰匙還回(free)的時候從哪來放哪去,下次拿還是從同一個地方,但是假如開始有記錄1234,你把2刪了,下次新建的時候,根據代碼邏輯可以知道是把索引表中原來索引項2的位置拿來放新的,因此這個索引表是允許碎片化的。

三、漏洞挖掘:

這樣一來,結合各函數功能和索引表機制的原理,程序的數據處理思路也就清晰了,下面我們來找程序的漏洞:

0x01、即便堆漏洞接觸不多,細心的讀者可能也很容易發現第一處漏洞,漏洞出現在新建記錄的那個函數裏面,上圖:

技術分享圖片

這個就是新建記錄函數中實現讀入記錄內容的子函數,a2是用戶輸入的記錄的長度,通過循環read讀進a2個字符

註意,讀進a2個字符!!不是長度為a2的字符串!!!

正常情況下長度為n的字符串,是有包含‘\x00‘結束符在內的n+1個ascii,但是這裏並沒有把結束符讀進來,少了結束符,在打印記錄時就不會正確的停下來,也就可以實現內存泄露!

0x02、本程序的核心漏洞,double free漏洞:

技術分享圖片

漏洞出現在記錄刪除函數中,我們仔細分析一下這個函數的邏輯實現就可以發現一個驚人的事實:在你輸入一個標號後,程序並沒有檢查索引表中標號位置的索引項的第一個成員變量是否已經為0、也沒有檢查對應索引項的堆指針成員變量指向的堆內存是否已經被free,也就是說,即使這個索引項已經刪過記錄了,你還可以再刪它一次,再像沒事兒人一樣對ptr_heap再進行一次free,而在程序代碼中,free之後並沒有將對應堆指針置空(點名批評!),這就對同一堆塊free了兩次,造成了double free漏洞!

(我知道你們不感興趣但是還是要吐槽一下修補措施:哪怕你做到隨手置空、檢查標誌位、檢查ptr、或刪除時清除索引項的ptr中的任何一點也不至於出現這個漏洞。。。)

0x03、巧奪天工unlink——“塊內切割”大法:

這個方法也有人叫“堆塊重構”技術

反正就是一通騷操作,違章改造房屋結構,是要犯法的。。。(畫風秒變皮)

好了,我們正經來講一下:

(為什麽沒有了呢?博主寫累了,一次寫不完啊....很快就更!別急!....未完待續)

堆漏洞——實戰double free和unlink漏洞