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
|
local datafiles = require "datafiles"
local nmap = require "nmap"
local shortport = require "shortport"
local stdnse = require "stdnse"
description = [[
Compares the detected service on a port against the expected service for that
port number (e.g. ssh on 22, http on 80) and reports deviations. The script
requires that a version scan has been run in order to be able to discover what
service is actually running on each port.
]]
---
-- @usage
-- nmap --script unusual-port <ip>
--
-- @output
-- 23/tcp open ssh OpenSSH 5.8p1 Debian 7ubuntu1 (protocol 2.0)
-- |_unusual-port: ssh unexpected on port tcp/23
-- 25/tcp open smtp Postfix smtpd
--
author = "Patrik Karlsson"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = { "safe" }
local svc_table
portrule = function()
local status
status, svc_table = datafiles.parse_services()
if not status then
return false --Can't check if we don't have a table!
end
return true
end
hostrule = function() return true end
-- the hostrule is only needed to warn
hostaction = function(host)
local port, state = nil, "open"
local is_version_scan = false
-- iterate over ports and check whether name_confidence > 3 this would
-- suggest that a version scan has been run
for _, proto in ipairs({"tcp", "udp"}) do
repeat
port = nmap.get_ports(host, port, proto, state)
if ( port and port.version.name_confidence > 3 ) then
is_version_scan = true
break
end
until( not(port) )
end
-- if no version scan has been run, warn the user as the script requires a
-- version scan in order to work.
if ( not(is_version_scan) ) then
return stdnse.format_output(true, "WARNING: this script depends on Nmap's service/version detection (-sV)")
end
end
portchecks = {
['tcp'] = {
[113] = function(host, port) return ( port.service == "ident" ) end,
[445] = function(host, port) return ( port.service == "netbios-ssn" ) end,
[587] = function(host, port) return ( port.service == "smtp" ) end,
[593] = function(host, port) return ( port.service == "ncacn_http" ) end,
[636] = function(host, port) return ( port.service == "ldapssl" ) end,
[3268] = function(host, port) return ( port.service == "ldap" ) end,
},
['udp'] = {
[5353] = function(host, port) return ( port.service == "mdns" ) end,
}
}
servicechecks = {
['http'] = function(host, port)
local service = port.service
port.service = "unknown"
local status = shortport.http(host, port)
port.service = service
return status
end,
-- accept msrpc on any port for now, we might want to limit it to certain
-- port ranges in the future.
['msrpc'] = function(host, port) return true end,
-- accept ncacn_http on any port for now, we might want to limit it to
-- certain port ranges in the future.
['ncacn_http'] = function(host, port) return true end,
}
portaction = function(host, port)
local ok = false
if ( port.version.name_confidence <= 3 ) then
return
end
if ( portchecks[port.protocol][port.number] ) then
ok = portchecks[port.protocol][port.number](host, port)
end
if ( not(ok) and servicechecks[port.service] ) then
ok = servicechecks[port.service](host, port)
end
if ( not(ok) and port.service and
( port.service == svc_table[port.protocol][port.number] or
"unknown" == svc_table[port.protocol][port.number] or
not(svc_table[port.protocol][port.number]) ) ) then
ok = true
end
if ( not(ok) ) then
return ("%s unexpected on port %s/%d"):format(port.service, port.protocol, port.number)
end
end
local Actions = {
hostrule = hostaction,
portrule = portaction
}
-- execute the action function corresponding to the current rule
action = function(...) return Actions[SCRIPT_TYPE](...) end
|