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
|