來源:Flanker Sky
作者:flanker017
ImageIO
適用于:iPhone 5 及更新機型、iPad 第 4 代及更新機型、iPod touch 第 6 代及更新機型
影響:處理惡意制作的圖像可能會導致任意代碼執行
說明:內存損壞問題已通過改進輸入驗證得到解決。
CVE-2017-2416:騰訊科恩實驗室的 @flanker_hqd
(For English version see https://blog.flanker017.me/cve-2017-2416-gif-remote-exec/)
Abstract
前段時間偶然發現了一個ImageIO.framework中的圖像解析漏洞,通過發送這個惡意圖片,可以在任何有圖片顯示功能的應用中直接觸發該漏洞,特別是各種IM應用(例如iMessage, Telegram, Slack, iMessage和國產流行IM,以及郵件應用例如Mail, Outlook, Inbox, Gmail,還有一些想做IM的金融應用例如alipay等),導致應用崩潰。在精心布置的內存布局下還有遠程代碼執行的可能。
讓問題變得更蛋疼的是,很多客戶端通常會在啟動的時候再去嘗試恢復加載之前的記錄,也包括圖片,這導致每次啟動的時候該漏洞都會被觸發,自動地成為了一個可持續的漏洞 – -b 例如iMessage和Mail即是如此。通過iMessage給一個沒有升級到10.12.4的人發送攻擊圖片,其iMessage就再也打不開了。
DEMO videos
第一個視頻展示了發送一條惡意imessage就導致對方崩潰的過程
然后被攻擊的設備就再也打不開imessage了
Crash trace
* thread #1: tid = 0x17570, 0x00007fff9557f1ab ImageIO`IIOReadPlugin::IIOReadPlugin(CGImagePlus*, unsigned int, unsigned int, long long, unsigned char) + 67, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
frame #0: 0x00007fff9557f1ab ImageIO`IIOReadPlugin::IIOReadPlugin(CGImagePlus*, unsigned int, unsigned int, long long, unsigned char) + 67
ImageIO`IIOReadPlugin::IIOReadPlugin:
-> 0x7fff9557f1ab <+67>: mov al, byte ptr [rdi + 0x40]
0x7fff9557f1ae <+70>: mov qword ptr [rbx + 0x20], rdi
0x7fff9557f1b2 <+74>: mov byte ptr [rbx + 0xc8], al
0x7fff9557f1b8 <+80>: xor eax, eax
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 com.apple.ImageIO.framework 0x00007fffa144d1ab IIOReadPlugin::IIOReadPlugin(CGImagePlus*, unsigned int, unsigned int, long long, unsigned char) + 67
1 com.apple.ImageIO.framework 0x00007fffa14b8c93 GIFReadPlugin::InitProc(CGImagePlugin*, unsigned long, unsigned long) + 59
2 com.apple.ImageIO.framework 0x00007fffa14177da IIOImageSource::makeImagePlus(unsigned long, __CFDictionary const*) + 252
3 com.apple.ImageIO.framework 0x00007fffa141918b IIOImageSource::getPropertiesAtIndexInternal(unsigned long, __CFDictionary const*) + 57
4 com.apple.ImageIO.framework 0x00007fffa141911c IIOImageSource::copyPropertiesAtIndex(unsigned long, __CFDictionary const*) + 98
5 com.apple.ImageIO.framework 0x00007fffa13f03ca CGImageSourceCopyPropertiesAtIndex + 181
6 com.apple.AppKit 0x00007fff9cfdbcae +[NSBitmapImageRep _imagesWithData:hfsFileType:extension:zone:expandImageContentNow:includeAllReps:] + 543
7 com.apple.AppKit 0x00007fff9cfdba68 +[NSBitmapImageRep _imageRepsWithData:hfsFileType:extension:expandImageContentNow:] + 93
8 com.apple.AppKit 0x00007fff9d4bf08e -[NSImage _initWithData:fileType:hfsType:] + 479
在蘋果平臺上,基本所有的圖像解析功能最后都會調用[NSImage _initWithData:fileType:hfsType:], 隨后IIOImageSource將圖像的解析根據圖像頭特征分配到對應的plugin中。注意這里并不是基于文件擴展名做的判斷,所以后續我們可以通過這個特性繞過過濾實現利用。
漏洞樣例圖片
如果把它拖動到任意macos/iOS app中的時候崩潰了,那么你的系統受該漏洞影響,趕快升級吧。 測試樣例文件下載:Sample PNG Sample GIF 僅供自測使用,請勿用于非法用途例如發送給他人。
漏洞分析
漏洞的一個源頭在GIFReadPlugin::init函數中,觀察如下反匯編代碼:
v32 = (signed __int16)width * (signed __int64)height;
if ( v32 > filesize * 1100 * v29 )
{
LOBYTE(aspectbyte) = 0;
v15 = 0LL;
if ( this->gapC0[8] )
{
LOBYTE(aspectbyte) = 0;
LogError(
"init",
498,
"malformed GIF file (%d x %d) - [canvasSize: %ld fileSize: %ld ratio: %d] \n",
(unsigned int)(signed __int16)width,
(unsigned int)(height), // width >> 16 is height
(signed __int16)width * (signed __int64)SHIWORD(width),
filesize,
v32 / filesize);
v15 = 0LL;
}
goto LABEL_71;
}
__text:00000000000CC51F movsx rax, r9w
__text:00000000000CC523 mov ecx, r9d
__text:00000000000CC526 shr ecx, 10h
__text:00000000000CC529 movsx rbx, cx
__text:00000000000CC52D imul rbx, rax
__text:00000000000CC531 imul rdx, r12, 44Ch
__text:00000000000CC538 mov rax, rdx
__text:00000000000CC53B imul rax, rsi
__text:00000000000CC53F cmp rbx, rax
一個攻擊者可以構造負數的高度和長度,bypass掉對filesize的比較,造成后續內存越界訪問。一般來講攻擊者可以通過手動構造圖片輸入流/hook進行發送,或者通過app服務自身提供的web服務來進行發送。前面提到過ImageIO解析圖片的時候并不是通過判斷擴展名來進行的,通過這個特性我們可以同樣bypass一些web圖片上傳界面的過濾,將惡意圖片成功發送到對方設備上,粗發漏洞。
相對來講稍微令人詫異的是蘋果的修復。補丁并沒有打在size比較這里,而是打在了IIOReadPlugin這里。在補丁之前,IIOReadPlugin的關鍵代碼如下所示:
bool __fastcall IIOReadPlugin::IIOReadPlugin(IIOReadPlugin *a1, __int64 a2, int a3, int a4, __int64 a5, unsigned __int8 a6)
{
unsigned __int8 v6; // r14@1
IIOReadPlugin *this; // rbx@1
__int64 v8; // rax@1
__int64 sessionwrap; // rdi@1
IIOImageReadSession *session; // rax@2
IIOImageRead *v11; // rdi@2
__int64 v12; // rax@2
__int64 *v13; // rcx@5
__int64 v14; // rdx@5
bool result; // al@5
v6 = a6;
this = a1;
a1->vt = (__int64)off_1659D0;
a1->field_8 = a2;
v8 = *(_QWORD *)(a2 + 24);
a1->field_10 = v8;
a1->field_38 = a3;
a1->field_3c = a4;
a1->field_30 = a5;
sessionwrap = *(_QWORD *)(v8 + 24);
if ( sessionwrap )
{
session = (IIOImageReadSession *)CGImageReadSessionGetSession(sessionwrap); //session is invalid
this->session = session;
v11 = (IIOImageRead *)session->imageread; //oob happens here and lead to crash
LOBYTE(session) = v11->field_40;
this->field_20 = (__int64)v11;
this->field_c8 = (char)session;
v12 = 0LL;
if ( v11 )
v12 = IIOImageRead::getSize(v11);
}
else
{
this->field_20 = 0LL;
this->session = 0LL;
this->field_c8 = 1;
v12 = 0LL;
}
在10.12.4中,if分支語句變成了如下所示:
a1->field_8 = cgimgplus;
imageplus = CGImagePlusGetIPlus(cgimgplus);
a1->field_10 = imageplus;
a1->field_38 = v9;
a1->field_3c = v8;
a1->field_30 = v7;
v12 = *(_QWORD *)(imageplus + 32);
a1->field_18 = v12;
imageread = *(IIOImageRead **)(v12 + 32);
if ( imageread )
{
v10->field_c8 = *((_BYTE *)imageread + 64);
v10->field_20 = (__int64)imageread;
v14 = IIOImageRead::getSize(imageread);
}
else
{
v10->field_c8 = 0;
v10->field_20 = 0LL;
v14 = 0LL;
}
IIOImageReadSession的使用在這里被移除了。這是否從根源上解決了問題?讓我們拭目以待。
對開發者和用戶的建議
對于想自行防御這個問題的開發者來說(畢竟有很多用戶沒有升級到最新版,鍋還是會被他們扣在開發者頭上),我建議在圖片顯示前先自行檢查下GIF寬度和高度。
對于終端用戶來講,當然升級系統是最好的辦法了。
Timeline
- 2017.1.10 Initial discovery
- 2017.1.16 Report to Apple
- 2017.1.24 Apple responds on they are working on a fix
- 2017.3.23 CVE-2017-2416 assigned
- 2017.3.28 Advisory published at https://support.apple.com/zh-cn/HT207617
- 2017.4.6 Public disclosure
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/268/
暫無評論