【ctf復現】CISCN2021-PWN

Ch33_1n'
Jun 12, 2021

--

拖了一個月emmm

LonwlyWolf

程式分析

環境:libc 2.27,tcache有key值(1.3之前沒有)

delete函數中存在uaf漏洞:

限制:只能申請chunk 0,size≤0x78。

補充:edit函數中,如果 “*v0=0;” 在 if(++v0==v1) 裏面,則存在off-by-null漏洞。這裏寫的是return語句,則不存在。

利用思路

  1. 利用uaf漏洞修改tcache中的key值,可以進行double free。double free后堆塊中有堆地址,直接show可以泄露。
  2. 若申請到unsorted bin中的chunk,就能泄露libc地址。前面拿到堆地址后算出tcache struct對應的位置,直接修改next指針申請到這裏,再把整個0x250的塊free到unsorted bin中。

要注意free之前先把tcache 0x250的鏈表數填滿(覆蓋為\x07),不然free的時候會因爲tcache鏈沒滿而直接放入tcache中。

3. 拿到libc偏移后直接改freehook就行。可以改one_gadget或者system。因爲這裏只能操縱一個chunk,所以改system的話,申請時可以申請到freehook-0x08的位置,前面0x08填充/bin/sh\x00,最後free掉自身就行。改為onegadget的話,申請到freehook改就可以了。

exp

SilverWolf

程式分析

在上一題的基礎上,增加了沙箱,其他條件相同。

只能orw:

利用思路

在chunk上寫入ROP鏈,利用setcontext完成棧遷移。但是ROP鏈的長度大於0x78,只用一個chunk是寫不完的。所以這裏需要用兩個chunk分開寫。

在拿到libc地址的時候,tcache struct已經是可控的了。也就意味著申請的地址也可控。我們可以在對應的tcache鏈上佈置heap地址,用於寫flag路徑和兩段ROP。要注意兩段ROP的位置要相鄰。

exp

Pwny

程式分析

只有read和write函數。程式一開始在全局變量my_fd上存儲了random文件的fd。之後能在數據的指定idx處寫入從my_fd獲取的數據(write函數),也能讀出array隨機位置(從my_fd獲取idx)的數據(read函數)。

基本上都是依據my_fd的内容進行讀寫。my_fd在bss段(可寫),兩個函數對輸入的idx也沒有判斷是否合法,也就是能越界了。

漏洞點在下面的write函數。有沒有覺得 id=0LL這個語句很多餘emmm。id的值是通過輸入和read函數獲取的,沒有必要再這兩者間再加一次賦值。感覺這裏就是出題者留下的提示。

如果第一次write的時候,使array[i] 剛好落在my_fd的位置,就會往這寫入一個隨機值,這時random文件的fd已經被覆蓋了。再調用write的時候,因爲此時的my_fd不合法,read失敗,id值沒有被刷新,還是id=0LL。這樣就能往my_fd寫入0,也就是標準輸入了。

之後的read、write都是從標準輸入獲取數據,加上array可越界訪問,這就相當於8字節的任意地址讀寫了。

利用思路

既然能實現任意讀寫,把返回地址改成onegadget應該就可以了。這裏需要libc地址和棧地址。

libc地址可以通過got表泄露。got表與array的偏移是固定的,可以直接算。

有了libc地址后,棧地址可以通過environ泄露。但是要算environ與array的偏移,就得先知道array的真實地址。所以要先泄露程序段的地址。

通過environ泄露出來的就是棧上存儲環境變量的位置的地址。再據此找到write時的ret地址,改成gadget。

exp

Channel

程式分析

先説運行的問題。打國賽的時候沒運行起來,拿到了qemu-aarch64-static不會用。emmm實際上看這個命名,應該就能想到qemu-system-arm 、qemu-system-aarch64等。用法是一樣的。

但是運行的時候會顯示缺少某些文件。後來我直接在 /usr/aarch64-linux-gnu/lib 中找到這些文件,把它們連同兩個2.31的so文件放到lib文件夾下(默認路徑)就能運行了。

或者把兩個2.31的so文件放到交叉編譯gnu的lib裏,用指定路徑-L的方法運行也可以:

但是我比賽的時候,把路徑改成 /usr/aarch64-linux-gnu/lib ,set-interpreter為ld-2.31.so就運行不起來emmmm。(還沒找到原因ww)

再說調試的問題。這裏我用的是gdb-multiarch,但基地址似乎有點不對。看vmmap手動算就好了,用$rebase地址會有偏差。但是用這種方法的話,設置不了architecture。arch必須在target之前設定。而且把arm架構當成x86的架構去調,不覺得有點危險嗎emmm…(vmmap顯示的程式段地址與$rebase算出來的地址不同,我猜正是這個原因)。

但一開始我用-g挂到端口上再target過去,一直下不了斷點emmmm。應該是剛挂載的時候程序還沒裝進内存(vmmap也看不到程序地址空間),還沒有地址,因此用不了$rebase。

./qemu-aarch64-static -g 4444 -L $(password)/lib ./channel

程式沒開PIE的話,可以直接算出斷點地址斷下來。雖然這個程式開了PIE,但我們用的qemu-aarch64確實是靜態的emmmm。因此程序段的地址是可以直接算的。

程式用0x110的chunk存儲了注冊時的key,在讀寫和free的時候都會進行檢查。同時以鏈表的形式鏈接key chunk,創建content chunk的時候也會在key chunk中記錄content chunk 的地址。

結構如下:

漏洞是uaf漏洞。free的是key chunk。

漏洞利用

  1. 泄露。

free到unsorted bin中,再在write的時候申請回來,泄露得到libc地址。

雖然去了符號表,但仍可以從got表獲得libc地址,結合前面泄露的地址算出正確的偏移。

(先🕊著555… 地址沒找對emmm)

--

--