1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
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
|