Simple PWN 0x40(2023 HW - UAF++)
Background
Source code
:::spoiler Source Code
1 |
|
:::
Recon
:::info
- 這一題是run在==20.04==的環境,在做題目之前要先看一下docker file
- 另外一個很重要的一點是題目是用==read==讀取輸入,所以我們不需要輸入null byte結尾 :::
這一題和lab有幾個關鍵的地方不太一樣,首先他把set_name的操作併到register的地方,另外他限制註冊的entity只能有==2個==,最重要的一點是他沒有給我們heap address或system address的天大好禮,所以我們還要想一下其他的方法
-
首先,思路會是先想辦法leak libc address,並且利用像lab的方式把system function trigger起來開一個shell給我們
leak libc的策略如下,就像background提到的,要leak libc就要先想辦法把chunk丟到unsorted bin中,所以大小不能太小,lab的作法是先把tcache填滿再free一個0x88(就是不會被丟到fastbin的大小),不過因為這一題只能讓我們註冊兩個entity,所以有沒有甚麼方式是可以直接丟到unsorted bin?那就是直接註冊超過0x410的大小,這樣free的時候就會被丟到unsorted bin
1
2
3
4
5
6register(0, 0x420, b'a') register(1, 0x420, b'a') delete(0) delete(1) register(0, 0x420, b'a') trigger_event(0)
下圖為停在delete完後的結果,因為entity 1的0x420被consolidate所以沒有被顯示出來
而再註冊一次的意思是要把unsorted bin的空間拿回來,又因為他沒有把空間洗掉,所以我們後面再trigger的時候他會把東西印出來給我們,從下圖可以知道entity 0的name指向==0x00005575416a52c0==,也就是一開始從unsorted bin拿到的chunk address,而裡面的數值也的確還殘留
如果實際trigger entity 0會如下圖一樣,print出name指向的東西
- 既然可以leak出libc的地址,當然我們也可以寫值進去,我們的目標是開一個shell,而唯一可以執行function的就是在trigger event的地方,假設我們可以寫成如下圖一樣,是不是就可以觸發shell了
- 要達成如上的效果,我會先reset各個entity,為甚麼要設定0x20之後會用到
1
2
3register(0, 0x20, b'a') register(0, 0x20, b'a') register(1, 0x20, b'a')
-
仔細看source code中註冊的部分,他一共會malloc兩個空間,一個是固定0x20的entity,另外一個就是我們自己設定的name空間,這個空間可以寫值;另外call function pointer的時候,也就是在trigger event的地方,他只會針對剛剛提到的0x20 entity space去call function,所以我們要想辦法把我們寫進去的值==被當成0x20的entity==,這樣的話就可以直接call system了,這最後一步想了超級久,原本是想隔天在戰,結果躺在床上五分鐘就來靈感了,再花五分鐘就把問題解掉了😑
具體流程如下
1
2
3
4delete(1) delete(0) register(0, 0x18, p64(0) + p64(bin_sh_addr) + p64(system_addr)) trigger_event(1)
首先把這兩個entity都free掉,這樣回收區就會如下圖一樣
接著我們註冊entity 0,又因為這一次要的空間是0x18,所以他會把前面entity 1的空間都拿回來使用,如果我們又把開shell的資訊寫進去,就會如下圖
此時原本被free掉的entity 1的空間就會變成entity 0的name space,此時我們只要trigger entity 1就會開shell了,如下圖
Exploit
1 |
|
1 |
|
Flag: flag{Y0u_Kn0w_H0w_T0_0veR1aP_N4me_aNd_EnT1Ty!!!}