天天看點

破解索尼PS4系列:使用者代碼執行(二)

本文講的是<b>破解索尼PS4系列:使用者代碼執行(二)</b>,

破解索尼PS4系列:使用者代碼執行(二)

本文會重點講解如何在WebKit程序中進行代碼執行。

代碼執行

正如上一篇文章講過的那樣,ROP隻是以一種聰明的方式執行記憶體中加載的現有代碼,而ROP在技術上完全可以實作圖靈完備(Turing complete),不過對于一些基本測試,ROP鍊反而顯得有點複雜,讓人感覺不太實用。

不過現在,我們已經能夠利用ROP來設定記憶體,這樣我們就可以将自己的代碼寫進去并執行它。

簡而言之,這意味着我們可以編譯C代碼,例如PS4-SDK中包含的這些樣本,并将其作為本機x86_64代碼執行。

雖然這是很大的進步,但我們仍然要通過頁面來執行,并且具有與之前相同的限制(如沙盒)。

譯者注:參考最近釋出的LLVM 3.7,如果将-target x86_64-scei-ps4指定為clang,我們就可以使用與索尼用于編譯PS4的官方代碼完全相同的選項來編譯代碼。

WebKit程序限制

如前文所述,浏覽器實際上由兩個獨立的程序組成。我們所劫持的代碼,執行的是核心的WebKit程序(它會對HTML和CSS進行解析,解碼圖像和執行JavaScript)。

我們可以使用以下代碼轉儲我們程序中通路的所有記憶體:

不過,在這個轉儲中,你将無法找到其他程序使用的字元串,例如“選項”,“關閉視窗”,“重新整理”或“可用系統記憶體不足”。

圖形

可以很明确的是,如果讓其他程序來處理顯示圖形,我們便不能輕易地劫持活動的libSceVideoOut句柄。

盡管我們一直都在重新初始化libSceVideoOut,但即使所有函數都傳回了讓我們滿意的值,我們還是無法更改浏覽器的顯示圖形。

為了确定我們的程序無法通路由其他程序建立的視訊句柄,我們必須嘗試使用強制代碼執行來進行驗證。

強制代碼執行

強制使用ROP架構的東西是不切實際的,不過我們可以每次測試後重新設定頁面,而且由于漏洞使用率并不是100%可靠,強制執行一分鐘左右就會出現錯誤提示。

通過代碼執行,我們可以嘗試讓浏覽器強制打開視訊句柄,并且可以使用套接字從PC遠端跟蹤進度。

如果sceVideoOutWaitVblank被賦予一個無效的句柄,則将傳回一個錯誤值,如果它被賦予一個有效的句柄,則傳回值為0:

可以看到,運作幾個小時後,傳回值為0,确認我們的程序無法通路其他程序的視訊句柄。

畫布

有一個并不太完善的解決方案可供我們選擇,如果我們建立一個HTML5畫布并用單一的顔色填充,我們可以在RAM中找到它的幀緩沖區的位址,并從本機代碼建立一個新的線程來呈現新的畫布。

如果畫布的分辨率太高,則更難找到其位址,并且通常重新整理率不高。但是,我們可以将低分辨率圖像拉伸為全屏,這樣就可以正常執行了:

不過,你可能想要在建立畫布之前删除所有其他元素,來提高運作效率:

最後,要隐藏光标:

控制器

libScePad子產品類似于libSceVideoOut,因為它不被我們的程序使用,是以我無法使其工作。

除非事先調用scePadInit,否則scePadOpen将産生運作錯誤。由此可以看出,單獨程序的子產品各自都有自己的内部狀态,而且我們的程序沒有使用libScePad(因為它還沒有被初始化)。

是以,像圖形一樣,我們将無法劫持已經打開的任何搖桿,并且嘗試建立新的搖桿也不會奏效。

我們不能從首個控制器讀取,因為它已經在使用了,也許我們能夠從第二個控制器讀取,但不幸的是,無法進行測試,因為我們隻有一個控制器。不過,我們可以使用USB庫接收來自第三方控制器的輸入或僅僅使用WIFI相容裝置來發送UDP套接字,我們選擇使用的是任天堂DS無線裝置。

USB閃存驅動器

将USB插入PS4時,新裝置會顯示/ dev /; ugen0.4為第一個插槽,ugen0.5為第二個插槽。但由于安裝系統調用(類似于nmount這樣的變體)總是傳回1,EPERM錯誤提示,是以我們無法安裝裝置。

然而,我們可以使用libSceUsbd.sprx子產品通路USB閃存驅動器,它非常類似于libusb。

以下是libusb的代碼:

可以轉換為libSceUsbd代碼:

這是一個将指令直接發送到USB裝置的底層庫,是以它不是真正的理想選擇,但是借助xerpi,我們可以将一個libusb移植到PS4,并讀取原始圖像的USB閃存驅動器。

雖然在将來可能會基于直接的USB指令來移植一個完整的FAT實作,但現在我隻是使用Win32 Disk Imager(類似于dd for Linux)将資料寫入USB閃存驅動器的原始圖像。

USB的發現與核心通路

插入USB時,PS4會自動嘗試安裝USB閃存驅動器。一旦使用核心代碼執行來啟用UART輸出,插入USB閃存驅動器後就會顯示以下消息:

隻有格式化為FAT32的裝置才能成功安裝,并且在使用核心代碼執行轉義檔案後,可以從/ mnt / usb0和/ mnt / usb1通路它們。然而,如果沒有使用核心,libSceUsbd子產品仍然是通路USB的唯一方法,實際上這個辦法可以更好地控制裝置,但卻不太友善讀取和寫入檔案。

Cinoop

Cinoop是一個我們之前寫的GameBoy模拟器,雖然它不是最好的GameBoy模拟器,但我們認為Cinoop足以移植到PS4來顯示網頁代碼執行。

更多相關流程

由于我們的運作環境受到諸多限制,使得程序之間的互動很少,雖然我們嘗試過劫持另一個程序以獲得更多潛在的通路,但都沒有成功。

雖然execve(59)系統調用是允許的,并且在libSceSystemService.sprx中還有一個名為sceSystemServiceLoadExec的函數,但是我們無法測試這些函數,因為檔案系統是隻讀的,我們無法加載USB閃存驅動器。 PS4上的可執行檔案具有自定義标題,内容也被加密。我們可以複制libprocstat中的一些功能,但是這個功能大都是無用的,因為我們隻想得到自己的程序的權限。

具有核心通路權限的可執行檔案

sceSblAuthMgrAuthHeader和sceSblAuthMgrIsLoadable這兩個核心函數似乎處理了大多數可執行檔案的完整性檢查: 使用核心代碼執行,可以在控制台上直接解密可執行檔案。

root困惑

我們在前文中提到getlogin傳回“root”,雖然使用者名可能是“root”,但我不相信這是正常的根目錄。

例如在這個所謂的root使用者下,getuid一直傳回0。但是實際上正常的root使用者是傳回1的。

另外,由于程序是在FreeBSD jail環境中運作的,是以我們不敢确定程序是否是在root權限下運作的。

加載子產品

我們可以使用libkernel中的sceKernelLoadStartModule加載子產品:

把子產品加載到記憶體中,我們可以讀取它的Base 編碼和大小,并像之前一樣進行轉儲。

這種加載子產品的方法比我們上一篇文章中提到的方法更好,因為它将初始化導入表,以便我們可以實際調用其中的函數,并在轉儲中使用其他子產品如libc和libkernel的方法。

根據函數名稱尋找函數的偏移量

FreeBSD使用系統調用337,kldsym,我們可以從其命名的一個動态庫中尋找函數的位址。

在C中,可以這樣使用:

在PS4核心中,此功能已被禁用,并将始終傳回0x4e,ENOSYS提示。

不過索尼在PS4核心中實作了動态連結器,用于使用者态的動态記憶體管理 ,我們可以使用它來處理使用者空間的函數。

