您好,登錄后才能下訂單哦!
Windows圖像如何解析Fuzzing顏色配置文件,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
一、概述
圖像解析和渲染是任何現代操作系統(OS)的基礎功能。同時,圖像解析也是一個易于訪問的攻擊面,這一功能可以導致遠程代碼執行或信息泄露風險,對攻擊者來說非常有價值。在這一系列文章中,我將回顧Windows操作系統內置的圖像解析器和相關文件格式,特別關注構建工具、尋找語料庫(Corpus)以及通過模糊測試(Fuzzing)發現漏洞的過程。在第一部分中,我們重點分析顏色配置文件。該文件并不是圖像格式本身,而是規則嵌入在圖像中的顏色。
二、ICC顏色配置文件分析
在維基百科上,提供了對ICC顏色配置文件的定義:“在顏色管理過程中,根據國際顏色協會(ICC)發布的標準,ICC配置文件是一組定義顏色輸入輸出設備以及顏色空間的數據。配置文件通過定義設備源或目標顏色空間與配置文件連接空間(PCS)之間的映射,描述特定設備的顏色屬性或預覽要求。這里的PCS可以是CIELAB (L*a*b*),或者是CIEXYZ。可以使用定義插值(Interpolation)的表格來指定映射,也可以通過一系列參數進行轉換。
簡而言之,ICC顏色配置文件是一個二進制文件,該文件會嵌入到圖像中,并在ICC支持的軟件處理圖像時進行解析。
三、ICC規范
ICC規范大概有100頁,相對比較容易瀏覽。通讀規范可以更好地理解文件格式,不同類型的顏色配置文件以及顏色轉換背后的數學原理。此外,了解文件格式的內部結構可以為我們提供信息,以便更好地優化模糊測試、選擇良好的語料庫以及準備模糊測試的字典。
四、關于Windows顏色管理
從Windows 95開始,發布了圖像顏色管理(ICM)的1.0版本,從Windows 98以后開始發布2.0版本。從Windows Vista開始,對Windows色彩系統(WCS)1.0版本進行了大幅改動。ICC顏色配置文件是二進制文件,而WCS顏色配置文件則使用XML作為其文件格式。在這篇文章中功能,我們專注于分析ICC顏色配置文件。
Microsoft曾發布過支持的Windows API的列表,其中就包含一些名稱非常明顯的API,例如OpenColorProfile,我們可以看到它是在MSCMS.dll中實現的。這個DLL是通用入口點,支持加載Microsoft的顏色管理模塊(CMM)和第三方顏色管理模塊(例如Adobe的CMM)。Microsoft的CMM(即ICM)可以在system32目錄中找到,名稱為ICM32.dll。
ICM32:
Windows的CMM是在Windows 95時代由第三方編寫的,發展至今仍然或多或少地包含當時的代碼,但已經經過了數十年來的安全修復。既然是如此古老的模塊,我們就有希望在其中發現新的漏洞。但是,這也是一個非常小的模塊,可能經過了多輪審計和模糊測試,包括內部產品安全團隊和外部研究人員,這個事實在一定程度上降低了我們找到漏洞的希望。我們檢索近期發現的ICM32漏洞,可以發現Project Zero和ZDI的研究人員在2017-2018年期間發現了多個漏洞,但從2019年開始就沒有找到更多的研究成果。
五、構建工具
盡管在MSDN上有ICM API的列表,但我們需要找到Windows用于所有ICC相關操作的API序列。要查找API序列,一種方式是搜索Windows DLL和EXE的反匯編并尋找用到的顏色配置文件API,另一種方式是找到適用于開源色彩管理系統(例如Little CMS,LCMS)的工具。使用這兩種方式,最終共同指向了很少的幾個API,這些API具有打開顏色配置文件和創建顏色轉換的功能。
基于上述信息,我編寫了一個簡單的初始工具:
#include < stdio.h > #include < Windows.h > #include < Icm.h > #pragma comment(lib, "mscms.lib") int main(int argc, char** argv) { char dstProfilePath[] = "sRGB Color Space Profile.icm"; tagPROFILE destinationProfile; HPROFILE hDstProfile = nullptr; destinationProfile.dwType = PROFILE_FILENAME; destinationProfile.pProfileData = dstProfilePath; destinationProfile.cbDataSize = (strlen(dstProfilePath) + 1); hDstProfile = OpenColorProfileA(&destinationProfile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING); if (nullptr == hDstProfile) { return -1; } tagPROFILE sourceProfile; HPROFILE hSrcProfile = nullptr; HTRANSFORM hColorTransform = nullptr; DWORD dwIntent[] = { INTENT_PERCEPTUAL, INTENT_PERCEPTUAL }; HPROFILE hProfileList[2]; sourceProfile.dwType = PROFILE_FILENAME; sourceProfile.pProfileData = argv[1]; sourceProfile.cbDataSize = (strlen(argv[1]) + 1); hSrcProfile = OpenColorProfileA(&sourceProfile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING); if (nullptr == hSrcProfile) { return -1; } hProfileList[0] = hSrcProfile; hProfileList[1] = hDstProfile; hColorTransform = CreateMultiProfileTransform( hProfileList, 2, dwIntent, 2, USE_RELATIVE_COLORIMETRIC | BEST_MODE, INDEX_DONT_CARE ); if (nullptr == hColorTransform) { return -1; } DeleteColorTransform(hColorTransform); CloseColorProfile(hSrcProfile); CloseColorProfile(hDstProfile); return 0; }
六、尋找語料庫和字典
在互聯網上,可以找到大量提供顏色配置文件的網站。顏色配置文件的另一個主要來源是圖像。有許多圖像文件都包含顏色配置文件,但需要一些工具將顏色配置文件轉儲到單獨的文件中。
簡單瀏覽規范,我們還可以保證語料庫至少包含來自7個不同顏色配置文件的所有樣本。而將它與代碼覆蓋率信息結合,可以準備第一套語料,用于模糊測試。
我們可以在梳理規范的過程中,創建唯一標簽名稱和對應值的列表,從而準備字典,幫助模糊工具查找其他代碼路徑。另外,還可以從LCMS這樣的開源模糊測試嘗試過程中找到字典。
七、模糊測試
我使用16核主機對第一套語料進行模糊處理,同時將來自MSCMS.dll和ICM32.dll的代碼覆蓋率信息作為我的模糊工具的反饋。在幾天后,開始出現崩潰。
八、CVE-2020-1117:InitNamedColorProfileData中的堆溢出
在嘗試越界讀取時,icm32!SwapShortOffset中發生了以下崩潰:
0:000 > r rax=0000023690497000 rbx=0000000000000000 rcx=00000000000000ff rdx=000000000000ffff rsi=0000023690496f00 rdi=0000023690496fee rip=00007ffa46bf3790 rsp=000000c2a56ff5a8 rbp=0000000000000001 r8=0000000000000014 r9=0000023690497002 r10=0000000000000014 r11=0000000000000014 r12=000000c2a56ff688 r13=0000023690492de0 r14=000000000000000a r15=000000004c616220 iopl=0 nv up ei ng nz ac pe cy cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000293 icm32!SwapShortOffset+0x10: 00007ffa`46bf3790 0fb610 movzx edx,byte ptr [rax] ds:00000236`90497000=?? 0:000 > !heap -p -a @rax address 0000023690497000 found in _DPH_HEAP_ROOT @ 23690411000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 23690412b60: 23690496f00 100 - 23690496000 2000 00007ffa51644807 ntdll!RtlDebugAllocateHeap+0x000000000000003f 00007ffa515f49d6 ntdll!RtlpAllocateHeap+0x0000000000077ae6 00007ffa5157babb ntdll!RtlpAllocateHeapInternal+0x00000000000001cb 00007ffa51479da0 msvcrt!malloc+0x0000000000000070 00007ffa46bf3805 icm32!SmartNewPtr+0x0000000000000011 00007ffa46bf37c8 icm32!SmartNewPtrClear+0x0000000000000014 00007ffa46c02d05 icm32!InitNamedColorProfileData+0x0000000000000085 00007ffa46bf6e39 icm32!Create_LH_ProfileSet+0x0000000000004e15 00007ffa46bf1973 icm32!PrepareCombiLUTs+0x0000000000000117 00007ffa46bf1814 icm32!CMMConcatInitPrivate+0x00000000000001f4 00007ffa46bf12a1 icm32!CWConcatColorWorld4MS+0x0000000000000075 00007ffa46bf11f4 icm32!CMCreateMultiProfileTransformInternal+0x00000000000000e8 00007ffa46bf1039 icm32!CMCreateMultiProfileTransform+0x0000000000000029 00007ffa48f16e6c mscms!CreateMultiProfileTransform+0x000000000000024c 00007ff774651191 ldr+0x0000000000001191 00007ff7746514b4 ldr+0x00000000000014b4 00007ffa505a7bd4 KERNEL32!BaseThreadInitThunk+0x0000000000000014 00007ffa515aced1 ntdll!RtlUserThreadStart+0x0000000000000021
icm32!SwapShortOffset讀取無符號的短值,對其進行bswap,并將它們存儲在相同的位置,這會導致讀寫原語崩潰。
反編譯的SwapShortOffset:
unsigned __int16 *__fastcall SwapShortOffset(void *sourceBuff, unsigned int offset, unsigned int len) { unsigned __int16 *endBuff; // r9 unsigned __int16 *result; // rax endBuff = (sourceBuff + len); for ( result = (sourceBuff + offset); result < endBuff; ++result ) *result = _byteswap_ushort(*result); // read, bswap and write return result; }
崩潰的函數icm32!SwapShortOffset并不能立即指向導致該問題的根本原因。為此,我們需要查看icm32!InitNamedColorProfileData。
反編譯的InitNamedColorProfileData:
__int64 __fastcall InitNamedColorProfileData(__int64 a1, void *hProfile, int a3, _DWORD *a4) { ... ... errCode = CMGetPartialProfileElement(hProfile, 'ncl2', 0, pBuffSize, 0i64); // getting size of ncl2 element if ( errCode ) return errCode; minSize = pBuffSize[0]; if ( pBuffSize[0] < 0x55 ) minSize = 0x55; pBuffSize[0] = minSize; outBuff = SmartNewPtrClear(minSize, &errCode); // allocating the buffer for ncl2 ... ... errCode = CMGetPartialProfileElement(hProfile, 'ncl2', 0, pBuffSize, outBuff); // reading ncl2 elements to buffer if ( !errCode ) { ... ... totalSizeToRead = count * totalDeviceCoord; if ( totalSizeToRead < 0xFFFFFFFFFFFFFFAEui64 && totalSizeToRead + 0x51 <= pBuffSize[0] ) // totalSizeToRead + 0x51 <= element size? { currPtr = outBuff + 0x54; // wrong offset of 0x54 is used ... ... do { SwapShortOffset((currPtr + 0x20), 0, 6u); ... --count; }while(count)
在這里,代碼嘗試讀取“ncl2”標簽/元素,并從文件中獲取流的大小。一個緩沖區會被分配,并再次進行相同的調用,以讀取元素ncl2的完整內容。該緩沖區將被解析,以查找設備位置的計數和編號,并通過確保讀寫操作位于緩沖區大小中來驗證該值。其中存在一個漏洞,用于驗證的偏移量(0x51)小于緩沖區指針的偏移量(0x54),該漏洞導致可以超過邊界讀寫3個字節。
該漏洞的修復方法非常簡單,將用于驗證的偏移量修改為0x54即可,這也是Microsoft實際修復此漏洞的方式。
九、其他漏洞
在分析上面的漏洞時,我們發現過程中會使用到CMGetPartialProfileElement函數讀取大小、進行分配和讀取內容。而這種模式可能會引入漏洞,例如大小不受限制、整數溢出、導致偏移量增加等。我決定分析這個函數,并尋找ICM32.dll中是否存在這樣的實例。
最終發現有3個實例具有未經檢查的偏移量訪問,分別是:CMConvIndexToNameProfile、CMConvNameToIndexProfile和CMGetNamedProfileInfoProfile。所有這些函數都可以通過導出的、有詳細說明的MSCMS函數進行訪問,分別是ConvertIndexToColorName、CMConvertColorNameToIndex和GetNamedProfileInfo。
反編譯后的CMConvIndexToNameProfile:
__int64 __fastcall CMConvIndexToNameProfile(HPROFILE hProfile, __int64 a2, __int64 a3, unsigned int a4) { ... ... errCode = CMGetPartialProfileElement(hProfile, 'ncl2', 0, pBuffSize, 0i64); // read size if ( !errCode ) { allocBuff = SmartNewPtr(pBuffSize[0], &errCode); if ( !errCode ) { errCode = CMGetPartialProfileElement(hProfile, 'ncl2', 0, pBuffSize, allocBuff); // read to buffer if ( !errCode ) { SwapLongOffset((allocBuff + 12), 0, 4u); // 12 > *pBuffSize ? SwapLongOffset((allocBuff + 16), v12, v13);
在CMConvIndexToNameProfile和其他兩個函數中,我們發現了漏洞,并沒有檢查ncl2元素的最小長度,且偏移量12和16可以直接訪問以進行讀取和寫入。那么如果allocBuffer的大小小于12,就可以實現對allocBuffer的越界讀寫。
由于在Windows中沒有二進制文件使用這些函數,因此Microsoft決定不會立即修復這三個漏洞。此外,我們也沒有找到使用這些API的任何Windows軟件或第三方軟件。
十、總結
在這一系列文章的第一部分中,我們對顏色配置文件進行了深入分析,編寫工具并成功找到了多個漏洞。請大家繼續關注第二部分,在第二部分中,我們將分析很少有人研究的一類漏洞——內存未初始化漏洞。
看完上述內容,你們掌握Windows圖像如何解析Fuzzing顏色配置文件的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。