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: