Nmap Development mailing list archives

Re: NSEC Enumeration script


From: David Fifield <david () bamsoftware com>
Date: Thu, 24 Mar 2011 21:49:40 -0700

On Tue, Mar 15, 2011 at 08:02:17PM +0100, John Bond wrote:
On 15 March 2011 17:59, David Fifield <david () bamsoftware com> wrote:
On Tue, Mar 15, 2011 at 08:33:11AM +0100, John Bond wrote:
Patrik Karlsson:

In essence, I think that the following change should be performed:
- return rPkt.dnssec,true, rPkt
+ return true, rPkt

This way it's more standardized and does not return redundant information.

 rPkt.dnssec is redundant if you are using the raw packet but if you
just want an answer then rPkt.dnssec could be usefull. what should the
library return if the query is successful but there is no dnssec?

I agree with Patrik here. I don't want to waste a return value just for
dnssec. Also, just indicating "dnssec" isn't saying much, it basically
means "NSEC or RRSIG or DNSKEY or DS or NSEC3". Anyone who actually
needs to use that specific information will need to dig into the packet,
as we are doing. It's fine if dns.query in normal mode (not retPkt mode)
doesn't return all the information.

Yes the more i thought about it the more i came to the same
conclusion.  the issue i was having is i wasn't sure what to return in
the status if you ask for dnssec but it is not available.  however dns
returns the answer with no error which is the best thing for this
library as well so all good.  And with that in mind the change seemed
pretty simple almost too simple :) also i tested your changes and they
all worked fine, cheers john

Thanks, I added your latest changes. In the development branch I'm
trying to understand the rest of the new code in dns.lua. I've deleted
decoders and answerFetchers that we don't use yet. I have a few
remaining specific questions:

What is going on here? What do the numbers 255, 46, 47, 48, and 50 mean?
Can you provide references to specifications that define them? This
piece of code could use a comment to say what it's doing.

@@ -536,13 +565,55 @@ function findNiceAnswer(dtype, dec, retAll)
    if (#dec.answers > 0) then
       if answerFetcher[dtype] then 
          return answerFetcher[dtype](dec, retAll)
+      elseif dtype == 255 then
+         local tmp_types, tmp_answers = {}, {} 
+         for _, answer in ipairs(dec.answers) do
+            if answerFetcher[answer.dtype] and answer.dtype ~= 46 and answer.dtype ~= 47 and answer.dtype ~= 48 and 
answer.dtype ~= 50 then 
+               if #tmp_types > 1 then
+                  local type_test = false
+                  for _,v in ipairs(tmp_types) do
+                      if v == answer.dtype then 
+                         type_test = true 
+                      end
+                   end
+                   if type_test == false then 
+                      table.insert(tmp_types,answer.dtype) 
+                   end
+                else 
+                   table.insert(tmp_types,answer.dtype) 
+                end
+             end
+          end
+          for _, tmp_type in ipairs(tmp_types) do
+             local tmp_status, tmp_ans = answerFetcher[tmp_type](dec, retAll) 
+             if tmp_status then 
+                if type(tmp_ans) == "table" then
+                   for _,tmp_an in ipairs(tmp_ans) do
+                      table.insert(tmp_answers, {tmp_type, tmp_an}) 
+                   end
+                else
+                   table.insert(tmp_answers,{tmp_type , tmp_ans})
+                end
+              end
+          end
+          return true, tmp_answers
       else 

To me it looks like this was a typo in the first place. I think it
should have been 'type(dtype) == "nil"', not 'type(dtype) or "nil"'. Why
did you need to add the extra "or dtype"?

          stdnse.print_debug(1, "dns.findNiceAnswer() does not have an answerFetcher for dtype %s",
-            (type(dtype) == 'string' and dtype) or type(dtype) or "nil")
+            (type(dtype) == 'string' and dtype) or dtype or type(dtype) or "nil")
          return false, "Unable to handle response"

How is this being used? Where does it make sense to have findNiceAnswer
return false but also do the extra work to fetch an NSEC record? What
makes NSEC special in this block of code?

    elseif (dec.flags.RC3 and dec.flags.RC4) then
-      return false, "No Such Name"
+      if #dec.auth > 0 then
+         for _, authrr in ipairs(dec.auth) do
+            if authrr.NSEC then
+               local _, answer = answerFetcher[types.NSEC](dec, retAll)
+               return false, answer
+            end
+         end
+            return false, "No Such Name"
+      else
+         return false, "No Such Name"
+      end
    else

Why did you have to define any ANY (type 255) decoder? Is this
compatible with other potential uses of ANY outside of DNSSEC?

@@ -994,6 +1169,22 @@ decoder[types.MX] =
       _, entry.MX.server = decStr(data, np)
    end
 
+-- Decodes ANY record, puts it in <code>entry.ANY</code>.
+-- <code>entry.ANY</code> has the fields <code>prio</code>,
+-- <code>weight</code>, <code>port</code> and 
+-- <code>target</code>.
+-- @param entry RR in packet.
+-- @param data Complete encoded DNS packet.
+-- @param pos Position in packet after RR.
+decoder[types.ANY] =
+  function(entry, data, pos)
+    local np = pos - #entry.data
+    local _
+    entry.ANY = {}
+    np, entry.ANY.prio, entry.ANY.weight, entry.ANY.port = bin.unpack(">S>S>S", data, np)
+    np, entry.ANY.target = decStr(data, np)
+  end
+
 -- Decodes SRV record, puts it in <code>entry.SRV</code>.

David Fifield
_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://seclists.org/nmap-dev/

Current thread: