Lucene search

K
nmapDaniel MillerNMAP:FCRDNS.NSE
HistoryJul 31, 2014 - 5:34 a.m.

fcrdns NSE Script

2014-07-3105:34:19
Daniel Miller
nmap.org
118

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

10 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

0.973 High

EPSS

Percentile

99.8%

Performs a Forward-confirmed Reverse DNS lookup and reports anomalous results.

References:

Example Usage

nmap -sn -Pn --script fcrdns <target>

Script Output

Host script results:
|_fcrdns: FAIL (12.19.29.17, 12.19.20.14, 23.10.13.25)

Host script results:
|_fcrdns: PASS (37.58.100.86-static.reverse.softlayer.com)

Host script results:
| fcrdns:
|   <none>:
|     status: fail
|_    reason: No PTR record

Host script results:
| fcrdns:
|   mail.example.com:
|     status: fail
|     reason: FCRDNS mismatch
|     addresses:
|       12.19.29.17
|   mail.contoso.net:
|     status: fail
|     reason: FCRDNS mismatch
|     addresses:
|       12.19.20.14
|_      23.10.13.25

Requires


local dns = require "dns"
local ipOps = require "ipOps"
local nmap = require "nmap"
local stdnse = require "stdnse"
local string = require "string"
local table = require "table"
local tableaux = require "tableaux"

description = [[
Performs a Forward-confirmed Reverse DNS lookup and reports anomalous results.

References:
* https://en.wikipedia.org/wiki/Forward-confirmed_reverse_DNS
]]

---
-- @usage
-- nmap -sn -Pn --script fcrdns <target>
--
-- @output
-- Host script results:
-- |_fcrdns: FAIL (12.19.29.17, 12.19.20.14, 23.10.13.25)
--
-- Host script results:
-- |_fcrdns: PASS (37.58.100.86-static.reverse.softlayer.com)
--
-- Host script results:
-- | fcrdns:
-- |   <none>:
-- |     status: fail
-- |_    reason: No PTR record
--
-- Host script results:
-- | fcrdns:
-- |   mail.example.com:
-- |     status: fail
-- |     reason: FCRDNS mismatch
-- |     addresses:
-- |       12.19.29.17
-- |   mail.contoso.net:
-- |     status: fail
-- |     reason: FCRDNS mismatch
-- |     addresses:
-- |       12.19.20.14
-- |_      23.10.13.25
--
--@xmloutput
-- <table key="mail.example.com">
--   <elem key="status">fail</elem>
--   <elem key="reason">FCRDNS mismatch</elem>
--   <table key="addresses">
--     <elem>12.19.29.17</elem>
--   </table>
-- </table>
-- <table key="mail.contoso.net">
--   <elem key="status">fail</elem>
--   <elem key="reason">FCRDNS mismatch</elem>
--   <table key="addresses">
--     <elem>12.19.20.14</elem>
--     <elem>23.10.13.25</elem>
--   </table>
-- </table>

author = "Daniel Miller"

license = "Same as Nmap--See https://nmap.org/book/man-legal.html"

-- not default, because user may choose -n and expect no DNS
categories = {"discovery", "safe"}


hostrule = function(host)
  -- Every host with an IP address can be checked
  return true
end

action = function(host)
  -- Do reverse-DNS lookup of the IP
  -- Can't just use host.name because some IPs have multiple PTR records
  local status, rdns = dns.query(dns.reverse(host.ip), {dtype="PTR", retAll=true})
  if not status then
    stdnse.debug("PTR request for %s failed: %s", host.ip, rdns)
    local ret = stdnse.output_table()
    ret.status = "fail"
    ret.reason = "No PTR record"
    return {["<none>"]=ret}, "FAIL (No PTR record)"
  end

  local str_out = nil
  -- Now do forward lookup of the name(s) we got
  local names = stdnse.output_table()
  local fcrdns
  local fail_addrs = {}
  local forward_type = nmap.address_family() == "inet" and "A" or "AAAA"
  local no_record_err = string.format("No %s record", forward_type)
  table.sort(rdns)
  for _, n in ipairs(rdns) do
    local name = stdnse.output_table()
    -- assume failure, we can override when/if we succeed
    name.status = "fail"
    name.reason = "FCRDNS mismatch"
    names[n] = name

    status, fcrdns = dns.query(n, {dtype=forward_type, retAll=true})
    if not status then
      stdnse.debug("%s request for %s failed: %s", forward_type, n, fcrdns)
      name.reason = no_record_err
    else
      for _, ip in ipairs(fcrdns) do
        if ipOps.compare_ip( ip, "eq", host.ip) then
          name.status = "pass"
          name.reason = nil
          str_out = string.format("PASS (%s)", n)
        end
      end
      name.addresses = fcrdns
      if name.status == "fail" then
        -- keep a list of unique addresses for short output
        for _, a in ipairs(name.addresses) do
          fail_addrs[a] = true
        end
      end
    end
  end

  if nmap.verbosity() > 0 then
    -- use default structured output for verbosity
    str_out = nil
  elseif str_out == nil then
    -- we failed, and need to format a short output string
    fail_addrs = tableaux.keys(fail_addrs)
    if #fail_addrs > 0 then
      table.sort(fail_addrs)
      str_out = string.format("FAIL (%s)", table.concat(fail_addrs, ", "))
    else
      str_out = string.format("FAIL (%s)", no_record_err)
    end
  end

  return names, str_out
end

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

10 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

0.973 High

EPSS

Percentile

99.8%

Related for NMAP:FCRDNS.NSE