UAF學習--原理及利用


0x00 UAF原理

 

如上代碼所示,指針p1申請內存,打印其地址,值

然后釋放p1

指針p2申請同樣大小的內存,打印p2的地址,p1指針指向的值

Gcc編譯,運行結果如下:

 

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與程序運行,簡要理解程序的功能。

 

選擇1可以留言,信息會存到1個鏈表中

選擇2將會遍歷鏈表找到對應的節點,打印節點信息

打印完,可以對其進行刪除修改等操作

 

鏈表節點結構如下

 

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

 2.       UAF漏洞代碼

 

鏈表節點被刪除后,可以繼續進入modify函數,modify函數之后可以繼續進入modify函數。

Delete函數如下:

 

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

Modify函數如下:

 

Modify函數從用戶讀取數據,然后拷貝到對應的指針中,但此時使用的是一個已經釋放的指針。當輸入content時,會取content的長度作為大小分配內存,當分配內存大小等於msg結構大小(48字節,通過前面的結構獲得)時,會將剛才釋放的內存分配給content指針。

如下所示

 

Content指向了msg結構本身

 

接着將content拷貝到content指針中,即我們的輸入會拷貝到這個被釋放的節點內存中。

 

在循環代碼中,modify完之后可以繼續進入modify。 此時會再對msg結構的author,title,content指針指向的地址進行拷貝。 由於上一步已經能夠對msg結構進行隨意更改了,所以將幾個memcpy的目的地址修改成想要的地址即可進行任意內存(屬於該程序的合法內存)的修改了。

 

至此我們已經能夠完成任意內存地址的修改了。

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

3.       漏洞利用執行命令

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

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

Tips:延遲加載

當調用標准函數時,需要從其他so文件中將標准函數加載進來,並不直接調用函數的地址,而是通過一張中間表跳轉到函數的真正地址。

以strlen函數的調用為例

 

 

在程序調試中,打印0x804c04c的信息

 

整個過程如下:

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)

 

Tips: 尋址system的真正地址

由於整個程序並沒有調用system函數,所以在程序的重定位表中找不到system。 所以需要自己定位一下system在這個程序中的真正地址。

 

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

編寫程序調用system函數

 

調試運行查看其libc地址空間

 

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

所以system在漏洞程序中的地址應為 =(system在調用程序中的地址-調用程序libc起始地址+漏洞程序libc起始地址)

 

0xb7e4e360

System在漏洞程序中地址= 0xb7e4e360-0xb7e10000+0xb75d6000= 0xb7614360

 4.       poc運行效果

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

Poc片段

 

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM