Nmap Development mailing list archives
[PATCH] Prevent execution of unintended Nmap scans when invalid targets are specified.
From: jah <jah () zadkiel plus com>
Date: Thu, 07 May 2009 01:31:25 +0100
Hi folks, The command: nmap #192.168.1.1 will result in a scan against 0.168.1.1. This is because the first character of a host expression not containing alpha chars is not checked (to determine whether it is one of the allowed characters) and is passed (as part of the first octet of an IPv4 address) to atoi() which cannot perform a valid conversion and so returns zero. I've attached the fix, as I see it, and nmap now reports "Invalid character in host specification..." as, I think, is expected. I wondered whether not checking the first char might have been by design in order to allow quoting of the host expression on the command line in which case more robust checking will likely be required in order to prevent the above example from happening. A command such as nmap 192.168.1.0/ or nmap 192.168.1.0/ab will be interpreted as having a netmask of zero causing nmap to scan the IPv4 internet (which is fun!) so the patch also includes a check for a numeric netmask and otherwise coerces it to a value of 32 - as is done if the supplied mask is numeric, but out of the proper range 0-32. patch1 makes the above changes, but patch2 does the same and also addresses some indenting in this region of TargetGroup.cc which made it harder to follow the code than I thought it should be. It looks like the file could so with some more of the same - I thought I'd just test the water with this little bit. I've tested the fixes with as many variations of host expression as I could imagine (both valid and not so) and it looks good, but another pair of eyes definitely won't hurt. Regards, jah
--- TargetGroup.cc.orig 2009-05-07 01:10:04.047375000 +0100 +++ TargetGroup.cc 2009-05-07 01:05:07.344250000 +0100 @@ -120,8 +120,8 @@ if (targets_type == IPV4_NETMASK) { currentaddr = startaddr; if (startaddr.s_addr <= endaddr.s_addr) { - ipsleft = ((unsigned long long) (endaddr.s_addr - startaddr.s_addr)) + 1; - return 0; + ipsleft = ((unsigned long long) (endaddr.s_addr - startaddr.s_addr)) + 1; + return 0; } else assert(0); @@ -182,6 +182,19 @@ if (s) { *s = '\0'; /* Make sure target_net is terminated before the /## */ s++; /* Point s at the netmask */ + unsigned l = strlen(s); + if (l == 0){ + error("Missing netmask value, must be /0 - /32 . Assuming /32 (one host)"); + s = "32"; + } else { + for ( i=0; i<l; i++){ + if (!isdigit(s[i])){ + error("Illegal netmask value, must be /0 - /32 . Assuming /32 (one host)"); + s = "32"; + break; + } + } + } } netmask = ( s ) ? atoi(s) : 32; if ((int) netmask < 0 || netmask > 32) { @@ -190,27 +203,27 @@ } for(i=0; *(hostexp + i); i++) if (isupper((int) *(hostexp +i)) || islower((int) *(hostexp +i))) { - namedhost = 1; - break; + namedhost = 1; + break; } if (netmask != 32 || namedhost) { targets_type = IPV4_NETMASK; if (!inet_pton(AF_INET, target_net, &(startaddr))) { - if ((target = gethostbyname(target_net))) { + if ((target = gethostbyname(target_net))) { int count=0; - memcpy(&(startaddr), target->h_addr_list[0], sizeof(struct in_addr)); + memcpy(&(startaddr), target->h_addr_list[0], sizeof(struct in_addr)); while (target->h_addr_list[count]) count++; if (count > 1) - error("Warning: Hostname %s resolves to %d IPs. Using %s.", target_net, count, inet_ntoa(*((struct in_addr *)target->h_addr_list[0]))); - } else { - error("Failed to resolve given hostname/IP: %s. Note that you can't use '/mask' AND '1-4,7,100-' style IP ranges", target_net); - free(hostexp); - return 1; - } - } + error("Warning: Hostname %s resolves to %d IPs. Using %s.", target_net, count, inet_ntoa(*((struct in_addr *)target->h_addr_list[0]))); + } else { + error("Failed to resolve given hostname/IP: %s. Note that you can't use '/mask' AND '1-4,7,100-' style IP ranges", target_net); + free(hostexp); + return 1; + } + } if (netmask) { unsigned long longtmp = ntohl(startaddr.s_addr); startaddr.s_addr = longtmp & (unsigned long) (0 - (1<<(32 - netmask))); @@ -224,9 +237,9 @@ } currentaddr = startaddr; if (startaddr.s_addr <= endaddr.s_addr) { - ipsleft = ((unsigned long long) (endaddr.s_addr - startaddr.s_addr)) + 1; - free(hostexp); - return 0; + ipsleft = ((unsigned long long) (endaddr.s_addr - startaddr.s_addr)) + 1; + free(hostexp); + return 0; } fprintf(stderr, "Host specification invalid"); free(hostexp); @@ -236,52 +249,53 @@ targets_type = IPV4_RANGES; i=0; - while(*++r) { - if (*r == '.' && ++i < 4) { - *r = '\0'; - addy[i] = r + 1; - } - else if (*r != '*' && *r != ',' && *r != '-' && !isdigit((int)*r)) - fatal("Invalid character in host specification. Note in particular that square brackets [] are no longer allowed. They were redundant and can simply be removed."); + while(*r) { + if (*r == '.' && ++i < 4) { + *r = '\0'; + addy[i] = r + 1; + } + else if (*r != '*' && *r != ',' && *r != '-' && !isdigit((int)*r)) { + fatal("Invalid character in host specification. Note in particular that square brackets [] are no longer allowed. They were redundant and can simply be removed."); + } + r++; } if (i != 3) fatal("Invalid target host specification: %s", target_expr); for(i=0; i < 4; i++) { - j=0; - do { - s = strchr(addy[i],','); - if (s) *s = '\0'; - if (*addy[i] == '*') { start = 0; end = 255; } - else if (*addy[i] == '-') { - start = 0; - if (*(addy[i] + 1) == '\0') end = 255; - else end = atoi(addy[i]+ 1); - } - else { - start = end = atoi(addy[i]); - if ((r = strchr(addy[i],'-')) && *(r+1) ) end = atoi(r + 1); - else if (r && !*(r+1)) end = 255; - } - /* if (o.debugging > 2) - log_write(LOG_STDOUT, "The first host is %d, and the last one is %d\n", start, end); */ - if (start < 0 || start > end || start > 255 || end > 255) - fatal("Your host specifications are illegal!"); - if (j + (end - start) > 255) - fatal("Your host specifications are illegal!"); - for(k=start; k <= end; k++) - addresses[i][j++] = k; - last[i] = j-1; - if (s) addy[i] = s + 1; - } while (s); + j=0; + do { + s = strchr(addy[i],','); + if (s) *s = '\0'; + if (*addy[i] == '*') { start = 0; end = 255; } + else if (*addy[i] == '-') { + start = 0; + if (*(addy[i] + 1) == '\0') end = 255; + else end = atoi(addy[i]+ 1); + } + else { + start = end = atoi(addy[i]); + if ((r = strchr(addy[i],'-')) && *(r+1) ) end = atoi(r + 1); + else if (r && !*(r+1)) end = 255; + } + /* if (o.debugging > 2) + log_write(LOG_STDOUT, "The first host is %d, and the last one is %d\n", start, end); */ + if (start < 0 || start > end || start > 255 || end > 255) + fatal("Your host specifications are illegal!"); + if (j + (end - start) > 255) + fatal("Your host specifications are illegal!"); + for(k=start; k <= end; k++) addresses[i][j++] = k; + last[i] = j-1; + if (s) addy[i] = s + 1; + } while (s); } } - memset((char *)current, 0, sizeof(current)); - ipsleft = (unsigned long long) (last[0] + 1) * - (unsigned long long) (last[1] + 1) * - (unsigned long long) (last[2] + 1) * - (unsigned long long) (last[3] + 1); - } - else { + memset((char *)current, 0, sizeof(current)); + ipsleft = (unsigned long long) (last[0] + 1) * + (unsigned long long) (last[1] + 1) * + (unsigned long long) (last[2] + 1) * + (unsigned long long) (last[3] + 1); + } + else { #if HAVE_IPV6 int rc = 0; assert(af == AF_INET6);
--- TargetGroup.cc.orig 2009-05-07 01:10:04.047375000 +0100 +++ TargetGroup.cc 2009-05-07 01:22:29.688000000 +0100 @@ -182,6 +182,19 @@ if (s) { *s = '\0'; /* Make sure target_net is terminated before the /## */ s++; /* Point s at the netmask */ + unsigned l = strlen(s); + if (l == 0){ + error("Missing netmask value, must be /0 - /32 . Assuming /32 (one host)"); + s = "32"; + } else { + for ( i=0; i<l; i++){ + if (!isdigit(s[i])){ + error("Illegal netmask value, must be /0 - /32 . Assuming /32 (one host)"); + s = "32"; + break; + } + } + } } netmask = ( s ) ? atoi(s) : 32; if ((int) netmask < 0 || netmask > 32) { @@ -236,13 +249,15 @@ targets_type = IPV4_RANGES; i=0; - while(*++r) { + while(*r) { if (*r == '.' && ++i < 4) { *r = '\0'; addy[i] = r + 1; } - else if (*r != '*' && *r != ',' && *r != '-' && !isdigit((int)*r)) - fatal("Invalid character in host specification. Note in particular that square brackets [] are no longer allowed. They were redundant and can simply be removed."); + else if (*r != '*' && *r != ',' && *r != '-' && !isdigit((int)*r)) { + fatal("Invalid character in host specification. Note in particular that square brackets [] are no longer allowed. They were redundant and can simply be removed."); + } + r++; } if (i != 3) fatal("Invalid target host specification: %s", target_expr);
_______________________________________________ Sent through the nmap-dev mailing list http://cgi.insecure.org/mailman/listinfo/nmap-dev Archived at http://SecLists.Org
Current thread:
- [PATCH] Prevent execution of unintended Nmap scans when invalid targets are specified. jah (May 06)
- Re: [PATCH] Prevent execution of unintended Nmap scans when invalid targets are specified. David Fifield (May 12)
- <Possible follow-ups>
- [PATCH] Prevent execution of unintended Nmap scans when invalid targets are specified. jah (May 06)