當前位置:
首頁 > 新聞 > Win10 Edge瀏覽器從越界寫到任意內存讀寫

Win10 Edge瀏覽器從越界寫到任意內存讀寫

*本文原創作者:BoA,本文屬FreeBuf原創獎勵計劃,未經許可禁止轉載


在剛剛發布的微軟11月份安全更新中,比較幸運刷了兩個Edge的腳本引擎漏洞,對微軟的腳本引擎漏洞有一定的見解,所以打算寫篇文章與大家分享一下。由於這兩個漏洞修復時間比較短,所以選擇一個比較舊的9月份的漏洞跟大家分享。

如果大家有什麼問題,歡迎通過老實敦厚的大寶微博與我交流。

漏洞簡介

在9月份微軟安全更新中,修復了一個chakra腳本引擎的類型混淆漏洞(CVE-2016-3377)。經過分析,該漏洞影響win10 x64平台的edge瀏覽器,攻擊者經過精心構造的網頁,可以在受害者機器上達到遠程代碼攻擊的效果。(x64平台的利用實在比x86的難太多:( )


0×0漏洞分析

由於chakra腳本引擎已經開源,所以可以從github上得到此次漏洞修復的代碼如下(in JavascriptArray.cppMapHelper()):

漏洞的修復很簡單,就是把原來的DirectSetItemAt函數變成SetItem,接下來重點分析這兩個函數的區別。

以下是兩者對應的源碼:

DirectSetIteamAt並不是一個虛函數,默認調用對象是JavascriptArray類型,但是裡面並沒有對typeId進行任何判斷。

如圖,SetItem是一個虛函數,會根據調用的對象分別調用不同的SetItem實現(JavascriptNativeIntArray是JavascriptArray的子類)。

而且在內部會對typeid進行判斷。在漏洞代碼中,假如newArr並不是JavascriptArray對象,而是其子類的對象,就會引發越界讀的漏洞。根據源碼分析與對比,最終構造的測試PoC如下:

由於此漏洞需要利用ES6的標準實現JS的類的繼承,所以只會影響Edge比較新的版本,Edge的舊版本和IE11並不影響。

通過Proxy類構造畸形的y,當在MapHelper遍歷y的prototype時候,會進入如下代碼:

調用y類的constructor函數,也就是fake函數,用於創建newObj對象,也就是Array.prototype.map()函數即將返回的對象。

在JS中,即使fake是一個類,但實際上它是一個函數,包括其他類Array等也是一個函數,當調用new fake()的時候實際上是進入了class fake中的[Symbol.species]函數中,換句話說,[Symbol.species]就是類fake的構造函數。

但是有一個概念需要區分,因為fake是函數,所以它的constructor就是Function,這與[Symbol.species]是不同的一個概念。

在構造函數中,返回的對象是n[5],這是一個JavascriptNativeIntArray類,因此newObj指針指向的是一個JavascriptNativeIntArray類,並不是JavascriptArray類。再往下,避過其他if,最後進入如下代碼:

newArr也就是上文提到的newObj,查看這個對象的typeId:

可以看到,JavascriptArray的typeId應該是0x1c,但是這裡是0x1d。


0×1 Out Of Bound Write

在64位的edge中,JavascriptArray的每個element佔用的內存大小是0×8位元組,因為要保存雙精度浮點數以及對象地址等信息,但是在JavascriptNativeIntArray中每個element佔用的內存大小是0×4位元組,如下圖所示,調用DirectSetItemAt之前:

因此每次調用JavascriptArray的DirectSetItemAt會佔用JavascriptNativeIntArray兩個element的位置,調用一次DirectSetItemAt之後:

在mapHelper遍歷的過程中,即使length沒有發生越界,最終也必然會導致越界寫的行為發生,因此此漏洞僅僅影響64位的edge瀏覽器。但是單單的越界寫是不足夠的,還需要滿足兩個條件最佳:


1. 可以控制越界寫越多少界,例如我想越8位元組時就8位元組,16位元組時就16位元組。

解決方法:根據此漏洞的特性,通過控制y和n[5]數組的長度可以控制越界寫的長度,當然還需要考慮內存對齊的細節。

2. 可以越過中間某些數據不寫。例如有時候我們只想修改後面數組的長度,但是在長度之前有某些重要的欄位,如果修改了就會導致edge的crash。

解決方法:首先查看漏洞附近的代碼:

假如可以令這個HasItem返回false,就可以跳過中間我們不想覆蓋的欄位,方法也很簡單,在數組中間某些index位置設置成null,如圖:

至此,任意越界寫已經實現,下一步就是通過越界寫修改相鄰IntArray的長度。


0×2 製造一個big_array

首先需要了解IntArray在內存中的數據結構:

圖中框著的地方分別是length,segment,segment的size,和segment的length,只要把length,segment_size和segment_length覆蓋了,就達到目的,而且中間重要的欄位,例如虛函數地址等要跳過,不然會導致crash。

而具體要覆蓋的值可以通過雙精度浮點型指定要覆蓋的值,覆蓋以後如圖:

具體JS代碼如下:

然後檢驗是否修改成功,並且保存這個數組的索引:


0×3 製造big_DataView

第一步通過heap feng shui把某個dataview放進big_array的後面:

然後以0×1034作為特徵值,查找這個dataview的內存位置,然後修改對應的length:

檢驗是否成功,並且保存這個dataview的索引:


0×4 任意內存讀寫

在查找dataview的bytelength特徵值的同時,保存dataview的buffer_address的地址的位置,保存下這個索引:

Dataview的內存結構,分別是bytelength和buffer_address

任意內存讀:

把需要讀的地址寫入dataview的buffer_address,再讀取這個dataview偏移0×0地方的數據。

同理任意內存寫:


0×5 獲取任意對象地址

最後一步,就是獲取任意對象的地址,我的代碼如下:

因為得到的big_array是n[6],所以把需要讀取的obj放入n[7][0],再通過越界讀獲取n[7]的segment的地址,再通過任意地址讀,讀取segment地址+0×18和0x1c的數據,即可得到這個對象的地址。


0×6 後續

至此,該漏洞的詳細原因分析和遠程代碼執行所需要的任意地址讀寫和獲取任意對象地址已經全部成功,剩下的部分(bypass cfg/dep)有興趣的同學可以嘗試實現(tips:利用JIT in WARP Shader,文章針對x86,在x64上會有比較大難度)。

(當然還需要一個逃逸沙箱的漏洞結合,不過這是後話。)文章中也提到在x64上利用的可能性:

在x86上會存在很好利用的gadgets用於構造ROP:

但是在x64平台想要編譯出比較好用的gadgets JIT code需要一點耐心去寫webGL代碼,而且在x64中參數是通過寄存器傳遞,這樣對棧中的數據的控制難度就會加大。

因此可以選擇使用push rcx//pop rsp//retn這樣的指令以控制rsp,然後通過精心構造的webGL代碼可以構造出需要的gadgets。

*本文原創作者:BoA,本文屬FreeBuf原創獎勵計劃,未經許可禁止轉載



請您繼續閱讀更多來自 FreeBuf 的精彩文章:

企業安全團隊強大與否,看這八個關鍵指標
日本化妝品牌資生堂確認42萬用戶數據泄露,包括大量信用卡信息
頻繁「被破解」,從「背鍋俠」特斯拉看IoT安全
內網穿透:Android木馬進入高級攻擊階段
政府與企業在網路安全上該如何「共贏」?聽聽NSA局長怎麼說

TAG:FreeBuf |

您可能感興趣

Netflix取消《越界》
爵士越界|專訪澳洲小號演奏家Toby Mak
娜扎用「越界光感唇」奪走鹿晗初吻?關鍵就是這0.5mm的越界畫法
咬唇、霧面唇都OUT啦!韓國妹子都在畫李聖經的越界「嘟嘟唇」!快來get吧~
外交部今天回答了11個問題,6個與「印軍越界」有關
中方再次拿出印度非法越界新證據:1960年印度照會
外交部9次例行記者會,37個問題談到印軍非法越界
24小時,6次!中方6大權威機構先後就印軍非法越界發聲!
(星相)托尼-2017年火星在雙子座和巨蟹座越界
24小時,6次!中方6大權威機構先後就印軍非法越界發聲
24小時6次!中方6大權威機構先後就印軍非法越界發聲!
官方:煤礦3月內2次以上超層越界開採應予以關閉
柬埔寨首相:30名寮國軍人越界 6天內不撤將開戰
厚重的啞光唇out啦,現在流行越界光感唇!
印軍越界至今未退,中印兩軍近距離對峙已達20天
柬埔寨首相:寮國30名士兵越界,滯留4個月,再不走將開戰
這棟別墅只賣74萬,一不小心就出國越界了
駐藏部隊近日有大動作,24小時,6次!中方6大權威機構向印軍非法越界發聲!
外交部披露印度非法越界細節:400餘人,武器、賬篷、推土機