系統安全與漏洞利用

釋放後使用利用(use-after-free exploit)

假設你把圖書館的書還到櫃台,卻留著寫有它書架位置的索書條。後來你走到那個書架,以為能拿回你的書——但館員早已在那裡擺上「另一本」不同的書。你讀錯了書,還以為是自己的。釋放後使用就是程式版的這件事:一個指標在某個堆積物件被釋放後仍指著它,而程式之後透過這個過時的指標去讀或寫。

把漏洞變成利用的這條鏈是這樣。你呼叫 free(p),它把 p 的區塊還給配置器,但「不會」清除其內容,也「不會」改變 p——p 現在是懸置指標(仍握著舊位址,仍「可用」,意思是解參考它能編譯也能執行)。攻擊者接著促使一次相同大小的「新」配置,而現代配置器為了區域性,最愛把剛釋放的區塊發回去。他們用自己控制的資料填滿這個新配置——例如一個假物件,其第一個欄位是函式指標。現在程式沿著「舊」指標 p 走,以為它仍指向原本的物件,於是透過攻擊者植入的函式指標呼叫過去。那個被釋放又被回收的槽位,已成了一個受控的讀/寫原語,往往也是一次控制流劫持。這就是為何帶 vtable 的 C++ 物件是首要目標:第一個字組正是指向方法表的指標。

它之所以重要,是因為近年來在瀏覽器、核心等大型 C/C++ 程式庫中,釋放後使用是被利用最多的單一記憶體漏洞——超越了經典的堆疊溢位。誠實的說法:修法不是「檢查是否為 NULL」,因為 free() 之後指標「並非」空指標,而是懸置;正確的紀律是釋放後立刻把指標設為 NULL(或用會替你做這件事的所有權工具),並記住 free() 既不歸零記憶體、也不會使指標的其他副本失效。

Widget *w = make_widget(); free(w); // w 現在懸置,並非空指標;記憶體未被清除 /* 攻擊者觸發一次相同大小的 malloc 並填入假 vtable */ w->draw(); // 透過攻擊者控制的函式指標呼叫

使用發生在釋放之後;被回收的槽位現在裝著偽裝成舊物件的攻擊者資料。

重複釋放(對同一個 p 呼叫兩次 free(p))是它的近親漏洞:第二次釋放會損毀配置器的自由串列,同樣能被導向任意寫入——free() 不會察覺 p 已經被釋放過。

又称
UAFdangling-pointer exploit釋放後使用懸置指標利用