環境:Libc2.32
漏洞:uaf
方法:double free檢測繞過&IOFILE
Libc2.32新增保護機制
先看看Libc2.31中的tcache_put函數。相比以往的libc版本新增了key值,指向tcache:
再看2020年8月的Libc2.32版本。很明顯 e->next 的值發生了變化,在2.32中通過 PROTECT_PTR 函數給它賦值。
該函數將next的地址右移12位,與 tcache->entries[tc_idx]作異或后返回結果。也就是最終chunk->fd中寫入的值。
相應地,在 tcache_get 中也加上了對應的 REVEAL_PTR 函數,跟加解密過程相似。
在free的時候會對tcache中的chunk進行檢查,檢查完key就檢查next,用的也是 REVEAL_PTR 函數。
如果next指針被我們修改成其他值,運算得到的結果就不相同。但是當tcache中只有1個bin時,tcache->entries[tc_idx]為0,異或結果等於其本身。
復現:ff - V&NCTF2021
程式分析
程式只能show一次,edit兩次。存在uaf漏洞。
圖上的idx是一個全局變量,導致每次只能操作最新malloc的chunk。并且申請的大小限制為0x7f。
libc版本是2.32,tcache新增的保護機制在前面已經提到過。
思路分析
當tcache中只有一個chunk時,將next和key改成任意值就能繞過double free檢測。但是之後tcache中的兩個chunk(實際上是同一個)的next又會被異或。因此需要在double free之前拿到heapbase地址,也就是chunk 0的key。與目標地址異或得到的值,就是chunk 1的next指針異或后正確的值。
爲了獲取這個值已經用了一次show函數:
之後不能再通過show泄露libc地址,但能實現任意地址讀寫(ptr^key寫入fd,劫持tcache)。
程式有調用puts函數,因此可利用_IO_2_1_stdout泄露。由於兩次edit到這一步的時候已經用完,需要在add的時候修改stdout結構躰。
由於爆破的時候需要前面8位的地址作基數,在修改fd之前需要一個放入unsorted bin 的chunk。這裏可以用heapbase,它的size有0x291.
exp