@@ -10,7 +10,7 @@ Its work is pretty simple:
10
10
11
11
---
12
12
-- @usage
13
- -- nmap -sV --script vulners <target>
13
+ -- nmap -sV --script vulners [--script-args mincvss=<arg_val>] <target>
14
14
--
15
15
-- @output
16
16
--
@@ -36,12 +36,13 @@ local json = require "json"
36
36
local string = require " string"
37
37
local table = require " table"
38
38
39
- local api_version = " 1.1"
39
+ local api_version = " 1.2"
40
+ local mincvss = nmap .registry .args .mincvss and tonumber (nmap .registry .args .mincvss ) or 0.0
40
41
41
42
42
43
portrule = function (host , port )
43
- local vers = port .version
44
- return vers ~= nil and vers .version ~= nil
44
+ local vers = port .version
45
+ return vers ~= nil and vers .version ~= nil
45
46
end
46
47
47
48
51
52
-- @param vulns a table with the parsed json response from the vulners server
52
53
--
53
54
function make_links (vulns )
54
- local output_str = " "
55
- local is_exploit = false
56
- local cvss_score = " "
55
+ local output_str = " "
56
+ local is_exploit = false
57
+ local cvss_score = " "
57
58
58
- -- NOTE[gmedian]: data.search is a "list" already, so just use table.sort with a custom compare function
59
- -- However, for the future it might be wiser to create a copy rather than do it in-place
59
+ -- NOTE[gmedian]: data.search is a "list" already, so just use table.sort with a custom compare function
60
+ -- However, for the future it might be wiser to create a copy rather than do it in-place
60
61
61
- local vulns_result = {}
62
- for _ , v in ipairs (vulns .data .search ) do
63
- table.insert (vulns_result , v )
64
- end
62
+ local vulns_result = {}
63
+ for _ , v in ipairs (vulns .data .search ) do
64
+ table.insert (vulns_result , v )
65
+ end
65
66
66
67
-- Sort the acquired vulns by the CVSS score
67
- table.sort (vulns_result , function (a , b )
68
- return a ._source .cvss .score > b ._source .cvss .score
69
- end
70
- )
71
-
72
- for _ , vuln in ipairs (vulns_result ) do
73
- -- Mark the exploits out
74
- is_exploit = vuln ._source .bulletinFamily :lower () == " exploit"
75
-
76
- -- Sometimes it might happen, so check the score availability
77
- cvss_score = vuln ._source .cvss and (" \t\t " .. vuln ._source .cvss .score ) or " "
78
- output_str = string.format (" %s\n\t %s" , output_str , vuln ._source .id .. cvss_score .. ' \t\t https://vulners.com/' .. vuln ._source .type .. ' /' .. vuln ._source .id .. (is_exploit and ' \t\t *EXPLOIT*' or ' ' ))
68
+ table.sort (vulns_result , function (a , b )
69
+ return a ._source .cvss .score > b ._source .cvss .score
70
+ end
71
+ )
72
+
73
+ for _ , vuln in ipairs (vulns_result ) do
74
+ -- Mark the exploits out
75
+ is_exploit = vuln ._source .bulletinFamily :lower () == " exploit"
76
+
77
+ -- Sometimes it might happen, so check the score availability
78
+ cvss_score = vuln ._source .cvss and (type (vuln ._source .cvss .score ) == " number" ) and (vuln ._source .cvss .score ) or " "
79
+
80
+ -- NOTE[gmedian]: exploits seem to have cvss == 0, so print them anyway
81
+ if is_exploit or (cvss_score ~= " " and mincvss <= tonumber (cvss_score )) then
82
+ output_str = string.format (" %s\n\t %s" , output_str , vuln ._source .id .. " \t\t " .. cvss_score .. ' \t\t https://vulners.com/' .. vuln ._source .type .. ' /' .. vuln ._source .id .. (is_exploit and ' \t\t *EXPLOIT*' or ' ' ))
79
83
end
80
-
81
- return output_str
84
+ end
85
+
86
+ return output_str
82
87
end
83
88
84
89
90
95
-- @param type string, the type query argument
91
96
--
92
97
function get_results (what , vers , type )
93
- local v_host = " vulners.com"
94
- local v_port = 443
95
- local response , path
96
- local status , error
97
- local vulns
98
- local option = {header = {}}
99
-
100
- option [' header' ][' User-Agent' ] = string.format (' Vulners NMAP Plugin %s' , api_version )
101
-
102
- path = ' /api/v3/burp/software/' .. ' ?software=' .. what .. ' &version=' .. vers .. ' &type=' .. type
103
-
104
- response = http .get (v_host , v_port , path , option )
105
-
106
- status = response .status
107
- if status == nil then
108
- -- Something went really wrong out there
109
- -- According to the NSE way we will die silently rather than spam user with error messages
110
- return " "
111
- elseif status == 418 then
112
- -- Too many requests
113
- return " You are doing it too fast. Lower the rate or contact isox AT vulners DOT com."
114
- elseif status ~= 200 then
115
- -- Again just die silently
116
- return " "
117
- end
98
+ local v_host = " vulners.com"
99
+ local v_port = 443
100
+ local response , path
101
+ local status , error
102
+ local vulns
103
+ local option = {header = {}}
118
104
119
- status , vulns = json . parse ( response . body )
105
+ option [ ' header ' ][ ' User-Agent ' ] = string.format ( ' Vulners NMAP Plugin %s ' , api_version )
120
106
121
- if status == true then
122
- if vulns .result == " OK" then
123
- return make_links (vulns )
124
- end
125
- end
107
+ path = ' /api/v3/burp/software/' .. ' ?software=' .. what .. ' &version=' .. vers .. ' &type=' .. type
108
+
109
+ response = http .get (v_host , v_port , path , option )
126
110
111
+ status = response .status
112
+ if status == nil then
113
+ -- Something went really wrong out there
114
+ -- According to the NSE way we will die silently rather than spam user with error messages
127
115
return " "
116
+ elseif status ~= 200 then
117
+ -- Again just die silently
118
+ return " "
119
+ end
120
+
121
+ status , vulns = json .parse (response .body )
122
+
123
+ if status == true then
124
+ if vulns .result == " OK" then
125
+ return make_links (vulns )
126
+ end
127
+ end
128
+
129
+ return " "
128
130
end
129
131
130
132
137
139
-- @param version string, the software version
138
140
--
139
141
function get_vulns_by_software (software , version )
140
- return get_results (software , version , " software" )
142
+ return get_results (software , version , " software" )
141
143
end
142
144
143
145
@@ -152,61 +154,61 @@ end
152
154
-- @param cpe string, the given cpe
153
155
--
154
156
function get_vulns_by_cpe (cpe )
155
- local vers
156
- local vers_regexp = " :([%d%.%-%_]+)([^:]*)$"
157
- local output_str = " "
158
-
159
- -- TODO[gmedian]: add check for cpe:/a as we might be interested in software rather than in OS (cpe:/o) and hardware (cpe:/h)
160
- -- TODO[gmedian]: work not with the LAST part but simply with the THIRD one (according to cpe doc it must be version)
157
+ local vers
158
+ local vers_regexp = " :([%d%.%-%_]+)([^:]*)$"
159
+ local output_str = " "
160
+
161
+ -- TODO[gmedian]: add check for cpe:/a as we might be interested in software rather than in OS (cpe:/o) and hardware (cpe:/h)
162
+ -- TODO[gmedian]: work not with the LAST part but simply with the THIRD one (according to cpe doc it must be version)
161
163
162
- -- NOTE[gmedian]: take only the numeric part of the version
163
- _ , _ , vers = cpe :find (vers_regexp )
164
+ -- NOTE[gmedian]: take only the numeric part of the version
165
+ _ , _ , vers = cpe :find (vers_regexp )
164
166
165
167
166
- if not vers then
167
- return " "
168
- end
168
+ if not vers then
169
+ return " "
170
+ end
169
171
170
- output_str = get_results (cpe , vers , " cpe" )
172
+ output_str = get_results (cpe , vers , " cpe" )
171
173
172
- if output_str == " " then
173
- local new_cpe
174
+ if output_str == " " then
175
+ local new_cpe
174
176
175
- new_cpe = cpe :gsub (vers_regexp , " :%1:%2" )
176
- output_str = get_results (new_cpe , vers , " cpe" )
177
- end
178
-
179
- return output_str
177
+ new_cpe = cpe :gsub (vers_regexp , " :%1:%2" )
178
+ output_str = get_results (new_cpe , vers , " cpe" )
179
+ end
180
+
181
+ return output_str
180
182
end
181
183
182
184
183
185
action = function (host , port )
184
- local tab = {}
185
- local changed = false
186
- local response
187
- local output_str = " "
188
-
189
- for i , cpe in ipairs (port .version .cpe ) do
190
- output_str = get_vulns_by_cpe (cpe , port .version )
191
- if output_str ~= " " then
192
- tab [cpe ] = output_str
193
- changed = true
194
- end
195
- end
196
-
197
- -- NOTE[gmedian]: issue request for type=software, but only when nothing is found so far
198
- if not changed then
199
- local vendor_version = port .version .product .. " " .. port .version .version
200
- output_str = get_vulns_by_software (port .version .product , port .version .version )
201
- if output_str ~= " " then
202
- tab [vendor_version ] = output_str
203
- changed = true
204
- end
205
- end
206
-
207
- if (not changed ) then
208
- return
209
- end
210
- return tab
186
+ local tab = {}
187
+ local changed = false
188
+ local response
189
+ local output_str = " "
190
+
191
+ for i , cpe in ipairs (port .version .cpe ) do
192
+ output_str = get_vulns_by_cpe (cpe , port .version )
193
+ if output_str ~= " " then
194
+ tab [cpe ] = output_str
195
+ changed = true
196
+ end
197
+ end
198
+
199
+ -- NOTE[gmedian]: issue request for type=software, but only when nothing is found so far
200
+ if not changed then
201
+ local vendor_version = port .version .product .. " " .. port .version .version
202
+ output_str = get_vulns_by_software (port .version .product , port .version .version )
203
+ if output_str ~= " " then
204
+ tab [vendor_version ] = output_str
205
+ changed = true
206
+ end
207
+ end
208
+
209
+ if (not changed ) then
210
+ return
211
+ end
212
+ return tab
211
213
end
212
214
0 commit comments