/* Program that processes a tcpdump file that contains traffic to/from a NVP backdoor and prints out the commands sent to the backdoor and the backdoor's responses. Eloy Paris, August 2002 */ #include #include #include #include #include #include #include #include #include #include #include #include #define IPPROTO_NVP 11 void decode(u_int len, const u_char *encoded, char *decoded); void dump_nvp(struct iphdr *ip); void dump_tcp(struct iphdr *ip); void dump_udp(struct iphdr *ip); void dump_icmp(struct iphdr *ip); void dump_ip(struct iphdr *ip); void Ts_print(register const struct timeval *tvp); int32_t gmt2local(time_t t); void usage(char *progname); void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet); void dump(const unsigned char *data, unsigned len); char *commands[] = { "Request status", "Initialize communication parameters", "Execute command, send back results", "DNS flood", "UDP or ICMP fragmentation attack", "Open remote shell", "Execute remote command, don't send back results", "Kill current task", "DNS flood", "TCP SYN flood", "TCP SYN flood with delay", "DNS flood specifying server" }; char *response_modes[] = { "To 1 specific IP address", "To 1 specific IP address and 9 random IP addresses", "To 10 specific IP addresses" }; int packet_counter; int dump_packet; int tflag = 1; /* print packet arrival time */ int32_t thiszone; /* seconds offset from gmt to local time */ int main(int argc, char **argv) { int c; char dumpfile[512]; int have_fname = 0; char errbuf[PCAP_ERRBUF_SIZE]; pcap_t *pcap; while ( (c = getopt(argc, argv, "f:d") ) != -1) switch (c) { case 'f': strncpy(dumpfile, optarg, sizeof(dumpfile) ); have_fname = 1; break; case 'd': dump_packet = 1; break; default: usage(argv[0]); } if (!have_fname) usage(argv[0]); thiszone = gmt2local(0); if ( (pcap = pcap_open_offline(dumpfile, errbuf) ) == NULL) { fprintf(stderr, "pcap_offline() return an error: %s\n", errbuf); exit(2); } printf("libcap version: %d.%d\n\n", pcap_major_version(pcap), pcap_minor_version(pcap) ); /* We'll use this inside our callback function */ packet_counter = 1; pcap_loop(pcap, -1, got_packet, NULL); pcap_close(pcap); return 0; } void decode(u_int len, const u_char *encoded, char *decoded) { u_char *buffer; /* word-aligned array of (len + 3) elements */ int eax, ebx, ecx; u_int edx; buffer = (u_char *) malloc( (len + 3) & 0xfffffffc); decoded[0] = 0; for (ebx = len - 1; ebx >= 0; ebx--) { eax = ebx ? encoded[ebx] - encoded[ebx - 1] : encoded[0]; ecx = eax - 23; while (ecx < 0) ecx += 256; for (edx = 0; edx < len; edx++) buffer[edx] = decoded[edx]; decoded[0] = (u_char) ecx; for (edx = 1; edx < len; edx++) decoded[edx] = buffer[edx - 1]; sprintf(decoded, "%c%s", (u_char) ecx, buffer); } free(buffer); } void usage(char *progname) { fprintf(stderr, "Usage: %s -f [-d]\n", progname); exit(1); } /* * Returns the difference between gmt and local time in seconds. * Use gmtime() and localtime() to keep things simple. (Stolen * verbatim from tcpdump.) */ int32_t gmt2local(time_t t) { register int dt, dir; register struct tm *gmt, *loc; struct tm sgmt; if (t == 0) t = time(NULL); gmt = &sgmt; *gmt = *gmtime(&t); loc = localtime(&t); dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + (loc->tm_min - gmt->tm_min) * 60; /* * If the year or julian day is different, we span 00:00 GMT * and must add or subtract a day. Check the year first to * avoid problems when the julian day wraps. */ dir = loc->tm_year - gmt->tm_year; if (dir == 0) dir = loc->tm_yday - gmt->tm_yday; dt += dir * 24 * 60 * 60; return (dt); } /* * Print the timestamp (stolen verbatim from tcpdump) */ void Ts_print(register const struct timeval *tvp) { register int s; struct tm *tm; time_t Time; static unsigned b_sec; static unsigned b_usec; switch(tflag) { case 1: /* Default */ s = (tvp->tv_sec + thiszone) % 86400; (void)printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60, (unsigned)tvp->tv_usec); break; case -1: /* Unix timeval style */ (void)printf("%u.%06u ", (unsigned)tvp->tv_sec, (unsigned)tvp->tv_usec); break; case -2: if (b_sec == 0) { printf("000000 "); } else { int d_usec = tvp->tv_usec - b_usec; int d_sec = tvp->tv_sec - b_sec; while (d_usec < 0) { d_usec += 1000000; d_sec--; } if (d_sec) printf("%d. ", d_sec); printf("%06d ", d_usec); } b_sec = tvp->tv_sec; b_usec = tvp->tv_usec; break; case -3: /* Default + Date*/ s = (tvp->tv_sec + thiszone) % 86400; Time = (tvp->tv_sec + thiszone) - s; tm = gmtime (&Time); (void)printf("%02d/%02d/%04d %02d:%02d:%02d.%06u ", tm->tm_mon+1, tm->tm_mday, tm->tm_year+1900, s / 3600, (s % 3600) / 60, s % 60, (unsigned)tvp->tv_usec); break; } } void dump_ip(struct iphdr *ip) { char src_ip[20], dest_ip[20]; /* Get source and destination addresses */ strcpy(src_ip, inet_ntoa( *(struct in_addr *) &ip->saddr) ); strcpy(dest_ip, inet_ntoa( *(struct in_addr *) &ip->daddr) ); printf("%s -> %s\n", src_ip, dest_ip); printf("Length of IP data: %d\n", ntohs(ip->tot_len) - sizeof(struct iphdr) ); } void dump_icmp(struct iphdr *ip) { printf("IP protocol is ICMP\n"); } void dump_udp(struct iphdr *ip) { struct udphdr *udp; printf("IP protocol is UDP\n"); udp = (struct udphdr *) ( (char *) ip + sizeof(struct iphdr) ); printf("Source port: %d, destination port %d\n", ntohs(udp->source), ntohs(udp->dest) ); } void dump_tcp(struct iphdr *ip) { struct tcphdr *tcp; printf("IP protocol is TCP\n"); tcp = (struct tcphdr *) ( (char *) ip + sizeof(struct iphdr) ); printf("Source port: %d, destination port %d\n", ntohs(tcp->source), ntohs(tcp->dest) ); } void dump_nvp(struct iphdr *ip) { u_char *payload; u_char decoded[2048]; int len; int command; int response_mode, number_of_ips; int i; struct in_addr dest_addr; printf("IP protocol is NVP\n"); if ( (len = ntohs(ip->tot_len) - sizeof(struct iphdr) ) <= 200) { printf("Too few bytes received.\n"); return; } payload = (u_char *) ip + sizeof(struct iphdr); if (payload[0] != 2 && payload[0] != 3) { printf("payload[0] is not 2 or 3. Invalid packet. Skipping\n"); return; } decode(len - 2, payload + 2, decoded); printf("Direction: %s\n", payload[0] == 2 ? "To agent" : "From agent"); command = decoded[1]; if (command < 1 || command > 12) { printf("Command %d is invalid. Skipping\n", command); return; } if (payload[0] == 2) { /* To agent */ printf("Command: %d (%s)\n", command, commands[command - 1]); if (command == 3 || command == 7) { /* Execute command ... */ printf("Command to execute: %s\n", decoded + 2); } else if (command == 2) { response_mode = decoded[2]; printf("Response mode: %d (%s)\n", decoded[2], response_modes[response_mode]); number_of_ips = (response_mode == 0 || response_mode == 1) ? 1 : 10; printf("Respond to: "); for (i = 0; i < number_of_ips; i++) { ((char *) &dest_addr)[0] = decoded[3 + i*sizeof(struct in_addr)]; ((char *) &dest_addr)[1] = decoded[4 + i*sizeof(struct in_addr)]; ((char *) &dest_addr)[2] = decoded[5 + i*sizeof(struct in_addr)]; ((char *) &dest_addr)[3] = decoded[6 + i*sizeof(struct in_addr)]; printf("%s ", inet_ntoa(dest_addr) ); } printf("\n"); } } else { /* From agent */ printf("Command output:\n"); printf("'%s'", decoded + 2); printf("\n"); } if (dump_packet) { printf("\n"); dump(decoded, len - 2); } } void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) { struct ether_header *ether; struct iphdr *ip; int len; if (header->caplen != header->len) { printf("%d != %d!!! Don't have complete packet. Skipping.\n", header->caplen, header->len); goto exit; } ether = (struct ether_header *) packet; if (ntohs(ether->ether_type) != ETHERTYPE_IP) { printf("Packet %d: protocol is not IP. Skipping.\n", packet_counter); goto exit; } ip = (struct iphdr *) (packet + sizeof(struct ether_header) ); printf("Packet %d, ", packet_counter); Ts_print(&header->ts); printf("\n\n"); len = ntohs(ip->tot_len) - sizeof(struct iphdr); printf("Length of IP data: %d bytes\n", len); dump_ip(ip); switch (ip->protocol) { case IPPROTO_ICMP: dump_icmp(ip); break; case IPPROTO_TCP: dump_tcp(ip); break; case IPPROTO_UDP: dump_udp(ip); break; case IPPROTO_NVP: dump_nvp(ip); break; default: printf("Unknown IP protocol %d.\n", ip->protocol); } exit: printf("--------------------------------------------------\n"); packet_counter++; } void dump(const unsigned char *data, unsigned len) { unsigned i, j; for (i = 0; i <= len/16; i++) { printf("%08x ", i*16); for (j = 0; j < 16; j++) { if (i*16 + j < len) printf("%02x", data[i*16 + j]); else printf(" "); if (j & 1) printf(" "); } for (j = 0; j < 16; j++) if (i*16 + j < len) printf("%c", isprint(data[i*16 + j]) ? data[i*16 + j] : '.'); printf("\n"); } printf("\n"); }