Sitemap

【ctf復現】CISCN2021-PWN

Jun 12, 2021

--

拖了一個月emmm

LonwlyWolf

程式分析

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

Press enter or click to view image in full size

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中。

Press enter or click to view image in full size

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

exp

SilverWolf

程式分析

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

只能orw:

Press enter or click to view image in full size

利用思路

在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。

Press enter or click to view image in full size

exp

Channel

程式分析

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

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

Press enter or click to view image in full size

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

Press enter or click to view image in full size

但是我比賽的時候,把路徑改成 /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算出來的地址不同,我猜正是這個原因)。

Press enter or click to view image in full size

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

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

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

Press enter or click to view image in full size

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

結構如下:

Press enter or click to view image in full size

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

Press enter or click to view image in full size

漏洞利用

  1. 泄露。

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

Press enter or click to view image in full size

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

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

--

--