系統調用591,sys_dynlib_dlsym已成為PS4-SDK的基礎,如果我們加載了一個子產品并獲得了它的句柄,我們就可以調用已知名稱和參數的任何函數。

以下ROP鍊将獲得libkernel中getpid包裝器中的偏移量:

對于固件1.76版本來說,傳回值為0xbbb0。

我們可以從我們的libkernel轉儲中驗證這個偏移量(getpid系統調用編号為20):

如果要擷取其他函數名稱,我們就應該使用經過反彙編的字元串視圖(或者在十六進制編輯器中搜尋sce),我們會發現索尼在許多子產品中留下了一些有用的調試消息。

例如,libkernel包含字元串“verify_header:sceKernelPread failed%x  n”。現在我們已經确定了一個sceKernelPread函數,下面,就讓我們來看看類似于sceKernelPwrite的函數能否被确認。

不過,sceKernelPread和sceKernelPwrite隻是與系統調用相關的普通FreeBSD正常包裝器。

由于索尼多年來使用的命名方式都是固定的,我們還可以嘗試使用一些PSP函數名稱,不過其中也有許多存在于PS4的子產品中。

線程

libkernel子產品包含了libpthread的實作,但是仍遵循了索尼的命名方式。

需要注意的是,我們建立的線程仍在背景運作,而其他應用程式也處于活動狀态。請點選以下視訊:

http://v.qq.com/iframe/player.html?vid=s017633wgds&amp;tiny=0&amp;auto=0"

為了示範這一點,我們可以建立一個線程,在任意逾時後啟動浏覽器:

讀取記憶體保護

我們可以使用索尼自定義的兩個系統調用547和572,來讀取一個記憶體頁面的内容(16KB) 的屬性,包括它的保護:

上面的代碼告訴我們,堆棧的名稱是“主棧”,其保護是3(讀和寫)。

列出所有記憶體頁面

正如我們上篇所講的的,由于ASLR機制,是以很難映射出所有PS4的記憶體。不過有個辦法可以部分解決這個問題,如果把系統調用572的第二個參數設定為1,并且我們指定一個未映射的位址,那麼下一個記憶體頁也就被使用了。

這意味着我們可以指定任意位址,并最終找到一個有效的記憶體頁面。例如,指定0作為位址将告訴我們有關第一個映射記憶體頁面的資訊:

這樣,我們可以從我們的程序中提取可通路的記憶體頁面的完整清單:

CompositorClient始終基于0x1100000000,但所有其他位址每次都會不同。

這個清單正是我們所想要的一堆子產品,每個子產品都有自己的資料、代碼頁、堆棧、一些堆棧保護和一些其他的各種映射。

不過還有一些我們無法解釋的子產品,CompositorClient被映射為0x33,這絕對不是一個标準的FreeBSD記憶體保護!

GPU

由于CPU和GPU共享一個統一的記憶體池,是以索尼添加了自己的保護标志來控制GPU可以通路的内容以及為CPU保留标準的FreeBSD保護。

這可以通過逆向libSceGnmDriver子產品來找到:

CompositorClient可以标記為0x33(1 | 2 | 16 | 32),CPU RW和GPU RW。

由于索尼非常巧妙地處理了GPU保護系統,是以我們也隻能給CPU同樣多的通路權限,例如:

但試圖繞過DEP還是失敗了:

系統資料庫

我們發現了一個名為libSceRegMgr.sprx的子產品,這表明索尼在PS4中添加了一些系統資料庫系統,而FreeBSD是沒有這樣的子產品的。

該子產品中的所有功能都是系統調用532的包裝器,之前我們認為是wait6,且第一個參數是一個指令。

事實上,wait6已經被索尼自定義的系統調用所修改,這表明系統調用的編号與我們最初了解的FreeBSD 9.0類似。

雖然這個子產品由浏覽器加載和使用,但由于我們的執行程序是有限的,所有函數調用均已0x80020001傳回,這表明是以使用"互斥鎖"。

