天天看點

UAF原理與利用

0x00 UAF原理

UAF原理與利用

如上代碼所示,指針p1申請記憶體,列印其位址,值

然後釋放p1

指針p2申請同樣大小的記憶體,列印p2的位址,p1指針指向的值

Gcc編譯,運作結果如下:

UAF原理與利用

p1與p2位址相同,p1指針釋放後,p2申請相同的大小的記憶體,作業系統會将之前給p1的位址配置設定給p2,修改p2的值,p1也被修改了。

由此我們可以知道:

1.在free一塊記憶體後,接着申請大小相同的一塊記憶體,作業系統會将剛剛free掉的記憶體再次配置設定。

根本原因是dllmalloc:

參考資料:http://blog.csdn.net/ycnian/article/details/12971863

當應用程式調用free()釋放記憶體時,如果記憶體塊小于256kb,dlmalloc并不馬上将記憶體塊釋放回記憶體,而是将記憶體塊标記為空閑狀态。這麼做的原因有兩個:一是記憶體塊不一定能馬上釋放會核心(比如記憶體塊不是位于堆頂端),二是供應用程式下次申請記憶體使用(這是主要原因)。當dlmalloc中空閑記憶體量達到一定值時dlmalloc才将空閑記憶體釋放會核心。如果應用程式申請的記憶體大于256kb,dlmalloc調用mmap()向核心申請一塊記憶體,傳回返還給應用程式使用。如果應用程式釋放的記憶體大于256kb,dlmalloc馬上調用munmap()釋放記憶體。dlmalloc不會緩存大于256kb的記憶體塊,因為這樣的記憶體塊太大了,最好不要長期占用這麼大的記憶體資源。

2.通過p2能夠操作p1,如果之後p1繼續被使用(use after free),則可以達到通過p2修改程式功能等目的。

0x01 一個利用場景

在網上找了一個有UAF漏洞的ctf程式,參考部落格如下:

http://www.syjzwjj.com/use-after-free-tutorial/

作者已經分析的很詳細了,通過對整個程式的調試,來了解UAF的利用。

1.       結合IDA與程式運作,簡要了解程式的功能。

UAF原理與利用

選擇1可以留言,資訊會存到1個連結清單中

選擇2将會周遊連結清單找到對應的節點,列印節點資訊

列印完,可以對其進行删除修改等操作

UAF原理與利用

連結清單節點結構如下

UAF原理與利用

Tips:在逆向代碼中應用資料結構參考《IDA Pro權威指南》第8章資料類型與資料結構

 2.       UAF漏洞代碼

UAF原理與利用

連結清單節點被删除後,可以繼續進入modify函數,modify函數之後可以繼續進入modify函數。

Delete函數如下:

UAF原理與利用

Delete函數中對節點的進行了free操作,如果在循環代碼中,進行delete操作,釋放節點之後,再選擇2進入modify函數。

Modify函數如下:

UAF原理與利用

Modify函數從使用者讀取資料,然後拷貝到對應的指針中,但此時使用的是一個已經釋放的指針。當輸入content時,會取content的長度作為大小配置設定記憶體,當配置設定記憶體大小等于msg結構大小(48位元組,通過前面的結構獲得)時,會将剛才釋放的記憶體配置設定給content指針。

如下所示

UAF原理與利用

Content指向了msg結構本身

UAF原理與利用

接着将content拷貝到content指針中,即我們的輸入會拷貝到這個被釋放的節點記憶體中。

在循環代碼中,modify完之後可以繼續進入modify。 此時會再對msg結構的author,title,content指針指向的位址進行拷貝。 由于上一步已經能夠對msg結構進行随意更改了,是以将幾個memcpy的目的位址修改成想要的位址即可進行任意記憶體(屬于該程式的合法記憶體)的修改了。

UAF原理與利用

至此我們已經能夠完成任意記憶體位址的修改了。

下面需要考慮的就是完成一些指令執行的利用。

3.       漏洞利用執行指令

要執行指令,需要調用system函數,但是代碼中并沒有system函數,需要如何完成指令執行呢?

可以利用linux的延遲加載功能,改變strlen函數的指向,将原本要執行的strlen,改成執行system。

Tips:延遲加載

當調用标準函數時,需要從其他so檔案中将标準函數加載進來,并不直接調用函數的位址,而是通過一張中間表跳轉到函數的真正位址。

以strlen函數的調用為例

UAF原理與利用
UAF原理與利用
UAF原理與利用

在程式調試中,列印0x804c04c的資訊

UAF原理與利用

整個過程如下:

Call strlen跳轉到strlen函數,裡面隻有一句jmp ds:off_804c04c

當程式運作起來時0x804c04c裡的值為0xb7658210,才是strlen的真正位址

即0x804c04c中存儲libc庫中的strlen的真正位址。

如果将0x804c04c的值改掉,改成system的位址0xb7614360。 雖然看起來調用的是strlen,但真正執行的是system函數。

修改前:

Call strlen  

                    Strlen:

                            Jmp 0x804c04c

                                                         0x804c04c: 0xb7658210(strlen)

修改後:

Call strlen  

                    Strlen:

                            Jmp 0x804c04c

                                                         0x804c04c: 0xb7614360 (system)

UAF原理與利用

Tips: 尋址system的真正位址

由于整個程式并沒有調用system函數,是以在程式的重定位表中找不到system。 是以需要自己定位一下system在這個程式中的真正位址。

UAF原理與利用

Libc被裝到0xb75d6000-0xb777a000 位址空間,大小為0x1a4000

編寫程式調用system函數

UAF原理與利用

調試運作檢視其libc位址空間

UAF原理與利用

被裝入到0xb7e10000-0xb7fb4000,大小也為0x1a4000。

是以system在漏洞程式中的位址應為 =(system在調用程式中的位址-調用程式libc起始位址+漏洞程式libc起始位址)

UAF原理與利用

0xb7e4e360

System在漏洞程式中位址= 0xb7e4e360-0xb7e10000+0xb75d6000= 0xb7614360

 4.       poc運作效果

執行一個mkdir hack指令建立一個hack目錄

Poc片段

UAF原理與利用
UAF原理與利用
UAF原理與利用

5.       過程回顧

1)  delete函數中釋放節點

2)  modify函數傳入被釋放的指針

3)  modify函數中配置設定記憶體大小可控,通過配置設定與節點相同的大小,取得被釋放記憶體的控制權

4)  修改将要被拷貝的目的位址msg->author指針指向将要被執行的函數strlen的中間表位址

5)  将strlen指向的真實strlen位址,修改為system的真實位址

6)  看似執行call strlen,實則執行了system函數

0x02 總結

在指針釋放後再申請相同大小的記憶體,系統會将釋放的位址進行配置設定,以提高系統運作速度,是以可以修改到被釋放的記憶體資料,如果被釋放的指針繼續被使用,則會造成UAF漏洞。

通過UAF漏洞,可能可以造成一些任意記憶體的修改,結合代碼特點,可能會造成任意記憶體的讀取或者,嚴重的能夠造成任意指令的執行,獲得shell。 取決于被釋放的指針是怎麼使用的。

相關知識點:gdb調試(如何調試fork出來的程式),延遲加載(plt與got),标準函數在記憶體中的定位,UAF修改被釋放指針内容的原因dllmalloc

繼續閱讀