--- nmap.c.orig Mon Feb 15 23:43:36 1999 +++ nmap.c Tue Feb 16 02:39:36 1999 @@ -1,10 +1,34 @@ #include "nmap.h" #include "osscan.h" +#include /* global options */ extern char *optarg; extern int optind; struct ops o; /* option structure */ +int indexnum; +int total_exploits; /* total number of exploits in exploit structure */ +#define MAX_EXPLOITS 512 +struct exploit { + char *os_name; + char *exploit_port; + char *exploit_prot; + char *wait_data1; + char *send_data1; + char *wait_data2; + char *exec_prog; + char *comment; +} exploit[MAX_EXPLOITS]; + /* function prototypes */ +char *assign_osname(struct hoststruct *currenths); +int vulnscan (struct hoststruct *currenths, portlist ports); +char *scan_host (struct hoststruct *currenths, char *dest_port, char *protocol, + char *wait_data1, char *send_data1, + char *wait_data2, char *exec_prog, + char *comment); +int get_exploits(struct hoststruct *currenths); +int regex_parse (char *port_data, char *regex_data); + int main(int argc, char *argv[]) { char *p, *q; @@ -67,6 +91,8 @@ fakeargv[argc] = NULL; printf("\nStarting nmap V. %s by Fyodor (fyodor@dhp.com, www.insecure.org/nmap/)\n", VERSION); +printf("vulnmap mods by Ajax (ajax@mobis.com, www.mobis.com/ajax/code/nmap/)\n"); + /* Seed our random generator */ gettimeofday(&tv, NULL); @@ -83,7 +109,7 @@ if (argc < 2 ) printusage(argv[0]); /* OK, lets parse these args! */ -while((arg = getopt(argc,fakeargv,"Ab:D:de:Ffg:hIi:M:m:NnOo:P:p:qRrS:s:T:Vv")) != EOF) { +while((arg = getopt(argc,fakeargv,"Ab:D:de:Ffg:hIi:M:m:NnOo:P:p:qRrS:s:T:Vvz")) != EOF) { switch(arg) { case 'A': o.allowall++; break; case 'b': @@ -252,6 +278,8 @@ exit(0); break; case 'v': o.verbose++; break; + case 'z': o.vulnerability_scan++; break; + } } @@ -549,7 +577,14 @@ if (o.osscan) { os_scan(currenths); } - + + if (o.vulnerability_scan) { + if (o.debugging) { + printf("[DEBUG]: Entering vulnerability scanning option.\n"); + } + vulnscan(currenths, currenths->ports); + } + if (!currenths->ports && !o.pingscan) { nmap_log("No ports open for host %s (%s)\n", currenths->name, inet_ntoa(currenths->host)); @@ -803,7 +838,8 @@ if (!o.allowall) printf(" -A Allow scanning .0 and .255 addresses" ); printf(" -v Verbose. Its use is recommended. Use twice for greater effect.\n\ -h help, print this junk. Also see http://www.insecure.org/nmap/\n\ - -V Print version number and exit.\n"); + -V Print version number and exit.\n\ + -z Vulnerabiltiy scanning enabled.\n"); printf(" -e . Send packets on interface (eth0,ppp0,etc.).\n"); printf(" -q quash argv to something benign, currently set to \"%s\". (deprecated)\n", FAKE_ARGV); printf("Hostnames specified as internet hostname or IP address. Optional '/mask' \ @@ -3038,3 +3074,459 @@ if (fp) fclose(fp); return (fp == NULL)? 0 : 1; } + +/* vulnerablity scanning option under nmap + + + notes: currenths->name = full name of host to scan + inet_ntoa(currenths->host) = ip address of host to scan + currenths->portno = destination port + of typedef portlist ports; port *current_port = ports; + currenths->FP_matches[0]->OS_name = first guessed OS fingerprint + fp2ascii(currenths->FPs[currenths->goodFP]) = matched OS fingerprint + (dont use this...) + nmap_log("blah%sblah\n",blah) = logs to screen and to logfile + pos_scan(currenths,ports,CONNECT_SCAN) = connectscan (-sT) + getidentdinfoz() = good ref + +TODO: allow send_data to support byte substitution, + \n = newline, \t = tab, etc + \nnn = decimal ascii character + \xnn = hex ascii character +*/ + +int vulnscan (struct hoststruct *currenths, portlist ports) +{ +/* + * vulnscan: This is the main function that is called by nmap.c + * All other subfunctions are called by vulnscan. + */ +int portindex; +port *current = ports, *tmp; /* open ports list */ +port *current_ports = ports; +/* struct hoststruct currenths = *tmpcurrenths; */ + + /* + * retrieve exploits from exploit.dat if we have not already + * done so. Store them in array of exploit structures. + * total_exploits = the number of exploits retrieved from exploit.dat + */ + if (o.debugging) { + printf("\n[DEBUG]: Entering vulnscan() function\n"); + printf(" currenths->name = %s\n", currenths->name); + printf(" inet_ntoa(currenths->host) = %s\n", + inet_ntoa(currenths->host)); + printf(" currenths->FP_matches[0]->OS_name = %s\n", + currenths->FP_matches[0]->OS_name); + } + if (total_exploits == 0) { + if (o.debugging) { + printf("[DEBUG]: vulnscan(): calling function"); + printf(" get_exploits(currenths)\n"); + } + get_exploits(currenths); + } + + /* + * cycle through the array of exploits, comparing each one + * to the current operating system we're working on now. + * For each exploit that is found that matches our current target OS, + * make sure the exploits destination port is one that was found to + * be an open port. (*ports) + */ + if (o.debugging) { + printf("[DEBUG]: cycling through array of exploits\n"); + } + /* current_os = assign_osname(currenths); */ + for (indexnum=0; indexnum < total_exploits; indexnum++) { + if (currenths->FP_matches[0]->OS_name != (char *)0) { + if (strstr(currenths->FP_matches[0]->OS_name, + exploit[indexnum].os_name)) + { + + /* + * cycle through current->portno looking for a destination + * port that matches the criteria in the current exploit struct + */ + if (o.debugging) { + printf("[DEBUG]: exploit[indexnum].os_name matches current_os,\n"); + printf(" checking current->portno for a port match.\n"); + printf(" indexnum = %d\n", indexnum); + printf(" exploit[indexnum].os_name = %s\n\n", + exploit[indexnum].os_name); + } + current_ports = current; + while (current_ports != NULL) { + portindex = atoi(exploit[indexnum].exploit_port); + if (o.debugging) { + printf("[DEBUG]: inside while loop... current != NULL\n"); + printf(" portindex = %d\n", portindex); + printf(" current_ports->portno = %d\n", + current_ports->portno); + } + if (portindex == current_ports->portno) { + /* + * scan_host for vulnerable services + */ + if (o.debugging) { + printf("[DEBUG]: current_ports->portno is equal to "); + printf("exploit[indexnum].exploit_port\n"); + printf(" executing scan_host()"); + printf(" for vulnerable services.\n"); + } + scan_host(currenths, exploit[indexnum].exploit_port, + exploit[indexnum].exploit_prot, exploit[indexnum].wait_data1, + exploit[indexnum].send_data1, exploit[indexnum].wait_data2, + exploit[indexnum].exec_prog, exploit[indexnum].comment); + break; + } + tmp = current_ports; + current_ports = current_ports->next; + } /* end while loop cycling through current->portno */ + } /* endif ststr exploit[indexnum].os_name for current_os */ + } else { /* endif fingerprint not equals null */ + if(o.debugging) { + printf("[DEBUG]: We have a null fingerprint... skipping for now\n"); + } + } + } /* end for loop cycling through exploits */ + return 0; +} + +/* + * scan_host: all purpose function for sending and + * receiving data over an inet domain socket. + */ + +char *scan_host (struct hoststruct *currenths, char *dest_port, char *protocol, + char *wait_data1, char *send_data1, + char *wait_data2, char *exec_prog, char *comment) { + +int socket_id, res, vulnerable_flag = 0; +struct sockaddr_in sock; /* destination socket structure */ +char response[1024]; /* data recieved from socket connection */ +char *execprog_token; /* token for each field of exec_prog */ +char execprog_buf[1024]; /* the whole buffer for exec_prog */ +int destport; + /* + * Create socket. socket_id must note equal < 0 + */ + destport = atoi(dest_port); + if (o.debugging) { + printf("[DEBUG]: Entering scan_host() function:\n"); + printf(" inet_ntoa(currenths->host) = %s\n", + inet_ntoa(currenths->host)); + printf(" currenths->host.s_addr = %d\n", + currenths->host.s_addr); + printf(" dest_port = %s\n", dest_port); + printf(" destport = %d\n", destport); + + } + if ((socket_id = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + perror("socket"); exit(1); } + + sock.sin_family = AF_INET; + sock.sin_addr.s_addr = currenths->host.s_addr; /* destination address */ + sock.sin_port = htons(destport); /* destination port */ + res=0; + res = connect(socket_id, (struct sockaddr_in *) &sock, + sizeof(struct sockaddr_in)); + +/* + res = connect(socket_id,(struct sockaddr_in *)&sock, sizeof(sock)); +*/ + if (res < 0) { + if (o.debugging || o.verbose) + printf("port %d not open for some reason.\n", destport); + close(socket_id); + return 0; + } + /* + * Port is open. Recieve data. + */ + if (o.debugging) { + printf("[DEBUG]: scan_host(): port is open."); + printf(" attempting to receive data.\n"); + } + bzero(response, 1024); + while ((res = recvtime(socket_id, response, 1024,4)) > 0) + if (res < 0) { + perror("recvtime problem"); + exit(1); + } +/* if ((res = read(socket_id, response, 1024)) == -1) { + perror("reading from port"); + close(socket_id); + return 0; + } */ + if (o.debugging) { + printf(" response = %s\n", response); + printf(" wait_data1 = %s\n", wait_data1); + } + /* if ((res = regex_parse(response, wait_data1)) == 0) */ + if (strstr(response, wait_data1)) { + if (o.debugging) { + printf("[DEBUG]: wait_data1 recieved from port\n"); + printf(" inet_ntoa(currenths->host) = %s\n", + inet_ntoa(currenths->host)); + printf(" wait_data1 = %s\n", wait_data1); + } + /* + * wait_data1 received. + */ + vulnerable_flag++; + if (strcmp(send_data1, "NULL")) { + if (o.debugging) { + printf("[DEBUG]: send_data1 does NOT contain the word NULL\n"); + printf(" inet_ntoa(currenths->host) = %s\n", + inet_ntoa(currenths->host)); + printf(" send_data1 = %s\n", send_data1); + } + /* + * send_data1 doesnt contain the word "NULL", + * attempt to send data (send_data1) to port + */ + if (write(socket_id, send_data1, strlen(send_data1) + 1) == -1) { + perror("writing send_dat1 to port"); + close(socket_id); + return 0; + } + if ((res = read(socket_id, response, 1024)) == -1) { + perror("reading from port"); + close(socket_id); + return 0; + } + /* + * compare wait_data2 to the port response + * if it compares correctly, increment vulnerable flag. + */ + if ((strstr(response, wait_data2)) != NULL) { + + } + } + if (vulnerable_flag > 0) { + if (o.debugging) { + printf("[DEBUG]: vulnerable_flag is greater than zero\n"); + printf(" vulnerable_flag = %d\n", vulnerable_flag); + printf(" currenths->name = %s\n", currenths->name); + printf(" inet_ntoa(currenths->host) = %s\n", + inet_ntoa(currenths->host)); + printf(" dest_port = %s\n", dest_port); + printf(" destport = %d\n", destport); + + } + /* + * this host was found to be vulnerable. + * use nmap_log to log it + */ + printf("Host %s (%s), port %d: %s", currenths->name, + inet_ntoa(currenths->host), destport, comment); + /* + * if the config file contains a program to execute for + * this exploit, parse the program to exec, looking for + * variables to be substituted using strtok(). + * + * The string "NULL" should be in the exec_prog field + * of the config file if there is no program to execute. + */ + if (strcmp(exploit[indexnum].exec_prog, "NULL")) { + if (o.debugging) { + printf("[DEBUG]: exec_prog field does not equal NULL."); + printf(" Parsing exec_prog args\n"); + } + while((execprog_token = + strtok(exploit[indexnum].exec_prog, " ")) != NULL) { + if (o.debugging) { + printf("[DEBUG]: exec_prog: inside while loop..\n"); + printf(" execprog_token = %s\n", execprog_token); + } + if (strstr(execprog_token, "%IP")) { + + /* + * if current token has the variable %IP, substitute it + * with the current IP address + */ + strncat(execprog_buf, inet_ntoa(currenths->host), + strlen(inet_ntoa(currenths->host))); + } else { + strncat(execprog_buf, execprog_token, + strlen(execprog_token)); + } + + } + execl(execprog_buf, execprog_buf, NULL); + } /* end compare exec_prog field to NULL */ + return 0; + /* work needs to be done here ? */ + } /* end if vulnerable_flag > 0 */ + + return 0; + + } /* end wait_data1 received from port */ + return 0; +} + +int get_exploits(struct hoststruct *currenths) { + +/* + * get_exploitis: open exploit.dat file and pull out all exploits + * matching os_type. Put this into exploit struct. + */ + +FILE *exploit_fp; /* file pointer for exploit.dat file */ +int exploit_num = 0; /* current index number in exploit struct */ +char line[1024]; /* max size of each line of exploit.dat file */ +char *copyline; + /* + * Open the file for parsing + */ + + if ((exploit_fp = fopen("exploit.dat", "r")) == NULL) { + if (o.debugging) { + printf("[DEBUG]: get_exploits(): error fopen exploit.dat\n"); + } + fprintf(stderr,"Error: can not open exploit.dat for reading.\n"); + perror("fopen"); + exit(1); + } + + /* + * loop until lines have been read. insert data into the exploit struct + * until all lines have been read. + */ + + while ((fgets (line, 1024, exploit_fp)) != NULL) { + /* + * total_exploits is set to zero on each execution of this function. + * if total_exploits is set to zero, we should zero out all old + * values stored in the exploit structure. + */ + + if (total_exploits == 0) { + if (o.debugging) { + printf("[DEBUG]: get_exploits(): total_exploits == 0,"); + printf(" trucating exploit structure\n"); + } + bzero(exploit, sizeof(*exploit)); + } + copyline = strdup(line); + + exploit[exploit_num].os_name = strtok(copyline, ","); + exploit[exploit_num].exploit_port = strtok(NULL, ","); + exploit[exploit_num].exploit_prot = strtok(NULL, ","); + exploit[exploit_num].wait_data1 = strtok(NULL, ","); + exploit[exploit_num].send_data1 = strtok(NULL, ","); + exploit[exploit_num].wait_data2 = strtok(NULL, ","); + exploit[exploit_num].exec_prog = strtok(NULL, ","); + exploit[exploit_num].comment = strtok(NULL, ","); + + +/* sscanf (line, "%s,%d,%s,%s,%s,%s,%s,%s", exploit[exploit_num].os_name, + exploit[exploit_num].exploit_port, exploit[exploit_num].exploit_prot, + exploit[exploit_num].wait_data1, exploit[exploit_num].send_data1, + exploit[exploit_num].wait_data2, + exploit[exploit_num].exec_prog, exploit[exploit_num].comment); */ + if (o.debugging) { + printf("[DEBUG]: get_exploits(): inside while loop...\n"); + printf(" line = %s", line); + printf(" exploit_num = %d\n", exploit_num); + printf(" exploit[exploit_num].os_name = %s\n", + exploit[exploit_num].os_name); + printf(" exploit[exploit_num].exploit_port = %s\n", + exploit[exploit_num].exploit_port); + printf(" exploit[exploit_num].exploit_prot = %s\n", + exploit[exploit_num].exploit_prot); + printf(" exploit[exploit_num].wait_data1 = %s\n", + exploit[exploit_num].wait_data1); + printf(" exploit[exploit_num].send_data1 = %s\n", + exploit[exploit_num].send_data1); + printf(" exploit[exploit_num].wait_data2 = %s\n", + exploit[exploit_num].wait_data2); + printf(" exploit[exploit_num].exec_prog = %s\n", + exploit[exploit_num].exec_prog); + printf(" exploit[exploit_num].comment = %s\n\n", + exploit[exploit_num].comment); + } + if (exploit_num == MAX_EXPLOITS) { + break; + break; + } + + exploit_num++; + total_exploits++; + } /* end while loop */ + + if (o.debugging) { + printf("[DEBUG]: get_exploits(): end while loop.\n"); + printf(" exploit_num = %d\n", exploit_num); + printf(" total_exploits = %d\n", total_exploits); + } + + /* Format of exploit.dat: + * OSTYPE,PORT,PROT,WAIT_DATA1,SEND_DATA1,WAIT_DATA2,SEND_DATA2, + * EXEC_PROG,COMMENT + * + * Definitions: + * OSTYPE=fingerprint to match up with + * PORT=[0-65536] + * PROT=TCP,UDP,RPC + * WAIT_DATA1=data to expect to recieve to compare if vulnerable + * SEND_DATA1=data to send (if null use "NULL") + * WAIT_DATA2=data to expect (if null use "NULL") + * if SEND_DATA1 is NULL, WAIT_DATA2 is skipped. + * EXEC_PROG=pathname/filename to exec with variable substitution, or "NULL" + * options: %IP = ip address in dot notation + * COMMENTS=comments to log if vulnerable + */ + + + /* + * Close the file + */ + if (o.debugging) { + printf("[DEBUG]: get_exploits(): fclose(exploit_fp)\n"); + } + fclose(exploit_fp); + /* current_os = assign_osname(currenths); */ + if (o.debugging){ + printf("[DEBUG]: get_exploits: return 0 for sucess.\n"); + } + return 0; /* everything went smooth. */ +} +/* + * regex_parse: parse port_data for regular expression pattern match + * regex_data. return 0 on successful pattern matching + */ +int regex_parse (char *port_data, char regex_data[]) { + +regex_t reg; +char error_buff[256]; +char pattern[256]; +int res; + + if ((regex_data[0]) == '/') { + if ((strlen(regex_data)) >= 256) { + regex_data[256] = '\0'; + } + sprintf(pattern, "/%s/", regex_data); + } + + if ((res = regcomp (®, pattern, REG_EXTENDED))) { + regerror(res, ®, error_buff, sizeof(error_buff)); + printf("%s\n", error_buff); + } + + if ((res = regexec(®, port_data, 0, NULL, 0)) == 0) { + regfree(®); + /* + * regexec returns 0 for successful match or REG_NOMATCH for failure. + */ + return res; + } else { + regfree(®); + return -1; + } + +} + +