缺少核心ASLR

系統調用617至少需要1個參數,并傳回一個核心指針,雖然我不知道這個系統調用的更多資訊,但是由于核心指針總是相同的,是以我們可以把它作為固件1.76上沒有核心ASLR的另一個證據。

轉儲檔案

通過代碼執行,檔案可以非常容易地轉儲。雖然也可以使用ROP來實作,但是有點麻煩,必須分多個階段才能完成。

通過使用PS4檔案浏覽器,我們應該能夠找到一些有趣的東西來轉儲,比如/sandboxDir/common/font/DFHEI5-SONY.ttf。

我們應該注意,如果要轉儲的檔案路徑以10個随機字元(沙箱目錄)開始,那每次重新啟動PS4時,此路徑都會發生更改,不過,可以使用下面的ROP鍊來找到它:

對我們來說,這是AaQj0xlzjX。對于非常小的檔案,我們可以簡單地讀入chain.data,但對于較大的檔案,我們需要配置設定記憶體。

我們可以通過标準的mmap系統調用來實作。重新整理頁面,并使用這個ROP鍊:

可以看到,傳回的位址為0x200744000。

再次重新整理頁面,并使用這個ROP鍊讀取檔案并擷取其大小,将AaQj0xlzjX替換為我們的沙箱目錄,并使用上述ROP鍊上的任意位址替換0x200744000:

如上所示,我們的字型大小為8312744位元組。

現在我們打開任何用于攔截計算機上流量的代理或網絡工具,并建立了一個名為TCP-Dump的簡單C伺服器。

重新整理頁面,并使用這個ROP鍊發送緩沖區,然後用适當的值替換IP,端口,位址和檔案大小:

使用cookies,我們就可以自動将資訊往後傳遞,但現在我們不會這麼做。

這裡還應該注意,由于檔案系統是隻讀的,例如,嘗試修改字型會使PS4崩潰(這個問題我們放在下一章來解決)。我們還可以轉儲位于/ sandboxDir / common / lib /的子產品,但它們是加密的。

加密

加密是PS4安全最重要的一部分,PS4使用的是AES加密,這樣就可阻止像我們這樣的人來對其固件以及遊戲進行分析。另外,人們似乎也沒有注意到在PS4中還同時使用多個加密密鑰,即使我們找到解密方法,我們仍然無法解密PUP更新。

但是,我們還是發現其中的一個加密漏洞——執行錯誤,如PS3不是執行随機數了,而是僅僅使用常數4。雖然索尼在PS4的加密方面不太可能再犯這樣的低級錯誤,但還是可以同ELF調試來窺探各種遊戲的伺服器更新。此外,PS4上的加密由一個稱為SAMU的單獨處理器來處理,這個處理器非常穩定。即使使用核心攻擊,SAMU處理器難以被攻破。雖然我們可以與它進行互動來解密幾乎所有的東西,但是不可能提取任何密鑰,以便在外部完成解密。

儲存

儲存資料存儲在以下位置:

例如:

我們可以轉儲這些檔案,但它們是加密的。

假設加密是由libSceSaveData子產品處理的,我們可以成功加載和初始化這個子產品:

但是,當我們嘗試安裝或讀取這些資料時,收到的确實錯誤代碼。

總結

代碼執行的能力跟目前的通路權限是挂鈎的,比如可以運作某些類型的自定義程式,例如GameBoy模拟器。

然而,由于我們無法使用官方控制器,是以對任何種類的輸入進行标準化是不切實際的,再加上我們無法使用官方圖形庫,想找到索尼自定義漏洞無比的困難。

從目前掌握的資訊來看,對PS4進行核心攻擊應該是個可行方案。

原文釋出時間為:2017年4月5日

本文作者:xiaohui

本文來自雲栖社群合作夥伴嘶吼,了解相關資訊可以關注嘶吼網站。

<a href="http://www.4hou.com/technology/3975.html" target="_blank">原文連結</a>

繼續閱讀